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