1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2016 Magnus Öberg <[email protected]>
4 */
5
6 /**
7 * @ingroup act
8 * @defgroup act_nat NAT
9 *
10 * @{
11 */
12
13 #include "nl-default.h"
14
15 #include <netlink/netlink.h>
16 #include <netlink/attr.h>
17 #include <netlink/utils.h>
18 #include <netlink/route/act/nat.h>
19 #include <netlink/route/tc.h>
20
21 #include "tc-api.h"
22
23 static struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
24 [TCA_NAT_PARMS] = { .minlen = sizeof(struct tc_nat) },
25 };
26
27 /**
28 * nat operations
29 */
30
nat_msg_parser(struct rtnl_tc * tc,void * data)31 static int nat_msg_parser(struct rtnl_tc *tc, void *data)
32 {
33 struct tc_nat *nat = data;
34 struct nlattr *tb[TCA_NAT_MAX + 1];
35 int err;
36
37 err = tca_parse(tb, TCA_NAT_MAX, tc, nat_policy);
38 if (err < 0)
39 return err;
40
41 if (!tb[TCA_NAT_PARMS])
42 return -NLE_MISSING_ATTR;
43
44 nla_memcpy(nat, tb[TCA_NAT_PARMS], sizeof(*nat));
45
46 return NLE_SUCCESS;
47 }
48
nat_free_data(struct rtnl_tc * tc,void * data)49 static void nat_free_data(struct rtnl_tc *tc, void *data)
50 {
51 }
52
nat_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)53 static int nat_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
54 {
55 struct tc_nat *nat = data;
56
57 if (!nat)
58 return -NLE_OBJ_NOTFOUND;
59
60 NLA_PUT(msg, TCA_NAT_PARMS, sizeof(*nat), nat);
61
62 return NLE_SUCCESS;
63
64 nla_put_failure:
65 return -NLE_NOMEM;
66 }
67
nat_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)68 static void nat_dump_line(struct rtnl_tc *tc, void *data,
69 struct nl_dump_params *p)
70 {
71 struct tc_nat *nat = data;
72 char buf[32];
73 uint32_t mask;
74 int pfx = 0;
75
76 if (!nat)
77 return;
78
79 if (nat->flags & TCA_NAT_FLAG_EGRESS)
80 nl_dump(p, " egress");
81 else
82 nl_dump(p, " ingress");
83
84 mask = nat->mask;
85 while (mask > 0) {
86 mask = mask >> 1;
87 pfx++;
88 }
89
90 inet_ntop(AF_INET, &nat->old_addr, buf, sizeof(buf));
91 nl_dump(p, " %s", buf);
92 if (pfx < 32)
93 nl_dump(p, "/%d", pfx);
94
95 inet_ntop(AF_INET, &nat->new_addr, buf, sizeof(buf));
96 nl_dump(p, " %s", buf);
97 if (pfx < 32)
98 nl_dump(p, "/%d", pfx);
99 }
100
101 /**
102 * @name Attribute Modifications
103 * @{
104 */
105
106 /**
107 * Set old IPv4 address on a netlink NAT action object
108 * @arg act Action object
109 * @arg addr Binary IPv4 address in host byte order
110 *
111 * @return 0 on success or negative error code in case of an error.
112 */
rtnl_nat_set_old_addr(struct rtnl_act * act,in_addr_t addr)113 int rtnl_nat_set_old_addr(struct rtnl_act *act, in_addr_t addr)
114 {
115 struct tc_nat *nat;
116
117 if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
118 return -NLE_NOMEM;
119
120 nat->old_addr = addr;
121
122 return NLE_SUCCESS;
123 }
124
rtnl_nat_get_old_addr(struct rtnl_act * act,in_addr_t * addr)125 int rtnl_nat_get_old_addr(struct rtnl_act *act, in_addr_t *addr)
126 {
127 struct tc_nat *nat;
128
129 if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
130 return -NLE_NOATTR;
131
132 *addr = nat->old_addr;
133
134 return NLE_SUCCESS;
135 }
136
137 /**
138 * Set new IPv4 address on a netlink NAT action object
139 * @arg act Action object
140 * @arg addr Binary IPv4 address in host byte order
141 *
142 * @return 0 on success or negative error code in case of an error.
143 */
rtnl_nat_set_new_addr(struct rtnl_act * act,in_addr_t addr)144 int rtnl_nat_set_new_addr(struct rtnl_act *act, in_addr_t addr)
145 {
146 struct tc_nat *nat;
147
148 if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
149 return -NLE_NOMEM;
150
151 nat->new_addr = addr;
152
153 return NLE_SUCCESS;
154 }
155
rtnl_nat_get_new_addr(struct rtnl_act * act,in_addr_t * addr)156 int rtnl_nat_get_new_addr(struct rtnl_act *act, in_addr_t *addr)
157 {
158 struct tc_nat *nat;
159
160 if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
161 return -NLE_NOATTR;
162
163 *addr = nat->new_addr;
164
165 return NLE_SUCCESS;
166 }
167
168 /**
169 * Set IPv4 address mask on a netlink NAT action object
170 * @arg act Action object
171 * @arg mask IPv4 address mask
172 *
173 * @return 0 on success or negative error code in case of an error.
174 */
rtnl_nat_set_mask(struct rtnl_act * act,in_addr_t bitmask)175 int rtnl_nat_set_mask(struct rtnl_act *act, in_addr_t bitmask)
176 {
177 struct tc_nat *nat;
178
179 if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
180 return -NLE_NOMEM;
181
182 nat->mask = bitmask;
183
184 return NLE_SUCCESS;
185 }
186
rtnl_nat_get_mask(struct rtnl_act * act,in_addr_t * bitmask)187 int rtnl_nat_get_mask(struct rtnl_act *act, in_addr_t *bitmask)
188 {
189 struct tc_nat *nat;
190
191 if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
192 return -NLE_NOATTR;
193
194 *bitmask = nat->mask;
195
196 return NLE_SUCCESS;
197 }
198
199 /**
200 * Set flags for a netlink NAT action object
201 * @arg act Action object
202 * @arg flags TCA_NAT_FLAG_* flags.
203 *
204 * Currently only TCA_NAT_FLAG_EGRESS is defined. Selects NAT on
205 * egress/IP src if set, ingress/IP dst otherwise.
206 *
207 * @return 0 on success or negative error code in case of an error.
208 */
rtnl_nat_set_flags(struct rtnl_act * act,uint32_t flags)209 int rtnl_nat_set_flags(struct rtnl_act *act, uint32_t flags)
210 {
211 struct tc_nat *nat;
212
213 if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
214 return -NLE_NOMEM;
215
216 nat->flags = flags;
217
218 return NLE_SUCCESS;
219 }
220
rtnl_nat_get_flags(struct rtnl_act * act,uint32_t * flags)221 int rtnl_nat_get_flags(struct rtnl_act *act, uint32_t *flags)
222 {
223 struct tc_nat *nat;
224
225 if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
226 return -NLE_NOATTR;
227
228 *flags = nat->flags;
229
230 return NLE_SUCCESS;
231 }
232
rtnl_nat_set_action(struct rtnl_act * act,int action)233 int rtnl_nat_set_action(struct rtnl_act *act, int action)
234 {
235 struct tc_nat *nat;
236
237 if (!(nat = (struct tc_nat *)rtnl_tc_data(TC_CAST(act))))
238 return -NLE_NOMEM;
239
240 if (action < TC_ACT_UNSPEC)
241 return -NLE_INVAL;
242
243 nat->action = action;
244
245 return NLE_SUCCESS;
246 }
247
rtnl_nat_get_action(struct rtnl_act * act,int * action)248 int rtnl_nat_get_action(struct rtnl_act *act, int *action)
249 {
250 struct tc_nat *nat;
251
252 if (!(nat = (struct tc_nat *)rtnl_tc_data_peek(TC_CAST(act))))
253 return -NLE_NOATTR;
254
255 *action = nat->action;
256
257 return NLE_SUCCESS;
258 }
259
260 /**
261 * @}
262 */
263
264 static struct rtnl_tc_ops nat_ops = {
265 .to_kind = "nat",
266 .to_type = RTNL_TC_TYPE_ACT,
267 .to_size = sizeof(struct tc_nat),
268 .to_msg_parser = nat_msg_parser,
269 .to_free_data = nat_free_data,
270 .to_clone = NULL,
271 .to_msg_fill = nat_msg_fill,
272 .to_dump = {
273 [NL_DUMP_LINE] = nat_dump_line,
274 },
275 };
276
nat_init(void)277 static void _nl_init nat_init(void)
278 {
279 rtnl_tc_register(&nat_ops);
280 }
281
nat_exit(void)282 static void _nl_exit nat_exit(void)
283 {
284 rtnl_tc_unregister(&nat_ops);
285 }
286
287 /**
288 * @}
289 */
290