xref: /aosp_15_r20/external/libnl/lib/netfilter/exp_obj.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2008 Thomas Graf <[email protected]>
4  * Copyright (c) 2007 Philip Craig <[email protected]>
5  * Copyright (c) 2007 Secure Computing Corporation
6  * Copyright (c) 2012 Rich Fought <[email protected]>
7  */
8 
9 #include "nl-default.h"
10 
11 #include <sys/types.h>
12 
13 #include <linux/netfilter/nfnetlink_conntrack.h>
14 #include <linux/netfilter/nf_conntrack_common.h>
15 
16 #include <linux/netfilter/nf_conntrack_tcp.h>
17 
18 #include <netlink/netfilter/nfnl.h>
19 #include <netlink/netfilter/exp.h>
20 
21 #include "nl-priv-dynamic-core/object-api.h"
22 #include "nl-netfilter.h"
23 #include "nl-priv-dynamic-core/nl-core.h"
24 
25 // The 32-bit attribute mask in the common object header isn't
26 // big enough to handle all attributes of an expectation.  So
27 // we'll for sure specify optional attributes + parent attributes
28 // that are required for valid object comparison.  Comparison of
29 // these parent attributes will include nested attributes.
30 
31 /** @cond SKIP */
32 #define EXP_ATTR_FAMILY			(1UL << 0) // 8-bit
33 #define EXP_ATTR_TIMEOUT		(1UL << 1) // 32-bit
34 #define EXP_ATTR_ID			(1UL << 2) // 32-bit
35 #define EXP_ATTR_HELPER_NAME		(1UL << 3) // string
36 #define EXP_ATTR_ZONE			(1UL << 4) // 16-bit
37 #define EXP_ATTR_FLAGS			(1UL << 5) // 32-bit
38 #define EXP_ATTR_CLASS			(1UL << 6) // 32-bit
39 #define EXP_ATTR_FN			(1UL << 7) // String
40 // Tuples
41 #define EXP_ATTR_EXPECT_IP_SRC		(1UL << 8)
42 #define EXP_ATTR_EXPECT_IP_DST		(1UL << 9)
43 #define EXP_ATTR_EXPECT_L4PROTO_NUM	(1UL << 10)
44 #define EXP_ATTR_EXPECT_L4PROTO_PORTS	(1UL << 11)
45 #define EXP_ATTR_EXPECT_L4PROTO_ICMP	(1UL << 12)
46 #define EXP_ATTR_MASTER_IP_SRC		(1UL << 13)
47 #define EXP_ATTR_MASTER_IP_DST		(1UL << 14)
48 #define EXP_ATTR_MASTER_L4PROTO_NUM	(1UL << 15)
49 #define EXP_ATTR_MASTER_L4PROTO_PORTS	(1UL << 16)
50 #define EXP_ATTR_MASTER_L4PROTO_ICMP	(1UL << 17)
51 #define EXP_ATTR_MASK_IP_SRC		(1UL << 18)
52 #define EXP_ATTR_MASK_IP_DST		(1UL << 19)
53 #define EXP_ATTR_MASK_L4PROTO_NUM	(1UL << 20)
54 #define EXP_ATTR_MASK_L4PROTO_PORTS	(1UL << 21)
55 #define EXP_ATTR_MASK_L4PROTO_ICMP	(1UL << 22)
56 #define EXP_ATTR_NAT_IP_SRC		(1UL << 23)
57 #define EXP_ATTR_NAT_IP_DST		(1UL << 24)
58 #define EXP_ATTR_NAT_L4PROTO_NUM	(1UL << 25)
59 #define EXP_ATTR_NAT_L4PROTO_PORTS	(1UL << 26)
60 #define EXP_ATTR_NAT_L4PROTO_ICMP	(1UL << 27)
61 #define EXP_ATTR_NAT_DIR		(1UL << 28)
62 /** @endcond */
63 
exp_free_data(struct nl_object * c)64 static void exp_free_data(struct nl_object *c)
65 {
66 	struct nfnl_exp *exp = (struct nfnl_exp *) c;
67 
68 	if (exp == NULL)
69 		return;
70 
71 	nl_addr_put(exp->exp_expect.src);
72 	nl_addr_put(exp->exp_expect.dst);
73 	nl_addr_put(exp->exp_master.src);
74 	nl_addr_put(exp->exp_master.dst);
75 	nl_addr_put(exp->exp_mask.src);
76 	nl_addr_put(exp->exp_mask.dst);
77 	nl_addr_put(exp->exp_nat.src);
78 	nl_addr_put(exp->exp_nat.dst);
79 
80 	free(exp->exp_fn);
81 	free(exp->exp_helper_name);
82 }
83 
exp_clone(struct nl_object * _dst,struct nl_object * _src)84 static int exp_clone(struct nl_object *_dst, struct nl_object *_src)
85 {
86 	struct nfnl_exp *dst = (struct nfnl_exp *) _dst;
87 	struct nfnl_exp *src = (struct nfnl_exp *) _src;
88 	struct nl_addr *addr;
89 
90 	dst->exp_helper_name = NULL;
91 	dst->exp_fn = NULL;
92 	dst->exp_expect.src = NULL;
93 	dst->exp_expect.dst = NULL;
94 	dst->exp_master.src = NULL;
95 	dst->exp_master.dst = NULL;
96 	dst->exp_mask.src = NULL;
97 	dst->exp_mask.dst = NULL;
98 	dst->exp_nat.src = NULL;
99 	dst->exp_nat.dst = NULL;
100 
101 	if (src->exp_expect.src) {
102 		addr = nl_addr_clone(src->exp_expect.src);
103 		if (!addr)
104 			return -NLE_NOMEM;
105 		dst->exp_expect.src = addr;
106 	}
107 
108 	if (src->exp_expect.dst) {
109 		addr = nl_addr_clone(src->exp_expect.dst);
110 		if (!addr)
111 			return -NLE_NOMEM;
112 		dst->exp_expect.dst = addr;
113 	}
114 
115 	if (src->exp_master.src) {
116 		addr = nl_addr_clone(src->exp_master.src);
117 		if (!addr)
118 			return -NLE_NOMEM;
119 		dst->exp_master.src = addr;
120 	}
121 
122 	if (src->exp_master.dst) {
123 		addr = nl_addr_clone(src->exp_master.dst);
124 		if (!addr)
125 			return -NLE_NOMEM;
126 		dst->exp_master.dst = addr;
127 	}
128 
129 	if (src->exp_mask.src) {
130 		addr = nl_addr_clone(src->exp_mask.src);
131 		if (!addr)
132 			return -NLE_NOMEM;
133 		dst->exp_mask.src = addr;
134 	}
135 
136 	if (src->exp_mask.dst) {
137 		addr = nl_addr_clone(src->exp_mask.dst);
138 		if (!addr)
139 			return -NLE_NOMEM;
140 		dst->exp_mask.dst = addr;
141 	}
142 
143 	if (src->exp_nat.src) {
144 		addr = nl_addr_clone(src->exp_nat.src);
145 		if (!addr)
146 			return -NLE_NOMEM;
147 		dst->exp_nat.src = addr;
148 	}
149 
150 	if (src->exp_nat.dst) {
151 		addr = nl_addr_clone(src->exp_nat.dst);
152 		if (!addr)
153 			return -NLE_NOMEM;
154 		dst->exp_nat.dst = addr;
155 	}
156 
157 	if (src->exp_fn)
158 		dst->exp_fn = strdup(src->exp_fn);
159 
160 	if (src->exp_helper_name)
161 		dst->exp_helper_name = strdup(src->exp_helper_name);
162 
163 	return 0;
164 }
165 
dump_addr(struct nl_dump_params * p,struct nl_addr * addr,int port)166 static void dump_addr(struct nl_dump_params *p, struct nl_addr *addr, int port)
167 {
168 	char buf[64];
169 
170 	if (addr)
171 		nl_dump(p, "%s", nl_addr2str(addr, buf, sizeof(buf)));
172 
173 	if (port)
174 		nl_dump(p, ":%u ", port);
175 	else if (addr)
176 		nl_dump(p, " ");
177 }
178 
dump_icmp(struct nl_dump_params * p,struct nfnl_exp * exp,int tuple)179 static void dump_icmp(struct nl_dump_params *p, struct nfnl_exp *exp, int tuple)
180 {
181 	if (nfnl_exp_test_icmp(exp, tuple)) {
182 
183 		nl_dump(p, "icmp type %d ", nfnl_exp_get_icmp_type(exp, tuple));
184 
185 		nl_dump(p, "code %d ", nfnl_exp_get_icmp_code(exp, tuple));
186 
187 		nl_dump(p, "id %d ", nfnl_exp_get_icmp_id(exp, tuple));
188 	}
189 }
190 
exp_dump_tuples(struct nfnl_exp * exp,struct nl_dump_params * p)191 static void exp_dump_tuples(struct nfnl_exp *exp, struct nl_dump_params *p)
192 {
193 	struct nl_addr *tuple_src, *tuple_dst;
194 	int tuple_sport, tuple_dport;
195 	int i = 0;
196 	char buf[64];
197 
198 	for (i = NFNL_EXP_TUPLE_EXPECT; i < NFNL_EXP_TUPLE_MAX; i++) {
199 		tuple_src = NULL;
200 		tuple_dst = NULL;
201 		tuple_sport = 0;
202 		tuple_dport = 0;
203 
204 		// Test needed for NAT case
205 		if (nfnl_exp_test_src(exp, i))
206 			tuple_src = nfnl_exp_get_src(exp, i);
207 		if (nfnl_exp_test_dst(exp, i))
208 			tuple_dst = nfnl_exp_get_dst(exp, i);
209 
210 		// Don't have tests for individual ports/types/codes/ids,
211 		if (nfnl_exp_test_l4protonum(exp, i)) {
212 			nl_dump(p, "%s ",
213 				nl_ip_proto2str(nfnl_exp_get_l4protonum(exp, i), buf, sizeof(buf)));
214 		}
215 
216 		if (nfnl_exp_test_ports(exp, i)) {
217 			tuple_sport = nfnl_exp_get_src_port(exp, i);
218 			tuple_dport = nfnl_exp_get_dst_port(exp, i);
219 		}
220 
221 		dump_addr(p, tuple_src, tuple_sport);
222 		dump_addr(p, tuple_dst, tuple_dport);
223 		dump_icmp(p, exp, 0);
224 	}
225 
226 	if (nfnl_exp_test_nat_dir(exp))
227 		nl_dump(p, "nat dir %u ", exp->exp_nat_dir);
228 
229 }
230 
231 /* FIXME Compatible with /proc/net/nf_conntrack */
exp_dump_line(struct nl_object * a,struct nl_dump_params * p)232 static void exp_dump_line(struct nl_object *a, struct nl_dump_params *p)
233 {
234 	struct nfnl_exp *exp = (struct nfnl_exp *) a;
235 
236 	nl_new_line(p);
237 
238 	exp_dump_tuples(exp, p);
239 
240 	nl_dump(p, "\n");
241 }
242 
exp_dump_details(struct nl_object * a,struct nl_dump_params * p)243 static void exp_dump_details(struct nl_object *a, struct nl_dump_params *p)
244 {
245 	struct nfnl_exp *exp = (struct nfnl_exp *) a;
246 	char buf[64];
247 	int fp = 0;
248 
249 	exp_dump_line(a, p);
250 
251 	nl_dump(p, "    id 0x%x ", exp->exp_id);
252 	nl_dump_line(p, "family %s ",
253 		nl_af2str(exp->exp_family, buf, sizeof(buf)));
254 
255 	if (nfnl_exp_test_timeout(exp)) {
256 		uint64_t timeout_ms = nfnl_exp_get_timeout(exp) * 1000UL;
257 		nl_dump(p, "timeout %s ",
258 			nl_msec2str(timeout_ms, buf, sizeof(buf)));
259 	}
260 
261 	if (nfnl_exp_test_helper_name(exp))
262 		nl_dump(p, "helper %s ", exp->exp_helper_name);
263 
264 	if (nfnl_exp_test_fn(exp))
265 		nl_dump(p, "fn %s ", exp->exp_fn);
266 
267 	if (nfnl_exp_test_class(exp))
268 		nl_dump(p, "class %u ", nfnl_exp_get_class(exp));
269 
270 	if (nfnl_exp_test_zone(exp))
271 		nl_dump(p, "zone %u ", nfnl_exp_get_zone(exp));
272 
273 	if (nfnl_exp_test_flags(exp))
274 		nl_dump(p, "<");
275 #define PRINT_FLAG(str) \
276 	{ nl_dump(p, "%s%s", fp++ ? "," : "", (str)); }
277 
278 	if (exp->exp_flags & NF_CT_EXPECT_PERMANENT)
279 		PRINT_FLAG("PERMANENT");
280 	if (exp->exp_flags & NF_CT_EXPECT_INACTIVE)
281 		PRINT_FLAG("INACTIVE");
282 	if (exp->exp_flags & NF_CT_EXPECT_USERSPACE)
283 		PRINT_FLAG("USERSPACE");
284 #undef PRINT_FLAG
285 
286 	if (nfnl_exp_test_flags(exp))
287 		nl_dump(p, ">");
288 
289 	nl_dump(p, "\n");
290 }
291 
exp_cmp_l4proto_ports(union nfnl_exp_protodata * a,union nfnl_exp_protodata * b)292 static int exp_cmp_l4proto_ports (union nfnl_exp_protodata *a, union nfnl_exp_protodata *b) {
293 	// Must return 0 for match, 1 for mismatch
294 	int d = 0;
295 	d = ( (a->port.src != b->port.src) ||
296 	      (a->port.dst != b->port.dst) );
297 
298 	return d;
299 }
300 
exp_cmp_l4proto_icmp(union nfnl_exp_protodata * a,union nfnl_exp_protodata * b)301 static int exp_cmp_l4proto_icmp (union nfnl_exp_protodata *a, union nfnl_exp_protodata *b) {
302 	// Must return 0 for match, 1 for mismatch
303 	int d = 0;
304 	d = ( (a->icmp.code != b->icmp.code) ||
305 	      (a->icmp.type != b->icmp.type) ||
306 	      (a->icmp.id != b->icmp.id) );
307 
308 	return d;
309 }
310 
exp_compare(struct nl_object * _a,struct nl_object * _b,uint64_t attrs,int flags)311 static uint64_t exp_compare(struct nl_object *_a, struct nl_object *_b,
312 			    uint64_t attrs, int flags)
313 {
314 	struct nfnl_exp *a = (struct nfnl_exp *) _a;
315 	struct nfnl_exp *b = (struct nfnl_exp *) _b;
316 	uint64_t diff = 0;
317 
318 #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
319 #define _DIFF_VAL(ATTR, FIELD) _DIFF(ATTR, a->FIELD != b->FIELD)
320 #define _DIFF_STRING(ATTR, FIELD) _DIFF(ATTR, (strcmp(a->FIELD, b->FIELD) != 0))
321 #define _DIFF_ADDR(ATTR, FIELD)                                                \
322 	((flags & LOOSE_COMPARISON) ?                                          \
323 		 _DIFF(ATTR, nl_addr_cmp_prefix(a->FIELD, b->FIELD)) :         \
324 		 _DIFF(ATTR, nl_addr_cmp(a->FIELD, b->FIELD)))
325 #define _DIFF_L4PROTO_PORTS(ATTR, FIELD)                                       \
326 	_DIFF(ATTR, exp_cmp_l4proto_ports(&(a->FIELD), &(b->FIELD)))
327 #define _DIFF_L4PROTO_ICMP(ATTR, FIELD)                                        \
328 	_DIFF(ATTR, exp_cmp_l4proto_icmp(&(a->FIELD), &(b->FIELD)))
329 	diff |= _DIFF_VAL(EXP_ATTR_FAMILY, exp_family);
330 	diff |= _DIFF_VAL(EXP_ATTR_TIMEOUT, exp_timeout);
331 	diff |= _DIFF_VAL(EXP_ATTR_ID, exp_id);
332 	diff |= _DIFF_VAL(EXP_ATTR_ZONE, exp_zone);
333 	diff |= _DIFF_VAL(EXP_ATTR_CLASS, exp_class);
334 	diff |= _DIFF_VAL(EXP_ATTR_FLAGS, exp_flags);
335 	diff |= _DIFF_VAL(EXP_ATTR_NAT_DIR, exp_nat_dir);
336 
337 	diff |= _DIFF_STRING(EXP_ATTR_FN, exp_fn);
338 	diff |= _DIFF_STRING(EXP_ATTR_HELPER_NAME, exp_helper_name);
339 
340 	diff |= _DIFF_ADDR(EXP_ATTR_EXPECT_IP_SRC, exp_expect.src);
341 	diff |= _DIFF_ADDR(EXP_ATTR_EXPECT_IP_DST, exp_expect.dst);
342 	diff |= _DIFF_VAL(EXP_ATTR_EXPECT_L4PROTO_NUM,
343 			  exp_expect.proto.l4protonum);
344 	diff |= _DIFF_L4PROTO_PORTS(EXP_ATTR_EXPECT_L4PROTO_PORTS,
345 				    exp_expect.proto.l4protodata);
346 	diff |= _DIFF_L4PROTO_ICMP(EXP_ATTR_EXPECT_L4PROTO_ICMP,
347 				   exp_expect.proto.l4protodata);
348 
349 	diff |= _DIFF_ADDR(EXP_ATTR_MASTER_IP_SRC, exp_master.src);
350 	diff |= _DIFF_ADDR(EXP_ATTR_MASTER_IP_DST, exp_master.dst);
351 	diff |= _DIFF_VAL(EXP_ATTR_MASTER_L4PROTO_NUM,
352 			  exp_master.proto.l4protonum);
353 	diff |= _DIFF_L4PROTO_PORTS(EXP_ATTR_MASTER_L4PROTO_PORTS,
354 				    exp_master.proto.l4protodata);
355 	diff |= _DIFF_L4PROTO_ICMP(EXP_ATTR_MASTER_L4PROTO_ICMP,
356 				   exp_master.proto.l4protodata);
357 
358 	diff |= _DIFF_ADDR(EXP_ATTR_MASK_IP_SRC, exp_mask.src);
359 	diff |= _DIFF_ADDR(EXP_ATTR_MASK_IP_DST, exp_mask.dst);
360 	diff |= _DIFF_VAL(EXP_ATTR_MASK_L4PROTO_NUM, exp_mask.proto.l4protonum);
361 	diff |= _DIFF_L4PROTO_PORTS(EXP_ATTR_MASK_L4PROTO_PORTS,
362 				    exp_mask.proto.l4protodata);
363 	diff |= _DIFF_L4PROTO_ICMP(EXP_ATTR_MASK_L4PROTO_ICMP,
364 				   exp_mask.proto.l4protodata);
365 
366 	diff |= _DIFF_ADDR(EXP_ATTR_NAT_IP_SRC, exp_nat.src);
367 	diff |= _DIFF_ADDR(EXP_ATTR_NAT_IP_DST, exp_nat.dst);
368 	diff |= _DIFF_VAL(EXP_ATTR_NAT_L4PROTO_NUM, exp_nat.proto.l4protonum);
369 	diff |= _DIFF_L4PROTO_PORTS(EXP_ATTR_NAT_L4PROTO_PORTS,
370 				    exp_nat.proto.l4protodata);
371 	diff |= _DIFF_L4PROTO_ICMP(EXP_ATTR_NAT_L4PROTO_ICMP,
372 				   exp_nat.proto.l4protodata);
373 #undef _DIFF
374 #undef _DIFF_VAL
375 #undef _DIFF_STRING
376 #undef _DIFF_ADDR
377 #undef _DIFF_L4PROTO_PORTS
378 #undef _DIFF_L4PROTO_ICMP
379 
380 	return diff;
381 }
382 
383 // CLI arguments?
384 static const struct trans_tbl exp_attrs[] = {
385 	__ADD(EXP_ATTR_FAMILY,				family),
386 	__ADD(EXP_ATTR_TIMEOUT,				timeout),
387 	__ADD(EXP_ATTR_ID,				id),
388 	__ADD(EXP_ATTR_HELPER_NAME,			helpername),
389 	__ADD(EXP_ATTR_ZONE,				zone),
390 	__ADD(EXP_ATTR_CLASS,				class),
391 	__ADD(EXP_ATTR_FLAGS,				flags),
392 	__ADD(EXP_ATTR_FN,				function),
393 	__ADD(EXP_ATTR_EXPECT_IP_SRC,			expectipsrc),
394 	__ADD(EXP_ATTR_EXPECT_IP_DST,			expectipdst),
395 	__ADD(EXP_ATTR_EXPECT_L4PROTO_NUM,		expectprotonum),
396 	__ADD(EXP_ATTR_EXPECT_L4PROTO_PORTS,		expectports),
397 	__ADD(EXP_ATTR_EXPECT_L4PROTO_ICMP,		expecticmp),
398 	__ADD(EXP_ATTR_MASTER_IP_SRC,			masteripsrc),
399 	__ADD(EXP_ATTR_MASTER_IP_DST,			masteripdst),
400 	__ADD(EXP_ATTR_MASTER_L4PROTO_NUM,		masterprotonum),
401 	__ADD(EXP_ATTR_MASTER_L4PROTO_PORTS,		masterports),
402 	__ADD(EXP_ATTR_MASTER_L4PROTO_ICMP,		mastericmp),
403 	__ADD(EXP_ATTR_MASK_IP_SRC,			maskipsrc),
404 	__ADD(EXP_ATTR_MASK_IP_DST,			maskipdst),
405 	__ADD(EXP_ATTR_MASK_L4PROTO_NUM,		maskprotonum),
406 	__ADD(EXP_ATTR_MASK_L4PROTO_PORTS,		maskports),
407 	__ADD(EXP_ATTR_MASK_L4PROTO_ICMP,		maskicmp),
408 	__ADD(EXP_ATTR_NAT_IP_SRC,			natipsrc),
409 	__ADD(EXP_ATTR_NAT_IP_DST,			natipdst),
410 	__ADD(EXP_ATTR_NAT_L4PROTO_NUM,			natprotonum),
411 	__ADD(EXP_ATTR_NAT_L4PROTO_PORTS,		natports),
412 	__ADD(EXP_ATTR_NAT_L4PROTO_ICMP,		naticmp),
413 	__ADD(EXP_ATTR_NAT_DIR,				natdir),
414 };
415 
exp_attrs2str(int attrs,char * buf,size_t len)416 static char *exp_attrs2str(int attrs, char *buf, size_t len)
417 {
418 	return __flags2str(attrs, buf, len, exp_attrs, ARRAY_SIZE(exp_attrs));
419 }
420 
421 /**
422  * @name Allocation/Freeing
423  * @{
424  */
425 
nfnl_exp_alloc(void)426 struct nfnl_exp *nfnl_exp_alloc(void)
427 {
428 	return (struct nfnl_exp *) nl_object_alloc(&exp_obj_ops);
429 }
430 
nfnl_exp_get(struct nfnl_exp * exp)431 void nfnl_exp_get(struct nfnl_exp *exp)
432 {
433 	nl_object_get((struct nl_object *) exp);
434 }
435 
nfnl_exp_put(struct nfnl_exp * exp)436 void nfnl_exp_put(struct nfnl_exp *exp)
437 {
438 	nl_object_put((struct nl_object *) exp);
439 }
440 
441 /** @} */
442 
443 /**
444  * @name Attributes
445  * @{
446  */
447 
nfnl_exp_set_family(struct nfnl_exp * exp,uint8_t family)448 void nfnl_exp_set_family(struct nfnl_exp *exp, uint8_t family)
449 {
450 	exp->exp_family = family;
451 	exp->ce_mask |= EXP_ATTR_FAMILY;
452 }
453 
nfnl_exp_get_family(const struct nfnl_exp * exp)454 uint8_t nfnl_exp_get_family(const struct nfnl_exp *exp)
455 {
456 	if (exp->ce_mask & EXP_ATTR_FAMILY)
457 		return exp->exp_family;
458 	else
459 		return AF_UNSPEC;
460 }
461 
nfnl_exp_set_flags(struct nfnl_exp * exp,uint32_t flags)462 void nfnl_exp_set_flags(struct nfnl_exp *exp, uint32_t flags)
463 {
464 	exp->exp_flags |= flags;
465 	exp->ce_mask |= EXP_ATTR_FLAGS;
466 }
467 
nfnl_exp_test_flags(const struct nfnl_exp * exp)468 int nfnl_exp_test_flags(const struct nfnl_exp *exp)
469 {
470 	return !!(exp->ce_mask & EXP_ATTR_FLAGS);
471 }
472 
nfnl_exp_unset_flags(struct nfnl_exp * exp,uint32_t flags)473 void nfnl_exp_unset_flags(struct nfnl_exp *exp, uint32_t flags)
474 {
475 	exp->exp_flags &= ~flags;
476 	exp->ce_mask |= EXP_ATTR_FLAGS;
477 }
478 
nfnl_exp_get_flags(const struct nfnl_exp * exp)479 uint32_t nfnl_exp_get_flags(const struct nfnl_exp *exp)
480 {
481 	return exp->exp_flags;
482 }
483 
484 static const struct trans_tbl flag_table[] = {
485 	__ADD(IPS_EXPECTED, expected),
486 	__ADD(IPS_SEEN_REPLY, seen_reply),
487 	__ADD(IPS_ASSURED, assured),
488 };
489 
nfnl_exp_flags2str(int flags,char * buf,size_t len)490 char * nfnl_exp_flags2str(int flags, char *buf, size_t len)
491 {
492 	return __flags2str(flags, buf, len, flag_table,
493 			   ARRAY_SIZE(flag_table));
494 }
495 
nfnl_exp_str2flags(const char * name)496 int nfnl_exp_str2flags(const char *name)
497 {
498 	return __str2flags(name, flag_table, ARRAY_SIZE(flag_table));
499 }
500 
nfnl_exp_set_timeout(struct nfnl_exp * exp,uint32_t timeout)501 void nfnl_exp_set_timeout(struct nfnl_exp *exp, uint32_t timeout)
502 {
503 	exp->exp_timeout = timeout;
504 	exp->ce_mask |= EXP_ATTR_TIMEOUT;
505 }
506 
nfnl_exp_test_timeout(const struct nfnl_exp * exp)507 int nfnl_exp_test_timeout(const struct nfnl_exp *exp)
508 {
509 	return !!(exp->ce_mask & EXP_ATTR_TIMEOUT);
510 }
511 
nfnl_exp_get_timeout(const struct nfnl_exp * exp)512 uint32_t nfnl_exp_get_timeout(const struct nfnl_exp *exp)
513 {
514 	return exp->exp_timeout;
515 }
516 
nfnl_exp_set_id(struct nfnl_exp * exp,uint32_t id)517 void nfnl_exp_set_id(struct nfnl_exp *exp, uint32_t id)
518 {
519 	exp->exp_id = id;
520 	exp->ce_mask |= EXP_ATTR_ID;
521 }
522 
nfnl_exp_test_id(const struct nfnl_exp * exp)523 int nfnl_exp_test_id(const struct nfnl_exp *exp)
524 {
525 	return !!(exp->ce_mask & EXP_ATTR_ID);
526 }
527 
nfnl_exp_get_id(const struct nfnl_exp * exp)528 uint32_t nfnl_exp_get_id(const struct nfnl_exp *exp)
529 {
530 	return exp->exp_id;
531 }
532 
nfnl_exp_set_helper_name(struct nfnl_exp * exp,void * name)533 int nfnl_exp_set_helper_name(struct nfnl_exp *exp, void *name)
534 {
535 	free(exp->exp_helper_name);
536 	exp->exp_helper_name = strdup(name);
537 	if (!exp->exp_helper_name)
538 		return -NLE_NOMEM;
539 
540 	exp->ce_mask |= EXP_ATTR_HELPER_NAME;
541 	return 0;
542 }
543 
nfnl_exp_test_helper_name(const struct nfnl_exp * exp)544 int  nfnl_exp_test_helper_name(const struct nfnl_exp *exp)
545 {
546 	return !!(exp->ce_mask & EXP_ATTR_HELPER_NAME);
547 }
548 
nfnl_exp_get_helper_name(const struct nfnl_exp * exp)549 const char * nfnl_exp_get_helper_name(const struct nfnl_exp *exp)
550 {
551 	return exp->exp_helper_name;
552 }
553 
nfnl_exp_set_zone(struct nfnl_exp * exp,uint16_t zone)554 void nfnl_exp_set_zone(struct nfnl_exp *exp, uint16_t zone)
555 {
556 	exp->exp_zone = zone;
557 	exp->ce_mask |= EXP_ATTR_ZONE;
558 }
559 
nfnl_exp_test_zone(const struct nfnl_exp * exp)560 int nfnl_exp_test_zone(const struct nfnl_exp *exp)
561 {
562 	return !!(exp->ce_mask & EXP_ATTR_ZONE);
563 }
564 
nfnl_exp_get_zone(const struct nfnl_exp * exp)565 uint16_t nfnl_exp_get_zone(const struct nfnl_exp *exp)
566 {
567 	return exp->exp_zone;
568 }
569 
nfnl_exp_set_class(struct nfnl_exp * exp,uint32_t class)570 void nfnl_exp_set_class(struct nfnl_exp *exp, uint32_t class)
571 {
572 	exp->exp_class = class;
573 	exp->ce_mask |= EXP_ATTR_CLASS;
574 }
575 
nfnl_exp_test_class(const struct nfnl_exp * exp)576 int nfnl_exp_test_class(const struct nfnl_exp *exp)
577 {
578 	return !!(exp->ce_mask & EXP_ATTR_CLASS);
579 }
580 
nfnl_exp_get_class(const struct nfnl_exp * exp)581 uint32_t nfnl_exp_get_class(const struct nfnl_exp *exp)
582 {
583 	return exp->exp_class;
584 }
585 
nfnl_exp_set_fn(struct nfnl_exp * exp,void * fn)586 int nfnl_exp_set_fn(struct nfnl_exp *exp, void *fn)
587 {
588 	free(exp->exp_fn);
589 	exp->exp_fn = strdup(fn);
590 	if (!exp->exp_fn)
591 		return -NLE_NOMEM;
592 
593 	exp->ce_mask |= EXP_ATTR_FN;
594 	return 0;
595 }
596 
nfnl_exp_test_fn(const struct nfnl_exp * exp)597 int nfnl_exp_test_fn(const struct nfnl_exp *exp)
598 {
599 	return !!(exp->ce_mask & EXP_ATTR_FN);
600 }
601 
nfnl_exp_get_fn(const struct nfnl_exp * exp)602 const char * nfnl_exp_get_fn(const struct nfnl_exp *exp)
603 {
604 	return exp->exp_fn;
605 }
606 
nfnl_exp_set_nat_dir(struct nfnl_exp * exp,uint8_t nat_dir)607 void nfnl_exp_set_nat_dir(struct nfnl_exp *exp, uint8_t nat_dir)
608 {
609 	exp->exp_nat_dir = nat_dir;
610 	exp->ce_mask |= EXP_ATTR_NAT_DIR;
611 }
612 
nfnl_exp_test_nat_dir(const struct nfnl_exp * exp)613 int nfnl_exp_test_nat_dir(const struct nfnl_exp *exp)
614 {
615 	return !!(exp->ce_mask & EXP_ATTR_NAT_DIR);
616 }
617 
nfnl_exp_get_nat_dir(const struct nfnl_exp * exp)618 uint8_t nfnl_exp_get_nat_dir(const struct nfnl_exp *exp)
619 {
620 	return exp->exp_nat_dir;
621 }
622 
623 #define EXP_GET_TUPLE(e, t) \
624 	(t == NFNL_EXP_TUPLE_MASTER) ? \
625 		&(e->exp_master) : \
626 	(t == NFNL_EXP_TUPLE_MASK) ? \
627 		&(e->exp_mask) : \
628 	(t == NFNL_EXP_TUPLE_NAT) ? \
629 		&(e->exp_nat) : &(exp->exp_expect)
630 
exp_get_src_attr(int tuple)631 static int exp_get_src_attr(int tuple)
632 {
633 	int attr = 0;
634 
635 	switch (tuple) {
636 		case NFNL_EXP_TUPLE_MASTER:
637 			attr = EXP_ATTR_MASTER_IP_SRC;
638 			break;
639 		case NFNL_EXP_TUPLE_MASK:
640 			attr = EXP_ATTR_MASK_IP_SRC;
641 			break;
642 		case NFNL_EXP_TUPLE_NAT:
643 			attr = EXP_ATTR_NAT_IP_SRC;
644 			break;
645 		case NFNL_EXP_TUPLE_EXPECT:
646 		default :
647 			attr = EXP_ATTR_EXPECT_IP_SRC;
648 	}
649 
650 	return attr;
651 }
652 
exp_get_dst_attr(int tuple)653 static int exp_get_dst_attr(int tuple)
654 {
655 	int attr = 0;
656 
657 	switch (tuple) {
658 		case NFNL_EXP_TUPLE_MASTER:
659 			attr = EXP_ATTR_MASTER_IP_DST;
660 			break;
661 		case NFNL_EXP_TUPLE_MASK:
662 			attr = EXP_ATTR_MASK_IP_DST;
663 			break;
664 		case NFNL_EXP_TUPLE_NAT:
665 			attr = EXP_ATTR_NAT_IP_DST;
666 			break;
667 		case NFNL_EXP_TUPLE_EXPECT:
668 		default :
669 			attr = EXP_ATTR_EXPECT_IP_DST;
670 	}
671 
672 	return attr;
673 }
674 
675 
exp_set_addr(struct nfnl_exp * exp,struct nl_addr * addr,int attr,struct nl_addr ** exp_addr)676 static int exp_set_addr(struct nfnl_exp *exp, struct nl_addr *addr,
677                           int attr, struct nl_addr ** exp_addr)
678 {
679 	if (exp->ce_mask & EXP_ATTR_FAMILY) {
680 		if (addr->a_family != exp->exp_family)
681 			return -NLE_AF_MISMATCH;
682 	} else
683 		nfnl_exp_set_family(exp, addr->a_family);
684 
685 	if (*exp_addr)
686 		nl_addr_put(*exp_addr);
687 
688 	nl_addr_get(addr);
689 	*exp_addr = addr;
690 	exp->ce_mask |= attr;
691 
692 	return 0;
693 }
694 
nfnl_exp_set_src(struct nfnl_exp * exp,int tuple,struct nl_addr * addr)695 int nfnl_exp_set_src(struct nfnl_exp *exp, int tuple, struct nl_addr *addr)
696 {
697 	struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
698 
699 	return exp_set_addr(exp, addr, exp_get_src_attr(tuple), &dir->src);
700 }
701 
nfnl_exp_set_dst(struct nfnl_exp * exp,int tuple,struct nl_addr * addr)702 int nfnl_exp_set_dst(struct nfnl_exp *exp, int tuple, struct nl_addr *addr)
703 {
704 	struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
705 
706 	return exp_set_addr(exp, addr, exp_get_dst_attr(tuple), &dir->dst);
707 }
708 
nfnl_exp_test_src(const struct nfnl_exp * exp,int tuple)709 int nfnl_exp_test_src(const struct nfnl_exp *exp, int tuple)
710 {
711 	return !!(exp->ce_mask & exp_get_src_attr(tuple));
712 }
713 
nfnl_exp_test_dst(const struct nfnl_exp * exp,int tuple)714 int nfnl_exp_test_dst(const struct nfnl_exp *exp, int tuple)
715 {
716 	return !!(exp->ce_mask & exp_get_dst_attr(tuple));
717 }
718 
nfnl_exp_get_src(const struct nfnl_exp * exp,int tuple)719 struct nl_addr *nfnl_exp_get_src(const struct nfnl_exp *exp, int tuple)
720 {
721 	const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
722 
723 	if (!(exp->ce_mask & exp_get_src_attr(tuple)))
724 		return NULL;
725 	return dir->src;
726 }
727 
nfnl_exp_get_dst(const struct nfnl_exp * exp,int tuple)728 struct nl_addr *nfnl_exp_get_dst(const struct nfnl_exp *exp, int tuple)
729 {
730 	const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
731 
732 	if (!(exp->ce_mask & exp_get_dst_attr(tuple)))
733 		return NULL;
734 	return dir->dst;
735 }
736 
exp_get_l4protonum_attr(int tuple)737 static int exp_get_l4protonum_attr(int tuple)
738 {
739 	int attr = 0;
740 
741 	switch (tuple) {
742 		case NFNL_EXP_TUPLE_MASTER:
743 			attr = EXP_ATTR_MASTER_L4PROTO_NUM;
744 			break;
745 		case NFNL_EXP_TUPLE_MASK:
746 			attr = EXP_ATTR_MASK_L4PROTO_NUM;
747 			break;
748 		case NFNL_EXP_TUPLE_NAT:
749 			attr = EXP_ATTR_NAT_L4PROTO_NUM;
750 			break;
751 		case NFNL_EXP_TUPLE_EXPECT:
752 		default :
753 			attr = EXP_ATTR_EXPECT_L4PROTO_NUM;
754 	}
755 
756 	return attr;
757 }
758 
nfnl_exp_set_l4protonum(struct nfnl_exp * exp,int tuple,uint8_t l4protonum)759 void nfnl_exp_set_l4protonum(struct nfnl_exp *exp, int tuple, uint8_t l4protonum)
760 {
761 	struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
762 
763 	dir->proto.l4protonum = l4protonum;
764 	exp->ce_mask |= exp_get_l4protonum_attr(tuple);
765 }
766 
nfnl_exp_test_l4protonum(const struct nfnl_exp * exp,int tuple)767 int nfnl_exp_test_l4protonum(const struct nfnl_exp *exp, int tuple)
768 {
769 	return !!(exp->ce_mask & exp_get_l4protonum_attr(tuple));
770 }
771 
nfnl_exp_get_l4protonum(const struct nfnl_exp * exp,int tuple)772 uint8_t nfnl_exp_get_l4protonum(const struct nfnl_exp *exp, int tuple)
773 {
774 	const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
775 	return dir->proto.l4protonum;
776 }
777 
exp_get_l4ports_attr(int tuple)778 static int exp_get_l4ports_attr(int tuple)
779 {
780 	int attr = 0;
781 
782 	switch (tuple) {
783 		case NFNL_EXP_TUPLE_MASTER:
784 			attr = EXP_ATTR_MASTER_L4PROTO_PORTS;
785 			break;
786 		case NFNL_EXP_TUPLE_MASK:
787 			attr = EXP_ATTR_MASK_L4PROTO_PORTS;
788 			break;
789 		case NFNL_EXP_TUPLE_NAT:
790 			attr = EXP_ATTR_NAT_L4PROTO_PORTS;
791 			break;
792 		case NFNL_EXP_TUPLE_EXPECT:
793 		default :
794 			attr = EXP_ATTR_EXPECT_L4PROTO_PORTS;
795 	}
796 
797 	return attr;
798 }
799 
nfnl_exp_set_ports(struct nfnl_exp * exp,int tuple,uint16_t srcport,uint16_t dstport)800 void nfnl_exp_set_ports(struct nfnl_exp *exp, int tuple, uint16_t srcport, uint16_t dstport)
801 {
802 	struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
803 
804 	dir->proto.l4protodata.port.src = srcport;
805 	dir->proto.l4protodata.port.dst = dstport;
806 
807 	exp->ce_mask |= exp_get_l4ports_attr(tuple);
808 }
809 
nfnl_exp_test_ports(const struct nfnl_exp * exp,int tuple)810 int nfnl_exp_test_ports(const struct nfnl_exp *exp, int tuple)
811 {
812 	return !!(exp->ce_mask & exp_get_l4ports_attr(tuple));
813 }
814 
nfnl_exp_get_src_port(const struct nfnl_exp * exp,int tuple)815 uint16_t nfnl_exp_get_src_port(const struct nfnl_exp *exp, int tuple)
816 {
817 	const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
818 	return dir->proto.l4protodata.port.src;
819 }
820 
nfnl_exp_get_dst_port(const struct nfnl_exp * exp,int tuple)821 uint16_t nfnl_exp_get_dst_port(const struct nfnl_exp *exp, int tuple)
822 {
823 	const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
824 
825 	return dir->proto.l4protodata.port.dst;
826 }
827 
exp_get_l4icmp_attr(int tuple)828 static int exp_get_l4icmp_attr(int tuple)
829 {
830 	int attr = 0;
831 
832 	switch (tuple) {
833 		case NFNL_EXP_TUPLE_MASTER:
834 			attr = EXP_ATTR_MASTER_L4PROTO_ICMP;
835 			break;
836 		case NFNL_EXP_TUPLE_MASK:
837 			attr = EXP_ATTR_MASK_L4PROTO_ICMP;
838 			break;
839 		case NFNL_EXP_TUPLE_NAT:
840 			attr = EXP_ATTR_NAT_L4PROTO_ICMP;
841 			break;
842 		case NFNL_EXP_TUPLE_EXPECT:
843 		default :
844 			attr = EXP_ATTR_EXPECT_L4PROTO_ICMP;
845 	}
846 
847 	return attr;
848 }
849 
nfnl_exp_set_icmp(struct nfnl_exp * exp,int tuple,uint16_t id,uint8_t type,uint8_t code)850 void nfnl_exp_set_icmp(struct nfnl_exp *exp, int tuple, uint16_t id, uint8_t type, uint8_t code)
851 {
852 	struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
853 
854 	dir->proto.l4protodata.icmp.id = id;
855 	dir->proto.l4protodata.icmp.type = type;
856 	dir->proto.l4protodata.icmp.code = code;
857 
858 	exp->ce_mask |= exp_get_l4icmp_attr(tuple);
859 }
860 
nfnl_exp_test_icmp(const struct nfnl_exp * exp,int tuple)861 int nfnl_exp_test_icmp(const struct nfnl_exp *exp, int tuple)
862 {
863 	int attr = exp_get_l4icmp_attr(tuple);
864 	return !!(exp->ce_mask & attr);
865 }
866 
nfnl_exp_get_icmp_id(const struct nfnl_exp * exp,int tuple)867 uint16_t nfnl_exp_get_icmp_id(const struct nfnl_exp *exp, int tuple)
868 {
869 	const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
870 
871 	return dir->proto.l4protodata.icmp.id;
872 }
873 
nfnl_exp_get_icmp_type(const struct nfnl_exp * exp,int tuple)874 uint8_t nfnl_exp_get_icmp_type(const struct nfnl_exp *exp, int tuple)
875 {
876 	const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
877 
878 	return dir->proto.l4protodata.icmp.type;
879 }
880 
nfnl_exp_get_icmp_code(const struct nfnl_exp * exp,int tuple)881 uint8_t nfnl_exp_get_icmp_code(const struct nfnl_exp *exp, int tuple)
882 {
883 	const struct nfnl_exp_dir *dir = EXP_GET_TUPLE(exp, tuple);
884 
885 	return dir->proto.l4protodata.icmp.code;
886 }
887 
888 /** @} */
889 
890 struct nl_object_ops exp_obj_ops = {
891 	.oo_name	= "netfilter/exp",
892 	.oo_size	= sizeof(struct nfnl_exp),
893 	.oo_free_data   = exp_free_data,
894 	.oo_clone	= exp_clone,
895 	.oo_dump = {
896 		[NL_DUMP_LINE]		= exp_dump_line,
897 		[NL_DUMP_DETAILS]	= exp_dump_details,
898 	},
899 	.oo_compare	= exp_compare,
900 	.oo_attrs2str	= exp_attrs2str,
901 };
902 
903 /** @} */
904