libnftnl  1.2.9
nat.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * (C) 2012-2014 Pablo Neira Ayuso <pablo@netfilter.org>
4  * (C) 2012 Intel Corporation
5  *
6  * Authors:
7  * Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
8  */
9 
10 #include "internal.h"
11 
12 #include <stdio.h>
13 #include <stdint.h>
14 #include <limits.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <arpa/inet.h>
18 #include <libmnl/libmnl.h>
19 #include <linux/netfilter/nf_tables.h>
20 #include <libnftnl/expr.h>
21 #include <libnftnl/rule.h>
22 
24  enum nft_registers sreg_addr_min;
25  enum nft_registers sreg_addr_max;
26  enum nft_registers sreg_proto_min;
27  enum nft_registers sreg_proto_max;
28  int family;
29  enum nft_nat_types type;
30  uint32_t flags;
31 };
32 
33 static int
34 nftnl_expr_nat_set(struct nftnl_expr *e, uint16_t type,
35  const void *data, uint32_t data_len)
36 {
37  struct nftnl_expr_nat *nat = nftnl_expr_data(e);
38 
39  switch(type) {
40  case NFTNL_EXPR_NAT_TYPE:
41  memcpy(&nat->type, data, data_len);
42  break;
43  case NFTNL_EXPR_NAT_FAMILY:
44  memcpy(&nat->family, data, data_len);
45  break;
46  case NFTNL_EXPR_NAT_REG_ADDR_MIN:
47  memcpy(&nat->sreg_addr_min, data, data_len);
48  break;
49  case NFTNL_EXPR_NAT_REG_ADDR_MAX:
50  memcpy(&nat->sreg_addr_max, data, data_len);
51  break;
52  case NFTNL_EXPR_NAT_REG_PROTO_MIN:
53  memcpy(&nat->sreg_proto_min, data, data_len);
54  break;
55  case NFTNL_EXPR_NAT_REG_PROTO_MAX:
56  memcpy(&nat->sreg_proto_max, data, data_len);
57  break;
58  case NFTNL_EXPR_NAT_FLAGS:
59  memcpy(&nat->flags, data, data_len);
60  break;
61  }
62 
63  return 0;
64 }
65 
66 static const void *
67 nftnl_expr_nat_get(const struct nftnl_expr *e, uint16_t type,
68  uint32_t *data_len)
69 {
70  struct nftnl_expr_nat *nat = nftnl_expr_data(e);
71 
72  switch(type) {
73  case NFTNL_EXPR_NAT_TYPE:
74  *data_len = sizeof(nat->type);
75  return &nat->type;
76  case NFTNL_EXPR_NAT_FAMILY:
77  *data_len = sizeof(nat->family);
78  return &nat->family;
79  case NFTNL_EXPR_NAT_REG_ADDR_MIN:
80  *data_len = sizeof(nat->sreg_addr_min);
81  return &nat->sreg_addr_min;
82  case NFTNL_EXPR_NAT_REG_ADDR_MAX:
83  *data_len = sizeof(nat->sreg_addr_max);
84  return &nat->sreg_addr_max;
85  case NFTNL_EXPR_NAT_REG_PROTO_MIN:
86  *data_len = sizeof(nat->sreg_proto_min);
87  return &nat->sreg_proto_min;
88  case NFTNL_EXPR_NAT_REG_PROTO_MAX:
89  *data_len = sizeof(nat->sreg_proto_max);
90  return &nat->sreg_proto_max;
91  case NFTNL_EXPR_NAT_FLAGS:
92  *data_len = sizeof(nat->flags);
93  return &nat->flags;
94  }
95  return NULL;
96 }
97 
98 static int nftnl_expr_nat_cb(const struct nlattr *attr, void *data)
99 {
100  const struct nlattr **tb = data;
101  int type = mnl_attr_get_type(attr);
102 
103  if (mnl_attr_type_valid(attr, NFTA_NAT_MAX) < 0)
104  return MNL_CB_OK;
105 
106  switch(type) {
107  case NFTA_NAT_TYPE:
108  case NFTA_NAT_FAMILY:
109  case NFTA_NAT_REG_ADDR_MIN:
110  case NFTA_NAT_REG_ADDR_MAX:
111  case NFTA_NAT_REG_PROTO_MIN:
112  case NFTA_NAT_REG_PROTO_MAX:
113  case NFTA_NAT_FLAGS:
114  if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
115  abi_breakage();
116  break;
117  }
118 
119  tb[type] = attr;
120  return MNL_CB_OK;
121 }
122 
123 static int
124 nftnl_expr_nat_parse(struct nftnl_expr *e, struct nlattr *attr)
125 {
126  struct nftnl_expr_nat *nat = nftnl_expr_data(e);
127  struct nlattr *tb[NFTA_NAT_MAX+1] = {};
128 
129  if (mnl_attr_parse_nested(attr, nftnl_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 << NFTNL_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 << NFTNL_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 << NFTNL_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 << NFTNL_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 << NFTNL_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 << NFTNL_EXPR_NAT_REG_PROTO_MAX);
159  }
160  if (tb[NFTA_NAT_FLAGS]) {
161  nat->flags = ntohl(mnl_attr_get_u32(tb[NFTA_NAT_FLAGS]));
162  e->flags |= (1 << NFTNL_EXPR_NAT_FLAGS);
163  }
164 
165  return 0;
166 }
167 
168 static void
169 nftnl_expr_nat_build(struct nlmsghdr *nlh, const struct nftnl_expr *e)
170 {
171  struct nftnl_expr_nat *nat = nftnl_expr_data(e);
172 
173  if (e->flags & (1 << NFTNL_EXPR_NAT_TYPE))
174  mnl_attr_put_u32(nlh, NFTA_NAT_TYPE, htonl(nat->type));
175  if (e->flags & (1 << NFTNL_EXPR_NAT_FAMILY))
176  mnl_attr_put_u32(nlh, NFTA_NAT_FAMILY, htonl(nat->family));
177  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MIN))
178  mnl_attr_put_u32(nlh, NFTA_NAT_REG_ADDR_MIN,
179  htonl(nat->sreg_addr_min));
180  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MAX))
181  mnl_attr_put_u32(nlh, NFTA_NAT_REG_ADDR_MAX,
182  htonl(nat->sreg_addr_max));
183  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MIN))
184  mnl_attr_put_u32(nlh, NFTA_NAT_REG_PROTO_MIN,
185  htonl(nat->sreg_proto_min));
186  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MAX))
187  mnl_attr_put_u32(nlh, NFTA_NAT_REG_PROTO_MAX,
188  htonl(nat->sreg_proto_max));
189  if (e->flags & (1 << NFTNL_EXPR_NAT_FLAGS))
190  mnl_attr_put_u32(nlh, NFTA_NAT_FLAGS, htonl(nat->flags));
191 }
192 
193 static inline const char *nat2str(uint16_t nat)
194 {
195  switch (nat) {
196  case NFT_NAT_SNAT:
197  return "snat";
198  case NFT_NAT_DNAT:
199  return "dnat";
200  default:
201  return "unknown";
202  }
203 }
204 
205 static int
206 nftnl_expr_nat_snprintf(char *buf, size_t remain,
207  uint32_t flags, const struct nftnl_expr *e)
208 {
209  struct nftnl_expr_nat *nat = nftnl_expr_data(e);
210  int offset = 0, ret = 0;
211 
212  ret = snprintf(buf, remain, "%s ", nat2str(nat->type));
213  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
214 
215  ret = snprintf(buf + offset, remain, "%s ",
216  nftnl_family2str(nat->family));
217  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
218 
219  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MIN)) {
220  ret = snprintf(buf + offset, remain,
221  "addr_min reg %u ", nat->sreg_addr_min);
222  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
223  }
224 
225  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MAX)) {
226  ret = snprintf(buf + offset, remain,
227  "addr_max reg %u ", nat->sreg_addr_max);
228  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
229  }
230 
231  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MIN)) {
232  ret = snprintf(buf + offset, remain,
233  "proto_min reg %u ", nat->sreg_proto_min);
234  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
235  }
236 
237  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MAX)) {
238  ret = snprintf(buf + offset, remain,
239  "proto_max reg %u ", nat->sreg_proto_max);
240  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
241  }
242 
243  if (e->flags & (1 << NFTNL_EXPR_NAT_FLAGS)) {
244  ret = snprintf(buf + offset, remain, "flags 0x%x ", nat->flags);
245  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
246  }
247 
248  return offset;
249 }
250 
251 static struct attr_policy nat_attr_policy[__NFTNL_EXPR_NAT_MAX] = {
252  [NFTNL_EXPR_NAT_TYPE] = { .maxlen = sizeof(uint32_t) },
253  [NFTNL_EXPR_NAT_FAMILY] = { .maxlen = sizeof(uint32_t) },
254  [NFTNL_EXPR_NAT_REG_ADDR_MIN] = { .maxlen = sizeof(uint32_t) },
255  [NFTNL_EXPR_NAT_REG_ADDR_MAX] = { .maxlen = sizeof(uint32_t) },
256  [NFTNL_EXPR_NAT_REG_PROTO_MIN] = { .maxlen = sizeof(uint32_t) },
257  [NFTNL_EXPR_NAT_REG_PROTO_MAX] = { .maxlen = sizeof(uint32_t) },
258  [NFTNL_EXPR_NAT_FLAGS] = { .maxlen = sizeof(uint32_t) },
259 };
260 
261 struct expr_ops expr_ops_nat = {
262  .name = "nat",
263  .alloc_len = sizeof(struct nftnl_expr_nat),
264  .nftnl_max_attr = __NFTNL_EXPR_NAT_MAX - 1,
265  .attr_policy = nat_attr_policy,
266  .set = nftnl_expr_nat_set,
267  .get = nftnl_expr_nat_get,
268  .parse = nftnl_expr_nat_parse,
269  .build = nftnl_expr_nat_build,
270  .output = nftnl_expr_nat_snprintf,
271 };