2 * (C) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation (or any later at your option).
8 * This software has been sponsored by Vyatta Inc. <http://www.vyatta.com>
10 #include <linux/init.h>
11 #include <linux/module.h>
12 #include <linux/kernel.h>
13 #include <linux/skbuff.h>
14 #include <linux/netlink.h>
15 #include <linux/rculist.h>
16 #include <linux/slab.h>
17 #include <linux/types.h>
18 #include <linux/list.h>
19 #include <linux/errno.h>
20 #include <net/netlink.h>
23 #include <net/netfilter/nf_conntrack_helper.h>
24 #include <net/netfilter/nf_conntrack_expect.h>
25 #include <net/netfilter/nf_conntrack_ecache.h>
27 #include <linux/netfilter/nfnetlink.h>
28 #include <linux/netfilter/nfnetlink_conntrack.h>
29 #include <linux/netfilter/nfnetlink_cthelper.h>
31 MODULE_LICENSE("GPL");
32 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
33 MODULE_DESCRIPTION("nfnl_cthelper: User-space connection tracking helpers");
36 nfnl_userspace_cthelper(struct sk_buff
*skb
, unsigned int protoff
,
37 struct nf_conn
*ct
, enum ip_conntrack_info ctinfo
)
39 const struct nf_conn_help
*help
;
40 struct nf_conntrack_helper
*helper
;
46 /* rcu_read_lock()ed by nf_hook_slow */
47 helper
= rcu_dereference(help
->helper
);
51 /* This is an user-space helper not yet configured, skip. */
53 (NF_CT_HELPER_F_USERSPACE
| NF_CT_HELPER_F_CONFIGURED
)) ==
54 NF_CT_HELPER_F_USERSPACE
)
57 /* If the user-space helper is not available, don't block traffic. */
58 return NF_QUEUE_NR(helper
->queue_num
) | NF_VERDICT_FLAG_QUEUE_BYPASS
;
61 static const struct nla_policy nfnl_cthelper_tuple_pol
[NFCTH_TUPLE_MAX
+1] = {
62 [NFCTH_TUPLE_L3PROTONUM
] = { .type
= NLA_U16
, },
63 [NFCTH_TUPLE_L4PROTONUM
] = { .type
= NLA_U8
, },
67 nfnl_cthelper_parse_tuple(struct nf_conntrack_tuple
*tuple
,
68 const struct nlattr
*attr
)
71 struct nlattr
*tb
[NFCTH_TUPLE_MAX
+1];
73 err
= nla_parse_nested(tb
, NFCTH_TUPLE_MAX
, attr
, nfnl_cthelper_tuple_pol
);
77 if (!tb
[NFCTH_TUPLE_L3PROTONUM
] || !tb
[NFCTH_TUPLE_L4PROTONUM
])
80 tuple
->src
.l3num
= ntohs(nla_get_be16(tb
[NFCTH_TUPLE_L3PROTONUM
]));
81 tuple
->dst
.protonum
= nla_get_u8(tb
[NFCTH_TUPLE_L4PROTONUM
]);
87 nfnl_cthelper_from_nlattr(struct nlattr
*attr
, struct nf_conn
*ct
)
89 const struct nf_conn_help
*help
= nfct_help(ct
);
94 if (help
->helper
->data_len
== 0)
97 memcpy(&help
->data
, nla_data(attr
), help
->helper
->data_len
);
102 nfnl_cthelper_to_nlattr(struct sk_buff
*skb
, const struct nf_conn
*ct
)
104 const struct nf_conn_help
*help
= nfct_help(ct
);
106 if (help
->helper
->data_len
&&
107 nla_put(skb
, CTA_HELP_INFO
, help
->helper
->data_len
, &help
->data
))
108 goto nla_put_failure
;
116 static const struct nla_policy nfnl_cthelper_expect_pol
[NFCTH_POLICY_MAX
+1] = {
117 [NFCTH_POLICY_NAME
] = { .type
= NLA_NUL_STRING
,
118 .len
= NF_CT_HELPER_NAME_LEN
-1 },
119 [NFCTH_POLICY_EXPECT_MAX
] = { .type
= NLA_U32
, },
120 [NFCTH_POLICY_EXPECT_TIMEOUT
] = { .type
= NLA_U32
, },
124 nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy
*expect_policy
,
125 const struct nlattr
*attr
)
128 struct nlattr
*tb
[NFCTH_POLICY_MAX
+1];
130 err
= nla_parse_nested(tb
, NFCTH_POLICY_MAX
, attr
, nfnl_cthelper_expect_pol
);
134 if (!tb
[NFCTH_POLICY_NAME
] ||
135 !tb
[NFCTH_POLICY_EXPECT_MAX
] ||
136 !tb
[NFCTH_POLICY_EXPECT_TIMEOUT
])
139 strncpy(expect_policy
->name
,
140 nla_data(tb
[NFCTH_POLICY_NAME
]), NF_CT_HELPER_NAME_LEN
);
141 expect_policy
->max_expected
=
142 ntohl(nla_get_be32(tb
[NFCTH_POLICY_EXPECT_MAX
]));
143 expect_policy
->timeout
=
144 ntohl(nla_get_be32(tb
[NFCTH_POLICY_EXPECT_TIMEOUT
]));
149 static const struct nla_policy
150 nfnl_cthelper_expect_policy_set
[NFCTH_POLICY_SET_MAX
+1] = {
151 [NFCTH_POLICY_SET_NUM
] = { .type
= NLA_U32
, },
155 nfnl_cthelper_parse_expect_policy(struct nf_conntrack_helper
*helper
,
156 const struct nlattr
*attr
)
159 struct nf_conntrack_expect_policy
*expect_policy
;
160 struct nlattr
*tb
[NFCTH_POLICY_SET_MAX
+1];
162 ret
= nla_parse_nested(tb
, NFCTH_POLICY_SET_MAX
, attr
,
163 nfnl_cthelper_expect_policy_set
);
167 if (!tb
[NFCTH_POLICY_SET_NUM
])
170 helper
->expect_class_max
=
171 ntohl(nla_get_be32(tb
[NFCTH_POLICY_SET_NUM
]));
173 if (helper
->expect_class_max
!= 0 &&
174 helper
->expect_class_max
> NF_CT_MAX_EXPECT_CLASSES
)
177 expect_policy
= kzalloc(sizeof(struct nf_conntrack_expect_policy
) *
178 helper
->expect_class_max
, GFP_KERNEL
);
179 if (expect_policy
== NULL
)
182 for (i
=0; i
<helper
->expect_class_max
; i
++) {
183 if (!tb
[NFCTH_POLICY_SET
+i
])
186 ret
= nfnl_cthelper_expect_policy(&expect_policy
[i
],
187 tb
[NFCTH_POLICY_SET
+i
]);
191 helper
->expect_policy
= expect_policy
;
194 kfree(expect_policy
);
199 nfnl_cthelper_create(const struct nlattr
* const tb
[],
200 struct nf_conntrack_tuple
*tuple
)
202 struct nf_conntrack_helper
*helper
;
205 if (!tb
[NFCTH_TUPLE
] || !tb
[NFCTH_POLICY
] || !tb
[NFCTH_PRIV_DATA_LEN
])
208 helper
= kzalloc(sizeof(struct nf_conntrack_helper
), GFP_KERNEL
);
212 ret
= nfnl_cthelper_parse_expect_policy(helper
, tb
[NFCTH_POLICY
]);
216 strncpy(helper
->name
, nla_data(tb
[NFCTH_NAME
]), NF_CT_HELPER_NAME_LEN
);
217 helper
->data_len
= ntohl(nla_get_be32(tb
[NFCTH_PRIV_DATA_LEN
]));
218 helper
->flags
|= NF_CT_HELPER_F_USERSPACE
;
219 memcpy(&helper
->tuple
, tuple
, sizeof(struct nf_conntrack_tuple
));
221 helper
->me
= THIS_MODULE
;
222 helper
->help
= nfnl_userspace_cthelper
;
223 helper
->from_nlattr
= nfnl_cthelper_from_nlattr
;
224 helper
->to_nlattr
= nfnl_cthelper_to_nlattr
;
226 /* Default to queue number zero, this can be updated at any time. */
227 if (tb
[NFCTH_QUEUE_NUM
])
228 helper
->queue_num
= ntohl(nla_get_be32(tb
[NFCTH_QUEUE_NUM
]));
230 if (tb
[NFCTH_STATUS
]) {
231 int status
= ntohl(nla_get_be32(tb
[NFCTH_STATUS
]));
234 case NFCT_HELPER_STATUS_ENABLED
:
235 helper
->flags
|= NF_CT_HELPER_F_CONFIGURED
;
237 case NFCT_HELPER_STATUS_DISABLED
:
238 helper
->flags
&= ~NF_CT_HELPER_F_CONFIGURED
;
243 ret
= nf_conntrack_helper_register(helper
);
254 nfnl_cthelper_update(const struct nlattr
* const tb
[],
255 struct nf_conntrack_helper
*helper
)
259 if (tb
[NFCTH_PRIV_DATA_LEN
])
262 if (tb
[NFCTH_POLICY
]) {
263 ret
= nfnl_cthelper_parse_expect_policy(helper
,
268 if (tb
[NFCTH_QUEUE_NUM
])
269 helper
->queue_num
= ntohl(nla_get_be32(tb
[NFCTH_QUEUE_NUM
]));
271 if (tb
[NFCTH_STATUS
]) {
272 int status
= ntohl(nla_get_be32(tb
[NFCTH_STATUS
]));
275 case NFCT_HELPER_STATUS_ENABLED
:
276 helper
->flags
|= NF_CT_HELPER_F_CONFIGURED
;
278 case NFCT_HELPER_STATUS_DISABLED
:
279 helper
->flags
&= ~NF_CT_HELPER_F_CONFIGURED
;
287 nfnl_cthelper_new(struct sock
*nfnl
, struct sk_buff
*skb
,
288 const struct nlmsghdr
*nlh
, const struct nlattr
* const tb
[])
290 const char *helper_name
;
291 struct nf_conntrack_helper
*cur
, *helper
= NULL
;
292 struct nf_conntrack_tuple tuple
;
295 if (!tb
[NFCTH_NAME
] || !tb
[NFCTH_TUPLE
])
298 helper_name
= nla_data(tb
[NFCTH_NAME
]);
300 ret
= nfnl_cthelper_parse_tuple(&tuple
, tb
[NFCTH_TUPLE
]);
305 for (i
= 0; i
< nf_ct_helper_hsize
&& !helper
; i
++) {
306 hlist_for_each_entry_rcu(cur
, &nf_ct_helper_hash
[i
], hnode
) {
308 /* skip non-userspace conntrack helpers. */
309 if (!(cur
->flags
& NF_CT_HELPER_F_USERSPACE
))
312 if (strncmp(cur
->name
, helper_name
,
313 NF_CT_HELPER_NAME_LEN
) != 0)
316 if ((tuple
.src
.l3num
!= cur
->tuple
.src
.l3num
||
317 tuple
.dst
.protonum
!= cur
->tuple
.dst
.protonum
))
320 if (nlh
->nlmsg_flags
& NLM_F_EXCL
) {
331 ret
= nfnl_cthelper_create(tb
, &tuple
);
333 ret
= nfnl_cthelper_update(tb
, helper
);
342 nfnl_cthelper_dump_tuple(struct sk_buff
*skb
,
343 struct nf_conntrack_helper
*helper
)
345 struct nlattr
*nest_parms
;
347 nest_parms
= nla_nest_start(skb
, NFCTH_TUPLE
| NLA_F_NESTED
);
348 if (nest_parms
== NULL
)
349 goto nla_put_failure
;
351 if (nla_put_be16(skb
, NFCTH_TUPLE_L3PROTONUM
,
352 htons(helper
->tuple
.src
.l3num
)))
353 goto nla_put_failure
;
355 if (nla_put_u8(skb
, NFCTH_TUPLE_L4PROTONUM
, helper
->tuple
.dst
.protonum
))
356 goto nla_put_failure
;
358 nla_nest_end(skb
, nest_parms
);
366 nfnl_cthelper_dump_policy(struct sk_buff
*skb
,
367 struct nf_conntrack_helper
*helper
)
370 struct nlattr
*nest_parms1
, *nest_parms2
;
372 nest_parms1
= nla_nest_start(skb
, NFCTH_POLICY
| NLA_F_NESTED
);
373 if (nest_parms1
== NULL
)
374 goto nla_put_failure
;
376 if (nla_put_be32(skb
, NFCTH_POLICY_SET_NUM
,
377 htonl(helper
->expect_class_max
)))
378 goto nla_put_failure
;
380 for (i
=0; i
<helper
->expect_class_max
; i
++) {
381 nest_parms2
= nla_nest_start(skb
,
382 (NFCTH_POLICY_SET
+i
) | NLA_F_NESTED
);
383 if (nest_parms2
== NULL
)
384 goto nla_put_failure
;
386 if (nla_put_string(skb
, NFCTH_POLICY_NAME
,
387 helper
->expect_policy
[i
].name
))
388 goto nla_put_failure
;
390 if (nla_put_be32(skb
, NFCTH_POLICY_EXPECT_MAX
,
391 htonl(helper
->expect_policy
[i
].max_expected
)))
392 goto nla_put_failure
;
394 if (nla_put_be32(skb
, NFCTH_POLICY_EXPECT_TIMEOUT
,
395 htonl(helper
->expect_policy
[i
].timeout
)))
396 goto nla_put_failure
;
398 nla_nest_end(skb
, nest_parms2
);
400 nla_nest_end(skb
, nest_parms1
);
408 nfnl_cthelper_fill_info(struct sk_buff
*skb
, u32 portid
, u32 seq
, u32 type
,
409 int event
, struct nf_conntrack_helper
*helper
)
411 struct nlmsghdr
*nlh
;
412 struct nfgenmsg
*nfmsg
;
413 unsigned int flags
= portid
? NLM_F_MULTI
: 0;
416 event
|= NFNL_SUBSYS_CTHELPER
<< 8;
417 nlh
= nlmsg_put(skb
, portid
, seq
, event
, sizeof(*nfmsg
), flags
);
421 nfmsg
= nlmsg_data(nlh
);
422 nfmsg
->nfgen_family
= AF_UNSPEC
;
423 nfmsg
->version
= NFNETLINK_V0
;
426 if (nla_put_string(skb
, NFCTH_NAME
, helper
->name
))
427 goto nla_put_failure
;
429 if (nla_put_be32(skb
, NFCTH_QUEUE_NUM
, htonl(helper
->queue_num
)))
430 goto nla_put_failure
;
432 if (nfnl_cthelper_dump_tuple(skb
, helper
) < 0)
433 goto nla_put_failure
;
435 if (nfnl_cthelper_dump_policy(skb
, helper
) < 0)
436 goto nla_put_failure
;
438 if (nla_put_be32(skb
, NFCTH_PRIV_DATA_LEN
, htonl(helper
->data_len
)))
439 goto nla_put_failure
;
441 if (helper
->flags
& NF_CT_HELPER_F_CONFIGURED
)
442 status
= NFCT_HELPER_STATUS_ENABLED
;
444 status
= NFCT_HELPER_STATUS_DISABLED
;
446 if (nla_put_be32(skb
, NFCTH_STATUS
, htonl(status
)))
447 goto nla_put_failure
;
454 nlmsg_cancel(skb
, nlh
);
459 nfnl_cthelper_dump_table(struct sk_buff
*skb
, struct netlink_callback
*cb
)
461 struct nf_conntrack_helper
*cur
, *last
;
464 last
= (struct nf_conntrack_helper
*)cb
->args
[1];
465 for (; cb
->args
[0] < nf_ct_helper_hsize
; cb
->args
[0]++) {
467 hlist_for_each_entry_rcu(cur
,
468 &nf_ct_helper_hash
[cb
->args
[0]], hnode
) {
470 /* skip non-userspace conntrack helpers. */
471 if (!(cur
->flags
& NF_CT_HELPER_F_USERSPACE
))
479 if (nfnl_cthelper_fill_info(skb
,
480 NETLINK_CB(cb
->skb
).portid
,
482 NFNL_MSG_TYPE(cb
->nlh
->nlmsg_type
),
483 NFNL_MSG_CTHELPER_NEW
, cur
) < 0) {
484 cb
->args
[1] = (unsigned long)cur
;
499 nfnl_cthelper_get(struct sock
*nfnl
, struct sk_buff
*skb
,
500 const struct nlmsghdr
*nlh
, const struct nlattr
* const tb
[])
502 int ret
= -ENOENT
, i
;
503 struct nf_conntrack_helper
*cur
;
504 struct sk_buff
*skb2
;
505 char *helper_name
= NULL
;
506 struct nf_conntrack_tuple tuple
;
507 bool tuple_set
= false;
509 if (nlh
->nlmsg_flags
& NLM_F_DUMP
) {
510 struct netlink_dump_control c
= {
511 .dump
= nfnl_cthelper_dump_table
,
513 return netlink_dump_start(nfnl
, skb
, nlh
, &c
);
517 helper_name
= nla_data(tb
[NFCTH_NAME
]);
519 if (tb
[NFCTH_TUPLE
]) {
520 ret
= nfnl_cthelper_parse_tuple(&tuple
, tb
[NFCTH_TUPLE
]);
527 for (i
= 0; i
< nf_ct_helper_hsize
; i
++) {
528 hlist_for_each_entry_rcu(cur
, &nf_ct_helper_hash
[i
], hnode
) {
530 /* skip non-userspace conntrack helpers. */
531 if (!(cur
->flags
& NF_CT_HELPER_F_USERSPACE
))
534 if (helper_name
&& strncmp(cur
->name
, helper_name
,
535 NF_CT_HELPER_NAME_LEN
) != 0) {
539 (tuple
.src
.l3num
!= cur
->tuple
.src
.l3num
||
540 tuple
.dst
.protonum
!= cur
->tuple
.dst
.protonum
))
543 skb2
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
549 ret
= nfnl_cthelper_fill_info(skb2
, NETLINK_CB(skb
).portid
,
551 NFNL_MSG_TYPE(nlh
->nlmsg_type
),
552 NFNL_MSG_CTHELPER_NEW
, cur
);
558 ret
= netlink_unicast(nfnl
, skb2
, NETLINK_CB(skb
).portid
,
563 /* this avoids a loop in nfnetlink. */
564 return ret
== -EAGAIN
? -ENOBUFS
: ret
;
571 nfnl_cthelper_del(struct sock
*nfnl
, struct sk_buff
*skb
,
572 const struct nlmsghdr
*nlh
, const struct nlattr
* const tb
[])
574 char *helper_name
= NULL
;
575 struct nf_conntrack_helper
*cur
;
576 struct hlist_node
*tmp
;
577 struct nf_conntrack_tuple tuple
;
578 bool tuple_set
= false, found
= false;
582 helper_name
= nla_data(tb
[NFCTH_NAME
]);
584 if (tb
[NFCTH_TUPLE
]) {
585 ret
= nfnl_cthelper_parse_tuple(&tuple
, tb
[NFCTH_TUPLE
]);
592 for (i
= 0; i
< nf_ct_helper_hsize
; i
++) {
593 hlist_for_each_entry_safe(cur
, tmp
, &nf_ct_helper_hash
[i
],
595 /* skip non-userspace conntrack helpers. */
596 if (!(cur
->flags
& NF_CT_HELPER_F_USERSPACE
))
601 if (helper_name
&& strncmp(cur
->name
, helper_name
,
602 NF_CT_HELPER_NAME_LEN
) != 0) {
606 (tuple
.src
.l3num
!= cur
->tuple
.src
.l3num
||
607 tuple
.dst
.protonum
!= cur
->tuple
.dst
.protonum
))
611 nf_conntrack_helper_unregister(cur
);
614 /* Make sure we return success if we flush and there is no helpers */
615 return (found
|| j
== 0) ? 0 : -ENOENT
;
618 static const struct nla_policy nfnl_cthelper_policy
[NFCTH_MAX
+1] = {
619 [NFCTH_NAME
] = { .type
= NLA_NUL_STRING
,
620 .len
= NF_CT_HELPER_NAME_LEN
-1 },
621 [NFCTH_QUEUE_NUM
] = { .type
= NLA_U32
, },
624 static const struct nfnl_callback nfnl_cthelper_cb
[NFNL_MSG_CTHELPER_MAX
] = {
625 [NFNL_MSG_CTHELPER_NEW
] = { .call
= nfnl_cthelper_new
,
626 .attr_count
= NFCTH_MAX
,
627 .policy
= nfnl_cthelper_policy
},
628 [NFNL_MSG_CTHELPER_GET
] = { .call
= nfnl_cthelper_get
,
629 .attr_count
= NFCTH_MAX
,
630 .policy
= nfnl_cthelper_policy
},
631 [NFNL_MSG_CTHELPER_DEL
] = { .call
= nfnl_cthelper_del
,
632 .attr_count
= NFCTH_MAX
,
633 .policy
= nfnl_cthelper_policy
},
636 static const struct nfnetlink_subsystem nfnl_cthelper_subsys
= {
638 .subsys_id
= NFNL_SUBSYS_CTHELPER
,
639 .cb_count
= NFNL_MSG_CTHELPER_MAX
,
640 .cb
= nfnl_cthelper_cb
,
643 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTHELPER
);
645 static int __init
nfnl_cthelper_init(void)
649 ret
= nfnetlink_subsys_register(&nfnl_cthelper_subsys
);
651 pr_err("nfnl_cthelper: cannot register with nfnetlink.\n");
659 static void __exit
nfnl_cthelper_exit(void)
661 struct nf_conntrack_helper
*cur
;
662 struct hlist_node
*tmp
;
665 nfnetlink_subsys_unregister(&nfnl_cthelper_subsys
);
667 for (i
=0; i
<nf_ct_helper_hsize
; i
++) {
668 hlist_for_each_entry_safe(cur
, tmp
, &nf_ct_helper_hash
[i
],
670 /* skip non-userspace conntrack helpers. */
671 if (!(cur
->flags
& NF_CT_HELPER_F_USERSPACE
))
674 nf_conntrack_helper_unregister(cur
);
679 module_init(nfnl_cthelper_init
);
680 module_exit(nfnl_cthelper_exit
);