X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fip_nat_irc.c;h=feb26b48f1d5040fce65fc36c48e95df42976fab;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=52b2e532568f351f50bd7d8b6ee606cf2cf6c3ed;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ip_nat_irc.c b/net/ipv4/netfilter/ip_nat_irc.c index 52b2e5325..feb26b48f 100644 --- a/net/ipv4/netfilter/ip_nat_irc.c +++ b/net/ipv4/netfilter/ip_nat_irc.c @@ -1,5 +1,6 @@ /* IRC extension for TCP NAT alteration. * (C) 2000-2001 by Harald Welte + * (C) 2004 Rusty Russell IBM Corporation * based on a copy of RR's ip_nat_ftp.c * * ip_nat_irc.c,v 1.16 2001/12/06 07:42:10 laforge Exp @@ -8,12 +9,6 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. - * - * Module load syntax: - * insmod ip_nat_irc.o ports=port1,port2,...port - * - * please give the ports of all IRC servers You wish to connect to. - * If You don't specify ports, the default will be port 6667 */ #include @@ -27,6 +22,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -34,102 +30,43 @@ #define DEBUGP(format, args...) #endif -#define MAX_PORTS 8 -static int ports[MAX_PORTS]; -static int ports_c; - MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("IRC (DCC) NAT helper"); MODULE_LICENSE("GPL"); -#ifdef MODULE_PARM -MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); -MODULE_PARM_DESC(ports, "port numbers of IRC servers"); -#endif - -/* protects irc part of conntracks */ -DECLARE_LOCK_EXTERN(ip_irc_lock); - -/* FIXME: Time out? --RR */ - -static unsigned int -irc_nat_expected(struct sk_buff **pskb, - unsigned int hooknum, - struct ip_conntrack *ct, - struct ip_nat_info *info) -{ - struct ip_nat_multi_range mr; - u_int32_t newdstip, newsrcip, newip; - - struct ip_conntrack *master = master_ct(ct); - - IP_NF_ASSERT(info); - IP_NF_ASSERT(master); - - IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); - - DEBUGP("nat_expected: We have a connection!\n"); - newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; - newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; - DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n", - NIPQUAD(newsrcip), NIPQUAD(newdstip)); - - if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) - newip = newsrcip; - else - newip = newdstip; - - DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); - - 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; - - return ip_nat_setup_info(ct, &mr, hooknum); -} - -static int irc_data_fixup(const struct ip_ct_irc_expect *ct_irc_info, - struct ip_conntrack *ct, - struct sk_buff **pskb, - enum ip_conntrack_info ctinfo, - struct ip_conntrack_expect *expect) +static unsigned int help(struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + unsigned int matchoff, + unsigned int matchlen, + struct ip_conntrack_expect *exp) { - u_int32_t newip; - struct ip_conntrack_tuple t; - struct iphdr *iph = (*pskb)->nh.iph; - struct tcphdr *tcph = (void *) iph + iph->ihl * 4; u_int16_t port; + unsigned int ret; /* "4294967296 65635 " */ char buffer[18]; - MUST_BE_LOCKED(&ip_irc_lock); - DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n", - expect->seq, ct_irc_info->len, + expect->seq, exp_irc_info->len, ntohl(tcph->seq)); - newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; - - /* Alter conntrack's expectations. */ + /* Reply comes from server. */ + exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; + exp->dir = IP_CT_DIR_REPLY; - /* We can read expect here without conntrack lock, since it's - only set in ip_conntrack_irc, with ip_irc_lock held - writable */ + /* When you see the packet, we need to NAT it the same as the + * this one. */ + exp->expectfn = ip_nat_follow_master; - t = expect->tuple; - t.dst.ip = newip; - for (port = ct_irc_info->port; port != 0; port++) { - t.dst.u.tcp.port = htons(port); - if (ip_conntrack_change_expect(expect, &t) == 0) { - DEBUGP("using port %d", 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; - } - } + if (port == 0) - return 0; + return NF_DROP; /* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27 * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28 @@ -144,139 +81,42 @@ static int irc_data_fixup(const struct ip_ct_irc_expect *ct_irc_info, * 0x01, \n: terminators */ - sprintf(buffer, "%u %u", ntohl(newip), port); + /* AAA = "us", ie. where server normally talks to. */ + sprintf(buffer, "%u %u", + ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), + port); DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n", - buffer, NIPQUAD(newip), port); + buffer, NIPQUAD(exp->tuple.src.ip), port); - return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, - expect->seq - ntohl(tcph->seq), - ct_irc_info->len, buffer, - strlen(buffer)); + ret = ip_nat_mangle_tcp_packet(pskb, exp->master, ctinfo, + matchoff, matchlen, buffer, + strlen(buffer)); + if (ret != NF_ACCEPT) + ip_conntrack_unexpect_related(exp); + return ret; } -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) +static void __exit ip_nat_irc_fini(void) { - struct iphdr *iph = (*pskb)->nh.iph; - struct tcphdr *tcph = (void *) iph + iph->ihl * 4; - unsigned int datalen; - int dir; - struct ip_ct_irc_expect *ct_irc_info; - - if (!exp) - DEBUGP("ip_nat_irc: no exp!!"); - - ct_irc_info = &exp->help.exp_irc_info; - - /* Only mangle things once: original direction in POST_ROUTING - and reply direction on PRE_ROUTING. */ - dir = CTINFO2DIR(ctinfo); - if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) - || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { - DEBUGP("nat_irc: Not touching dir %s at hook %s\n", - dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", - hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" - : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" - : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); - return NF_ACCEPT; - } - DEBUGP("got beyond not touching\n"); - - datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; - LOCK_BH(&ip_irc_lock); - /* Check whether the whole IP/address pattern is carried in the payload */ - if (between(exp->seq + ct_irc_info->len, - ntohl(tcph->seq), - ntohl(tcph->seq) + datalen)) { - if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) { - UNLOCK_BH(&ip_irc_lock); - return NF_DROP; - } - } else { - /* Half a match? This means a partial retransmisison. - It's a cracker being funky. */ - if (net_ratelimit()) { - printk - ("IRC_NAT: partial packet %u/%u in %u/%u\n", - exp->seq, ct_irc_info->len, - ntohl(tcph->seq), - ntohl(tcph->seq) + datalen); - } - UNLOCK_BH(&ip_irc_lock); - return NF_DROP; - } - UNLOCK_BH(&ip_irc_lock); - - return NF_ACCEPT; + rcu_assign_pointer(ip_nat_irc_hook, NULL); + synchronize_rcu(); } -static struct ip_nat_helper ip_nat_irc_helpers[MAX_PORTS]; -static char irc_names[MAX_PORTS][10]; - -/* This function is intentionally _NOT_ defined as __exit, because - * it is needed by init() */ -static void fini(void) +static int __init ip_nat_irc_init(void) { - int i; - - for (i = 0; i < ports_c; i++) { - DEBUGP("ip_nat_irc: unregistering helper for port %d\n", - ports[i]); - ip_nat_helper_unregister(&ip_nat_irc_helpers[i]); - } + BUG_ON(rcu_dereference(ip_nat_irc_hook)); + rcu_assign_pointer(ip_nat_irc_hook, help); + return 0; } -static int __init init(void) +/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ +static int warn_set(const char *val, struct kernel_param *kp) { - int ret = 0; - int i; - struct ip_nat_helper *hlpr; - char *tmpname; - - if (ports[0] == 0) { - ports[0] = IRC_PORT; - } - - for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) { - hlpr = &ip_nat_irc_helpers[i]; - hlpr->tuple.dst.protonum = IPPROTO_TCP; - hlpr->tuple.src.u.tcp.port = htons(ports[i]); - hlpr->mask.src.u.tcp.port = 0xFFFF; - hlpr->mask.dst.protonum = 0xFFFF; - hlpr->help = help; - hlpr->flags = 0; - hlpr->me = THIS_MODULE; - hlpr->expect = irc_nat_expected; - - tmpname = &irc_names[i][0]; - if (ports[i] == IRC_PORT) - sprintf(tmpname, "irc"); - else - sprintf(tmpname, "irc-%d", i); - hlpr->name = tmpname; - - DEBUGP - ("ip_nat_irc: Trying to register helper for port %d: name %s\n", - ports[i], hlpr->name); - ret = ip_nat_helper_register(hlpr); - - if (ret) { - printk - ("ip_nat_irc: error registering helper for port %d\n", - ports[i]); - fini(); - return 1; - } - ports_c++; - } - return ret; + printk(KERN_INFO KBUILD_MODNAME + ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); + return 0; } +module_param_call(ports, warn_set, NULL, NULL, 0); -NEEDS_CONNTRACK(irc); - -module_init(init); -module_exit(fini); +module_init(ip_nat_irc_init); +module_exit(ip_nat_irc_fini);