libnl  3.2.21
ct.c
1 /*
2  * lib/netfilter/ct.c Conntrack
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10  * Copyright (c) 2007 Philip Craig <philipc@snapgear.com>
11  * Copyright (c) 2007 Secure Computing Corporation
12  * Copyright (c= 2008 Patrick McHardy <kaber@trash.net>
13  */
14 
15 /**
16  * @ingroup nfnl
17  * @defgroup ct Conntrack
18  * @brief
19  * @{
20  */
21 
22 #include <byteswap.h>
23 #include <sys/types.h>
24 #include <linux/netfilter/nfnetlink_conntrack.h>
25 
26 #include <netlink-private/netlink.h>
27 #include <netlink/attr.h>
28 #include <netlink/netfilter/nfnl.h>
29 #include <netlink/netfilter/ct.h>
30 
31 static struct nl_cache_ops nfnl_ct_ops;
32 
33 #if __BYTE_ORDER == __BIG_ENDIAN
34 static uint64_t ntohll(uint64_t x)
35 {
36  return x;
37 }
38 #elif __BYTE_ORDER == __LITTLE_ENDIAN
39 static uint64_t ntohll(uint64_t x)
40 {
41  return bswap_64(x);
42 }
43 #endif
44 
45 static struct nla_policy ct_policy[CTA_MAX+1] = {
46  [CTA_TUPLE_ORIG] = { .type = NLA_NESTED },
47  [CTA_TUPLE_REPLY] = { .type = NLA_NESTED },
48  [CTA_STATUS] = { .type = NLA_U32 },
49  [CTA_PROTOINFO] = { .type = NLA_NESTED },
50  //[CTA_HELP]
51  //[CTA_NAT_SRC]
52  [CTA_TIMEOUT] = { .type = NLA_U32 },
53  [CTA_MARK] = { .type = NLA_U32 },
54  [CTA_COUNTERS_ORIG] = { .type = NLA_NESTED },
55  [CTA_COUNTERS_REPLY] = { .type = NLA_NESTED },
56  [CTA_USE] = { .type = NLA_U32 },
57  [CTA_ID] = { .type = NLA_U32 },
58  //[CTA_NAT_DST]
59 };
60 
61 static struct nla_policy ct_tuple_policy[CTA_TUPLE_MAX+1] = {
62  [CTA_TUPLE_IP] = { .type = NLA_NESTED },
63  [CTA_TUPLE_PROTO] = { .type = NLA_NESTED },
64 };
65 
66 static struct nla_policy ct_ip_policy[CTA_IP_MAX+1] = {
67  [CTA_IP_V4_SRC] = { .type = NLA_U32 },
68  [CTA_IP_V4_DST] = { .type = NLA_U32 },
69  [CTA_IP_V6_SRC] = { .minlen = 16 },
70  [CTA_IP_V6_DST] = { .minlen = 16 },
71 };
72 
73 static struct nla_policy ct_proto_policy[CTA_PROTO_MAX+1] = {
74  [CTA_PROTO_NUM] = { .type = NLA_U8 },
75  [CTA_PROTO_SRC_PORT] = { .type = NLA_U16 },
76  [CTA_PROTO_DST_PORT] = { .type = NLA_U16 },
77  [CTA_PROTO_ICMP_ID] = { .type = NLA_U16 },
78  [CTA_PROTO_ICMP_TYPE] = { .type = NLA_U8 },
79  [CTA_PROTO_ICMP_CODE] = { .type = NLA_U8 },
80  [CTA_PROTO_ICMPV6_ID] = { .type = NLA_U16 },
81  [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 },
82  [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 },
83 };
84 
85 static struct nla_policy ct_protoinfo_policy[CTA_PROTOINFO_MAX+1] = {
86  [CTA_PROTOINFO_TCP] = { .type = NLA_NESTED },
87 };
88 
89 static struct nla_policy ct_protoinfo_tcp_policy[CTA_PROTOINFO_TCP_MAX+1] = {
90  [CTA_PROTOINFO_TCP_STATE] = { .type = NLA_U8 },
91  [CTA_PROTOINFO_TCP_WSCALE_ORIGINAL] = { .type = NLA_U8 },
92  [CTA_PROTOINFO_TCP_WSCALE_REPLY] = { .type = NLA_U8 },
93  [CTA_PROTOINFO_TCP_FLAGS_ORIGINAL] = { .minlen = 2 },
94  [CTA_PROTOINFO_TCP_FLAGS_REPLY] = { .minlen = 2 },
95 
96 };
97 
98 static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = {
99  [CTA_COUNTERS_PACKETS] = { .type = NLA_U64 },
100  [CTA_COUNTERS_BYTES] = { .type = NLA_U64 },
101  [CTA_COUNTERS32_PACKETS]= { .type = NLA_U32 },
102  [CTA_COUNTERS32_BYTES] = { .type = NLA_U32 },
103 };
104 
105 static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
106 {
107  struct nlattr *tb[CTA_IP_MAX+1];
108  struct nl_addr *addr;
109  int err;
110 
111  err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
112  if (err < 0)
113  goto errout;
114 
115  if (tb[CTA_IP_V4_SRC]) {
116  addr = nl_addr_alloc_attr(tb[CTA_IP_V4_SRC], AF_INET);
117  if (addr == NULL)
118  goto errout_enomem;
119  err = nfnl_ct_set_src(ct, repl, addr);
120  nl_addr_put(addr);
121  if (err < 0)
122  goto errout;
123  }
124  if (tb[CTA_IP_V4_DST]) {
125  addr = nl_addr_alloc_attr(tb[CTA_IP_V4_DST], AF_INET);
126  if (addr == NULL)
127  goto errout_enomem;
128  err = nfnl_ct_set_dst(ct, repl, addr);
129  nl_addr_put(addr);
130  if (err < 0)
131  goto errout;
132  }
133  if (tb[CTA_IP_V6_SRC]) {
134  addr = nl_addr_alloc_attr(tb[CTA_IP_V6_SRC], AF_INET6);
135  if (addr == NULL)
136  goto errout_enomem;
137  err = nfnl_ct_set_src(ct, repl, addr);
138  nl_addr_put(addr);
139  if (err < 0)
140  goto errout;
141  }
142  if (tb[CTA_IP_V6_DST]) {
143  addr = nl_addr_alloc_attr(tb[CTA_IP_V6_DST], AF_INET6);
144  if (addr == NULL)
145  goto errout_enomem;
146  err = nfnl_ct_set_dst(ct, repl, addr);
147  nl_addr_put(addr);
148  if (err < 0)
149  goto errout;
150  }
151 
152  return 0;
153 
154 errout_enomem:
155  err = -NLE_NOMEM;
156 errout:
157  return err;
158 }
159 
160 static int ct_parse_proto(struct nfnl_ct *ct, int repl, struct nlattr *attr)
161 {
162  struct nlattr *tb[CTA_PROTO_MAX+1];
163  int err;
164 
165  err = nla_parse_nested(tb, CTA_PROTO_MAX, attr, ct_proto_policy);
166  if (err < 0)
167  return err;
168 
169  if (!repl && tb[CTA_PROTO_NUM])
170  nfnl_ct_set_proto(ct, nla_get_u8(tb[CTA_PROTO_NUM]));
171  if (tb[CTA_PROTO_SRC_PORT])
172  nfnl_ct_set_src_port(ct, repl,
173  ntohs(nla_get_u16(tb[CTA_PROTO_SRC_PORT])));
174  if (tb[CTA_PROTO_DST_PORT])
175  nfnl_ct_set_dst_port(ct, repl,
176  ntohs(nla_get_u16(tb[CTA_PROTO_DST_PORT])));
177 
178  if (ct->ct_family == AF_INET) {
179  if (tb[CTA_PROTO_ICMP_ID])
180  nfnl_ct_set_icmp_id(ct, repl,
181  ntohs(nla_get_u16(tb[CTA_PROTO_ICMP_ID])));
182  if (tb[CTA_PROTO_ICMP_TYPE])
183  nfnl_ct_set_icmp_type(ct, repl,
184  nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]));
185  if (tb[CTA_PROTO_ICMP_CODE])
186  nfnl_ct_set_icmp_code(ct, repl,
187  nla_get_u8(tb[CTA_PROTO_ICMP_CODE]));
188  } else if (ct->ct_family == AF_INET6) {
189  if (tb[CTA_PROTO_ICMPV6_ID])
190  nfnl_ct_set_icmp_id(ct, repl,
191  ntohs(nla_get_u16(tb[CTA_PROTO_ICMPV6_ID])));
192  if (tb[CTA_PROTO_ICMPV6_TYPE])
193  nfnl_ct_set_icmp_type(ct, repl,
194  nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]));
195  if (tb[CTA_PROTO_ICMPV6_CODE])
196  nfnl_ct_set_icmp_code(ct, repl,
197  nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]));
198  }
199 
200  return 0;
201 }
202 
203 static int ct_parse_tuple(struct nfnl_ct *ct, int repl, struct nlattr *attr)
204 {
205  struct nlattr *tb[CTA_TUPLE_MAX+1];
206  int err;
207 
208  err = nla_parse_nested(tb, CTA_TUPLE_MAX, attr, ct_tuple_policy);
209  if (err < 0)
210  return err;
211 
212  if (tb[CTA_TUPLE_IP]) {
213  err = ct_parse_ip(ct, repl, tb[CTA_TUPLE_IP]);
214  if (err < 0)
215  return err;
216  }
217 
218  if (tb[CTA_TUPLE_PROTO]) {
219  err = ct_parse_proto(ct, repl, tb[CTA_TUPLE_PROTO]);
220  if (err < 0)
221  return err;
222  }
223 
224  return 0;
225 }
226 
227 static int ct_parse_protoinfo_tcp(struct nfnl_ct *ct, struct nlattr *attr)
228 {
229  struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1];
230  int err;
231 
232  err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr,
233  ct_protoinfo_tcp_policy);
234  if (err < 0)
235  return err;
236 
237  if (tb[CTA_PROTOINFO_TCP_STATE])
238  nfnl_ct_set_tcp_state(ct,
239  nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]));
240 
241  return 0;
242 }
243 
244 static int ct_parse_protoinfo(struct nfnl_ct *ct, struct nlattr *attr)
245 {
246  struct nlattr *tb[CTA_PROTOINFO_MAX+1];
247  int err;
248 
249  err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr,
250  ct_protoinfo_policy);
251  if (err < 0)
252  return err;
253 
254  if (tb[CTA_PROTOINFO_TCP]) {
255  err = ct_parse_protoinfo_tcp(ct, tb[CTA_PROTOINFO_TCP]);
256  if (err < 0)
257  return err;
258  }
259 
260  return 0;
261 }
262 
263 static int ct_parse_counters(struct nfnl_ct *ct, int repl, struct nlattr *attr)
264 {
265  struct nlattr *tb[CTA_COUNTERS_MAX+1];
266  int err;
267 
268  err = nla_parse_nested(tb, CTA_COUNTERS_MAX, attr, ct_counters_policy);
269  if (err < 0)
270  return err;
271 
272  if (tb[CTA_COUNTERS_PACKETS])
273  nfnl_ct_set_packets(ct, repl,
274  ntohll(nla_get_u64(tb[CTA_COUNTERS_PACKETS])));
275  if (tb[CTA_COUNTERS32_PACKETS])
276  nfnl_ct_set_packets(ct, repl,
277  ntohl(nla_get_u32(tb[CTA_COUNTERS32_PACKETS])));
278  if (tb[CTA_COUNTERS_BYTES])
279  nfnl_ct_set_bytes(ct, repl,
280  ntohll(nla_get_u64(tb[CTA_COUNTERS_BYTES])));
281  if (tb[CTA_COUNTERS32_BYTES])
282  nfnl_ct_set_bytes(ct, repl,
283  ntohl(nla_get_u32(tb[CTA_COUNTERS32_BYTES])));
284 
285  return 0;
286 }
287 
288 int nfnlmsg_ct_group(struct nlmsghdr *nlh)
289 {
290  switch (nfnlmsg_subtype(nlh)) {
291  case IPCTNL_MSG_CT_NEW:
292  if (nlh->nlmsg_flags & (NLM_F_CREATE|NLM_F_EXCL))
293  return NFNLGRP_CONNTRACK_NEW;
294  else
295  return NFNLGRP_CONNTRACK_UPDATE;
296  case IPCTNL_MSG_CT_DELETE:
297  return NFNLGRP_CONNTRACK_DESTROY;
298  default:
299  return NFNLGRP_NONE;
300  }
301 }
302 
303 int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result)
304 {
305  struct nfnl_ct *ct;
306  struct nlattr *tb[CTA_MAX+1];
307  int err;
308 
309  ct = nfnl_ct_alloc();
310  if (!ct)
311  return -NLE_NOMEM;
312 
313  ct->ce_msgtype = nlh->nlmsg_type;
314 
315  err = nlmsg_parse(nlh, sizeof(struct nfgenmsg), tb, CTA_MAX,
316  ct_policy);
317  if (err < 0)
318  goto errout;
319 
320  nfnl_ct_set_family(ct, nfnlmsg_family(nlh));
321 
322  if (tb[CTA_TUPLE_ORIG]) {
323  err = ct_parse_tuple(ct, 0, tb[CTA_TUPLE_ORIG]);
324  if (err < 0)
325  goto errout;
326  }
327  if (tb[CTA_TUPLE_REPLY]) {
328  err = ct_parse_tuple(ct, 1, tb[CTA_TUPLE_REPLY]);
329  if (err < 0)
330  goto errout;
331  }
332 
333  if (tb[CTA_PROTOINFO]) {
334  err = ct_parse_protoinfo(ct, tb[CTA_PROTOINFO]);
335  if (err < 0)
336  goto errout;
337  }
338 
339  if (tb[CTA_STATUS])
340  nfnl_ct_set_status(ct, ntohl(nla_get_u32(tb[CTA_STATUS])));
341  if (tb[CTA_TIMEOUT])
342  nfnl_ct_set_timeout(ct, ntohl(nla_get_u32(tb[CTA_TIMEOUT])));
343  if (tb[CTA_MARK])
344  nfnl_ct_set_mark(ct, ntohl(nla_get_u32(tb[CTA_MARK])));
345  if (tb[CTA_USE])
346  nfnl_ct_set_use(ct, ntohl(nla_get_u32(tb[CTA_USE])));
347  if (tb[CTA_ID])
348  nfnl_ct_set_id(ct, ntohl(nla_get_u32(tb[CTA_ID])));
349 
350  if (tb[CTA_COUNTERS_ORIG]) {
351  err = ct_parse_counters(ct, 0, tb[CTA_COUNTERS_ORIG]);
352  if (err < 0)
353  goto errout;
354  }
355 
356  if (tb[CTA_COUNTERS_REPLY]) {
357  err = ct_parse_counters(ct, 1, tb[CTA_COUNTERS_REPLY]);
358  if (err < 0)
359  goto errout;
360  }
361 
362  *result = ct;
363  return 0;
364 
365 errout:
366  nfnl_ct_put(ct);
367  return err;
368 }
369 
370 static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
371  struct nlmsghdr *nlh, struct nl_parser_param *pp)
372 {
373  struct nfnl_ct *ct;
374  int err;
375 
376  if ((err = nfnlmsg_ct_parse(nlh, &ct)) < 0)
377  goto errout;
378 
379  err = pp->pp_cb((struct nl_object *) ct, pp);
380 errout:
381  nfnl_ct_put(ct);
382  return err;
383 }
384 
385 int nfnl_ct_dump_request(struct nl_sock *sk)
386 {
387  return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
388  NLM_F_DUMP, AF_UNSPEC, 0);
389 }
390 
391 static int ct_request_update(struct nl_cache *cache, struct nl_sock *sk)
392 {
393  return nfnl_ct_dump_request(sk);
394 }
395 
396 static int nfnl_ct_build_tuple(struct nl_msg *msg, const struct nfnl_ct *ct,
397  int repl)
398 {
399  struct nlattr *tuple, *ip, *proto;
400  struct nl_addr *addr;
401  int family;
402 
403  family = nfnl_ct_get_family(ct);
404 
405  tuple = nla_nest_start(msg, repl ? CTA_TUPLE_REPLY : CTA_TUPLE_ORIG);
406  if (!tuple)
407  goto nla_put_failure;
408 
409  ip = nla_nest_start(msg, CTA_TUPLE_IP);
410  if (!ip)
411  goto nla_put_failure;
412 
413  addr = nfnl_ct_get_src(ct, repl);
414  if (addr)
415  NLA_PUT_ADDR(msg,
416  family == AF_INET ? CTA_IP_V4_SRC : CTA_IP_V6_SRC,
417  addr);
418 
419  addr = nfnl_ct_get_dst(ct, repl);
420  if (addr)
421  NLA_PUT_ADDR(msg,
422  family == AF_INET ? CTA_IP_V4_DST : CTA_IP_V6_DST,
423  addr);
424 
425  nla_nest_end(msg, ip);
426 
427  proto = nla_nest_start(msg, CTA_TUPLE_PROTO);
428  if (!proto)
429  goto nla_put_failure;
430 
431  if (nfnl_ct_test_proto(ct))
432  NLA_PUT_U8(msg, CTA_PROTO_NUM, nfnl_ct_get_proto(ct));
433 
434  if (nfnl_ct_test_src_port(ct, repl))
435  NLA_PUT_U16(msg, CTA_PROTO_SRC_PORT,
436  htons(nfnl_ct_get_src_port(ct, repl)));
437 
438  if (nfnl_ct_test_dst_port(ct, repl))
439  NLA_PUT_U16(msg, CTA_PROTO_DST_PORT,
440  htons(nfnl_ct_get_dst_port(ct, repl)));
441 
442  if (family == AF_INET) {
443  if (nfnl_ct_test_icmp_id(ct, repl))
444  NLA_PUT_U16(msg, CTA_PROTO_ICMP_ID,
445  htons(nfnl_ct_get_icmp_id(ct, repl)));
446 
447  if (nfnl_ct_test_icmp_type(ct, repl))
448  NLA_PUT_U8(msg, CTA_PROTO_ICMP_TYPE,
449  nfnl_ct_get_icmp_type(ct, repl));
450 
451  if (nfnl_ct_test_icmp_code(ct, repl))
452  NLA_PUT_U8(msg, CTA_PROTO_ICMP_CODE,
453  nfnl_ct_get_icmp_code(ct, repl));
454  } else if (family == AF_INET6) {
455  if (nfnl_ct_test_icmp_id(ct, repl))
456  NLA_PUT_U16(msg, CTA_PROTO_ICMPV6_ID,
457  htons(nfnl_ct_get_icmp_id(ct, repl)));
458 
459  if (nfnl_ct_test_icmp_type(ct, repl))
460  NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_TYPE,
461  nfnl_ct_get_icmp_type(ct, repl));
462 
463  if (nfnl_ct_test_icmp_code(ct, repl))
464  NLA_PUT_U8(msg, CTA_PROTO_ICMPV6_CODE,
465  nfnl_ct_get_icmp_code(ct, repl));
466  }
467 
468  nla_nest_end(msg, proto);
469 
470  nla_nest_end(msg, tuple);
471  return 0;
472 
473 nla_put_failure:
474  return -NLE_MSGSIZE;
475 }
476 
477 static int nfnl_ct_build_message(const struct nfnl_ct *ct, int cmd, int flags,
478  struct nl_msg **result)
479 {
480  struct nl_msg *msg;
481  int err;
482 
483  msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK, cmd, flags,
484  nfnl_ct_get_family(ct), 0);
485  if (msg == NULL)
486  return -NLE_NOMEM;
487 
488  if ((err = nfnl_ct_build_tuple(msg, ct, 0)) < 0)
489  goto err_out;
490 
491  *result = msg;
492  return 0;
493 
494 err_out:
495  nlmsg_free(msg);
496  return err;
497 }
498 
499 int nfnl_ct_build_add_request(const struct nfnl_ct *ct, int flags,
500  struct nl_msg **result)
501 {
502  return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_NEW, flags, result);
503 }
504 
505 int nfnl_ct_add(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
506 {
507  struct nl_msg *msg;
508  int err;
509 
510  if ((err = nfnl_ct_build_add_request(ct, flags, &msg)) < 0)
511  return err;
512 
513  err = nl_send_auto_complete(sk, msg);
514  nlmsg_free(msg);
515  if (err < 0)
516  return err;
517 
518  return wait_for_ack(sk);
519 }
520 
521 int nfnl_ct_build_delete_request(const struct nfnl_ct *ct, int flags,
522  struct nl_msg **result)
523 {
524  return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_DELETE, flags, result);
525 }
526 
527 int nfnl_ct_del(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
528 {
529  struct nl_msg *msg;
530  int err;
531 
532  if ((err = nfnl_ct_build_delete_request(ct, flags, &msg)) < 0)
533  return err;
534 
535  err = nl_send_auto_complete(sk, msg);
536  nlmsg_free(msg);
537  if (err < 0)
538  return err;
539 
540  return wait_for_ack(sk);
541 }
542 
543 int nfnl_ct_build_query_request(const struct nfnl_ct *ct, int flags,
544  struct nl_msg **result)
545 {
546  return nfnl_ct_build_message(ct, IPCTNL_MSG_CT_GET, flags, result);
547 }
548 
549 int nfnl_ct_query(struct nl_sock *sk, const struct nfnl_ct *ct, int flags)
550 {
551  struct nl_msg *msg;
552  int err;
553 
554  if ((err = nfnl_ct_build_query_request(ct, flags, &msg)) < 0)
555  return err;
556 
557  err = nl_send_auto_complete(sk, msg);
558  nlmsg_free(msg);
559  if (err < 0)
560  return err;
561 
562  return wait_for_ack(sk);
563 }
564 
565 /**
566  * @name Cache Management
567  * @{
568  */
569 
570 /**
571  * Build a conntrack cache holding all conntrack currently in the kernel
572  * @arg sk Netlink socket.
573  * @arg result Pointer to store resulting cache.
574  *
575  * Allocates a new cache, initializes it properly and updates it to
576  * contain all conntracks currently in the kernel.
577  *
578  * @return 0 on success or a negative error code.
579  */
580 int nfnl_ct_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
581 {
582  return nl_cache_alloc_and_fill(&nfnl_ct_ops, sk, result);
583 }
584 
585 /** @} */
586 
587 /**
588  * @name Conntrack Addition
589  * @{
590  */
591 
592 /** @} */
593 
594 static struct nl_af_group ct_groups[] = {
595  { AF_UNSPEC, NFNLGRP_CONNTRACK_NEW },
596  { AF_UNSPEC, NFNLGRP_CONNTRACK_UPDATE },
597  { AF_UNSPEC, NFNLGRP_CONNTRACK_DESTROY },
598  { END_OF_GROUP_LIST },
599 };
600 
601 #define NFNLMSG_CT_TYPE(type) NFNLMSG_TYPE(NFNL_SUBSYS_CTNETLINK, (type))
602 static struct nl_cache_ops nfnl_ct_ops = {
603  .co_name = "netfilter/ct",
604  .co_hdrsize = NFNL_HDRLEN,
605  .co_msgtypes = {
606  { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_NEW), NL_ACT_NEW, "new" },
607  { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_GET), NL_ACT_GET, "get" },
608  { NFNLMSG_CT_TYPE(IPCTNL_MSG_CT_DELETE), NL_ACT_DEL, "del" },
609  END_OF_MSGTYPES_LIST,
610  },
611  .co_protocol = NETLINK_NETFILTER,
612  .co_groups = ct_groups,
613  .co_request_update = ct_request_update,
614  .co_msg_parser = ct_msg_parser,
615  .co_obj_ops = &ct_obj_ops,
616 };
617 
618 static void __init ct_init(void)
619 {
620  nl_cache_mngt_register(&nfnl_ct_ops);
621 }
622 
623 static void __exit ct_exit(void)
624 {
625  nl_cache_mngt_unregister(&nfnl_ct_ops);
626 }
627 
628 /** @} */