libnftnl  1.0.2
nat.c
1 /*
2  * (C) 2012 Intel Corporation
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published
6  * by the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * Authors:
10  * Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
11  */
12 
13 #include "internal.h"
14 
15 #include <stdio.h>
16 #include <stdint.h>
17 #include <limits.h>
18 #include <string.h>
19 #include <errno.h>
20 #include <arpa/inet.h>
21 #include <libmnl/libmnl.h>
22 #include <linux/netfilter/nf_tables.h>
23 #include <libnftnl/expr.h>
24 #include <libnftnl/rule.h>
25 #include "expr_ops.h"
26 
27 struct nft_expr_nat {
28  enum nft_registers sreg_addr_min;
29  enum nft_registers sreg_addr_max;
30  enum nft_registers sreg_proto_min;
31  enum nft_registers sreg_proto_max;
32  int family;
33  enum nft_nat_types type;
34 };
35 
36 static int
37 nft_rule_expr_nat_set(struct nft_rule_expr *e, uint16_t type,
38  const void *data, uint32_t data_len)
39 {
40  struct nft_expr_nat *nat = nft_expr_data(e);
41 
42  switch(type) {
43  case NFT_EXPR_NAT_TYPE:
44  nat->type = *((uint32_t *)data);
45  break;
46  case NFT_EXPR_NAT_FAMILY:
47  nat->family = *((uint32_t *)data);
48  break;
49  case NFT_EXPR_NAT_REG_ADDR_MIN:
50  nat->sreg_addr_min = *((uint32_t *)data);
51  break;
52  case NFT_EXPR_NAT_REG_ADDR_MAX:
53  nat->sreg_addr_max = *((uint32_t *)data);
54  break;
55  case NFT_EXPR_NAT_REG_PROTO_MIN:
56  nat->sreg_proto_min = *((uint32_t *)data);
57  break;
58  case NFT_EXPR_NAT_REG_PROTO_MAX:
59  nat->sreg_proto_max = *((uint32_t *)data);
60  break;
61  default:
62  return -1;
63  }
64 
65  return 0;
66 }
67 
68 static const void *
69 nft_rule_expr_nat_get(const struct nft_rule_expr *e, uint16_t type,
70  uint32_t *data_len)
71 {
72  struct nft_expr_nat *nat = nft_expr_data(e);
73 
74  switch(type) {
75  case NFT_EXPR_NAT_TYPE:
76  *data_len = sizeof(nat->type);
77  return &nat->type;
78  case NFT_EXPR_NAT_FAMILY:
79  *data_len = sizeof(nat->family);
80  return &nat->family;
81  case NFT_EXPR_NAT_REG_ADDR_MIN:
82  *data_len = sizeof(nat->sreg_addr_min);
83  return &nat->sreg_addr_min;
84  case NFT_EXPR_NAT_REG_ADDR_MAX:
85  *data_len = sizeof(nat->sreg_addr_max);
86  return &nat->sreg_addr_max;
87  case NFT_EXPR_NAT_REG_PROTO_MIN:
88  *data_len = sizeof(nat->sreg_proto_min);
89  return &nat->sreg_proto_min;
90  case NFT_EXPR_NAT_REG_PROTO_MAX:
91  *data_len = sizeof(nat->sreg_proto_max);
92  return &nat->sreg_proto_max;
93  }
94  return NULL;
95 }
96 
97 static int nft_rule_expr_nat_cb(const struct nlattr *attr, void *data)
98 {
99  const struct nlattr **tb = data;
100  int type = mnl_attr_get_type(attr);
101 
102  if (mnl_attr_type_valid(attr, NFTA_NAT_MAX) < 0)
103  return MNL_CB_OK;
104 
105  switch(type) {
106  case NFTA_NAT_TYPE:
107  case NFTA_NAT_FAMILY:
108  case NFTA_NAT_REG_ADDR_MIN:
109  case NFTA_NAT_REG_ADDR_MAX:
110  case NFTA_NAT_REG_PROTO_MIN:
111  case NFTA_NAT_REG_PROTO_MAX:
112  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
113  perror("mnl_attr_validate");
114  return MNL_CB_ERROR;
115  }
116  break;
117  }
118 
119  tb[type] = attr;
120  return MNL_CB_OK;
121 }
122 
123 static int
124 nft_rule_expr_nat_parse(struct nft_rule_expr *e, struct nlattr *attr)
125 {
126  struct nft_expr_nat *nat = nft_expr_data(e);
127  struct nlattr *tb[NFTA_NAT_MAX+1] = {};
128 
129  if (mnl_attr_parse_nested(attr, nft_rule_expr_nat_cb, tb) < 0)
130  return -1;
131 
132  if (tb[NFTA_NAT_TYPE]) {
133  nat->type = ntohl(mnl_attr_get_u32(tb[NFTA_NAT_TYPE]));
134  e->flags |= (1 << NFT_EXPR_NAT_TYPE);
135  }
136  if (tb[NFTA_NAT_FAMILY]) {
137  nat->family = ntohl(mnl_attr_get_u32(tb[NFTA_NAT_FAMILY]));
138  e->flags |= (1 << NFT_EXPR_NAT_FAMILY);
139  }
140  if (tb[NFTA_NAT_REG_ADDR_MIN]) {
141  nat->sreg_addr_min =
142  ntohl(mnl_attr_get_u32(tb[NFTA_NAT_REG_ADDR_MIN]));
143  e->flags |= (1 << NFT_EXPR_NAT_REG_ADDR_MIN);
144  }
145  if (tb[NFTA_NAT_REG_ADDR_MAX]) {
146  nat->sreg_addr_max =
147  ntohl(mnl_attr_get_u32(tb[NFTA_NAT_REG_ADDR_MAX]));
148  e->flags |= (1 << NFT_EXPR_NAT_REG_ADDR_MAX);
149  }
150  if (tb[NFTA_NAT_REG_PROTO_MIN]) {
151  nat->sreg_proto_min =
152  ntohl(mnl_attr_get_u32(tb[NFTA_NAT_REG_PROTO_MIN]));
153  e->flags |= (1 << NFT_EXPR_NAT_REG_PROTO_MIN);
154  }
155  if (tb[NFTA_NAT_REG_PROTO_MAX]) {
156  nat->sreg_proto_max =
157  ntohl(mnl_attr_get_u32(tb[NFTA_NAT_REG_PROTO_MAX]));
158  e->flags |= (1 << NFT_EXPR_NAT_REG_PROTO_MAX);
159  }
160 
161  return 0;
162 }
163 
164 static void
165 nft_rule_expr_nat_build(struct nlmsghdr *nlh, struct nft_rule_expr *e)
166 {
167  struct nft_expr_nat *nat = nft_expr_data(e);
168 
169  if (e->flags & (1 << NFT_EXPR_NAT_TYPE))
170  mnl_attr_put_u32(nlh, NFTA_NAT_TYPE, htonl(nat->type));
171  if (e->flags & (1 << NFT_EXPR_NAT_FAMILY))
172  mnl_attr_put_u32(nlh, NFTA_NAT_FAMILY, htonl(nat->family));
173  if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MIN))
174  mnl_attr_put_u32(nlh, NFTA_NAT_REG_ADDR_MIN,
175  htonl(nat->sreg_addr_min));
176  if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MAX))
177  mnl_attr_put_u32(nlh, NFTA_NAT_REG_ADDR_MAX,
178  htonl(nat->sreg_addr_max));
179  if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MIN))
180  mnl_attr_put_u32(nlh, NFTA_NAT_REG_PROTO_MIN,
181  htonl(nat->sreg_proto_min));
182  if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MAX))
183  mnl_attr_put_u32(nlh, NFTA_NAT_REG_PROTO_MAX,
184  htonl(nat->sreg_proto_max));
185 }
186 
187 static inline const char *nft_nat2str(uint16_t nat)
188 {
189  switch (nat) {
190  case NFT_NAT_SNAT:
191  return "snat";
192  case NFT_NAT_DNAT:
193  return "dnat";
194  default:
195  return "unknown";
196  }
197 }
198 
199 static inline int nft_str2nat(const char *nat)
200 {
201  if (strcmp(nat, "snat") == 0)
202  return NFT_NAT_SNAT;
203  else if (strcmp(nat, "dnat") == 0)
204  return NFT_NAT_DNAT;
205  else {
206  errno = EINVAL;
207  return -1;
208  }
209 }
210 
211 static int nft_rule_expr_nat_json_parse(struct nft_rule_expr *e, json_t *root,
212  struct nft_parse_err *err)
213 {
214 #ifdef JSON_PARSING
215  const char *nat_type, *family_str;
216  uint32_t reg;
217  int val32;
218 
219  nat_type = nft_jansson_parse_str(root, "nat_type", err);
220  if (nat_type == NULL)
221  return -1;
222 
223  val32 = nft_str2nat(nat_type);
224  if (val32 < 0)
225  return -1;
226 
227  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_TYPE, val32);
228 
229  family_str = nft_jansson_parse_str(root, "family", err);
230  if (family_str == NULL)
231  return -1;
232 
233  val32 = nft_str2family(family_str);
234  if (val32 < 0)
235  return -1;
236 
237  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_FAMILY, val32);
238 
239  if (nft_jansson_parse_reg(root, "sreg_addr_min", NFT_TYPE_U32,
240  &reg, err) == 0)
241  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MIN, reg);
242 
243  if (nft_jansson_parse_reg(root, "sreg_addr_max", NFT_TYPE_U32,
244  &reg, err) == 0)
245  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MAX, reg);
246 
247  if (nft_jansson_parse_reg(root, "sreg_proto_min", NFT_TYPE_U32,
248  &reg, err) == 0)
249  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_PROTO_MIN, reg);
250 
251  if (nft_jansson_parse_reg(root, "sreg_proto_max", NFT_TYPE_U32,
252  &reg, err) == 0)
253  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_PROTO_MAX, reg);
254 
255  return 0;
256 #else
257  errno = EOPNOTSUPP;
258  return -1;
259 #endif
260 }
261 
262 static int nft_rule_expr_nat_xml_parse(struct nft_rule_expr *e, mxml_node_t *tree,
263  struct nft_parse_err *err)
264 {
265 #ifdef XML_PARSING
266  const char *nat_type;
267  uint32_t family, nat_type_value;
268  uint32_t reg_addr_min, reg_addr_max;
269  uint32_t reg_proto_min, reg_proto_max;
270 
271  nat_type = nft_mxml_str_parse(tree, "type", MXML_DESCEND_FIRST,
272  NFT_XML_MAND, err);
273  if (nat_type == NULL)
274  return -1;
275 
276  nat_type_value = nft_str2nat(nat_type);
277  if (nat_type_value < 0)
278  return -1;
279  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_TYPE, nat_type_value);
280 
281  family = nft_mxml_family_parse(tree, "family", MXML_DESCEND_FIRST,
282  NFT_XML_MAND, err);
283  if (family < 0) {
284  mxmlDelete(tree);
285  return -1;
286  }
287  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_FAMILY, family);
288 
289  if (nft_mxml_reg_parse(tree, "sreg_addr_min", &reg_addr_min,
290  MXML_DESCEND, NFT_XML_MAND, err) == 0)
291  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MIN, reg_addr_min);
292 
293  if (nft_mxml_reg_parse(tree, "sreg_addr_max", &reg_addr_max,
294  MXML_DESCEND, NFT_XML_MAND, err) == 0)
295  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_ADDR_MAX, reg_addr_max);
296 
297  if (nft_mxml_reg_parse(tree, "sreg_proto_min", &reg_proto_min,
298  MXML_DESCEND, NFT_XML_MAND, err) == 0)
299  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_PROTO_MIN, reg_proto_min);
300 
301  if (nft_mxml_reg_parse(tree, "sreg_proto_max", &reg_proto_max,
302  MXML_DESCEND, NFT_XML_MAND, err) == 0)
303  nft_rule_expr_set_u32(e, NFT_EXPR_NAT_REG_PROTO_MAX, reg_proto_max);
304 
305  return 0;
306 #else
307  errno = EOPNOTSUPP;
308  return -1;
309 #endif
310 }
311 
312 static int
313 nft_rule_expr_nat_snprintf_json(char *buf, size_t size,
314  struct nft_rule_expr *e)
315 {
316  struct nft_expr_nat *nat = nft_expr_data(e);
317  int len = size, offset = 0, ret = 0;
318 
319  ret = snprintf(buf, len, "\"nat_type\":\"%s\",",
320  nft_nat2str(nat->type));
321  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
322 
323  ret = snprintf(buf+offset, len, "\"family\":\"%s\",",
324  nft_family2str(nat->family));
325  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
326 
327  if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MIN)) {
328  ret = snprintf(buf+offset, len, "\"sreg_addr_min\":%u,"
329  "\"sreg_addr_max\":%u,",
330  nat->sreg_addr_min, nat->sreg_addr_max);
331  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
332  }
333 
334  if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MIN)) {
335  ret = snprintf(buf+offset, len, "\"sreg_proto_min\":%u,"
336  "\"sreg_proto_max\":%u",
337  nat->sreg_proto_min, nat->sreg_proto_max);
338  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
339  }
340 
341  return offset;
342 }
343 
344 
345 static int
346 nft_rule_expr_nat_snprintf_xml(char *buf, size_t size,
347  struct nft_rule_expr *e)
348 {
349  struct nft_expr_nat *nat = nft_expr_data(e);
350  int len = size, offset = 0, ret = 0;
351 
352  ret = snprintf(buf, len, "<type>%s</type>", nft_nat2str(nat->type));
353  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
354 
355  ret = snprintf(buf+offset, len, "<family>%s</family>",
356  nft_family2str(nat->family));
357  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
358 
359  if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MIN)) {
360  ret = snprintf(buf+offset, len,
361  "<sreg_addr_min>%u</sreg_addr_min>"
362  "<sreg_addr_max>%u</sreg_addr_max>",
363  nat->sreg_addr_min, nat->sreg_addr_max);
364  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
365  }
366 
367  if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MIN)) {
368  ret = snprintf(buf+offset, len,
369  "<sreg_proto_min>%u</sreg_proto_min>"
370  "<sreg_proto_max>%u</sreg_proto_max>",
371  nat->sreg_proto_min, nat->sreg_proto_max);
372  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
373  }
374 
375  return offset;
376 }
377 
378 static int
379 nft_rule_expr_nat_snprintf_default(char *buf, size_t size,
380  struct nft_rule_expr *e)
381 {
382  struct nft_expr_nat *nat = nft_expr_data(e);
383  int len = size, offset = 0, ret = 0;
384 
385  ret = snprintf(buf, len, "%s ", nft_nat2str(nat->type));
386  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
387 
388  ret = snprintf(buf+offset, len, "%s ", nft_family2str(nat->family));
389  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
390 
391  if (e->flags & (1 << NFT_EXPR_NAT_REG_ADDR_MIN)) {
392  ret = snprintf(buf+offset, len,
393  "addr_min reg %u addr_max reg %u ",
394  nat->sreg_addr_min, nat->sreg_addr_max);
395  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
396  }
397 
398  if (e->flags & (1 << NFT_EXPR_NAT_REG_PROTO_MIN)) {
399  ret = snprintf(buf+offset, len,
400  "proto_min reg %u proto_max reg %u ",
401  nat->sreg_proto_min, nat->sreg_proto_max);
402  SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
403  }
404 
405  return offset;
406 }
407 
408 static int
409 nft_rule_expr_nat_snprintf(char *buf, size_t size, uint32_t type,
410  uint32_t flags, struct nft_rule_expr *e)
411 {
412  switch (type) {
413  case NFT_OUTPUT_DEFAULT:
414  return nft_rule_expr_nat_snprintf_default(buf, size, e);
415  case NFT_OUTPUT_XML:
416  return nft_rule_expr_nat_snprintf_xml(buf, size, e);
417  case NFT_OUTPUT_JSON:
418  return nft_rule_expr_nat_snprintf_json(buf, size, e);
419  default:
420  break;
421  }
422  return -1;
423 }
424 
425 struct expr_ops expr_ops_nat = {
426  .name = "nat",
427  .alloc_len = sizeof(struct nft_expr_nat),
428  .max_attr = NFTA_NAT_MAX,
429  .set = nft_rule_expr_nat_set,
430  .get = nft_rule_expr_nat_get,
431  .parse = nft_rule_expr_nat_parse,
432  .build = nft_rule_expr_nat_build,
433  .snprintf = nft_rule_expr_nat_snprintf,
434  .xml_parse = nft_rule_expr_nat_xml_parse,
435  .json_parse = nft_rule_expr_nat_json_parse,
436 };
437 
438 static void __init expr_nat_init(void)
439 {
440  nft_expr_ops_register(&expr_ops_nat);
441 }