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