X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fnetfilter%2Fnf_conntrack_netlink.c;fp=net%2Fnetfilter%2Fnf_conntrack_netlink.c;h=40edeefb28146f4be4a7c8e46e7533491202316d;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=6527d4e048d81395f1e5263eb3103f6d65ed2114;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 6527d4e04..40edeefb2 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -2,9 +2,9 @@ * protocol helpers and general trouble making from userspace. * * (C) 2001 by Jay Schulist - * (C) 2002-2006 by Harald Welte + * (C) 2002-2005 by Harald Welte * (C) 2003 by Patrick Mchardy - * (C) 2005-2006 by Pablo Neira Ayuso + * (C) 2005 by Pablo Neira Ayuso * * I've reworked this stuff to use attributes instead of conntrack * structures. 5.44 am. I need more tea. --pablo 05/07/11. @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -45,7 +44,7 @@ MODULE_LICENSE("GPL"); -static char __initdata version[] = "0.93"; +static char __initdata version[] = "0.92"; #if 0 #define DEBUGP printk @@ -56,18 +55,20 @@ static char __initdata version[] = "0.93"; static inline int ctnetlink_dump_tuples_proto(struct sk_buff *skb, - const struct nf_conntrack_tuple *tuple, - struct nf_conntrack_protocol *proto) + const struct nf_conntrack_tuple *tuple) { + struct nf_conntrack_protocol *proto; int ret = 0; - struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); + /* If no protocol helper is found, this function will return the + * generic protocol helper, so proto won't *ever* be NULL */ + proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); if (likely(proto->tuple_to_nfattr)) ret = proto->tuple_to_nfattr(skb, tuple); - NFA_NEST_END(skb, nest_parms); + nf_ct_proto_put(proto); return ret; @@ -76,44 +77,33 @@ nfattr_failure: } static inline int -ctnetlink_dump_tuples_ip(struct sk_buff *skb, - const struct nf_conntrack_tuple *tuple, - struct nf_conntrack_l3proto *l3proto) +ctnetlink_dump_tuples(struct sk_buff *skb, + const struct nf_conntrack_tuple *tuple) { + struct nfattr *nest_parms; + struct nf_conntrack_l3proto *l3proto; int ret = 0; - struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); - + + l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); + + nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); if (likely(l3proto->tuple_to_nfattr)) ret = l3proto->tuple_to_nfattr(skb, tuple); - NFA_NEST_END(skb, nest_parms); - return ret; - -nfattr_failure: - return -1; -} - -static inline int -ctnetlink_dump_tuples(struct sk_buff *skb, - const struct nf_conntrack_tuple *tuple) -{ - int ret; - struct nf_conntrack_l3proto *l3proto; - struct nf_conntrack_protocol *proto; - - l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); - ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); nf_ct_l3proto_put(l3proto); if (unlikely(ret < 0)) return ret; - proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); - ret = ctnetlink_dump_tuples_proto(skb, tuple, proto); - nf_ct_proto_put(proto); + nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); + ret = ctnetlink_dump_tuples_proto(skb, tuple); + NFA_NEST_END(skb, nest_parms); return ret; + +nfattr_failure: + return -1; } static inline int @@ -175,16 +165,15 @@ static inline int ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) { struct nfattr *nest_helper; - const struct nf_conn_help *help = nfct_help(ct); - if (!help || !help->helper) + if (!ct->helper) return 0; nest_helper = NFA_NEST(skb, CTA_HELP); - NFA_PUT(skb, CTA_HELP_NAME, strlen(help->helper->name), help->helper->name); + NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); - if (help->helper->to_nfattr) - help->helper->to_nfattr(skb, ct); + if (ct->helper->to_nfattr) + ct->helper->to_nfattr(skb, ct); NFA_NEST_END(skb, nest_helper); @@ -348,10 +337,9 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, group = NFNLGRP_CONNTRACK_UPDATE; } else return NOTIFY_DONE; - - if (!nfnetlink_has_listeners(group)) - return NOTIFY_DONE; - + + /* FIXME: Check if there are any listeners before, don't hurt performance */ + skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); if (!skb) return NOTIFY_DONE; @@ -408,8 +396,6 @@ nfattr_failure: static int ctnetlink_done(struct netlink_callback *cb) { - if (cb->args[1]) - nf_ct_put((struct nf_conn *)cb->args[1]); DEBUGP("entered %s\n", __FUNCTION__); return 0; } @@ -419,9 +405,10 @@ static int ctnetlink_done(struct netlink_callback *cb) static int ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) { - struct nf_conn *ct, *last; + struct nf_conn *ct = NULL; struct nf_conntrack_tuple_hash *h; struct list_head *i; + u_int32_t *id = (u_int32_t *) &cb->args[1]; struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); u_int8_t l3proto = nfmsg->nfgen_family; @@ -429,9 +416,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) cb->args[0], *id); read_lock_bh(&nf_conntrack_lock); - last = (struct nf_conn *)cb->args[1]; - for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { -restart: + for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) { list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { h = (struct nf_conntrack_tuple_hash *) i; if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) @@ -442,31 +427,21 @@ restart: * then dump everything. */ if (l3proto && L3PROTO(ct) != l3proto) continue; - if (cb->args[1]) { - if (ct != last) - continue; - cb->args[1] = 0; - } + if (ct->id <= *id) + continue; if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, IPCTNL_MSG_CT_NEW, - 1, ct) < 0) { - nf_conntrack_get(&ct->ct_general); - cb->args[1] = (unsigned long)ct; + 1, ct) < 0) goto out; - } - } - if (cb->args[1]) { - cb->args[1] = 0; - goto restart; + *id = ct->id; } } -out: +out: read_unlock_bh(&nf_conntrack_lock); - if (last) - nf_ct_put(last); DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); + return skb->len; } @@ -655,7 +630,7 @@ static const size_t cta_min_nat[CTA_NAT_MAX] = { }; static inline int -ctnetlink_parse_nat(struct nfattr *nat, +ctnetlink_parse_nat(struct nfattr *cda[], const struct nf_conn *ct, struct ip_nat_range *range) { struct nfattr *tb[CTA_NAT_MAX]; @@ -665,7 +640,7 @@ ctnetlink_parse_nat(struct nfattr *nat, memset(range, 0, sizeof(*range)); - nfattr_parse_nested(tb, CTA_NAT_MAX, nat); + nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]); if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) return -EINVAL; @@ -880,30 +855,39 @@ ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) /* ASSURED bit can only be set */ return -EINVAL; - if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { + if (cda[CTA_NAT-1]) { #ifndef CONFIG_IP_NF_NAT_NEEDED return -EINVAL; #else + unsigned int hooknum; struct ip_nat_range range; - if (cda[CTA_NAT_DST-1]) { - if (ctnetlink_parse_nat(cda[CTA_NAT_DST-1], ct, - &range) < 0) - return -EINVAL; - if (ip_nat_initialized(ct, - HOOK2MANIP(NF_IP_PRE_ROUTING))) - return -EEXIST; - ip_nat_setup_info(ct, &range, hooknum); - } - if (cda[CTA_NAT_SRC-1]) { - if (ctnetlink_parse_nat(cda[CTA_NAT_SRC-1], ct, - &range) < 0) - return -EINVAL; - if (ip_nat_initialized(ct, - HOOK2MANIP(NF_IP_POST_ROUTING))) - return -EEXIST; - ip_nat_setup_info(ct, &range, hooknum); - } + if (ctnetlink_parse_nat(cda, ct, &range) < 0) + return -EINVAL; + + DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", + NIPQUAD(range.min_ip), NIPQUAD(range.max_ip), + htons(range.min.all), htons(range.max.all)); + + /* This is tricky but it works. ip_nat_setup_info needs the + * hook number as parameter, so let's do the correct + * conversion and run away */ + if (status & IPS_SRC_NAT_DONE) + hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */ + else if (status & IPS_DST_NAT_DONE) + hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */ + else + return -EINVAL; /* Missing NAT flags */ + + DEBUGP("NAT status: %lu\n", + status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); + + if (ip_nat_initialized(ct, HOOK2MANIP(hooknum))) + return -EEXIST; + ip_nat_setup_info(ct, &range, hooknum); + + DEBUGP("NAT status after setup_info: %lu\n", + ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); #endif } @@ -919,17 +903,11 @@ static inline int ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) { struct nf_conntrack_helper *helper; - struct nf_conn_help *help = nfct_help(ct); char *helpname; int err; DEBUGP("entered %s\n", __FUNCTION__); - if (!help) { - /* FIXME: we need to reallocate and rehash */ - return -EBUSY; - } - /* don't change helper of sibling connections */ if (ct->master) return -EINVAL; @@ -946,18 +924,18 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) return -EINVAL; } - if (help->helper) { + if (ct->helper) { if (!helper) { /* we had a helper before ... */ nf_ct_remove_expectations(ct); - help->helper = NULL; + ct->helper = NULL; } else { /* need to zero data of old helper */ - memset(&help->help, 0, sizeof(help->help)); + memset(&ct->help, 0, sizeof(ct->help)); } } - help->helper = helper; + ct->helper = helper; return 0; } @@ -1027,7 +1005,7 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[]) return err; } -#if defined(CONFIG_NF_CONNTRACK_MARK) +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) if (cda[CTA_MARK-1]) ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); #endif @@ -1067,14 +1045,19 @@ ctnetlink_create_conntrack(struct nfattr *cda[], return err; } -#if defined(CONFIG_NF_CONNTRACK_MARK) +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) if (cda[CTA_MARK-1]) ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); #endif + ct->helper = nf_ct_helper_find_get(rtuple); + add_timer(&ct->timeout); nf_conntrack_hash_insert(ct); + if (ct->helper) + nf_ct_helper_put(ct->helper); + DEBUGP("conntrack with id %u inserted\n", ct->id); return 0; @@ -1127,7 +1110,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, /* implicit 'else' */ /* we only allow nat config for new conntracks */ - if (cda[CTA_NAT_SRC-1] || cda[CTA_NAT_DST-1]) { + if (cda[CTA_NAT-1]) { err = -EINVAL; goto out_unlock; } @@ -1166,37 +1149,6 @@ nfattr_failure: return -1; } -static inline int -ctnetlink_exp_dump_mask(struct sk_buff *skb, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *mask) -{ - int ret; - struct nf_conntrack_l3proto *l3proto; - struct nf_conntrack_protocol *proto; - struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK); - - l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); - ret = ctnetlink_dump_tuples_ip(skb, mask, l3proto); - nf_ct_l3proto_put(l3proto); - - if (unlikely(ret < 0)) - goto nfattr_failure; - - proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); - ret = ctnetlink_dump_tuples_proto(skb, mask, proto); - nf_ct_proto_put(proto); - if (unlikely(ret < 0)) - goto nfattr_failure; - - NFA_NEST_END(skb, nest_parms); - - return 0; - -nfattr_failure: - return -1; -} - static inline int ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct nf_conntrack_expect *exp) @@ -1207,7 +1159,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) goto nfattr_failure; - if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) + if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0) goto nfattr_failure; if (ctnetlink_exp_dump_tuple(skb, &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, @@ -1465,8 +1417,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, } list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) { - struct nf_conn_help *m_help = nfct_help(exp->master); - if (m_help->helper == h + if (exp->master->helper == h && del_timer(&exp->timeout)) { nf_ct_unlink_expect(exp); nf_conntrack_expect_put(exp); @@ -1501,7 +1452,6 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) struct nf_conntrack_tuple_hash *h = NULL; struct nf_conntrack_expect *exp; struct nf_conn *ct; - struct nf_conn_help *help; int err = 0; DEBUGP("entered %s\n", __FUNCTION__); @@ -1522,9 +1472,8 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) if (!h) return -ENOENT; ct = nf_ct_tuplehash_to_ctrack(h); - help = nfct_help(ct); - if (!help || !help->helper) { + if (!ct->helper) { /* such conntrack hasn't got any helper, abort */ err = -EINVAL; goto out;