This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / net / ipv4 / netfilter / ip_nat_standalone.c
index 79f56f6..bf66672 100644 (file)
                                 : ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN"  \
                                    : "*ERROR*")))
 
+static inline int call_expect(struct ip_conntrack *master,
+                             struct sk_buff **pskb,
+                             unsigned int hooknum,
+                             struct ip_conntrack *ct,
+                             struct ip_nat_info *info)
+{
+       return master->nat.info.helper->expect(pskb, hooknum, ct, info);
+}
+
 static unsigned int
 ip_nat_fn(unsigned int hooknum,
          struct sk_buff **pskb,
@@ -106,7 +115,7 @@ ip_nat_fn(unsigned int hooknum,
        case IP_CT_RELATED:
        case IP_CT_RELATED+IP_CT_IS_REPLY:
                if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
-                       if (!icmp_reply_translation(pskb, ct, maniptype,
+                       if (!icmp_reply_translation(pskb, ct, hooknum,
                                                    CTINFO2DIR(ctinfo)))
                                return NF_DROP;
                        else
@@ -116,26 +125,47 @@ ip_nat_fn(unsigned int hooknum,
        case IP_CT_NEW:
                info = &ct->nat.info;
 
+               WRITE_LOCK(&ip_nat_lock);
                /* Seen it before?  This can happen for loopback, retrans,
                   or local packets.. */
-               if (!ip_nat_initialized(ct, maniptype)) {
+               if (!(info->initialized & (1 << maniptype))
+#ifndef CONFIG_IP_NF_NAT_LOCAL
+                   /* If this session has already been confirmed we must not
+                    * touch it again even if there is no mapping set up.
+                    * Can only happen on local->local traffic with
+                    * CONFIG_IP_NF_NAT_LOCAL disabled.
+                    */
+                   && !(ct->status & IPS_CONFIRMED)
+#endif
+                   ) {
                        unsigned int ret;
 
-                       /* LOCAL_IN hook doesn't have a chain!  */
-                       if (hooknum == NF_IP_LOCAL_IN)
-                               ret = alloc_null_binding(ct, info, hooknum);
-                       else
-                               ret = ip_nat_rule_find(pskb, hooknum,
-                                                      in, out, ct,
-                                                      info);
+                       if (ct->master
+                           && master_ct(ct)->nat.info.helper
+                           && master_ct(ct)->nat.info.helper->expect) {
+                               ret = call_expect(master_ct(ct), pskb, 
+                                                 hooknum, ct, info);
+                       } else {
+#ifdef CONFIG_IP_NF_NAT_LOCAL
+                               /* LOCAL_IN hook doesn't have a chain!  */
+                               if (hooknum == NF_IP_LOCAL_IN)
+                                       ret = alloc_null_binding(ct, info,
+                                                                hooknum);
+                               else
+#endif
+                               ret = ip_nat_rule_find(pskb, hooknum, in, out,
+                                                      ct, info);
+                       }
 
                        if (ret != NF_ACCEPT) {
+                               WRITE_UNLOCK(&ip_nat_lock);
                                return ret;
                        }
                } else
                        DEBUGP("Already setup manip %s for ct %p\n",
                               maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
                               ct);
+               WRITE_UNLOCK(&ip_nat_lock);
                break;
 
        default:
@@ -146,30 +176,7 @@ ip_nat_fn(unsigned int hooknum,
        }
 
        IP_NF_ASSERT(info);
-       return nat_packet(ct, ctinfo, hooknum, pskb);
-}
-
-static unsigned int
-ip_nat_in(unsigned int hooknum,
-          struct sk_buff **pskb,
-          const struct net_device *in,
-          const struct net_device *out,
-          int (*okfn)(struct sk_buff *))
-{
-       u_int32_t saddr, daddr;
-       unsigned int ret;
-
-       saddr = (*pskb)->nh.iph->saddr;
-       daddr = (*pskb)->nh.iph->daddr;
-
-       ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
-       if (ret != NF_DROP && ret != NF_STOLEN
-           && ((*pskb)->nh.iph->saddr != saddr
-               || (*pskb)->nh.iph->daddr != daddr)) {
-               dst_release((*pskb)->dst);
-               (*pskb)->dst = NULL;
-       }
-       return ret;
+       return do_bindings(ct, ctinfo, info, hooknum, pskb);
 }
 
 static unsigned int
@@ -204,6 +211,7 @@ ip_nat_out(unsigned int hooknum,
        return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
+#ifdef CONFIG_IP_NF_NAT_LOCAL
 static unsigned int
 ip_nat_local_fn(unsigned int hooknum,
                struct sk_buff **pskb,
@@ -229,31 +237,13 @@ ip_nat_local_fn(unsigned int hooknum,
                return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
        return ret;
 }
-
-static unsigned int
-ip_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 ip_conntrack *ct;
-       enum ip_conntrack_info ctinfo;
-
-       ct = ip_conntrack_get(*pskb, &ctinfo);
-       if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
-               DEBUGP("ip_nat_standalone: adjusting sequence number\n");
-               if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
-                       return NF_DROP;
-       }
-       return NF_ACCEPT;
-}
+#endif
 
 /* We must be after connection tracking and before packet filtering. */
 
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_in_ops = {
-       .hook           = ip_nat_in,
+       .hook           = ip_nat_fn,
        .owner          = THIS_MODULE,
        .pf             = PF_INET,
        .hooknum        = NF_IP_PRE_ROUTING,
@@ -269,15 +259,7 @@ static struct nf_hook_ops ip_nat_out_ops = {
        .priority       = NF_IP_PRI_NAT_SRC,
 };
 
-/* After conntrack, adjust sequence number */
-static struct nf_hook_ops ip_nat_adjust_out_ops = {
-       .hook           = ip_nat_adjust,
-       .owner          = THIS_MODULE,
-       .pf             = PF_INET,
-       .hooknum        = NF_IP_POST_ROUTING,
-       .priority       = NF_IP_PRI_NAT_SEQ_ADJUST,
-};
-
+#ifdef CONFIG_IP_NF_NAT_LOCAL
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_local_out_ops = {
        .hook           = ip_nat_local_fn,
@@ -295,16 +277,34 @@ static struct nf_hook_ops ip_nat_local_in_ops = {
        .hooknum        = NF_IP_LOCAL_IN,
        .priority       = NF_IP_PRI_NAT_SRC,
 };
+#endif
 
-/* After conntrack, adjust sequence number */
-static struct nf_hook_ops ip_nat_adjust_in_ops = {
-       .hook           = ip_nat_adjust,
-       .owner          = THIS_MODULE,
-       .pf             = PF_INET,
-       .hooknum        = NF_IP_LOCAL_IN,
-       .priority       = NF_IP_PRI_NAT_SEQ_ADJUST,
-};
+/* Protocol registration. */
+int ip_nat_protocol_register(struct ip_nat_protocol *proto)
+{
+       int ret = 0;
 
+       WRITE_LOCK(&ip_nat_lock);
+       if (ip_nat_protos[proto->protonum] != &ip_nat_unknown_protocol) {
+               ret = -EBUSY;
+               goto out;
+       }
+       ip_nat_protos[proto->protonum] = proto;
+ out:
+       WRITE_UNLOCK(&ip_nat_lock);
+       return ret;
+}
+
+/* Noone stores the protocol anywhere; simply delete it. */
+void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
+{
+       WRITE_LOCK(&ip_nat_lock);
+       ip_nat_protos[proto->protonum] = &ip_nat_unknown_protocol;
+       WRITE_UNLOCK(&ip_nat_lock);
+
+       /* Someone could be still looking at the proto in a bh. */
+       synchronize_net();
+}
 
 static int init_or_cleanup(int init)
 {
@@ -334,37 +334,27 @@ static int init_or_cleanup(int init)
                printk("ip_nat_init: can't register out hook.\n");
                goto cleanup_inops;
        }
-       ret = nf_register_hook(&ip_nat_adjust_in_ops);
-       if (ret < 0) {
-               printk("ip_nat_init: can't register adjust in hook.\n");
-               goto cleanup_outops;
-       }
-       ret = nf_register_hook(&ip_nat_adjust_out_ops);
-       if (ret < 0) {
-               printk("ip_nat_init: can't register adjust out hook.\n");
-               goto cleanup_adjustin_ops;
-       }
+#ifdef CONFIG_IP_NF_NAT_LOCAL
        ret = nf_register_hook(&ip_nat_local_out_ops);
        if (ret < 0) {
                printk("ip_nat_init: can't register local out hook.\n");
-               goto cleanup_adjustout_ops;;
+               goto cleanup_outops;
        }
        ret = nf_register_hook(&ip_nat_local_in_ops);
        if (ret < 0) {
                printk("ip_nat_init: can't register local in hook.\n");
                goto cleanup_localoutops;
        }
+#endif
        return ret;
 
  cleanup:
+#ifdef CONFIG_IP_NF_NAT_LOCAL
        nf_unregister_hook(&ip_nat_local_in_ops);
  cleanup_localoutops:
        nf_unregister_hook(&ip_nat_local_out_ops);
- cleanup_adjustout_ops:
-       nf_unregister_hook(&ip_nat_adjust_out_ops);
- cleanup_adjustin_ops:
-       nf_unregister_hook(&ip_nat_adjust_in_ops);
  cleanup_outops:
+#endif
        nf_unregister_hook(&ip_nat_out_ops);
  cleanup_inops:
        nf_unregister_hook(&ip_nat_in_ops);
@@ -393,9 +383,12 @@ module_exit(fini);
 EXPORT_SYMBOL(ip_nat_setup_info);
 EXPORT_SYMBOL(ip_nat_protocol_register);
 EXPORT_SYMBOL(ip_nat_protocol_unregister);
+EXPORT_SYMBOL(ip_nat_helper_register);
+EXPORT_SYMBOL(ip_nat_helper_unregister);
 EXPORT_SYMBOL(ip_nat_cheat_check);
 EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
 EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
 EXPORT_SYMBOL(ip_nat_used_tuple);
-EXPORT_SYMBOL(ip_nat_follow_master);
+EXPORT_SYMBOL(ip_nat_find_helper);
+EXPORT_SYMBOL(__ip_nat_find_helper);
 MODULE_LICENSE("GPL");