libnftnl  1.2.3
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  memcpy(&nat->type, data, sizeof(nat->type));
46  break;
47  case NFTNL_EXPR_NAT_FAMILY:
48  memcpy(&nat->family, data, sizeof(nat->family));
49  break;
50  case NFTNL_EXPR_NAT_REG_ADDR_MIN:
51  memcpy(&nat->sreg_addr_min, data, sizeof(nat->sreg_addr_min));
52  break;
53  case NFTNL_EXPR_NAT_REG_ADDR_MAX:
54  memcpy(&nat->sreg_addr_max, data, sizeof(nat->sreg_addr_max));
55  break;
56  case NFTNL_EXPR_NAT_REG_PROTO_MIN:
57  memcpy(&nat->sreg_proto_min, data, sizeof(nat->sreg_proto_min));
58  break;
59  case NFTNL_EXPR_NAT_REG_PROTO_MAX:
60  memcpy(&nat->sreg_proto_max, data, sizeof(nat->sreg_proto_max));
61  break;
62  case NFTNL_EXPR_NAT_FLAGS:
63  memcpy(&nat->flags, data, sizeof(nat->flags));
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
224 nftnl_expr_nat_snprintf(char *buf, size_t remain,
225  uint32_t flags, const struct nftnl_expr *e)
226 {
227  struct nftnl_expr_nat *nat = nftnl_expr_data(e);
228  int offset = 0, ret = 0;
229 
230  ret = snprintf(buf, remain, "%s ", nat2str(nat->type));
231  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
232 
233  ret = snprintf(buf + offset, remain, "%s ",
234  nftnl_family2str(nat->family));
235  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
236 
237  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MIN)) {
238  ret = snprintf(buf + offset, remain,
239  "addr_min reg %u ", nat->sreg_addr_min);
240  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
241  }
242 
243  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_ADDR_MAX)) {
244  ret = snprintf(buf + offset, remain,
245  "addr_max reg %u ", nat->sreg_addr_max);
246  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
247  }
248 
249  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MIN)) {
250  ret = snprintf(buf + offset, remain,
251  "proto_min reg %u ", nat->sreg_proto_min);
252  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
253  }
254 
255  if (e->flags & (1 << NFTNL_EXPR_NAT_REG_PROTO_MAX)) {
256  ret = snprintf(buf + offset, remain,
257  "proto_max reg %u ", nat->sreg_proto_max);
258  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
259  }
260 
261  if (e->flags & (1 << NFTNL_EXPR_NAT_FLAGS)) {
262  ret = snprintf(buf + offset, remain, "flags 0x%x ", nat->flags);
263  SNPRINTF_BUFFER_SIZE(ret, remain, offset);
264  }
265 
266  return offset;
267 }
268 
269 struct expr_ops expr_ops_nat = {
270  .name = "nat",
271  .alloc_len = sizeof(struct nftnl_expr_nat),
272  .max_attr = NFTA_NAT_MAX,
273  .set = nftnl_expr_nat_set,
274  .get = nftnl_expr_nat_get,
275  .parse = nftnl_expr_nat_parse,
276  .build = nftnl_expr_nat_build,
277  .output = nftnl_expr_nat_snprintf,
278 };
nftnl_expr_nat
Definition: nat.c:27