1 /* Connection tracking via netlink socket. Allows for user space
2 * protocol helpers and general trouble making from userspace.
4 * (C) 2001 by Jay Schulist <jschlst@samba.org>
5 * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
6 * (C) 2003 by Patrick Mchardy <kaber@trash.net>
7 * (C) 2005-2006 by Pablo Neira Ayuso <pablo@eurodev.net>
9 * I've reworked this stuff to use attributes instead of conntrack
10 * structures. 5.44 am. I need more tea. --pablo 05/07/11.
12 * Initial connection tracking via netlink development funded and
13 * generally made possible by Network Robots, Inc. (www.networkrobots.com)
15 * Further development of this code funded by Astaro AG (http://www.astaro.com)
17 * This software may be used and distributed according to the terms
18 * of the GNU General Public License, incorporated herein by reference.
21 #include <linux/init.h>
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/types.h>
25 #include <linux/timer.h>
26 #include <linux/skbuff.h>
27 #include <linux/errno.h>
28 #include <linux/netlink.h>
29 #include <linux/spinlock.h>
30 #include <linux/interrupt.h>
31 #include <linux/notifier.h>
33 #include <linux/netfilter.h>
34 #include <linux/netfilter_ipv4/ip_conntrack.h>
35 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
36 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
37 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
38 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
40 #include <linux/netfilter/nfnetlink.h>
41 #include <linux/netfilter/nfnetlink_conntrack.h>
43 MODULE_LICENSE("GPL");
45 static char __initdata version
[] = "0.90";
48 ctnetlink_dump_tuples_proto(struct sk_buff
*skb
,
49 const struct ip_conntrack_tuple
*tuple
,
50 struct ip_conntrack_protocol
*proto
)
53 struct nfattr
*nest_parms
= NFA_NEST(skb
, CTA_TUPLE_PROTO
);
55 NFA_PUT(skb
, CTA_PROTO_NUM
, sizeof(u_int8_t
), &tuple
->dst
.protonum
);
57 if (likely(proto
->tuple_to_nfattr
))
58 ret
= proto
->tuple_to_nfattr(skb
, tuple
);
60 NFA_NEST_END(skb
, nest_parms
);
69 ctnetlink_dump_tuples_ip(struct sk_buff
*skb
,
70 const struct ip_conntrack_tuple
*tuple
)
72 struct nfattr
*nest_parms
= NFA_NEST(skb
, CTA_TUPLE_IP
);
74 NFA_PUT(skb
, CTA_IP_V4_SRC
, sizeof(__be32
), &tuple
->src
.ip
);
75 NFA_PUT(skb
, CTA_IP_V4_DST
, sizeof(__be32
), &tuple
->dst
.ip
);
77 NFA_NEST_END(skb
, nest_parms
);
86 ctnetlink_dump_tuples(struct sk_buff
*skb
,
87 const struct ip_conntrack_tuple
*tuple
)
90 struct ip_conntrack_protocol
*proto
;
92 ret
= ctnetlink_dump_tuples_ip(skb
, tuple
);
93 if (unlikely(ret
< 0))
96 proto
= ip_conntrack_proto_find_get(tuple
->dst
.protonum
);
97 ret
= ctnetlink_dump_tuples_proto(skb
, tuple
, proto
);
98 ip_conntrack_proto_put(proto
);
104 ctnetlink_dump_status(struct sk_buff
*skb
, const struct ip_conntrack
*ct
)
106 __be32 status
= htonl((u_int32_t
) ct
->status
);
107 NFA_PUT(skb
, CTA_STATUS
, sizeof(status
), &status
);
115 ctnetlink_dump_timeout(struct sk_buff
*skb
, const struct ip_conntrack
*ct
)
117 long timeout_l
= ct
->timeout
.expires
- jiffies
;
123 timeout
= htonl(timeout_l
/ HZ
);
125 NFA_PUT(skb
, CTA_TIMEOUT
, sizeof(timeout
), &timeout
);
133 ctnetlink_dump_protoinfo(struct sk_buff
*skb
, const struct ip_conntrack
*ct
)
135 struct ip_conntrack_protocol
*proto
= ip_conntrack_proto_find_get(ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.protonum
);
137 struct nfattr
*nest_proto
;
140 if (!proto
->to_nfattr
) {
141 ip_conntrack_proto_put(proto
);
145 nest_proto
= NFA_NEST(skb
, CTA_PROTOINFO
);
147 ret
= proto
->to_nfattr(skb
, nest_proto
, ct
);
149 ip_conntrack_proto_put(proto
);
151 NFA_NEST_END(skb
, nest_proto
);
156 ip_conntrack_proto_put(proto
);
161 ctnetlink_dump_helpinfo(struct sk_buff
*skb
, const struct ip_conntrack
*ct
)
163 struct nfattr
*nest_helper
;
168 nest_helper
= NFA_NEST(skb
, CTA_HELP
);
169 NFA_PUT(skb
, CTA_HELP_NAME
, strlen(ct
->helper
->name
), ct
->helper
->name
);
171 if (ct
->helper
->to_nfattr
)
172 ct
->helper
->to_nfattr(skb
, ct
);
174 NFA_NEST_END(skb
, nest_helper
);
182 #ifdef CONFIG_IP_NF_CT_ACCT
184 ctnetlink_dump_counters(struct sk_buff
*skb
, const struct ip_conntrack
*ct
,
185 enum ip_conntrack_dir dir
)
187 enum ctattr_type type
= dir
? CTA_COUNTERS_REPLY
: CTA_COUNTERS_ORIG
;
188 struct nfattr
*nest_count
= NFA_NEST(skb
, type
);
191 tmp
= htonl(ct
->counters
[dir
].packets
);
192 NFA_PUT(skb
, CTA_COUNTERS32_PACKETS
, sizeof(__be32
), &tmp
);
194 tmp
= htonl(ct
->counters
[dir
].bytes
);
195 NFA_PUT(skb
, CTA_COUNTERS32_BYTES
, sizeof(__be32
), &tmp
);
197 NFA_NEST_END(skb
, nest_count
);
205 #define ctnetlink_dump_counters(a, b, c) (0)
208 #ifdef CONFIG_IP_NF_CONNTRACK_MARK
210 ctnetlink_dump_mark(struct sk_buff
*skb
, const struct ip_conntrack
*ct
)
212 __be32 mark
= htonl(ct
->mark
);
214 NFA_PUT(skb
, CTA_MARK
, sizeof(__be32
), &mark
);
221 #define ctnetlink_dump_mark(a, b) (0)
225 ctnetlink_dump_id(struct sk_buff
*skb
, const struct ip_conntrack
*ct
)
227 __be32 id
= htonl(ct
->id
);
228 NFA_PUT(skb
, CTA_ID
, sizeof(__be32
), &id
);
236 ctnetlink_dump_use(struct sk_buff
*skb
, const struct ip_conntrack
*ct
)
238 __be32 use
= htonl(atomic_read(&ct
->ct_general
.use
));
240 NFA_PUT(skb
, CTA_USE
, sizeof(__be32
), &use
);
247 #define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple)
250 ctnetlink_fill_info(struct sk_buff
*skb
, u32 pid
, u32 seq
,
251 int event
, int nowait
,
252 const struct ip_conntrack
*ct
)
254 struct nlmsghdr
*nlh
;
255 struct nfgenmsg
*nfmsg
;
256 struct nfattr
*nest_parms
;
261 event
|= NFNL_SUBSYS_CTNETLINK
<< 8;
262 nlh
= NLMSG_PUT(skb
, pid
, seq
, event
, sizeof(struct nfgenmsg
));
263 nfmsg
= NLMSG_DATA(nlh
);
265 nlh
->nlmsg_flags
= (nowait
&& pid
) ? NLM_F_MULTI
: 0;
266 nfmsg
->nfgen_family
= AF_INET
;
267 nfmsg
->version
= NFNETLINK_V0
;
270 nest_parms
= NFA_NEST(skb
, CTA_TUPLE_ORIG
);
271 if (ctnetlink_dump_tuples(skb
, tuple(ct
, IP_CT_DIR_ORIGINAL
)) < 0)
273 NFA_NEST_END(skb
, nest_parms
);
275 nest_parms
= NFA_NEST(skb
, CTA_TUPLE_REPLY
);
276 if (ctnetlink_dump_tuples(skb
, tuple(ct
, IP_CT_DIR_REPLY
)) < 0)
278 NFA_NEST_END(skb
, nest_parms
);
280 if (ctnetlink_dump_status(skb
, ct
) < 0 ||
281 ctnetlink_dump_timeout(skb
, ct
) < 0 ||
282 ctnetlink_dump_counters(skb
, ct
, IP_CT_DIR_ORIGINAL
) < 0 ||
283 ctnetlink_dump_counters(skb
, ct
, IP_CT_DIR_REPLY
) < 0 ||
284 ctnetlink_dump_protoinfo(skb
, ct
) < 0 ||
285 ctnetlink_dump_helpinfo(skb
, ct
) < 0 ||
286 ctnetlink_dump_mark(skb
, ct
) < 0 ||
287 ctnetlink_dump_id(skb
, ct
) < 0 ||
288 ctnetlink_dump_use(skb
, ct
) < 0)
291 nlh
->nlmsg_len
= skb
->tail
- b
;
296 skb_trim(skb
, b
- skb
->data
);
300 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
301 static int ctnetlink_conntrack_event(struct notifier_block
*this,
302 unsigned long events
, void *ptr
)
304 struct nlmsghdr
*nlh
;
305 struct nfgenmsg
*nfmsg
;
306 struct nfattr
*nest_parms
;
307 struct ip_conntrack
*ct
= (struct ip_conntrack
*)ptr
;
311 unsigned int flags
= 0, group
;
313 /* ignore our fake conntrack entry */
314 if (ct
== &ip_conntrack_untracked
)
317 if (events
& IPCT_DESTROY
) {
318 type
= IPCTNL_MSG_CT_DELETE
;
319 group
= NFNLGRP_CONNTRACK_DESTROY
;
320 } else if (events
& (IPCT_NEW
| IPCT_RELATED
)) {
321 type
= IPCTNL_MSG_CT_NEW
;
322 flags
= NLM_F_CREATE
|NLM_F_EXCL
;
323 group
= NFNLGRP_CONNTRACK_NEW
;
324 } else if (events
& (IPCT_STATUS
| IPCT_PROTOINFO
)) {
325 type
= IPCTNL_MSG_CT_NEW
;
326 group
= NFNLGRP_CONNTRACK_UPDATE
;
330 if (!nfnetlink_has_listeners(group
))
333 skb
= alloc_skb(NLMSG_GOODSIZE
, GFP_ATOMIC
);
339 type
|= NFNL_SUBSYS_CTNETLINK
<< 8;
340 nlh
= NLMSG_PUT(skb
, 0, 0, type
, sizeof(struct nfgenmsg
));
341 nfmsg
= NLMSG_DATA(nlh
);
343 nlh
->nlmsg_flags
= flags
;
344 nfmsg
->nfgen_family
= AF_INET
;
345 nfmsg
->version
= NFNETLINK_V0
;
348 nest_parms
= NFA_NEST(skb
, CTA_TUPLE_ORIG
);
349 if (ctnetlink_dump_tuples(skb
, tuple(ct
, IP_CT_DIR_ORIGINAL
)) < 0)
351 NFA_NEST_END(skb
, nest_parms
);
353 nest_parms
= NFA_NEST(skb
, CTA_TUPLE_REPLY
);
354 if (ctnetlink_dump_tuples(skb
, tuple(ct
, IP_CT_DIR_REPLY
)) < 0)
356 NFA_NEST_END(skb
, nest_parms
);
358 if (events
& IPCT_DESTROY
) {
359 if (ctnetlink_dump_counters(skb
, ct
, IP_CT_DIR_ORIGINAL
) < 0 ||
360 ctnetlink_dump_counters(skb
, ct
, IP_CT_DIR_REPLY
) < 0)
363 if (ctnetlink_dump_status(skb
, ct
) < 0)
366 if (ctnetlink_dump_timeout(skb
, ct
) < 0)
369 if (events
& IPCT_PROTOINFO
370 && ctnetlink_dump_protoinfo(skb
, ct
) < 0)
373 if ((events
& IPCT_HELPER
|| ct
->helper
)
374 && ctnetlink_dump_helpinfo(skb
, ct
) < 0)
377 if ((events
& IPCT_MARK
|| ct
->mark
)
378 && ctnetlink_dump_mark(skb
, ct
) < 0)
381 if (events
& IPCT_COUNTER_FILLING
&&
382 (ctnetlink_dump_counters(skb
, ct
, IP_CT_DIR_ORIGINAL
) < 0 ||
383 ctnetlink_dump_counters(skb
, ct
, IP_CT_DIR_REPLY
) < 0))
387 nlh
->nlmsg_len
= skb
->tail
- b
;
388 nfnetlink_send(skb
, 0, group
, 0);
396 #endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
398 static int ctnetlink_done(struct netlink_callback
*cb
)
401 ip_conntrack_put((struct ip_conntrack
*)cb
->args
[1]);
406 ctnetlink_dump_table(struct sk_buff
*skb
, struct netlink_callback
*cb
)
408 struct ip_conntrack
*ct
, *last
;
409 struct ip_conntrack_tuple_hash
*h
;
412 read_lock_bh(&ip_conntrack_lock
);
413 last
= (struct ip_conntrack
*)cb
->args
[1];
414 for (; cb
->args
[0] < ip_conntrack_htable_size
; cb
->args
[0]++) {
416 list_for_each_prev(i
, &ip_conntrack_hash
[cb
->args
[0]]) {
417 h
= (struct ip_conntrack_tuple_hash
*) i
;
418 if (DIRECTION(h
) != IP_CT_DIR_ORIGINAL
)
420 ct
= tuplehash_to_ctrack(h
);
426 if (ctnetlink_fill_info(skb
, NETLINK_CB(cb
->skb
).pid
,
430 nf_conntrack_get(&ct
->ct_general
);
431 cb
->args
[1] = (unsigned long)ct
;
434 #ifdef CONFIG_NF_CT_ACCT
435 if (NFNL_MSG_TYPE(cb
->nlh
->nlmsg_type
) ==
436 IPCTNL_MSG_CT_GET_CTRZERO
)
437 memset(&ct
->counters
, 0, sizeof(ct
->counters
));
446 read_unlock_bh(&ip_conntrack_lock
);
448 ip_conntrack_put(last
);
453 static const size_t cta_min_ip
[CTA_IP_MAX
] = {
454 [CTA_IP_V4_SRC
-1] = sizeof(__be32
),
455 [CTA_IP_V4_DST
-1] = sizeof(__be32
),
459 ctnetlink_parse_tuple_ip(struct nfattr
*attr
, struct ip_conntrack_tuple
*tuple
)
461 struct nfattr
*tb
[CTA_IP_MAX
];
463 nfattr_parse_nested(tb
, CTA_IP_MAX
, attr
);
465 if (nfattr_bad_size(tb
, CTA_IP_MAX
, cta_min_ip
))
468 if (!tb
[CTA_IP_V4_SRC
-1])
470 tuple
->src
.ip
= *(__be32
*)NFA_DATA(tb
[CTA_IP_V4_SRC
-1]);
472 if (!tb
[CTA_IP_V4_DST
-1])
474 tuple
->dst
.ip
= *(__be32
*)NFA_DATA(tb
[CTA_IP_V4_DST
-1]);
479 static const size_t cta_min_proto
[CTA_PROTO_MAX
] = {
480 [CTA_PROTO_NUM
-1] = sizeof(u_int8_t
),
481 [CTA_PROTO_SRC_PORT
-1] = sizeof(u_int16_t
),
482 [CTA_PROTO_DST_PORT
-1] = sizeof(u_int16_t
),
483 [CTA_PROTO_ICMP_TYPE
-1] = sizeof(u_int8_t
),
484 [CTA_PROTO_ICMP_CODE
-1] = sizeof(u_int8_t
),
485 [CTA_PROTO_ICMP_ID
-1] = sizeof(u_int16_t
),
489 ctnetlink_parse_tuple_proto(struct nfattr
*attr
,
490 struct ip_conntrack_tuple
*tuple
)
492 struct nfattr
*tb
[CTA_PROTO_MAX
];
493 struct ip_conntrack_protocol
*proto
;
496 nfattr_parse_nested(tb
, CTA_PROTO_MAX
, attr
);
498 if (nfattr_bad_size(tb
, CTA_PROTO_MAX
, cta_min_proto
))
501 if (!tb
[CTA_PROTO_NUM
-1])
503 tuple
->dst
.protonum
= *(u_int8_t
*)NFA_DATA(tb
[CTA_PROTO_NUM
-1]);
505 proto
= ip_conntrack_proto_find_get(tuple
->dst
.protonum
);
507 if (likely(proto
->nfattr_to_tuple
))
508 ret
= proto
->nfattr_to_tuple(tb
, tuple
);
510 ip_conntrack_proto_put(proto
);
516 ctnetlink_parse_tuple(struct nfattr
*cda
[], struct ip_conntrack_tuple
*tuple
,
517 enum ctattr_tuple type
)
519 struct nfattr
*tb
[CTA_TUPLE_MAX
];
522 memset(tuple
, 0, sizeof(*tuple
));
524 nfattr_parse_nested(tb
, CTA_TUPLE_MAX
, cda
[type
-1]);
526 if (!tb
[CTA_TUPLE_IP
-1])
529 err
= ctnetlink_parse_tuple_ip(tb
[CTA_TUPLE_IP
-1], tuple
);
533 if (!tb
[CTA_TUPLE_PROTO
-1])
536 err
= ctnetlink_parse_tuple_proto(tb
[CTA_TUPLE_PROTO
-1], tuple
);
540 /* orig and expect tuples get DIR_ORIGINAL */
541 if (type
== CTA_TUPLE_REPLY
)
542 tuple
->dst
.dir
= IP_CT_DIR_REPLY
;
544 tuple
->dst
.dir
= IP_CT_DIR_ORIGINAL
;
549 #ifdef CONFIG_IP_NF_NAT_NEEDED
550 static const size_t cta_min_protonat
[CTA_PROTONAT_MAX
] = {
551 [CTA_PROTONAT_PORT_MIN
-1] = sizeof(u_int16_t
),
552 [CTA_PROTONAT_PORT_MAX
-1] = sizeof(u_int16_t
),
555 static int ctnetlink_parse_nat_proto(struct nfattr
*attr
,
556 const struct ip_conntrack
*ct
,
557 struct ip_nat_range
*range
)
559 struct nfattr
*tb
[CTA_PROTONAT_MAX
];
560 struct ip_nat_protocol
*npt
;
562 nfattr_parse_nested(tb
, CTA_PROTONAT_MAX
, attr
);
564 if (nfattr_bad_size(tb
, CTA_PROTONAT_MAX
, cta_min_protonat
))
567 npt
= ip_nat_proto_find_get(ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.protonum
);
569 if (!npt
->nfattr_to_range
) {
570 ip_nat_proto_put(npt
);
574 /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */
575 if (npt
->nfattr_to_range(tb
, range
) > 0)
576 range
->flags
|= IP_NAT_RANGE_PROTO_SPECIFIED
;
578 ip_nat_proto_put(npt
);
583 static const size_t cta_min_nat
[CTA_NAT_MAX
] = {
584 [CTA_NAT_MINIP
-1] = sizeof(__be32
),
585 [CTA_NAT_MAXIP
-1] = sizeof(__be32
),
589 ctnetlink_parse_nat(struct nfattr
*nat
,
590 const struct ip_conntrack
*ct
, struct ip_nat_range
*range
)
592 struct nfattr
*tb
[CTA_NAT_MAX
];
595 memset(range
, 0, sizeof(*range
));
597 nfattr_parse_nested(tb
, CTA_NAT_MAX
, nat
);
599 if (nfattr_bad_size(tb
, CTA_NAT_MAX
, cta_min_nat
))
602 if (tb
[CTA_NAT_MINIP
-1])
603 range
->min_ip
= *(__be32
*)NFA_DATA(tb
[CTA_NAT_MINIP
-1]);
605 if (!tb
[CTA_NAT_MAXIP
-1])
606 range
->max_ip
= range
->min_ip
;
608 range
->max_ip
= *(__be32
*)NFA_DATA(tb
[CTA_NAT_MAXIP
-1]);
611 range
->flags
|= IP_NAT_RANGE_MAP_IPS
;
613 if (!tb
[CTA_NAT_PROTO
-1])
616 err
= ctnetlink_parse_nat_proto(tb
[CTA_NAT_PROTO
-1], ct
, range
);
625 ctnetlink_parse_help(struct nfattr
*attr
, char **helper_name
)
627 struct nfattr
*tb
[CTA_HELP_MAX
];
629 nfattr_parse_nested(tb
, CTA_HELP_MAX
, attr
);
631 if (!tb
[CTA_HELP_NAME
-1])
634 *helper_name
= NFA_DATA(tb
[CTA_HELP_NAME
-1]);
639 static const size_t cta_min
[CTA_MAX
] = {
640 [CTA_STATUS
-1] = sizeof(__be32
),
641 [CTA_TIMEOUT
-1] = sizeof(__be32
),
642 [CTA_MARK
-1] = sizeof(__be32
),
643 [CTA_USE
-1] = sizeof(__be32
),
644 [CTA_ID
-1] = sizeof(__be32
)
648 ctnetlink_del_conntrack(struct sock
*ctnl
, struct sk_buff
*skb
,
649 struct nlmsghdr
*nlh
, struct nfattr
*cda
[], int *errp
)
651 struct ip_conntrack_tuple_hash
*h
;
652 struct ip_conntrack_tuple tuple
;
653 struct ip_conntrack
*ct
;
656 if (nfattr_bad_size(cda
, CTA_MAX
, cta_min
))
659 if (cda
[CTA_TUPLE_ORIG
-1])
660 err
= ctnetlink_parse_tuple(cda
, &tuple
, CTA_TUPLE_ORIG
);
661 else if (cda
[CTA_TUPLE_REPLY
-1])
662 err
= ctnetlink_parse_tuple(cda
, &tuple
, CTA_TUPLE_REPLY
);
664 /* Flush the whole table */
665 ip_conntrack_flush();
672 h
= ip_conntrack_find_get(&tuple
, NULL
);
676 ct
= tuplehash_to_ctrack(h
);
679 u_int32_t id
= ntohl(*(__be32
*)NFA_DATA(cda
[CTA_ID
-1]));
681 ip_conntrack_put(ct
);
685 if (del_timer(&ct
->timeout
))
686 ct
->timeout
.function((unsigned long)ct
);
688 ip_conntrack_put(ct
);
694 ctnetlink_get_conntrack(struct sock
*ctnl
, struct sk_buff
*skb
,
695 struct nlmsghdr
*nlh
, struct nfattr
*cda
[], int *errp
)
697 struct ip_conntrack_tuple_hash
*h
;
698 struct ip_conntrack_tuple tuple
;
699 struct ip_conntrack
*ct
;
700 struct sk_buff
*skb2
= NULL
;
703 if (nlh
->nlmsg_flags
& NLM_F_DUMP
) {
704 struct nfgenmsg
*msg
= NLMSG_DATA(nlh
);
707 if (msg
->nfgen_family
!= AF_INET
)
708 return -EAFNOSUPPORT
;
710 #ifndef CONFIG_IP_NF_CT_ACCT
711 if (NFNL_MSG_TYPE(nlh
->nlmsg_type
) == IPCTNL_MSG_CT_GET_CTRZERO
)
714 if ((*errp
= netlink_dump_start(ctnl
, skb
, nlh
,
715 ctnetlink_dump_table
,
716 ctnetlink_done
)) != 0)
719 rlen
= NLMSG_ALIGN(nlh
->nlmsg_len
);
726 if (nfattr_bad_size(cda
, CTA_MAX
, cta_min
))
729 if (cda
[CTA_TUPLE_ORIG
-1])
730 err
= ctnetlink_parse_tuple(cda
, &tuple
, CTA_TUPLE_ORIG
);
731 else if (cda
[CTA_TUPLE_REPLY
-1])
732 err
= ctnetlink_parse_tuple(cda
, &tuple
, CTA_TUPLE_REPLY
);
739 h
= ip_conntrack_find_get(&tuple
, NULL
);
743 ct
= tuplehash_to_ctrack(h
);
746 skb2
= alloc_skb(NLMSG_GOODSIZE
, GFP_KERNEL
);
748 ip_conntrack_put(ct
);
752 err
= ctnetlink_fill_info(skb2
, NETLINK_CB(skb
).pid
, nlh
->nlmsg_seq
,
753 IPCTNL_MSG_CT_NEW
, 1, ct
);
754 ip_conntrack_put(ct
);
758 err
= netlink_unicast(ctnl
, skb2
, NETLINK_CB(skb
).pid
, MSG_DONTWAIT
);
771 ctnetlink_change_status(struct ip_conntrack
*ct
, struct nfattr
*cda
[])
774 unsigned status
= ntohl(*(__be32
*)NFA_DATA(cda
[CTA_STATUS
-1]));
775 d
= ct
->status
^ status
;
777 if (d
& (IPS_EXPECTED
|IPS_CONFIRMED
|IPS_DYING
))
781 if (d
& IPS_SEEN_REPLY
&& !(status
& IPS_SEEN_REPLY
))
782 /* SEEN_REPLY bit can only be set */
786 if (d
& IPS_ASSURED
&& !(status
& IPS_ASSURED
))
787 /* ASSURED bit can only be set */
790 if (cda
[CTA_NAT_SRC
-1] || cda
[CTA_NAT_DST
-1]) {
791 #ifndef CONFIG_IP_NF_NAT_NEEDED
794 struct ip_nat_range range
;
796 if (cda
[CTA_NAT_DST
-1]) {
797 if (ctnetlink_parse_nat(cda
[CTA_NAT_DST
-1], ct
,
800 if (ip_nat_initialized(ct
,
801 HOOK2MANIP(NF_IP_PRE_ROUTING
)))
803 ip_nat_setup_info(ct
, &range
, NF_IP_PRE_ROUTING
);
805 if (cda
[CTA_NAT_SRC
-1]) {
806 if (ctnetlink_parse_nat(cda
[CTA_NAT_SRC
-1], ct
,
809 if (ip_nat_initialized(ct
,
810 HOOK2MANIP(NF_IP_POST_ROUTING
)))
812 ip_nat_setup_info(ct
, &range
, NF_IP_POST_ROUTING
);
817 /* Be careful here, modifying NAT bits can screw up things,
818 * so don't let users modify them directly if they don't pass
820 ct
->status
|= status
& ~(IPS_NAT_DONE_MASK
| IPS_NAT_MASK
);
826 ctnetlink_change_helper(struct ip_conntrack
*ct
, struct nfattr
*cda
[])
828 struct ip_conntrack_helper
*helper
;
832 /* don't change helper of sibling connections */
836 err
= ctnetlink_parse_help(cda
[CTA_HELP
-1], &helpname
);
840 helper
= __ip_conntrack_helper_find_byname(helpname
);
842 if (!strcmp(helpname
, ""))
850 /* we had a helper before ... */
851 ip_ct_remove_expectations(ct
);
854 /* need to zero data of old helper */
855 memset(&ct
->help
, 0, sizeof(ct
->help
));
865 ctnetlink_change_timeout(struct ip_conntrack
*ct
, struct nfattr
*cda
[])
867 u_int32_t timeout
= ntohl(*(__be32
*)NFA_DATA(cda
[CTA_TIMEOUT
-1]));
869 if (!del_timer(&ct
->timeout
))
872 ct
->timeout
.expires
= jiffies
+ timeout
* HZ
;
873 add_timer(&ct
->timeout
);
879 ctnetlink_change_protoinfo(struct ip_conntrack
*ct
, struct nfattr
*cda
[])
881 struct nfattr
*tb
[CTA_PROTOINFO_MAX
], *attr
= cda
[CTA_PROTOINFO
-1];
882 struct ip_conntrack_protocol
*proto
;
883 u_int16_t npt
= ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.protonum
;
886 nfattr_parse_nested(tb
, CTA_PROTOINFO_MAX
, attr
);
888 proto
= ip_conntrack_proto_find_get(npt
);
890 if (proto
->from_nfattr
)
891 err
= proto
->from_nfattr(tb
, ct
);
892 ip_conntrack_proto_put(proto
);
898 ctnetlink_change_conntrack(struct ip_conntrack
*ct
, struct nfattr
*cda
[])
902 if (cda
[CTA_HELP
-1]) {
903 err
= ctnetlink_change_helper(ct
, cda
);
908 if (cda
[CTA_TIMEOUT
-1]) {
909 err
= ctnetlink_change_timeout(ct
, cda
);
914 if (cda
[CTA_STATUS
-1]) {
915 err
= ctnetlink_change_status(ct
, cda
);
920 if (cda
[CTA_PROTOINFO
-1]) {
921 err
= ctnetlink_change_protoinfo(ct
, cda
);
926 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
928 ct
->mark
= ntohl(*(__be32
*)NFA_DATA(cda
[CTA_MARK
-1]));
935 ctnetlink_create_conntrack(struct nfattr
*cda
[],
936 struct ip_conntrack_tuple
*otuple
,
937 struct ip_conntrack_tuple
*rtuple
)
939 struct ip_conntrack
*ct
;
942 ct
= ip_conntrack_alloc(otuple
, rtuple
);
943 if (ct
== NULL
|| IS_ERR(ct
))
946 if (!cda
[CTA_TIMEOUT
-1])
948 ct
->timeout
.expires
= ntohl(*(__be32
*)NFA_DATA(cda
[CTA_TIMEOUT
-1]));
950 ct
->timeout
.expires
= jiffies
+ ct
->timeout
.expires
* HZ
;
951 ct
->status
|= IPS_CONFIRMED
;
953 if (cda
[CTA_STATUS
-1]) {
954 err
= ctnetlink_change_status(ct
, cda
);
959 if (cda
[CTA_PROTOINFO
-1]) {
960 err
= ctnetlink_change_protoinfo(ct
, cda
);
965 #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
967 ct
->mark
= ntohl(*(__be32
*)NFA_DATA(cda
[CTA_MARK
-1]));
970 ct
->helper
= ip_conntrack_helper_find_get(rtuple
);
972 add_timer(&ct
->timeout
);
973 ip_conntrack_hash_insert(ct
);
976 ip_conntrack_helper_put(ct
->helper
);
981 ip_conntrack_free(ct
);
986 ctnetlink_new_conntrack(struct sock
*ctnl
, struct sk_buff
*skb
,
987 struct nlmsghdr
*nlh
, struct nfattr
*cda
[], int *errp
)
989 struct ip_conntrack_tuple otuple
, rtuple
;
990 struct ip_conntrack_tuple_hash
*h
= NULL
;
993 if (nfattr_bad_size(cda
, CTA_MAX
, cta_min
))
996 if (cda
[CTA_TUPLE_ORIG
-1]) {
997 err
= ctnetlink_parse_tuple(cda
, &otuple
, CTA_TUPLE_ORIG
);
1002 if (cda
[CTA_TUPLE_REPLY
-1]) {
1003 err
= ctnetlink_parse_tuple(cda
, &rtuple
, CTA_TUPLE_REPLY
);
1008 write_lock_bh(&ip_conntrack_lock
);
1009 if (cda
[CTA_TUPLE_ORIG
-1])
1010 h
= __ip_conntrack_find(&otuple
, NULL
);
1011 else if (cda
[CTA_TUPLE_REPLY
-1])
1012 h
= __ip_conntrack_find(&rtuple
, NULL
);
1015 write_unlock_bh(&ip_conntrack_lock
);
1017 if (nlh
->nlmsg_flags
& NLM_F_CREATE
)
1018 err
= ctnetlink_create_conntrack(cda
, &otuple
, &rtuple
);
1021 /* implicit 'else' */
1023 /* we only allow nat config for new conntracks */
1024 if (cda
[CTA_NAT_SRC
-1] || cda
[CTA_NAT_DST
-1]) {
1029 /* We manipulate the conntrack inside the global conntrack table lock,
1030 * so there's no need to increase the refcount */
1032 if (!(nlh
->nlmsg_flags
& NLM_F_EXCL
))
1033 err
= ctnetlink_change_conntrack(tuplehash_to_ctrack(h
), cda
);
1036 write_unlock_bh(&ip_conntrack_lock
);
1040 /***********************************************************************
1042 ***********************************************************************/
1045 ctnetlink_exp_dump_tuple(struct sk_buff
*skb
,
1046 const struct ip_conntrack_tuple
*tuple
,
1047 enum ctattr_expect type
)
1049 struct nfattr
*nest_parms
= NFA_NEST(skb
, type
);
1051 if (ctnetlink_dump_tuples(skb
, tuple
) < 0)
1052 goto nfattr_failure
;
1054 NFA_NEST_END(skb
, nest_parms
);
1063 ctnetlink_exp_dump_mask(struct sk_buff
*skb
,
1064 const struct ip_conntrack_tuple
*tuple
,
1065 const struct ip_conntrack_tuple
*mask
)
1068 struct ip_conntrack_protocol
*proto
;
1069 struct nfattr
*nest_parms
= NFA_NEST(skb
, CTA_EXPECT_MASK
);
1071 ret
= ctnetlink_dump_tuples_ip(skb
, mask
);
1072 if (unlikely(ret
< 0))
1073 goto nfattr_failure
;
1075 proto
= ip_conntrack_proto_find_get(tuple
->dst
.protonum
);
1076 ret
= ctnetlink_dump_tuples_proto(skb
, mask
, proto
);
1077 ip_conntrack_proto_put(proto
);
1078 if (unlikely(ret
< 0))
1079 goto nfattr_failure
;
1081 NFA_NEST_END(skb
, nest_parms
);
1090 ctnetlink_exp_dump_expect(struct sk_buff
*skb
,
1091 const struct ip_conntrack_expect
*exp
)
1093 struct ip_conntrack
*master
= exp
->master
;
1094 __be32 timeout
= htonl((exp
->timeout
.expires
- jiffies
) / HZ
);
1095 __be32 id
= htonl(exp
->id
);
1097 if (ctnetlink_exp_dump_tuple(skb
, &exp
->tuple
, CTA_EXPECT_TUPLE
) < 0)
1098 goto nfattr_failure
;
1099 if (ctnetlink_exp_dump_mask(skb
, &exp
->tuple
, &exp
->mask
) < 0)
1100 goto nfattr_failure
;
1101 if (ctnetlink_exp_dump_tuple(skb
,
1102 &master
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
,
1103 CTA_EXPECT_MASTER
) < 0)
1104 goto nfattr_failure
;
1106 NFA_PUT(skb
, CTA_EXPECT_TIMEOUT
, sizeof(__be32
), &timeout
);
1107 NFA_PUT(skb
, CTA_EXPECT_ID
, sizeof(__be32
), &id
);
1116 ctnetlink_exp_fill_info(struct sk_buff
*skb
, u32 pid
, u32 seq
,
1119 const struct ip_conntrack_expect
*exp
)
1121 struct nlmsghdr
*nlh
;
1122 struct nfgenmsg
*nfmsg
;
1127 event
|= NFNL_SUBSYS_CTNETLINK_EXP
<< 8;
1128 nlh
= NLMSG_PUT(skb
, pid
, seq
, event
, sizeof(struct nfgenmsg
));
1129 nfmsg
= NLMSG_DATA(nlh
);
1131 nlh
->nlmsg_flags
= (nowait
&& pid
) ? NLM_F_MULTI
: 0;
1132 nfmsg
->nfgen_family
= AF_INET
;
1133 nfmsg
->version
= NFNETLINK_V0
;
1136 if (ctnetlink_exp_dump_expect(skb
, exp
) < 0)
1137 goto nfattr_failure
;
1139 nlh
->nlmsg_len
= skb
->tail
- b
;
1144 skb_trim(skb
, b
- skb
->data
);
1148 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1149 static int ctnetlink_expect_event(struct notifier_block
*this,
1150 unsigned long events
, void *ptr
)
1152 struct nlmsghdr
*nlh
;
1153 struct nfgenmsg
*nfmsg
;
1154 struct ip_conntrack_expect
*exp
= (struct ip_conntrack_expect
*)ptr
;
1155 struct sk_buff
*skb
;
1160 if (events
& IPEXP_NEW
) {
1161 type
= IPCTNL_MSG_EXP_NEW
;
1162 flags
= NLM_F_CREATE
|NLM_F_EXCL
;
1166 if (!nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW
))
1169 skb
= alloc_skb(NLMSG_GOODSIZE
, GFP_ATOMIC
);
1175 type
|= NFNL_SUBSYS_CTNETLINK_EXP
<< 8;
1176 nlh
= NLMSG_PUT(skb
, 0, 0, type
, sizeof(struct nfgenmsg
));
1177 nfmsg
= NLMSG_DATA(nlh
);
1179 nlh
->nlmsg_flags
= flags
;
1180 nfmsg
->nfgen_family
= AF_INET
;
1181 nfmsg
->version
= NFNETLINK_V0
;
1184 if (ctnetlink_exp_dump_expect(skb
, exp
) < 0)
1185 goto nfattr_failure
;
1187 nlh
->nlmsg_len
= skb
->tail
- b
;
1188 nfnetlink_send(skb
, 0, NFNLGRP_CONNTRACK_EXP_NEW
, 0);
1199 ctnetlink_exp_dump_table(struct sk_buff
*skb
, struct netlink_callback
*cb
)
1201 struct ip_conntrack_expect
*exp
= NULL
;
1202 struct list_head
*i
;
1203 u_int32_t
*id
= (u_int32_t
*) &cb
->args
[0];
1205 read_lock_bh(&ip_conntrack_lock
);
1206 list_for_each_prev(i
, &ip_conntrack_expect_list
) {
1207 exp
= (struct ip_conntrack_expect
*) i
;
1210 if (ctnetlink_exp_fill_info(skb
, NETLINK_CB(cb
->skb
).pid
,
1218 read_unlock_bh(&ip_conntrack_lock
);
1223 static const size_t cta_min_exp
[CTA_EXPECT_MAX
] = {
1224 [CTA_EXPECT_TIMEOUT
-1] = sizeof(__be32
),
1225 [CTA_EXPECT_ID
-1] = sizeof(__be32
)
1229 ctnetlink_get_expect(struct sock
*ctnl
, struct sk_buff
*skb
,
1230 struct nlmsghdr
*nlh
, struct nfattr
*cda
[], int *errp
)
1232 struct ip_conntrack_tuple tuple
;
1233 struct ip_conntrack_expect
*exp
;
1234 struct sk_buff
*skb2
;
1237 if (nfattr_bad_size(cda
, CTA_EXPECT_MAX
, cta_min_exp
))
1240 if (nlh
->nlmsg_flags
& NLM_F_DUMP
) {
1241 struct nfgenmsg
*msg
= NLMSG_DATA(nlh
);
1244 if (msg
->nfgen_family
!= AF_INET
)
1245 return -EAFNOSUPPORT
;
1247 if ((*errp
= netlink_dump_start(ctnl
, skb
, nlh
,
1248 ctnetlink_exp_dump_table
,
1249 ctnetlink_done
)) != 0)
1251 rlen
= NLMSG_ALIGN(nlh
->nlmsg_len
);
1252 if (rlen
> skb
->len
)
1254 skb_pull(skb
, rlen
);
1258 if (cda
[CTA_EXPECT_MASTER
-1])
1259 err
= ctnetlink_parse_tuple(cda
, &tuple
, CTA_EXPECT_MASTER
);
1266 exp
= ip_conntrack_expect_find_get(&tuple
);
1270 if (cda
[CTA_EXPECT_ID
-1]) {
1271 __be32 id
= *(__be32
*)NFA_DATA(cda
[CTA_EXPECT_ID
-1]);
1272 if (exp
->id
!= ntohl(id
)) {
1273 ip_conntrack_expect_put(exp
);
1279 skb2
= alloc_skb(NLMSG_GOODSIZE
, GFP_KERNEL
);
1283 err
= ctnetlink_exp_fill_info(skb2
, NETLINK_CB(skb
).pid
,
1284 nlh
->nlmsg_seq
, IPCTNL_MSG_EXP_NEW
,
1289 ip_conntrack_expect_put(exp
);
1291 return netlink_unicast(ctnl
, skb2
, NETLINK_CB(skb
).pid
, MSG_DONTWAIT
);
1296 ip_conntrack_expect_put(exp
);
1301 ctnetlink_del_expect(struct sock
*ctnl
, struct sk_buff
*skb
,
1302 struct nlmsghdr
*nlh
, struct nfattr
*cda
[], int *errp
)
1304 struct ip_conntrack_expect
*exp
, *tmp
;
1305 struct ip_conntrack_tuple tuple
;
1306 struct ip_conntrack_helper
*h
;
1309 if (nfattr_bad_size(cda
, CTA_EXPECT_MAX
, cta_min_exp
))
1312 if (cda
[CTA_EXPECT_TUPLE
-1]) {
1313 /* delete a single expect by tuple */
1314 err
= ctnetlink_parse_tuple(cda
, &tuple
, CTA_EXPECT_TUPLE
);
1318 /* bump usage count to 2 */
1319 exp
= ip_conntrack_expect_find_get(&tuple
);
1323 if (cda
[CTA_EXPECT_ID
-1]) {
1325 *(__be32
*)NFA_DATA(cda
[CTA_EXPECT_ID
-1]);
1326 if (exp
->id
!= ntohl(id
)) {
1327 ip_conntrack_expect_put(exp
);
1332 /* after list removal, usage count == 1 */
1333 ip_conntrack_unexpect_related(exp
);
1334 /* have to put what we 'get' above.
1335 * after this line usage count == 0 */
1336 ip_conntrack_expect_put(exp
);
1337 } else if (cda
[CTA_EXPECT_HELP_NAME
-1]) {
1338 char *name
= NFA_DATA(cda
[CTA_EXPECT_HELP_NAME
-1]);
1340 /* delete all expectations for this helper */
1341 write_lock_bh(&ip_conntrack_lock
);
1342 h
= __ip_conntrack_helper_find_byname(name
);
1344 write_unlock_bh(&ip_conntrack_lock
);
1347 list_for_each_entry_safe(exp
, tmp
, &ip_conntrack_expect_list
,
1349 if (exp
->master
->helper
== h
1350 && del_timer(&exp
->timeout
)) {
1351 ip_ct_unlink_expect(exp
);
1352 ip_conntrack_expect_put(exp
);
1355 write_unlock_bh(&ip_conntrack_lock
);
1357 /* This basically means we have to flush everything*/
1358 write_lock_bh(&ip_conntrack_lock
);
1359 list_for_each_entry_safe(exp
, tmp
, &ip_conntrack_expect_list
,
1361 if (del_timer(&exp
->timeout
)) {
1362 ip_ct_unlink_expect(exp
);
1363 ip_conntrack_expect_put(exp
);
1366 write_unlock_bh(&ip_conntrack_lock
);
1372 ctnetlink_change_expect(struct ip_conntrack_expect
*x
, struct nfattr
*cda
[])
1378 ctnetlink_create_expect(struct nfattr
*cda
[])
1380 struct ip_conntrack_tuple tuple
, mask
, master_tuple
;
1381 struct ip_conntrack_tuple_hash
*h
= NULL
;
1382 struct ip_conntrack_expect
*exp
;
1383 struct ip_conntrack
*ct
;
1386 /* caller guarantees that those three CTA_EXPECT_* exist */
1387 err
= ctnetlink_parse_tuple(cda
, &tuple
, CTA_EXPECT_TUPLE
);
1390 err
= ctnetlink_parse_tuple(cda
, &mask
, CTA_EXPECT_MASK
);
1393 err
= ctnetlink_parse_tuple(cda
, &master_tuple
, CTA_EXPECT_MASTER
);
1397 /* Look for master conntrack of this expectation */
1398 h
= ip_conntrack_find_get(&master_tuple
, NULL
);
1401 ct
= tuplehash_to_ctrack(h
);
1404 /* such conntrack hasn't got any helper, abort */
1409 exp
= ip_conntrack_expect_alloc(ct
);
1415 exp
->expectfn
= NULL
;
1418 memcpy(&exp
->tuple
, &tuple
, sizeof(struct ip_conntrack_tuple
));
1419 memcpy(&exp
->mask
, &mask
, sizeof(struct ip_conntrack_tuple
));
1421 err
= ip_conntrack_expect_related(exp
);
1422 ip_conntrack_expect_put(exp
);
1425 ip_conntrack_put(tuplehash_to_ctrack(h
));
1430 ctnetlink_new_expect(struct sock
*ctnl
, struct sk_buff
*skb
,
1431 struct nlmsghdr
*nlh
, struct nfattr
*cda
[], int *errp
)
1433 struct ip_conntrack_tuple tuple
;
1434 struct ip_conntrack_expect
*exp
;
1437 if (nfattr_bad_size(cda
, CTA_EXPECT_MAX
, cta_min_exp
))
1440 if (!cda
[CTA_EXPECT_TUPLE
-1]
1441 || !cda
[CTA_EXPECT_MASK
-1]
1442 || !cda
[CTA_EXPECT_MASTER
-1])
1445 err
= ctnetlink_parse_tuple(cda
, &tuple
, CTA_EXPECT_TUPLE
);
1449 write_lock_bh(&ip_conntrack_lock
);
1450 exp
= __ip_conntrack_expect_find(&tuple
);
1453 write_unlock_bh(&ip_conntrack_lock
);
1455 if (nlh
->nlmsg_flags
& NLM_F_CREATE
)
1456 err
= ctnetlink_create_expect(cda
);
1461 if (!(nlh
->nlmsg_flags
& NLM_F_EXCL
))
1462 err
= ctnetlink_change_expect(exp
, cda
);
1463 write_unlock_bh(&ip_conntrack_lock
);
1468 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1469 static struct notifier_block ctnl_notifier
= {
1470 .notifier_call
= ctnetlink_conntrack_event
,
1473 static struct notifier_block ctnl_notifier_exp
= {
1474 .notifier_call
= ctnetlink_expect_event
,
1478 static struct nfnl_callback ctnl_cb
[IPCTNL_MSG_MAX
] = {
1479 [IPCTNL_MSG_CT_NEW
] = { .call
= ctnetlink_new_conntrack
,
1480 .attr_count
= CTA_MAX
, },
1481 [IPCTNL_MSG_CT_GET
] = { .call
= ctnetlink_get_conntrack
,
1482 .attr_count
= CTA_MAX
, },
1483 [IPCTNL_MSG_CT_DELETE
] = { .call
= ctnetlink_del_conntrack
,
1484 .attr_count
= CTA_MAX
, },
1485 [IPCTNL_MSG_CT_GET_CTRZERO
] = { .call
= ctnetlink_get_conntrack
,
1486 .attr_count
= CTA_MAX
, },
1489 static struct nfnl_callback ctnl_exp_cb
[IPCTNL_MSG_EXP_MAX
] = {
1490 [IPCTNL_MSG_EXP_GET
] = { .call
= ctnetlink_get_expect
,
1491 .attr_count
= CTA_EXPECT_MAX
, },
1492 [IPCTNL_MSG_EXP_NEW
] = { .call
= ctnetlink_new_expect
,
1493 .attr_count
= CTA_EXPECT_MAX
, },
1494 [IPCTNL_MSG_EXP_DELETE
] = { .call
= ctnetlink_del_expect
,
1495 .attr_count
= CTA_EXPECT_MAX
, },
1498 static struct nfnetlink_subsystem ctnl_subsys
= {
1499 .name
= "conntrack",
1500 .subsys_id
= NFNL_SUBSYS_CTNETLINK
,
1501 .cb_count
= IPCTNL_MSG_MAX
,
1505 static struct nfnetlink_subsystem ctnl_exp_subsys
= {
1506 .name
= "conntrack_expect",
1507 .subsys_id
= NFNL_SUBSYS_CTNETLINK_EXP
,
1508 .cb_count
= IPCTNL_MSG_EXP_MAX
,
1512 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK
);
1513 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP
);
1515 static int __init
ctnetlink_init(void)
1519 printk("ctnetlink v%s: registering with nfnetlink.\n", version
);
1520 ret
= nfnetlink_subsys_register(&ctnl_subsys
);
1522 printk("ctnetlink_init: cannot register with nfnetlink.\n");
1526 ret
= nfnetlink_subsys_register(&ctnl_exp_subsys
);
1528 printk("ctnetlink_init: cannot register exp with nfnetlink.\n");
1529 goto err_unreg_subsys
;
1532 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1533 ret
= ip_conntrack_register_notifier(&ctnl_notifier
);
1535 printk("ctnetlink_init: cannot register notifier.\n");
1536 goto err_unreg_exp_subsys
;
1539 ret
= ip_conntrack_expect_register_notifier(&ctnl_notifier_exp
);
1541 printk("ctnetlink_init: cannot expect register notifier.\n");
1542 goto err_unreg_notifier
;
1548 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1550 ip_conntrack_unregister_notifier(&ctnl_notifier
);
1551 err_unreg_exp_subsys
:
1552 nfnetlink_subsys_unregister(&ctnl_exp_subsys
);
1555 nfnetlink_subsys_unregister(&ctnl_subsys
);
1560 static void __exit
ctnetlink_exit(void)
1562 printk("ctnetlink: unregistering from nfnetlink.\n");
1564 #ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
1565 ip_conntrack_expect_unregister_notifier(&ctnl_notifier_exp
);
1566 ip_conntrack_unregister_notifier(&ctnl_notifier
);
1569 nfnetlink_subsys_unregister(&ctnl_exp_subsys
);
1570 nfnetlink_subsys_unregister(&ctnl_subsys
);
1574 module_init(ctnetlink_init
);
1575 module_exit(ctnetlink_exit
);