X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fnf_nat_standalone.c;h=b7dd695691a0858bf20bda8b4f756e05f585ab1f;hb=2ab61b01110aa04cd853c619a74881e3225a5e24;hp=46cc99def165fc5e80f5ae3f1596890afa17f6e6;hpb=27196c30db1ed4ab09c2071149b3324a1a53cfb9;p=linux-2.6 diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 46cc99def1..b7dd695691 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -30,8 +30,8 @@ #ifdef CONFIG_XFRM static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) { - struct nf_conn *ct; - struct nf_conntrack_tuple *t; + const struct nf_conn *ct; + const struct nf_conntrack_tuple *t; enum ip_conntrack_info ctinfo; enum ip_conntrack_dir dir; unsigned long statusbit; @@ -50,7 +50,10 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) if (ct->status & statusbit) { fl->fl4_dst = t->dst.u3.ip; if (t->dst.protonum == IPPROTO_TCP || - t->dst.protonum == IPPROTO_UDP) + t->dst.protonum == IPPROTO_UDP || + t->dst.protonum == IPPROTO_UDPLITE || + t->dst.protonum == IPPROTO_DCCP || + t->dst.protonum == IPPROTO_SCTP) fl->fl_ip_dport = t->dst.u.tcp.port; } @@ -59,7 +62,10 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) if (ct->status & statusbit) { fl->fl4_src = t->src.u3.ip; if (t->dst.protonum == IPPROTO_TCP || - t->dst.protonum == IPPROTO_UDP) + t->dst.protonum == IPPROTO_UDP || + t->dst.protonum == IPPROTO_UDPLITE || + t->dst.protonum == IPPROTO_DCCP || + t->dst.protonum == IPPROTO_SCTP) fl->fl_ip_sport = t->src.u.tcp.port; } } @@ -67,7 +73,7 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) static unsigned int nf_nat_fn(unsigned int hooknum, - struct sk_buff **pskb, + struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) @@ -80,28 +86,15 @@ nf_nat_fn(unsigned int hooknum, /* We never see fragments: conntrack defrags on pre-routing and local-out, and nf_nat_out protects post-routing. */ - NF_CT_ASSERT(!(ip_hdr(*pskb)->frag_off & htons(IP_MF | IP_OFFSET))); + NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET))); - ct = nf_ct_get(*pskb, &ctinfo); + ct = nf_ct_get(skb, &ctinfo); /* Can't track? It's not due to stress, or conntrack would have dropped it. Hence it's the user's responsibilty to packet filter it out, or implement conntrack/NAT for that protocol. 8) --RR */ - if (!ct) { - /* Exception: ICMP redirect to new connection (not in - hash table yet). We must not let this through, in - case we're doing NAT to the same network. */ - if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) { - struct icmphdr _hdr, *hp; - - hp = skb_header_pointer(*pskb, ip_hdrlen(*pskb), - sizeof(_hdr), &_hdr); - if (hp != NULL && - hp->type == ICMP_REDIRECT) - return NF_DROP; - } + if (!ct) return NF_ACCEPT; - } /* Don't try to NAT if this packet is not conntracked */ if (ct == &nf_conntrack_untracked) @@ -109,6 +102,9 @@ nf_nat_fn(unsigned int hooknum, nat = nfct_nat(ct); if (!nat) { + /* NAT module was loaded late. */ + if (nf_ct_is_confirmed(ct)) + return NF_ACCEPT; nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); if (nat == NULL) { pr_debug("failed to add NAT extension\n"); @@ -119,9 +115,9 @@ nf_nat_fn(unsigned int hooknum, switch (ctinfo) { case IP_CT_RELATED: case IP_CT_RELATED+IP_CT_IS_REPLY: - if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) { + if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { if (!nf_nat_icmp_reply_translation(ct, ctinfo, - hooknum, pskb)) + hooknum, skb)) return NF_DROP; else return NF_ACCEPT; @@ -134,14 +130,11 @@ nf_nat_fn(unsigned int hooknum, if (!nf_nat_initialized(ct, maniptype)) { unsigned int ret; - if (unlikely(nf_ct_is_confirmed(ct))) - /* NAT module was loaded late */ - ret = alloc_null_binding_confirmed(ct, hooknum); - else if (hooknum == NF_IP_LOCAL_IN) + if (hooknum == NF_INET_LOCAL_IN) /* LOCAL_IN hook doesn't have a chain! */ ret = alloc_null_binding(ct, hooknum); else - ret = nf_nat_rule_find(pskb, hooknum, in, out, + ret = nf_nat_rule_find(skb, hooknum, in, out, ct); if (ret != NF_ACCEPT) { @@ -159,50 +152,50 @@ nf_nat_fn(unsigned int hooknum, ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); } - return nf_nat_packet(ct, ctinfo, hooknum, pskb); + return nf_nat_packet(ct, ctinfo, hooknum, skb); } static unsigned int nf_nat_in(unsigned int hooknum, - struct sk_buff **pskb, + struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { unsigned int ret; - __be32 daddr = ip_hdr(*pskb)->daddr; + __be32 daddr = ip_hdr(skb)->daddr; - ret = nf_nat_fn(hooknum, pskb, in, out, okfn); + ret = nf_nat_fn(hooknum, skb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && - daddr != ip_hdr(*pskb)->daddr) { - dst_release((*pskb)->dst); - (*pskb)->dst = NULL; + daddr != ip_hdr(skb)->daddr) { + dst_release(skb->dst); + skb->dst = NULL; } return ret; } static unsigned int nf_nat_out(unsigned int hooknum, - struct sk_buff **pskb, + struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { #ifdef CONFIG_XFRM - struct nf_conn *ct; + const struct nf_conn *ct; enum ip_conntrack_info ctinfo; #endif unsigned int ret; /* root is playing with raw sockets. */ - if ((*pskb)->len < sizeof(struct iphdr) || - ip_hdrlen(*pskb) < sizeof(struct iphdr)) + if (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; - ret = nf_nat_fn(hooknum, pskb, in, out, okfn); + ret = nf_nat_fn(hooknum, skb, in, out, okfn); #ifdef CONFIG_XFRM if (ret != NF_DROP && ret != NF_STOLEN && - (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { + (ct = nf_ct_get(skb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.src.u3.ip != @@ -210,7 +203,7 @@ nf_nat_out(unsigned int hooknum, || ct->tuplehash[dir].tuple.src.u.all != ct->tuplehash[!dir].tuple.dst.u.all ) - return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP; + return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP; } #endif return ret; @@ -218,68 +211,49 @@ nf_nat_out(unsigned int hooknum, static unsigned int nf_nat_local_fn(unsigned int hooknum, - struct sk_buff **pskb, + struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - struct nf_conn *ct; + const struct nf_conn *ct; enum ip_conntrack_info ctinfo; unsigned int ret; /* root is playing with raw sockets. */ - if ((*pskb)->len < sizeof(struct iphdr) || - ip_hdrlen(*pskb) < sizeof(struct iphdr)) + if (skb->len < sizeof(struct iphdr) || + ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; - ret = nf_nat_fn(hooknum, pskb, in, out, okfn); + ret = nf_nat_fn(hooknum, skb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && - (ct = nf_ct_get(*pskb, &ctinfo)) != NULL) { + (ct = nf_ct_get(skb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.dst.u3.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { - if (ip_route_me_harder(pskb, RTN_UNSPEC)) + if (ip_route_me_harder(skb, RTN_UNSPEC)) ret = NF_DROP; } #ifdef CONFIG_XFRM else if (ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[!dir].tuple.src.u.all) - if (ip_xfrm_me_harder(pskb)) + if (ip_xfrm_me_harder(skb)) ret = NF_DROP; #endif } return ret; } -static unsigned int -nf_nat_adjust(unsigned int hooknum, - struct sk_buff **pskb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - struct nf_conn *ct; - enum ip_conntrack_info ctinfo; - - ct = nf_ct_get(*pskb, &ctinfo); - if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { - pr_debug("nf_nat_standalone: adjusting sequence number\n"); - if (!nf_nat_seq_adjust(pskb, ct, ctinfo)) - return NF_DROP; - } - return NF_ACCEPT; -} - /* We must be after connection tracking and before packet filtering. */ -static struct nf_hook_ops nf_nat_ops[] = { +static struct nf_hook_ops nf_nat_ops[] __read_mostly = { /* Before packet filtering, change destination */ { .hook = nf_nat_in, .owner = THIS_MODULE, .pf = PF_INET, - .hooknum = NF_IP_PRE_ROUTING, + .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_NAT_DST, }, /* After packet filtering, change source */ @@ -287,23 +261,15 @@ static struct nf_hook_ops nf_nat_ops[] = { .hook = nf_nat_out, .owner = THIS_MODULE, .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, + .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP_PRI_NAT_SRC, }, - /* After conntrack, adjust sequence number */ - { - .hook = nf_nat_adjust, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_POST_ROUTING, - .priority = NF_IP_PRI_NAT_SEQ_ADJUST, - }, /* Before packet filtering, change destination */ { .hook = nf_nat_local_fn, .owner = THIS_MODULE, .pf = PF_INET, - .hooknum = NF_IP_LOCAL_OUT, + .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_NAT_DST, }, /* After packet filtering, change source */ @@ -311,17 +277,9 @@ static struct nf_hook_ops nf_nat_ops[] = { .hook = nf_nat_fn, .owner = THIS_MODULE, .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, + .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_NAT_SRC, }, - /* After conntrack, adjust sequence number */ - { - .hook = nf_nat_adjust, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_IP_LOCAL_IN, - .priority = NF_IP_PRI_NAT_SEQ_ADJUST, - }, }; static int __init nf_nat_standalone_init(void) @@ -332,7 +290,7 @@ static int __init nf_nat_standalone_init(void) #ifdef CONFIG_XFRM BUG_ON(ip_nat_decode_session != NULL); - ip_nat_decode_session = nat_decode_session; + rcu_assign_pointer(ip_nat_decode_session, nat_decode_session); #endif ret = nf_nat_rule_init(); if (ret < 0) { @@ -350,7 +308,7 @@ static int __init nf_nat_standalone_init(void) nf_nat_rule_cleanup(); cleanup_decode_session: #ifdef CONFIG_XFRM - ip_nat_decode_session = NULL; + rcu_assign_pointer(ip_nat_decode_session, NULL); synchronize_net(); #endif return ret; @@ -361,7 +319,7 @@ static void __exit nf_nat_standalone_fini(void) nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops)); nf_nat_rule_cleanup(); #ifdef CONFIG_XFRM - ip_nat_decode_session = NULL; + rcu_assign_pointer(ip_nat_decode_session, NULL); synchronize_net(); #endif /* Conntrack caches are unregistered in nf_conntrack_cleanup */