X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fip_conntrack_irc.c;h=91832eca4106470de11dbcd2c6a4aa3a52c3bab2;hb=refs%2Fheads%2Fvserver;hp=31ff05349c96aa54d476427c01e2ab51b8229f2c;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index 31ff05349..91832eca4 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c @@ -22,43 +22,45 @@ * */ -#include #include #include #include #include #include -#include #include #include +#include #define MAX_PORTS 8 -static int ports[MAX_PORTS]; +static unsigned short ports[MAX_PORTS]; static int ports_c; -static int max_dcc_channels = 8; +static unsigned int max_dcc_channels = 8; static unsigned int dcc_timeout = 300; /* This is slow, but it's simple. --RR */ -static char irc_buffer[65536]; +static char *irc_buffer; +static DEFINE_SPINLOCK(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 "); MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); MODULE_LICENSE("GPL"); -#ifdef MODULE_PARM -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +module_param_array(ports, ushort, &ports_c, 0400); MODULE_PARM_DESC(ports, "port numbers of IRC servers"); -MODULE_PARM(max_dcc_channels, "i"); +module_param(max_dcc_channels, uint, 0400); MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session"); -MODULE_PARM(dcc_timeout, "i"); +module_param(dcc_timeout, uint, 0400); MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); -#endif -static char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; +static const char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; #define MINMATCHLEN 5 -DECLARE_LOCK(ip_irc_lock); -struct module *ip_conntrack_irc = THIS_MODULE; - #if 0 #define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \ __FILE__, __FUNCTION__ , ## args) @@ -66,8 +68,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 @@ -99,20 +101,20 @@ 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; - struct tcphdr tcph; - char *data, *data_limit; + struct tcphdr _tcph, *th; + 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; + typeof(ip_nat_irc_hook) ip_nat_irc; DEBUGP("entered\n"); @@ -128,19 +130,23 @@ static int help(struct sk_buff *skb, } /* Not a full tcp header? */ - if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0) + 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 + tcph.doff*4; - if (dataoff >= skb->len) + dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4; + if (dataoff >= (*pskb)->len) return NF_ACCEPT; - LOCK_BH(&ip_irc_lock); - skb_copy_bits(skb, dataoff, irc_buffer, skb->len - dataoff); + spin_lock_bh(&irc_buffer_lock); + ib_ptr = skb_header_pointer(*pskb, dataoff, + (*pskb)->len - dataoff, irc_buffer); + BUG_ON(ib_ptr == NULL); - data = irc_buffer; - data_limit = irc_buffer + skb->len - dataoff; + data = ib_ptr; + 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 */ @@ -154,8 +160,8 @@ static int help(struct sk_buff *skb, /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", - NIPQUAD(iph->saddr), ntohs(tcph.source), - NIPQUAD(iph->daddr), ntohs(tcph.dest)); + NIPQUAD(iph->saddr), ntohs(th->source), + NIPQUAD(iph->daddr), ntohs(th->dest)); for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { @@ -191,54 +197,56 @@ static int help(struct sk_buff *skb, continue; } - exp = ip_conntrack_expect_alloc(); - if (exp == NULL) + exp = ip_conntrack_expect_alloc(ct); + 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", tcph.seq); - exp->seq = ntohl(tcph.seq) + (addr_beg_p - irc_buffer); - 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); + DEBUGP("tcph->seq = %u\n", th->seq); + 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 }}); - + { htonl(0xFFFFFFFF), + { .tcp = { htons(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->flags = 0; + ip_nat_irc = rcu_dereference(ip_nat_irc_hook); + if (ip_nat_irc) + ret = ip_nat_irc(pskb, ctinfo, + addr_beg_p - ib_ptr, + addr_end_p - addr_beg_p, + exp); + else if (ip_conntrack_expect_related(exp) != 0) + ret = NF_DROP; + ip_conntrack_expect_put(exp); goto out; } /* for .. NUM_DCCPROTO */ } /* while data < ... */ out: - UNLOCK_BH(&ip_irc_lock); - return NF_ACCEPT; + spin_unlock_bh(&irc_buffer_lock); + return ret; } static struct ip_conntrack_helper irc_helpers[MAX_PORTS]; -static char irc_names[MAX_PORTS][10]; +static char irc_names[MAX_PORTS][sizeof("irc-65535")]; -static void fini(void); +static void ip_conntrack_irc_fini(void); -static int __init init(void) +static int __init ip_conntrack_irc_init(void) { int i, ret; struct ip_conntrack_helper *hlpr; @@ -248,25 +256,24 @@ static int __init init(void) printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n"); return -EBUSY; } - if (dcc_timeout < 0) { - printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n"); - return -EBUSY; - } + + irc_buffer = kmalloc(65536, GFP_KERNEL); + if (!irc_buffer) + return -ENOMEM; /* If no port given, default to standard irc port */ - if (ports[0] == 0) - ports[0] = IRC_PORT; + if (ports_c == 0) + ports[ports_c++] = IRC_PORT; - for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + for (i = 0; i < ports_c; i++) { hlpr = &irc_helpers[i]; 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.src.u.tcp.port = htons(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]; @@ -283,17 +290,16 @@ static int __init init(void) if (ret) { printk("ip_conntrack_irc: ERROR registering port %d\n", ports[i]); - fini(); + ip_conntrack_irc_fini(); return -EBUSY; } - ports_c++; } return 0; } /* This function is intentionally _NOT_ defined as __exit, because * it is needed by the init function */ -static void fini(void) +static void ip_conntrack_irc_fini(void) { int i; for (i = 0; i < ports_c; i++) { @@ -301,10 +307,8 @@ static void fini(void) ports[i]); ip_conntrack_helper_unregister(&irc_helpers[i]); } + kfree(irc_buffer); } -PROVIDES_CONNTRACK(irc); -EXPORT_SYMBOL(ip_irc_lock); - -module_init(init); -module_exit(fini); +module_init(ip_conntrack_irc_init); +module_exit(ip_conntrack_irc_fini);