Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / ipv4 / netfilter / ip_conntrack_tftp.c
index ddee737..7e33d3b 100644 (file)
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
 #include <linux/netfilter_ipv4/ip_conntrack_tftp.h>
+#include <linux/moduleparam.h>
 
 MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
 MODULE_DESCRIPTION("tftp connection tracking helper");
 MODULE_LICENSE("GPL");
 
 #define MAX_PORTS 8
-static int ports[MAX_PORTS];
+static unsigned short ports[MAX_PORTS];
 static int ports_c;
-MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
+module_param_array(ports, ushort, &ports_c, 0400);
 MODULE_PARM_DESC(ports, "port numbers of tftp servers");
 
 #if 0
@@ -37,18 +38,26 @@ MODULE_PARM_DESC(ports, "port numbers of tftp servers");
 #define DEBUGP(format, args...)
 #endif
 
-static int tftp_help(struct sk_buff *skb,
+unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb,
+                                enum ip_conntrack_info ctinfo,
+                                struct ip_conntrack_expect *exp);
+EXPORT_SYMBOL_GPL(ip_nat_tftp_hook);
+
+static int tftp_help(struct sk_buff **pskb,
                     struct ip_conntrack *ct,
                     enum ip_conntrack_info ctinfo)
 {
-       struct tftphdr tftph;
+       struct tftphdr _tftph, *tfh;
        struct ip_conntrack_expect *exp;
+       unsigned int ret = NF_ACCEPT;
 
-       if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr),
-                         &tftph, sizeof(tftph)) != 0)
+       tfh = skb_header_pointer(*pskb,
+                                (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr),
+                                sizeof(_tftph), &_tftph);
+       if (tfh == NULL)
                return NF_ACCEPT;
 
-       switch (ntohs(tftph.opcode)) {
+       switch (ntohs(tfh->opcode)) {
        /* RRQ and WRQ works the same way */
        case TFTP_OPCODE_READ:
        case TFTP_OPCODE_WRITE:
@@ -56,21 +65,27 @@ static int tftp_help(struct sk_buff *skb,
                DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
                DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
 
-               exp = ip_conntrack_expect_alloc();
+               exp = ip_conntrack_expect_alloc(ct);
                if (exp == NULL)
-                       return NF_ACCEPT;
+                       return NF_DROP;
 
                exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
                exp->mask.src.ip = 0xffffffff;
+               exp->mask.src.u.udp.port = 0;
                exp->mask.dst.ip = 0xffffffff;
                exp->mask.dst.u.udp.port = 0xffff;
-               exp->mask.dst.protonum = 0xffff;
+               exp->mask.dst.protonum = 0xff;
                exp->expectfn = NULL;
+               exp->flags = 0;
 
                DEBUGP("expect: ");
                DUMP_TUPLE(&exp->tuple);
                DUMP_TUPLE(&exp->mask);
-               ip_conntrack_expect_related(exp, ct);
+               if (ip_nat_tftp_hook)
+                       ret = ip_nat_tftp_hook(pskb, ctinfo, exp);
+               else if (ip_conntrack_expect_related(exp) != 0)
+                       ret = NF_DROP;
+               ip_conntrack_expect_put(exp);
                break;
        case TFTP_OPCODE_DATA:
        case TFTP_OPCODE_ACK:
@@ -86,9 +101,9 @@ static int tftp_help(struct sk_buff *skb,
 }
 
 static struct ip_conntrack_helper tftp[MAX_PORTS];
-static char tftp_names[MAX_PORTS][10];
+static char tftp_names[MAX_PORTS][sizeof("tftp-65535")];
 
-static void fini(void)
+static void ip_conntrack_tftp_fini(void)
 {
        int i;
 
@@ -99,25 +114,24 @@ static void fini(void)
        } 
 }
 
-static int __init init(void)
+static int __init ip_conntrack_tftp_init(void)
 {
        int i, ret;
        char *tmpname;
 
-       if (!ports[0])
-               ports[0]=TFTP_PORT;
+       if (ports_c == 0)
+               ports[ports_c++] = TFTP_PORT;
 
-       for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
+       for (i = 0; i < ports_c; i++) {
                /* Create helper structure */
                memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper));
 
                tftp[i].tuple.dst.protonum = IPPROTO_UDP;
                tftp[i].tuple.src.u.udp.port = htons(ports[i]);
-               tftp[i].mask.dst.protonum = 0xFFFF;
+               tftp[i].mask.dst.protonum = 0xFF;
                tftp[i].mask.src.u.udp.port = 0xFFFF;
                tftp[i].max_expected = 1;
-               tftp[i].timeout = 0;
-               tftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
+               tftp[i].timeout = 5 * 60; /* 5 minutes */
                tftp[i].me = THIS_MODULE;
                tftp[i].help = tftp_help;
 
@@ -134,15 +148,12 @@ static int __init init(void)
                if (ret) {
                        printk("ERROR registering helper for port %d\n",
                                ports[i]);
-                       fini();
+                       ip_conntrack_tftp_fini();
                        return(ret);
                }
-               ports_c++;
        }
        return(0);
 }
 
-PROVIDES_CONNTRACK(tftp);
-
-module_init(init);
-module_exit(fini);
+module_init(ip_conntrack_tftp_init);
+module_exit(ip_conntrack_tftp_fini);