libnl  3.5.0
exp_obj.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * lib/netfilter/exp_obj.c Conntrack Expectation Object
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation version 2.1
8  * of the License.
9  *
10  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
11  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
12  * Copyright (c) 2007 Secure Computing Corporation
13  * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
14  */
15 
16 #include <sys/types.h>
17 #include <netinet/in.h>
18 #include <linux/netfilter/nfnetlink_conntrack.h>
19 #include <linux/netfilter/nf_conntrack_common.h>
20 #include <linux/netfilter/nf_conntrack_tcp.h>
21 
22 #include <netlink-private/netlink.h>
23 #include <netlink/netfilter/nfnl.h>
24 #include <netlink/netfilter/exp.h>
25 
26 // The 32-bit attribute mask in the common object header isn't
27 // big enough to handle all attributes of an expectation. So
28 // we'll for sure specify optional attributes + parent attributes
29 // that are required for valid object comparison. Comparison of
30 // these parent attributes will include nested attributes.
31 
32 /** @cond SKIP */
33 #define EXP_ATTR_FAMILY (1UL << 0) // 8-bit
34 #define EXP_ATTR_TIMEOUT (1UL << 1) // 32-bit
35 #define EXP_ATTR_ID (1UL << 2) // 32-bit
36 #define EXP_ATTR_HELPER_NAME (1UL << 3) // string
37 #define EXP_ATTR_ZONE (1UL << 4) // 16-bit
38 #define EXP_ATTR_FLAGS (1UL << 5) // 32-bit
39 #define EXP_ATTR_CLASS (1UL << 6) // 32-bit
40 #define EXP_ATTR_FN (1UL << 7) // String
41 // Tuples
42 #define EXP_ATTR_EXPECT_IP_SRC (1UL << 8)
43 #define EXP_ATTR_EXPECT_IP_DST (1UL << 9)
44 #define EXP_ATTR_EXPECT_L4PROTO_NUM (1UL << 10)
45 #define EXP_ATTR_EXPECT_L4PROTO_PORTS (1UL << 11)
46 #define EXP_ATTR_EXPECT_L4PROTO_ICMP (1UL << 12)
47 #define EXP_ATTR_MASTER_IP_SRC (1UL << 13)
48 #define EXP_ATTR_MASTER_IP_DST (1UL << 14)
49 #define EXP_ATTR_MASTER_L4PROTO_NUM (1UL << 15)
50 #define EXP_ATTR_MASTER_L4PROTO_PORTS (1UL << 16)
51 #define EXP_ATTR_MASTER_L4PROTO_ICMP (1UL << 17)
52 #define EXP_ATTR_MASK_IP_SRC (1UL << 18)
53 #define EXP_ATTR_MASK_IP_DST (1UL << 19)
54 #define EXP_ATTR_MASK_L4PROTO_NUM (1UL << 20)
55 #define EXP_ATTR_MASK_L4PROTO_PORTS (1UL << 21)
56 #define EXP_ATTR_MASK_L4PROTO_ICMP (1UL << 22)
57 #define EXP_ATTR_NAT_IP_SRC (1UL << 23)
58 #define EXP_ATTR_NAT_IP_DST (1UL << 24)
59 #define EXP_ATTR_NAT_L4PROTO_NUM (1UL << 25)
60 #define EXP_ATTR_NAT_L4PROTO_PORTS (1UL << 26)
61 #define EXP_ATTR_NAT_L4PROTO_ICMP (1UL << 27)
62 #define EXP_ATTR_NAT_DIR (1UL << 28)
63 /** @endcond */
64 
65 static void exp_free_data(struct nl_object *c)
66 {
67  struct nfnl_exp *exp = (struct nfnl_exp *) c;
68 
69  if (exp == NULL)
70  return;
71 
72  nl_addr_put(exp->exp_expect.src);
73  nl_addr_put(exp->exp_expect.dst);
74  nl_addr_put(exp->exp_master.src);
75  nl_addr_put(exp->exp_master.dst);
76  nl_addr_put(exp->exp_mask.src);
77  nl_addr_put(exp->exp_mask.dst);
78  nl_addr_put(exp->exp_nat.src);
79  nl_addr_put(exp->exp_nat.dst);
80 
81  free(exp->exp_fn);
82  free(exp->exp_helper_name);
83 }
84 
85 static int exp_clone(struct nl_object *_dst, struct nl_object *_src)
86 {
87  struct nfnl_exp *dst = (struct nfnl_exp *) _dst;
88  struct nfnl_exp *src = (struct nfnl_exp *) _src;
89  struct nl_addr *addr;
90 
91  // Expectation
92  if (src->exp_expect.src) {
93  addr = nl_addr_clone(src->exp_expect.src);
94  if (!addr)
95  return -NLE_NOMEM;
96  dst->exp_expect.src = addr;
97  }
98 
99  if (src->exp_expect.dst) {
100  addr = nl_addr_clone(src->exp_expect.dst);
101  if (!addr)
102  return -NLE_NOMEM;
103  dst->exp_expect.dst = addr;
104  }
105 
106  // Master CT
107  if (src->exp_master.src) {
108  addr = nl_addr_clone(src->exp_master.src);
109  if (!addr)
110  return -NLE_NOMEM;
111  dst->exp_master.src = addr;
112  }
113 
114  if (src->exp_master.dst) {
115  addr = nl_addr_clone(src->exp_master.dst);
116  if (!addr)
117  return -NLE_NOMEM;
118  dst->exp_master.dst = addr;
119  }
120 
121  // Mask
122  if (src->exp_mask.src) {
123  addr = nl_addr_clone(src->exp_mask.src);
124  if (!addr)
125  return -NLE_NOMEM;
126  dst->exp_mask.src = addr;
127  }
128 
129  if (src->exp_mask.dst) {
130  addr = nl_addr_clone(src->exp_mask.dst);
131  if (!addr)
132  return -NLE_NOMEM;
133  dst->exp_mask.dst = addr;
134  }
135 
136  // NAT
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 
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 
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 
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 %s ", exp->exp_nat_dir);
222 
223 }
224 
225 /* FIXME Compatible with /proc/net/nf_conntrack */
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 
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 
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 
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 
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 
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 
412 struct nfnl_exp *nfnl_exp_alloc(void)
413 {
414  return (struct nfnl_exp *) nl_object_alloc(&exp_obj_ops);
415 }
416 
417 void nfnl_exp_get(struct nfnl_exp *exp)
418 {
419  nl_object_get((struct nl_object *) exp);
420 }
421 
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 
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 
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 
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 
454 int nfnl_exp_test_flags(const struct nfnl_exp *exp)
455 {
456  return !!(exp->ce_mask & EXP_ATTR_FLAGS);
457 }
458 
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 
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 
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 
482 int nfnl_exp_str2flags(const char *name)
483 {
484  return __str2flags(name, flag_table, ARRAY_SIZE(flag_table));
485 }
486 
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 
493 int nfnl_exp_test_timeout(const struct nfnl_exp *exp)
494 {
495  return !!(exp->ce_mask & EXP_ATTR_TIMEOUT);
496 }
497 
498 uint32_t nfnl_exp_get_timeout(const struct nfnl_exp *exp)
499 {
500  return exp->exp_timeout;
501 }
502 
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 
509 int nfnl_exp_test_id(const struct nfnl_exp *exp)
510 {
511  return !!(exp->ce_mask & EXP_ATTR_ID);
512 }
513 
514 uint32_t nfnl_exp_get_id(const struct nfnl_exp *exp)
515 {
516  return exp->exp_id;
517 }
518 
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 
530 int nfnl_exp_test_helper_name(const struct nfnl_exp *exp)
531 {
532  return !!(exp->ce_mask & EXP_ATTR_HELPER_NAME);
533 }
534 
535 const char * nfnl_exp_get_helper_name(const struct nfnl_exp *exp)
536 {
537  return exp->exp_helper_name;
538 }
539 
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 
546 int nfnl_exp_test_zone(const struct nfnl_exp *exp)
547 {
548  return !!(exp->ce_mask & EXP_ATTR_ZONE);
549 }
550 
551 uint16_t nfnl_exp_get_zone(const struct nfnl_exp *exp)
552 {
553  return exp->exp_zone;
554 }
555 
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 
562 int nfnl_exp_test_class(const struct nfnl_exp *exp)
563 {
564  return !!(exp->ce_mask & EXP_ATTR_CLASS);
565 }
566 
567 uint32_t nfnl_exp_get_class(const struct nfnl_exp *exp)
568 {
569  return exp->exp_class;
570 }
571 
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 
583 int nfnl_exp_test_fn(const struct nfnl_exp *exp)
584 {
585  return !!(exp->ce_mask & EXP_ATTR_FN);
586 }
587 
588 const char * nfnl_exp_get_fn(const struct nfnl_exp *exp)
589 {
590  return exp->exp_fn;
591 }
592 
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 
599 int nfnl_exp_test_nat_dir(const struct nfnl_exp *exp)
600 {
601  return !!(exp->ce_mask & EXP_ATTR_NAT_DIR);
602 }
603 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 /** @} */
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition: addr.c:494
Dump object briefly on one line.
Definition: types.h:22
void nl_new_line(struct nl_dump_params *params)
Handle a new line while dumping.
Definition: utils.c:913
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:55
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:205
char * nl_msec2str(uint64_t msec, char *buf, size_t len)
Convert milliseconds to a character string.
Definition: utils.c:595
struct nl_addr * nl_addr_get(struct nl_addr *addr)
Increase the reference counter of an abstract address.
Definition: addr.c:524
Dump all attributes but no statistics.
Definition: types.h:23
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition: object.c:216
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:540
Dumping parameters.
Definition: types.h:33
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:962
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition: addr.c:1000