• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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