libnl 3.7.0
exp_obj.c
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
58static 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
78static 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
160static 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
173static 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
185static 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 */
226static 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
237static 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
286static 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
295static 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
305static 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?
370static 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
402static 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
412struct nfnl_exp *nfnl_exp_alloc(void)
413{
414 return (struct nfnl_exp *) nl_object_alloc(&exp_obj_ops);
415}
416
417void nfnl_exp_get(struct nfnl_exp *exp)
418{
419 nl_object_get((struct nl_object *) exp);
420}
421
422void 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
434void 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
440uint8_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
448void 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
454int nfnl_exp_test_flags(const struct nfnl_exp *exp)
455{
456 return !!(exp->ce_mask & EXP_ATTR_FLAGS);
457}
458
459void 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
465uint32_t nfnl_exp_get_flags(const struct nfnl_exp *exp)
466{
467 return exp->exp_flags;
468}
469
470static 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
476char * 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
482int nfnl_exp_str2flags(const char *name)
483{
484 return __str2flags(name, flag_table, ARRAY_SIZE(flag_table));
485}
486
487void 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
493int nfnl_exp_test_timeout(const struct nfnl_exp *exp)
494{
495 return !!(exp->ce_mask & EXP_ATTR_TIMEOUT);
496}
497
498uint32_t nfnl_exp_get_timeout(const struct nfnl_exp *exp)
499{
500 return exp->exp_timeout;
501}
502
503void 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
509int nfnl_exp_test_id(const struct nfnl_exp *exp)
510{
511 return !!(exp->ce_mask & EXP_ATTR_ID);
512}
513
514uint32_t nfnl_exp_get_id(const struct nfnl_exp *exp)
515{
516 return exp->exp_id;
517}
518
519int 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
530int nfnl_exp_test_helper_name(const struct nfnl_exp *exp)
531{
532 return !!(exp->ce_mask & EXP_ATTR_HELPER_NAME);
533}
534
535const char * nfnl_exp_get_helper_name(const struct nfnl_exp *exp)
536{
537 return exp->exp_helper_name;
538}
539
540void 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
546int nfnl_exp_test_zone(const struct nfnl_exp *exp)
547{
548 return !!(exp->ce_mask & EXP_ATTR_ZONE);
549}
550
551uint16_t nfnl_exp_get_zone(const struct nfnl_exp *exp)
552{
553 return exp->exp_zone;
554}
555
556void 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
562int nfnl_exp_test_class(const struct nfnl_exp *exp)
563{
564 return !!(exp->ce_mask & EXP_ATTR_CLASS);
565}
566
567uint32_t nfnl_exp_get_class(const struct nfnl_exp *exp)
568{
569 return exp->exp_class;
570}
571
572int 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
583int nfnl_exp_test_fn(const struct nfnl_exp *exp)
584{
585 return !!(exp->ce_mask & EXP_ATTR_FN);
586}
587
588const char * nfnl_exp_get_fn(const struct nfnl_exp *exp)
589{
590 return exp->exp_fn;
591}
592
593void 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
599int nfnl_exp_test_nat_dir(const struct nfnl_exp *exp)
600{
601 return !!(exp->ce_mask & EXP_ATTR_NAT_DIR);
602}
603
604uint8_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
617static 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
639static 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
662static 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
681int 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
688int 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
695int nfnl_exp_test_src(const struct nfnl_exp *exp, int tuple)
696{
697 return !!(exp->ce_mask & exp_get_src_attr(tuple));
698}
699
700int nfnl_exp_test_dst(const struct nfnl_exp *exp, int tuple)
701{
702 return !!(exp->ce_mask & exp_get_dst_attr(tuple));
703}
704
705struct 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
714struct 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
723static 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
745void 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
753int nfnl_exp_test_l4protonum(const struct nfnl_exp *exp, int tuple)
754{
755 return !!(exp->ce_mask & exp_get_l4protonum_attr(tuple));
756}
757
758uint8_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
764static 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
786void 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
796int nfnl_exp_test_ports(const struct nfnl_exp *exp, int tuple)
797{
798 return !!(exp->ce_mask & exp_get_l4ports_attr(tuple));
799}
800
801uint16_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
807uint16_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
814static 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
836void 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
847int 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
853uint16_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
860uint8_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
867uint8_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
876struct 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/** @} */
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition: addr.c:522
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition: addr.c:492
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition: addr.c:998
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:538
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:214
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:203
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
Definition: object.c:48
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
void nl_new_line(struct nl_dump_params *params)
Handle a new line while dumping.
Definition: utils.c:906
char * nl_msec2str(uint64_t msec, char *buf, size_t len)
Convert milliseconds to a character string.
Definition: utils.c:588
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition: types.h:16
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:17
Dumping parameters.
Definition: types.h:28