libnftnl 1.2.6
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
37static int
38nftnl_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
72static const void *
73nftnl_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
104static 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
129static int
130nftnl_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
174static void
175nftnl_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
199static 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
211static 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
223static int
224nftnl_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
269struct 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};