vserver 1.9.5.x5
[linux-2.6.git] / net / ipv4 / netfilter / ip_nat_amanda.c
index 811caad..da1f412 100644 (file)
@@ -31,119 +31,58 @@ MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
 MODULE_DESCRIPTION("Amanda NAT helper");
 MODULE_LICENSE("GPL");
 
-static unsigned int
-amanda_nat_expected(struct sk_buff **pskb,
-                    unsigned int hooknum,
-                    struct ip_conntrack *ct,
-                    struct ip_nat_info *info)
+static unsigned int help(struct sk_buff **pskb,
+                        enum ip_conntrack_info ctinfo,
+                        unsigned int matchoff,
+                        unsigned int matchlen,
+                        struct ip_conntrack_expect *exp)
 {
-       struct ip_conntrack *master = master_ct(ct);
-       struct ip_ct_amanda_expect *exp_amanda_info;
-       struct ip_nat_multi_range mr;
-       u_int32_t newip;
-
-       IP_NF_ASSERT(info);
-       IP_NF_ASSERT(master);
-       IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
+       char buffer[sizeof("65535")];
+       u_int16_t port;
+       unsigned int ret;
 
-       if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
-               newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
-       else
-               newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+       /* Connection comes from client. */
+       exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+       exp->dir = IP_CT_DIR_ORIGINAL;
 
-       mr.rangesize = 1;
-       /* We don't want to manip the per-protocol, just the IPs. */
-       mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
-       mr.range[0].min_ip = mr.range[0].max_ip = newip;
+       /* When you see the packet, we need to NAT it the same as the
+        * this one (ie. same IP: it will be TCP and master is UDP). */
+       exp->expectfn = ip_nat_follow_master;
 
-       if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
-               exp_amanda_info = &ct->master->help.exp_amanda_info;
-               mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
-               mr.range[0].min = mr.range[0].max
-                       = ((union ip_conntrack_manip_proto)
-                               { .udp = { htons(exp_amanda_info->port) } });
+       /* Try to get same port: if not, try to change it. */
+       for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
+               exp->tuple.dst.u.tcp.port = htons(port);
+               if (ip_conntrack_expect_related(exp) == 0)
+                       break;
        }
 
-       return ip_nat_setup_info(ct, &mr, hooknum);
-}
-
-static int amanda_data_fixup(struct ip_conntrack *ct,
-                             struct sk_buff **pskb,
-                             enum ip_conntrack_info ctinfo,
-                             struct ip_conntrack_expect *exp)
-{
-       struct ip_ct_amanda_expect *exp_amanda_info;
-       struct ip_conntrack_tuple t = exp->tuple;
-       char buffer[sizeof("65535")];
-       u_int16_t port;
-
-       /* Alter conntrack's expectations. */
-       exp_amanda_info = &exp->help.exp_amanda_info;
-       t.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
-       for (port = exp_amanda_info->port; port != 0; port++) {
-               t.dst.u.tcp.port = htons(port);
-               if (ip_conntrack_change_expect(exp, &t) == 0)
-                       break;
+       if (port == 0) {
+               ip_conntrack_expect_free(exp);
+               return NF_DROP;
        }
-       if (port == 0)
-               return 0;
 
        sprintf(buffer, "%u", port);
-       return ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
-                                       exp_amanda_info->offset,
-                                       exp_amanda_info->len,
-                                       buffer, strlen(buffer));
-}
-
-static unsigned int help(struct ip_conntrack *ct,
-                         struct ip_conntrack_expect *exp,
-                         struct ip_nat_info *info,
-                         enum ip_conntrack_info ctinfo,
-                         unsigned int hooknum,
-                         struct sk_buff **pskb)
-{
-       int dir = CTINFO2DIR(ctinfo);
-       int ret = NF_ACCEPT;
-
-       /* Only mangle things once: original direction in POST_ROUTING
-          and reply direction on PRE_ROUTING. */
-       if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
-             || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY)))
-               return NF_ACCEPT;
-
-       /* if this exectation has a "offset" the packet needs to be mangled */
-       if (exp->help.exp_amanda_info.offset != 0)
-               if (!amanda_data_fixup(ct, pskb, ctinfo, exp))
-                       ret = NF_DROP;
-       exp->help.exp_amanda_info.offset = 0;
-
+       ret = ip_nat_mangle_udp_packet(pskb, exp->master, ctinfo,
+                                      matchoff, matchlen,
+                                      buffer, strlen(buffer));
+       if (ret != NF_ACCEPT)
+               ip_conntrack_unexpect_related(exp);
        return ret;
 }
 
-static struct ip_nat_helper ip_nat_amanda_helper;
-
 static void __exit fini(void)
 {
-       ip_nat_helper_unregister(&ip_nat_amanda_helper);
+       ip_nat_amanda_hook = NULL;
+       /* Make sure noone calls it, meanwhile. */
+       synchronize_net();
 }
 
 static int __init init(void)
 {
-       struct ip_nat_helper *hlpr = &ip_nat_amanda_helper;
-
-       hlpr->tuple.dst.protonum = IPPROTO_UDP;
-       hlpr->tuple.src.u.udp.port = htons(10080);
-       hlpr->mask.src.u.udp.port = 0xFFFF;
-       hlpr->mask.dst.protonum = 0xFFFF;
-       hlpr->help = help;
-       hlpr->flags = 0;
-       hlpr->me = THIS_MODULE;
-       hlpr->expect = amanda_nat_expected;
-       hlpr->name = "amanda";
-
-       return ip_nat_helper_register(hlpr);
+       BUG_ON(ip_nat_amanda_hook);
+       ip_nat_amanda_hook = help;
+       return 0;
 }
 
-NEEDS_CONNTRACK(amanda);
 module_init(init);
 module_exit(fini);