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