1 /* IRC extension for TCP NAT alteration.
2 * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
3 * based on a copy of RR's ip_nat_ftp.c
5 * ip_nat_irc.c,v 1.16 2001/12/06 07:42:10 laforge Exp
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
13 * insmod ip_nat_irc.o ports=port1,port2,...port<MAX_PORTS>
15 * please give the ports of all IRC servers You wish to connect to.
16 * If You don't specify ports, the default will be port 6667
19 #include <linux/module.h>
20 #include <linux/netfilter_ipv4.h>
22 #include <linux/tcp.h>
23 #include <linux/kernel.h>
25 #include <linux/netfilter_ipv4/ip_nat.h>
26 #include <linux/netfilter_ipv4/ip_nat_helper.h>
27 #include <linux/netfilter_ipv4/ip_nat_rule.h>
28 #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
29 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
34 #define DEBUGP(format, args...)
38 static int ports[MAX_PORTS];
41 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
42 MODULE_DESCRIPTION("IRC (DCC) NAT helper");
43 MODULE_LICENSE("GPL");
45 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
46 MODULE_PARM_DESC(ports, "port numbers of IRC servers");
49 /* protects irc part of conntracks */
50 DECLARE_LOCK_EXTERN(ip_irc_lock);
52 /* FIXME: Time out? --RR */
55 irc_nat_expected(struct sk_buff **pskb,
57 struct ip_conntrack *ct,
58 struct ip_nat_info *info)
60 struct ip_nat_multi_range mr;
61 u_int32_t newdstip, newsrcip, newip;
63 struct ip_conntrack *master = master_ct(ct);
68 IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
70 DEBUGP("nat_expected: We have a connection!\n");
72 newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
73 newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
74 DEBUGP("nat_expected: DCC cmd. %u.%u.%u.%u->%u.%u.%u.%u\n",
75 NIPQUAD(newsrcip), NIPQUAD(newdstip));
77 if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
82 DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
85 /* We don't want to manip the per-protocol, just the IPs. */
86 mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
87 mr.range[0].min_ip = mr.range[0].max_ip = newip;
89 return ip_nat_setup_info(ct, &mr, hooknum);
92 static int irc_data_fixup(const struct ip_ct_irc_expect *ct_irc_info,
93 struct ip_conntrack *ct,
94 struct sk_buff **pskb,
95 enum ip_conntrack_info ctinfo,
96 struct ip_conntrack_expect *expect)
99 struct ip_conntrack_tuple t;
100 struct iphdr *iph = (*pskb)->nh.iph;
101 struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
104 /* "4294967296 65635 " */
107 MUST_BE_LOCKED(&ip_irc_lock);
109 DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
110 expect->seq, ct_irc_info->len,
113 newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
115 /* Alter conntrack's expectations. */
117 /* We can read expect here without conntrack lock, since it's
118 only set in ip_conntrack_irc, with ip_irc_lock held
123 for (port = ct_irc_info->port; port != 0; port++) {
124 t.dst.u.tcp.port = htons(port);
125 if (ip_conntrack_change_expect(expect, &t) == 0) {
126 DEBUGP("using port %d", port);
134 /* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27
135 * strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28
136 * strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26
137 * strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26
138 * strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27
139 * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits,
140 * 255.255.255.255==4294967296, 10 digits)
141 * P: bound port (min 1 d, max 5d (65635))
142 * F: filename (min 1 d )
144 * 0x01, \n: terminators
147 sprintf(buffer, "%u %u", ntohl(newip), port);
148 DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n",
149 buffer, NIPQUAD(newip), port);
151 return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
152 expect->seq - ntohl(tcph->seq),
153 ct_irc_info->len, buffer,
157 static unsigned int help(struct ip_conntrack *ct,
158 struct ip_conntrack_expect *exp,
159 struct ip_nat_info *info,
160 enum ip_conntrack_info ctinfo,
161 unsigned int hooknum,
162 struct sk_buff **pskb)
164 struct iphdr *iph = (*pskb)->nh.iph;
165 struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
166 unsigned int datalen;
168 struct ip_ct_irc_expect *ct_irc_info;
171 DEBUGP("ip_nat_irc: no exp!!");
173 ct_irc_info = &exp->help.exp_irc_info;
175 /* Only mangle things once: original direction in POST_ROUTING
176 and reply direction on PRE_ROUTING. */
177 dir = CTINFO2DIR(ctinfo);
178 if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
179 || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
180 DEBUGP("nat_irc: Not touching dir %s at hook %s\n",
181 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
182 hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
183 : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
184 : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
187 DEBUGP("got beyond not touching\n");
189 datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
190 LOCK_BH(&ip_irc_lock);
191 /* Check whether the whole IP/address pattern is carried in the payload */
192 if (between(exp->seq + ct_irc_info->len,
194 ntohl(tcph->seq) + datalen)) {
195 if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) {
196 UNLOCK_BH(&ip_irc_lock);
200 /* Half a match? This means a partial retransmisison.
201 It's a cracker being funky. */
202 if (net_ratelimit()) {
204 ("IRC_NAT: partial packet %u/%u in %u/%u\n",
205 exp->seq, ct_irc_info->len,
207 ntohl(tcph->seq) + datalen);
209 UNLOCK_BH(&ip_irc_lock);
212 UNLOCK_BH(&ip_irc_lock);
217 static struct ip_nat_helper ip_nat_irc_helpers[MAX_PORTS];
218 static char irc_names[MAX_PORTS][10];
220 /* This function is intentionally _NOT_ defined as __exit, because
221 * it is needed by init() */
222 static void fini(void)
226 for (i = 0; i < ports_c; i++) {
227 DEBUGP("ip_nat_irc: unregistering helper for port %d\n",
229 ip_nat_helper_unregister(&ip_nat_irc_helpers[i]);
233 static int __init init(void)
237 struct ip_nat_helper *hlpr;
244 for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) {
245 hlpr = &ip_nat_irc_helpers[i];
246 hlpr->tuple.dst.protonum = IPPROTO_TCP;
247 hlpr->tuple.src.u.tcp.port = htons(ports[i]);
248 hlpr->mask.src.u.tcp.port = 0xFFFF;
249 hlpr->mask.dst.protonum = 0xFFFF;
252 hlpr->me = THIS_MODULE;
253 hlpr->expect = irc_nat_expected;
255 tmpname = &irc_names[i][0];
256 if (ports[i] == IRC_PORT)
257 sprintf(tmpname, "irc");
259 sprintf(tmpname, "irc-%d", i);
260 hlpr->name = tmpname;
263 ("ip_nat_irc: Trying to register helper for port %d: name %s\n",
264 ports[i], hlpr->name);
265 ret = ip_nat_helper_register(hlpr);
269 ("ip_nat_irc: error registering helper for port %d\n",
279 NEEDS_CONNTRACK(irc);