vserver 1.9.5.x5
[linux-2.6.git] / net / ipv4 / netfilter / ip_conntrack_irc.c
index d007bc9..33cc734 100644 (file)
@@ -43,10 +43,17 @@ static unsigned int dcc_timeout = 300;
 static char irc_buffer[65536];
 static DECLARE_LOCK(irc_buffer_lock);
 
+unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb,
+                               enum ip_conntrack_info ctinfo,
+                               unsigned int matchoff,
+                               unsigned int matchlen,
+                               struct ip_conntrack_expect *exp);
+EXPORT_SYMBOL_GPL(ip_nat_irc_hook);
+
 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
 MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
 MODULE_LICENSE("GPL");
-module_param_array(ports, int, ports_c, 0400);
+module_param_array(ports, int, &ports_c, 0400);
 MODULE_PARM_DESC(ports, "port numbers of IRC servers");
 module_param(max_dcc_channels, int, 0400);
 MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
@@ -56,8 +63,6 @@ MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
 static char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " };
 #define MINMATCHLEN    5
 
-struct module *ip_conntrack_irc = THIS_MODULE;
-
 #if 0
 #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \
                                        __FILE__, __FUNCTION__ , ## args)
@@ -65,8 +70,8 @@ struct module *ip_conntrack_irc = THIS_MODULE;
 #define DEBUGP(format, args...)
 #endif
 
-int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port,
-             char **ad_beg_p, char **ad_end_p)
+static int parse_dcc(char *data, char *data_end, u_int32_t *ip,
+                    u_int16_t *port, char **ad_beg_p, char **ad_end_p)
 /* tries to get the ip_addr and port out of a dcc command
    return value: -1 on failure, 0 on success 
        data            pointer to first byte of DCC command data
@@ -98,7 +103,7 @@ int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port,
        return 0;
 }
 
-static int help(struct sk_buff *skb,
+static int help(struct sk_buff **pskb,
                struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
 {
        unsigned int dataoff;
@@ -106,11 +111,10 @@ static int help(struct sk_buff *skb,
        char *data, *data_limit, *ib_ptr;
        int dir = CTINFO2DIR(ctinfo);
        struct ip_conntrack_expect *exp;
-       struct ip_ct_irc_expect *exp_irc_info = NULL;
-
+       u32 seq;
        u_int32_t dcc_ip;
        u_int16_t dcc_port;
-       int i;
+       int i, ret = NF_ACCEPT;
        char *addr_beg_p, *addr_end_p;
 
        DEBUGP("entered\n");
@@ -127,23 +131,23 @@ static int help(struct sk_buff *skb,
        }
 
        /* Not a full tcp header? */
-       th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+       th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
                                sizeof(_tcph), &_tcph);
        if (th == NULL)
                return NF_ACCEPT;
 
        /* No data? */
-       dataoff = skb->nh.iph->ihl*4 + th->doff*4;
-       if (dataoff >= skb->len)
+       dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4;
+       if (dataoff >= (*pskb)->len)
                return NF_ACCEPT;
 
        LOCK_BH(&irc_buffer_lock);
-       ib_ptr = skb_header_pointer(skb, dataoff,
-                                   skb->len - dataoff, irc_buffer);
+       ib_ptr = skb_header_pointer(*pskb, dataoff,
+                                   (*pskb)->len - dataoff, irc_buffer);
        BUG_ON(ib_ptr == NULL);
 
        data = ib_ptr;
-       data_limit = ib_ptr + skb->len - dataoff;
+       data_limit = ib_ptr + (*pskb)->len - dataoff;
 
        /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
         * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
@@ -195,45 +199,46 @@ static int help(struct sk_buff *skb,
                        }
 
                        exp = ip_conntrack_expect_alloc();
-                       if (exp == NULL)
+                       if (exp == NULL) {
+                               ret = NF_DROP;
                                goto out;
-
-                       exp_irc_info = &exp->help.exp_irc_info;
+                       }
 
                        /* save position of address in dcc string,
                         * necessary for NAT */
                        DEBUGP("tcph->seq = %u\n", th->seq);
-                       exp->seq = ntohl(th->seq) + (addr_beg_p - ib_ptr);
-                       exp_irc_info->len = (addr_end_p - addr_beg_p);
-                       exp_irc_info->port = dcc_port;
-                       DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
-                               exp->seq, (addr_end_p - _data), exp_irc_info->len);
+                       seq = ntohl(th->seq) + (addr_beg_p - ib_ptr);
 
+                       /* We refer to the reverse direction ("!dir")
+                        * tuples here, because we're expecting
+                        * something in the other * direction.
+                        * Doesn't matter unless NAT is happening.  */
                        exp->tuple = ((struct ip_conntrack_tuple)
                                { { 0, { 0 } },
-                                 { ct->tuplehash[dir].tuple.src.ip, { .tcp = { htons(dcc_port) } },
+                                 { ct->tuplehash[!dir].tuple.dst.ip,
+                                   { .tcp = { htons(dcc_port) } },
                                    IPPROTO_TCP }});
                        exp->mask = ((struct ip_conntrack_tuple)
                                { { 0, { 0 } },
-                                 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
-
+                                 { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
                        exp->expectfn = NULL;
-
-                       DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
-                               NIPQUAD(exp->tuple.src.ip),
-                               ntohs(exp->tuple.src.u.tcp.port),
-                               NIPQUAD(exp->tuple.dst.ip),
-                               ntohs(exp->tuple.dst.u.tcp.port));
-
-                       ip_conntrack_expect_related(exp, ct);
-
+                       exp->master = ct;
+                       if (ip_nat_irc_hook)
+                               ret = ip_nat_irc_hook(pskb, ctinfo, 
+                                                     addr_beg_p - ib_ptr,
+                                                     addr_end_p - addr_beg_p,
+                                                     exp);
+                       else if (ip_conntrack_expect_related(exp) != 0) {
+                               ip_conntrack_expect_free(exp);
+                               ret = NF_DROP;
+                       }
                        goto out;
                } /* for .. NUM_DCCPROTO */
        } /* while data < ... */
 
  out:
        UNLOCK_BH(&irc_buffer_lock);
-       return NF_ACCEPT;
+       return ret;
 }
 
 static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
@@ -265,11 +270,10 @@ static int __init init(void)
                hlpr->tuple.src.u.tcp.port = htons(ports[i]);
                hlpr->tuple.dst.protonum = IPPROTO_TCP;
                hlpr->mask.src.u.tcp.port = 0xFFFF;
-               hlpr->mask.dst.protonum = 0xFFFF;
+               hlpr->mask.dst.protonum = 0xFF;
                hlpr->max_expected = max_dcc_channels;
                hlpr->timeout = dcc_timeout;
-               hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
-               hlpr->me = ip_conntrack_irc;
+               hlpr->me = THIS_MODULE;
                hlpr->help = help;
 
                tmpname = &irc_names[i][0];
@@ -305,7 +309,5 @@ static void fini(void)
        }
 }
 
-PROVIDES_CONNTRACK(irc);
-
 module_init(init);
 module_exit(fini);