libnftnl  1.0.8
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, const 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_export(char *buf, size_t size,
279  const struct nftnl_expr *e, int type)
280 {
281  struct nftnl_expr_nat *nat = nftnl_expr_data(e);
282  NFTNL_BUF_INIT(b, buf, size);
283 
284  if (e->flags & (1 << NFTNL_EXPR_NAT_TYPE))
285  nftnl_buf_str(&b, type, nat2str(nat->type), NAT_TYPE);
286  if (e->flags & (1 << NFTNL_EXPR_NAT_FAMILY))
287  nftnl_buf_str(&b, type, nftnl_family2str(nat->family), FAMILY);
288  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MIN))
289  nftnl_buf_u32(&b, type, nat->sreg_addr_min, SREG_ADDR_MIN);
290  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MAX))
291  nftnl_buf_u32(&b, type, nat->sreg_addr_max, SREG_ADDR_MAX);
292  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MIN))
293  nftnl_buf_u32(&b, type, nat->sreg_proto_min, SREG_PROTO_MIN);
294  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MAX))
295  nftnl_buf_u32(&b, type, nat->sreg_proto_max, SREG_PROTO_MAX);
296  if (e->flags & (1 << NFTNL_EXPR_NAT_FLAGS))
297  nftnl_buf_u32(&b, type, nat->flags, FLAGS);
298 
299  return nftnl_buf_done(&b);
300 }
301 
302 static int
303 nftnl_expr_nat_snprintf_default(char *buf, size_t size,
304  const struct nftnl_expr *e)
305 {
306  struct nftnl_expr_nat *nat = nftnl_expr_data(e);
307  int remain = size, offset = 0, ret = 0;
308 
309  ret = snprintf(buf, remain, "%s ", nat2str(nat->type));
310  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
311 
312  ret = snprintf(buf + offset, remain, "%s ",
313  nftnl_family2str(nat->family));
314  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
315 
316  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MIN)) {
317  ret = snprintf(buf + offset, remain,
318  "addr_min reg %u addr_max reg %u ",
319  nat->sreg_addr_min, nat->sreg_addr_max);
320  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
321  }
322 
323  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MIN)) {
324  ret = snprintf(buf + offset, remain,
325  "proto_min reg %u proto_max reg %u ",
326  nat->sreg_proto_min, nat->sreg_proto_max);
327  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
328  }
329 
330  if (e->flags & (1 << NFTNL_EXPR_NAT_FLAGS)) {
331  ret = snprintf(buf + offset, remain, "flags %u", nat->flags);
332  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
333  }
334 
335  return offset;
336 }
337 
338 static int
339 nftnl_expr_nat_snprintf(char *buf, size_t size, uint32_t type,
340  uint32_t flags, const struct nftnl_expr *e)
341 {
342  switch (type) {
343  case NFTNL_OUTPUT_DEFAULT:
344  return nftnl_expr_nat_snprintf_default(buf, size, e);
345  case NFTNL_OUTPUT_XML:
346  case NFTNL_OUTPUT_JSON:
347  return nftnl_expr_nat_export(buf, size, e, type);
348  default:
349  break;
350  }
351  return -1;
352 }
353 
354 static bool nftnl_expr_nat_cmp(const struct nftnl_expr *e1,
355  const struct nftnl_expr *e2)
356 {
357  struct nftnl_expr_nat *n1 = nftnl_expr_data(e1);
358  struct nftnl_expr_nat *n2 = nftnl_expr_data(e2);
359  bool eq = true;
360  if (e1->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MIN))
361  eq &= (n1->sreg_addr_min == n2->sreg_addr_min);
362  if (e1->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MAX))
363  eq &= (n1->sreg_addr_max == n2->sreg_addr_max);
364  if (e1->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MIN))
365  eq &= (n1->sreg_proto_min == n2->sreg_proto_min);
366  if (e1->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MAX))
367  eq &= (n1->sreg_proto_max == n2->sreg_proto_max);
368  if (e1->flags & (1 << NFTNL_EXPR_NAT_FAMILY))
369  eq &= (n1->family == n2->family);
370  if (e1->flags & (1 << NFTNL_EXPR_NAT_TYPE))
371  eq &= (n1->type == n2->type);
372  if (e1->flags & (1 << NFTNL_EXPR_NAT_FLAGS))
373  eq &= (n1->flags == n2->flags);
374 
375  return eq;
376 }
377 
378 struct expr_ops expr_ops_nat = {
379  .name = "nat",
380  .alloc_len = sizeof(struct nftnl_expr_nat),
381  .max_attr = NFTA_NAT_MAX,
382  .cmp = nftnl_expr_nat_cmp,
383  .set = nftnl_expr_nat_set,
384  .get = nftnl_expr_nat_get,
385  .parse = nftnl_expr_nat_parse,
386  .build = nftnl_expr_nat_build,
387  .snprintf = nftnl_expr_nat_snprintf,
388  .json_parse = nftnl_expr_nat_json_parse,
389 };