libnl  3.6.0
exp.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) 2008 Patrick McHardy <kaber@trash.net>
7  * Copyright (c) 2012 Rich Fought <rich.fought@watchguard.com>
8  */
9 
10 /**
11  * @ingroup nfnl
12  * @defgroup exp Expectation
13  * @brief
14  * @{
15  */
16 
17 #include <byteswap.h>
18 #include <sys/types.h>
19 #include <linux/netfilter/nfnetlink_conntrack.h>
20 
21 #include <netlink-private/netlink.h>
22 #include <netlink/attr.h>
23 #include <netlink/netfilter/nfnl.h>
24 #include <netlink/netfilter/exp.h>
25 
26 static struct nl_cache_ops nfnl_exp_ops;
27 
28 static struct nla_policy exp_policy[CTA_EXPECT_MAX+1] = {
29  [CTA_EXPECT_MASTER] = { .type = NLA_NESTED },
30  [CTA_EXPECT_TUPLE] = { .type = NLA_NESTED },
31  [CTA_EXPECT_MASK] = { .type = NLA_NESTED },
32  [CTA_EXPECT_TIMEOUT] = { .type = NLA_U32 },
33  [CTA_EXPECT_ID] = { .type = NLA_U32 },
34  [CTA_EXPECT_HELP_NAME] = { .type = NLA_STRING },
35  [CTA_EXPECT_ZONE] = { .type = NLA_U16 },
36  [CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, // Added in kernel 2.6.37
37  [CTA_EXPECT_CLASS] = { .type = NLA_U32 }, // Added in kernel 3.5
38  [CTA_EXPECT_NAT] = { .type = NLA_NESTED }, // Added in kernel 3.5
39  [CTA_EXPECT_FN] = { .type = NLA_STRING }, // Added in kernel 3.5
40 };
41 
42 static struct nla_policy exp_tuple_policy[CTA_TUPLE_MAX+1] = {
43  [CTA_TUPLE_IP] = { .type = NLA_NESTED },
44  [CTA_TUPLE_PROTO] = { .type = NLA_NESTED },
45 };
46 
47 static struct nla_policy exp_ip_policy[CTA_IP_MAX+1] = {
48  [CTA_IP_V4_SRC] = { .type = NLA_U32 },
49  [CTA_IP_V4_DST] = { .type = NLA_U32 },
50  [CTA_IP_V6_SRC] = { .minlen = 16 },
51  [CTA_IP_V6_DST] = { .minlen = 16 },
52 };
53 
54 static struct nla_policy exp_proto_policy[CTA_PROTO_MAX+1] = {
55  [CTA_PROTO_NUM] = { .type = NLA_U8 },
56  [CTA_PROTO_SRC_PORT] = { .type = NLA_U16 },
57  [CTA_PROTO_DST_PORT] = { .type = NLA_U16 },
58  [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 },
59  [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 },
60  [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 },
61  [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 },
62  [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 },
63  [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 },
64 };
65 
66 static struct nla_policy exp_nat_policy[CTA_EXPECT_NAT_MAX+1] = {
67  [CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 },
68  [CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED },
69 };
70 
71 static int exp_parse_ip(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
72 {
73  struct nlattr *tb[CTA_IP_MAX+1];
74  struct nl_addr *addr;
75  int err;
76 
77  err = nla_parse_nested(tb, CTA_IP_MAX, attr, exp_ip_policy);
78  if (err < 0)
79  goto errout;
80 
81  if (tb[CTA_IP_V4_SRC]) {
82  addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
83  if (addr == NULL)
84  goto errout_enomem;
85  err = nfnl_exp_set_src(exp, tuple, addr);
86  nl_addr_put(addr);
87  if (err < 0)
88  goto errout;
89  }
90  if (tb[CTA_IP_V4_DST]) {
91  addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
92  if (addr == NULL)
93  goto errout_enomem;
94  err = nfnl_exp_set_dst(exp, tuple, addr);
95  nl_addr_put(addr);
96  if (err < 0)
97  goto errout;
98  }
99  if (tb[CTA_IP_V6_SRC]) {
100  addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
101  if (addr == NULL)
102  goto errout_enomem;
103  err = nfnl_exp_set_src(exp, tuple, addr);
104  nl_addr_put(addr);
105  if (err < 0)
106  goto errout;
107  }
108  if (tb[CTA_IP_V6_DST]) {
109  addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
110  if (addr == NULL)
111  goto errout_enomem;
112  err = nfnl_exp_set_dst(exp, tuple, addr);
113  nl_addr_put(addr);
114  if (err < 0)
115  goto errout;
116  }
117 
118  return 0;
119 
120 errout_enomem:
121  err = -NLE_NOMEM;
122 errout:
123  return err;
124 }
125 
126 static int exp_parse_proto(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
127 {
128  struct nlattr *tb[CTA_PROTO_MAX+1];
129  int err;
130  uint16_t srcport = 0, dstport = 0, icmpid = 0;
131  uint8_t icmptype = 0, icmpcode = 0;
132 
133  err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, exp_proto_policy);
134  if (err < 0)
135  return err;
136 
137  if (tb[CTA_PROTO_NUM])
138  nfnl_exp_set_l4protonum(exp, tuple, nla_get_u8(tb[CTA_PROTO_NUM]));
139 
140  if (tb[CTA_PROTO_SRC_PORT])
141  srcport = ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT]));
142  if (tb[CTA_PROTO_DST_PORT])
143  dstport = ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT]));
144  if (tb[CTA_PROTO_SRC_PORT] || tb[CTA_PROTO_DST_PORT])
145  nfnl_exp_set_ports(exp, tuple, srcport, dstport);
146 
147  if (tb[CTA_PROTO_ICMP_ID])
148  icmpid = ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID]));
149  if (tb[CTA_PROTO_ICMP_TYPE])
150  icmptype = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]);
151  if (tb[CTA_PROTO_ICMP_CODE])
152  icmpcode = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]);
153  if (tb[CTA_PROTO_ICMP_ID] || tb[CTA_PROTO_ICMP_TYPE] || tb[CTA_PROTO_ICMP_CODE])
154  nfnl_exp_set_icmp(exp, tuple, icmpid, icmptype, icmpcode);
155  return 0;
156 }
157 
158 static int exp_parse_tuple(struct nfnl_exp *exp, int tuple, struct nlattr *attr)
159 {
160  struct nlattr *tb[CTA_TUPLE_MAX+1];
161  int err;
162 
163  err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, exp_tuple_policy);
164  if (err < 0)
165  return err;
166 
167  if (tb[CTA_TUPLE_IP]) {
168  err = exp_parse_ip(exp, tuple, tb[CTA_TUPLE_IP]);
169  if (err < 0)
170  return err;
171  }
172 
173  if (tb[CTA_TUPLE_PROTO]) {
174  err = exp_parse_proto(exp, tuple, tb[CTA_TUPLE_PROTO]);
175  if (err < 0)
176  return err;
177  }
178 
179  return 0;
180 }
181 
182 static int exp_parse_nat(struct nfnl_exp *exp, struct nlattr *attr)
183 {
184  struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
185  int err;
186 
187  err = nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_policy);
188  if (err < 0)
189  return err;
190 
191  if (tb[CTA_EXPECT_NAT_DIR])
192  nfnl_exp_set_nat_dir(exp, nla_get_u32(tb[CTA_EXPECT_NAT_DIR]));
193 
194  if (tb[CTA_EXPECT_NAT_TUPLE]) {
195  err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_NAT, tb[CTA_EXPECT_NAT_TUPLE]);
196  if (err < 0)
197  return err;
198  }
199 
200  return 0;
201 }
202 
203 int nfnlmsg_exp_group(struct nlmsghdr *nlh)
204 {
205  switch (nfnlmsg_subtype(nlh)) {
206  case IPCTNL_MSG_EXP_NEW:
207  if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
208  return NFNLGRP_CONNTRACK_EXP_NEW;
209  else
210  return NFNLGRP_CONNTRACK_EXP_UPDATE;
211  case IPCTNL_MSG_EXP_DELETE:
212  return NFNLGRP_CONNTRACK_EXP_DESTROY;
213  default:
214  return NFNLGRP_NONE;
215  }
216 }
217 
218 int nfnlmsg_exp_parse(struct nlmsghdr *nlh, struct nfnl_exp **result)
219 {
220  struct nfnl_exp *exp;
221  struct nlattr *tb[CTA_MAX+1];
222  int err;
223 
224  exp = nfnl_exp_alloc();
225  if (!exp)
226  return -NLE_NOMEM;
227 
228  exp->ce_msgtype = nlh->nlmsg_type;
229 
230  err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_EXPECT_MAX,
231  exp_policy);
232  if (err < 0)
233  goto errout;
234 
235  nfnl_exp_set_family(exp, nfnlmsg_family(nlh));
236 
237  if (tb[CTA_EXPECT_TUPLE]) {
238  err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_EXPECT, tb[CTA_EXPECT_TUPLE]);
239  if (err < 0)
240  goto errout;
241  }
242  if (tb[CTA_EXPECT_MASTER]) {
243  err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASTER, tb[CTA_EXPECT_MASTER]);
244  if (err < 0)
245  goto errout;
246  }
247  if (tb[CTA_EXPECT_MASK]) {
248  err = exp_parse_tuple(exp, NFNL_EXP_TUPLE_MASK, tb[CTA_EXPECT_MASK]);
249  if (err < 0)
250  goto errout;
251  }
252 
253  if (tb[CTA_EXPECT_NAT]) {
254  err = exp_parse_nat(exp, tb[CTA_EXPECT_MASK]);
255  if (err < 0)
256  goto errout;
257  }
258 
259  if (tb[CTA_EXPECT_CLASS])
260  nfnl_exp_set_class(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_CLASS])));
261 
262  if (tb[CTA_EXPECT_FN])
263  nfnl_exp_set_fn(exp, nla_data(tb[CTA_EXPECT_FN]));
264 
265  if (tb[CTA_EXPECT_TIMEOUT])
266  nfnl_exp_set_timeout(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_TIMEOUT])));
267 
268  if (tb[CTA_EXPECT_ID])
269  nfnl_exp_set_id(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_ID])));
270 
271  if (tb[CTA_EXPECT_HELP_NAME])
272  nfnl_exp_set_helper_name(exp, nla_data(tb[CTA_EXPECT_HELP_NAME]));
273 
274  if (tb[CTA_EXPECT_ZONE])
275  nfnl_exp_set_zone(exp, ntohs(nla_get_u16(tb[CTA_EXPECT_ZONE])));
276 
277  if (tb[CTA_EXPECT_FLAGS])
278  nfnl_exp_set_flags(exp, ntohl(nla_get_u32(tb[CTA_EXPECT_FLAGS])));
279 
280  *result = exp;
281  return 0;
282 
283 errout:
284  nfnl_exp_put(exp);
285  return err;
286 }
287 
288 static int exp_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
289  struct nlmsghdr *nlh, struct nl_parser_param *pp)
290 {
291  struct nfnl_exp *exp;
292  int err;
293 
294  if ((err = nfnlmsg_exp_parse(nlh, &exp)) < 0)
295  return err;
296 
297  err = pp->pp_cb((struct nl_object *) exp, pp);
298  nfnl_exp_put(exp);
299  return err;
300 }
301 
302 /**
303  * Send nfnl exp dump request
304  * @arg sk Netlink socket.
305  *
306  * @return 0 on success or a negative error code. Due to a bug, this function
307  * returns the number of bytes sent. Treat any non-negative number as success.
308  */
309 int nfnl_exp_dump_request(struct nl_sock *sk)
310 {
311  return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET,
312  NLM_F_DUMP, AF_UNSPEC, 0);
313 }
314 
315 static int exp_request_update(struct nl_cache *cache, struct nl_sock *sk)
316 {
317  return nfnl_exp_dump_request(sk);
318 }
319 
320 static int exp_get_tuple_attr(int tuple)
321 {
322  int attr = 0;
323 
324  switch (tuple) {
325  case CTA_EXPECT_MASTER:
326  attr = NFNL_EXP_TUPLE_MASTER;
327  break;
328  case CTA_EXPECT_MASK:
329  attr = NFNL_EXP_TUPLE_MASK;
330  break;
331  case CTA_EXPECT_NAT:
332  attr = NFNL_EXP_TUPLE_NAT;
333  break;
334  case CTA_EXPECT_TUPLE:
335  default :
336  attr = NFNL_EXP_TUPLE_EXPECT;
337  break;
338  }
339 
340  return attr;
341 }
342 
343 static int nfnl_exp_build_tuple(struct nl_msg *msg, const struct nfnl_exp *exp,
344  int cta)
345 {
346  struct nlattr *tuple, *ip, *proto;
347  struct nl_addr *addr;
348  int family;
349  int type;
350 
351  family = nfnl_exp_get_family(exp);
352 
353  type = exp_get_tuple_attr(cta);
354 
355  if (cta == CTA_EXPECT_NAT)
356  tuple = nla_nest_start(msg, CTA_EXPECT_NAT_TUPLE);
357  else
358  tuple = nla_nest_start(msg, cta);
359 
360  if (!tuple)
361  goto nla_put_failure;
362 
363  ip = nla_nest_start(msg, CTA_TUPLE_IP);
364  if (!ip)
365  goto nla_put_failure;
366 
367  addr = nfnl_exp_get_src(exp, type);
368  if (addr)
369  NLA_PUT_ADDR(msg,
370  family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
371  addr);
372 
373  addr = nfnl_exp_get_dst(exp, type);
374  if (addr)
375  NLA_PUT_ADDR(msg,
376  family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
377  addr);
378 
379  nla_nest_end(msg, ip);
380 
381  proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
382  if (!proto)
383  goto nla_put_failure;
384 
385  if (nfnl_exp_test_l4protonum(exp, type))
386  NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_exp_get_l4protonum(exp, type));
387 
388  if (nfnl_exp_test_ports(exp, type)) {
389  NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
390  htons(nfnl_exp_get_src_port(exp, type)));
391 
392  NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
393  htons(nfnl_exp_get_dst_port(exp, type)));
394  }
395 
396  if (nfnl_exp_test_icmp(exp, type)) {
397  NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
398  htons(nfnl_exp_get_icmp_id(exp, type)));
399 
400  NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
401  nfnl_exp_get_icmp_type(exp, type));
402 
403  NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
404  nfnl_exp_get_icmp_code(exp, type));
405  }
406 
407  nla_nest_end(msg, proto);
408 
409  nla_nest_end(msg, tuple);
410  return 0;
411 
412 nla_put_failure:
413  return -NLE_MSGSIZE;
414 }
415 
416 static int nfnl_exp_build_nat(struct nl_msg *msg, const struct nfnl_exp *exp)
417 {
418  struct nlattr *nat;
419  int err;
420 
421  nat = nla_nest_start(msg, CTA_EXPECT_NAT);
422 
423  if (nfnl_exp_test_nat_dir(exp)) {
424  NLA_PUT_U32(msg, CTA_EXPECT_NAT_DIR,
425  nfnl_exp_get_nat_dir(exp));
426  }
427 
428  if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_NAT)) < 0)
429  goto nla_put_failure;
430 
431  nla_nest_end(msg, nat);
432  return 0;
433 
434 nla_put_failure:
435  return -NLE_MSGSIZE;
436 }
437 
438 static int nfnl_exp_build_message(const struct nfnl_exp *exp, int cmd, int flags,
439  struct nl_msg **result)
440 {
441  struct nl_msg *msg;
442  int err;
443 
444  msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK_EXP, cmd, flags,
445  nfnl_exp_get_family(exp), 0);
446  if (msg == NULL)
447  return -NLE_NOMEM;
448 
449  if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_TUPLE)) < 0)
450  goto err_out;
451 
452  if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASTER)) < 0)
453  goto err_out;
454 
455  if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASK)) < 0)
456  goto err_out;
457 
458  if (nfnl_exp_test_src(exp, NFNL_EXP_TUPLE_NAT)) {
459  if ((err = nfnl_exp_build_nat(msg, exp)) < 0)
460  goto err_out;
461  }
462 
463  if (nfnl_exp_test_class(exp))
464  NLA_PUT_U32(msg, CTA_EXPECT_CLASS, htonl(nfnl_exp_get_class(exp)));
465 
466  if (nfnl_exp_test_fn(exp))
467  NLA_PUT_STRING(msg, CTA_EXPECT_FN, nfnl_exp_get_fn(exp));
468 
469  if (nfnl_exp_test_id(exp))
470  NLA_PUT_U32(msg, CTA_EXPECT_ID, htonl(nfnl_exp_get_id(exp)));
471 
472  if (nfnl_exp_test_timeout(exp))
473  NLA_PUT_U32(msg, CTA_EXPECT_TIMEOUT, htonl(nfnl_exp_get_timeout(exp)));
474 
475  if (nfnl_exp_test_helper_name(exp))
476  NLA_PUT_STRING(msg, CTA_EXPECT_HELP_NAME, nfnl_exp_get_helper_name(exp));
477 
478  if (nfnl_exp_test_zone(exp))
479  NLA_PUT_U16(msg, CTA_EXPECT_ZONE, htons(nfnl_exp_get_zone(exp)));
480 
481  if (nfnl_exp_test_flags(exp))
482  NLA_PUT_U32(msg, CTA_EXPECT_FLAGS, htonl(nfnl_exp_get_flags(exp)));
483 
484  *result = msg;
485  return 0;
486 
487 nla_put_failure:
488  err = -NLE_NOMEM;
489 
490 err_out:
491  nlmsg_free(msg);
492  return err;
493 }
494 
495 int nfnl_exp_build_add_request(const struct nfnl_exp *exp, int flags,
496  struct nl_msg **result)
497 {
498  return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_NEW, flags, result);
499 }
500 
501 int nfnl_exp_add(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
502 {
503  struct nl_msg *msg;
504  int err;
505 
506  if ((err = nfnl_exp_build_add_request(exp, flags, &msg)) < 0)
507  return err;
508 
509  err = nl_send_auto_complete(sk, msg);
510  nlmsg_free(msg);
511  if (err < 0)
512  return err;
513 
514  return wait_for_ack(sk);
515 }
516 
517 int nfnl_exp_build_delete_request(const struct nfnl_exp *exp, int flags,
518  struct nl_msg **result)
519 {
520  return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_DELETE, flags, result);
521 }
522 
523 int nfnl_exp_del(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
524 {
525  struct nl_msg *msg;
526  int err;
527 
528  if ((err = nfnl_exp_build_delete_request(exp, flags, &msg)) < 0)
529  return err;
530 
531  err = nl_send_auto_complete(sk, msg);
532  nlmsg_free(msg);
533  if (err < 0)
534  return err;
535 
536  return wait_for_ack(sk);
537 }
538 
539 int nfnl_exp_build_query_request(const struct nfnl_exp *exp, int flags,
540  struct nl_msg **result)
541 {
542  return nfnl_exp_build_message(exp, IPCTNL_MSG_EXP_GET, flags, result);
543 }
544 
545 int nfnl_exp_query(struct nl_sock *sk, const struct nfnl_exp *exp, int flags)
546 {
547  struct nl_msg *msg;
548  int err;
549 
550  if ((err = nfnl_exp_build_query_request(exp, flags, &msg)) < 0)
551  return err;
552 
553  err = nl_send_auto_complete(sk, msg);
554  nlmsg_free(msg);
555  if (err < 0)
556  return err;
557 
558  return wait_for_ack(sk);
559 }
560 
561 /**
562  * @name Cache Management
563  * @{
564  */
565 
566 /**
567  * Build a expectation cache holding all expectations currently in the kernel
568  * @arg sk Netlink socket.
569  * @arg result Pointer to store resulting cache.
570  *
571  * Allocates a new cache, initializes it properly and updates it to
572  * contain all expectations currently in the kernel.
573  *
574  * @return 0 on success or a negative error code.
575  */
576 int nfnl_exp_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
577 {
578  return nl_cache_alloc_and_fill(&nfnl_exp_ops, sk, result);
579 }
580 
581 /** @} */
582 
583 /**
584  * @name Expectation Addition
585  * @{
586  */
587 
588 /** @} */
589 
590 static struct nl_af_group exp_groups[] = {
591  { AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_NEW },
592  { AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_UPDATE },
593  { AF_UNSPEC, NFNLGRP_CONNTRACK_EXP_DESTROY },
594  { END_OF_GROUP_LIST },
595 };
596 
597 #define NFNLMSG_EXP_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK_EXP, (type))
598 static struct nl_cache_ops nfnl_exp_ops = {
599  .co_name = "netfilter/exp",
600  .co_hdrsize = NFNL_HDRLEN,
601  .co_msgtypes = {
602  { NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_NEW), NL_ACT_NEW, "new" },
603  { NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_GET), NL_ACT_GET, "get" },
604  { NFNLMSG_EXP_TYPE(IPCTNL_MSG_EXP_DELETE), NL_ACT_DEL, "del" },
605  END_OF_MSGTYPES_LIST,
606  },
607  .co_protocol = NETLINK_NETFILTER,
608  .co_groups = exp_groups,
609  .co_request_update = exp_request_update,
610  .co_msg_parser = exp_msg_parser,
611  .co_obj_ops = &exp_obj_ops,
612 };
613 
614 static void __init exp_init(void)
615 {
616  nl_cache_mngt_register(&nfnl_exp_ops);
617 }
618 
619 static void __exit exp_exit(void)
620 {
621  nl_cache_mngt_unregister(&nfnl_exp_ops);
622 }
623 
624 /** @} */
struct nl_addr * nl_addr_alloc_attr(const struct nlattr *nla, int family)
Allocate abstract address based on Netlink attribute.
Definition: addr.c:256
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition: addr.c:533
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:699
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition: attr.c:649
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
Definition: attr.h:212
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition: attr.h:194
#define NLA_PUT_ADDR(msg, attrtype, addr)
Add address attribute to netlink message.
Definition: attr.h:283
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:230
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition: attr.c:599
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:895
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition: attr.c:1013
#define NLA_PUT_STRING(msg, attrtype, value)
Add string attribute to netlink message.
Definition: attr.h:257
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:958
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition: attr.c:114
@ NLA_STRING
NUL terminated character string.
Definition: attr.h:39
@ NLA_U8
8 bit integer
Definition: attr.h:35
@ NLA_U16
16 bit integer
Definition: attr.h:36
@ NLA_NESTED
Nested attributes.
Definition: attr.h:42
@ NLA_U32
32 bit integer
Definition: attr.h:37
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition: cache_mngt.c:281
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition: cache_mngt.c:246
int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, struct nl_cache **result)
Allocate new cache and fill it.
Definition: cache.c:228
int nfnl_exp_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
Build a expectation cache holding all expectations currently in the kernel.
Definition: exp.c:576
int nfnl_exp_dump_request(struct nl_sock *sk)
Send nfnl exp dump request.
Definition: exp.c:309
void nlmsg_free(struct nl_msg *msg)
Release a reference from an netlink message.
Definition: msg.c:558
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
Definition: msg.c:208
uint8_t nfnlmsg_family(struct nlmsghdr *nlh)
Get netfilter family from message.
Definition: nfnl.c:146
int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type, int flags, uint8_t family, uint16_t res_id)
Send trivial netfilter netlink message.
Definition: nfnl.c:104
uint8_t nfnlmsg_subtype(struct nlmsghdr *nlh)
Get netfilter message type from message.
Definition: nfnl.c:137
struct nl_msg * nfnlmsg_alloc_simple(uint8_t subsys_id, uint8_t type, int flags, uint8_t family, uint16_t res_id)
Allocate a new netfilter netlink message.
Definition: nfnl.c:197
int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
Definition: nl.c:1241
Attribute validation policy.
Definition: attr.h:63
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:65