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
33static int
34nftnl_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
66static const void *
67nftnl_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
98static 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
123static int
124nftnl_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
168static void
169nftnl_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
193static 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
205static int
206nftnl_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
251static 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
261struct 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};