pre-2.3.4..
[davej-history.git] / net / ipv4 / ip_masq_irc.c
blob11c0ca83f0d04ec0e17cb6d04ff02a24ffeb6afd
1 /*
2 * IP_MASQ_IRC irc masquerading module
5 * Version: @(#)ip_masq_irc.c 0.03 97/11/30
7 * Author: Juan Jose Ciarlante
8 *
9 * Additions:
10 * - recognize a few non-irc-II DCC requests (Oliver Wagner)
11 * DCC MOVE (AmIRC/DCC.MOVE; SEND with resuming)
12 * DCC SCHAT (AmIRC IDEA encrypted CHAT)
13 * DCC TSEND (AmIRC/PIRCH SEND without ACKs)
14 * Fixes:
15 * Juan Jose Ciarlante : set NO_DADDR flag in ip_masq_new()
16 * Nigel Metheringham : Added multiple port support
17 * Juan Jose Ciarlante : litl bits for 2.1
18 * Oliver Wagner : more IRC cmds processing
19 * <winmute@lucifer.gv.kotnet.org>
20 * Juan Jose Ciarlante : put new ms entry to listen()
22 * FIXME:
23 * - detect also previous "PRIVMSG" string ?.
25 * This program is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU General Public License
27 * as published by the Free Software Foundation; either version
28 * 2 of the License, or (at your option) any later version.
30 * Multiple Port Support
31 * The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
32 * with the port numbers being defined at module load time. The module
33 * uses the symbol "ports" to define a list of monitored ports, which can
34 * be specified on the insmod command line as
35 * ports=x1,x2,x3...
36 * where x[n] are integer port numbers. This option can be put into
37 * /etc/conf.modules (or /etc/modules.conf depending on your config)
38 * where modload will pick it up should you use modload to load your
39 * modules.
43 #include <linux/config.h>
44 #include <linux/module.h>
46 #include <linux/types.h>
47 #include <linux/kernel.h>
48 #include <asm/system.h>
49 #include <linux/skbuff.h>
50 #include <linux/in.h>
51 #include <linux/ip.h>
52 #include <linux/init.h>
53 #include <net/protocol.h>
54 #include <net/tcp.h>
55 #include <net/ip_masq.h>
58 /*
59 * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
60 * First port is set to the default port.
62 int ports[MAX_MASQ_APP_PORTS] = {6667}; /* I rely on the trailing items being set to zero */
63 struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
65 * Debug level
67 #ifdef CONFIG_IP_MASQ_DEBUG
68 static int debug=0;
69 MODULE_PARM(debug, "i");
70 #endif
72 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
76 * List of supported DCC protocols
79 #define NUM_DCCPROTO 5
81 struct dccproto
83 char *match;
84 int matchlen;
85 int xtra_args;
88 struct dccproto dccprotos[NUM_DCCPROTO] = {
89 { "SEND ", 5, 1 },
90 { "CHAT ", 5, 0, },
91 { "MOVE ", 5, 1 },
92 { "TSEND ", 6, 1, },
93 { "SCHAT ", 6, 0, }
95 #define MAXMATCHLEN 6
97 static int
98 masq_irc_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
100 MOD_INC_USE_COUNT;
101 return 0;
104 static int
105 masq_irc_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
107 MOD_DEC_USE_COUNT;
108 return 0;
112 masq_irc_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
114 struct sk_buff *skb;
115 struct iphdr *iph;
116 struct tcphdr *th;
117 char *data, *data_limit;
118 __u32 s_addr;
119 __u16 s_port;
120 struct ip_masq *n_ms;
121 char buf[20]; /* "m_addr m_port" (dec base)*/
122 unsigned buf_len;
123 int diff;
124 int xtra_args = 0; /* extra int args wanted after addr */
125 char *dcc_p, *addr_beg_p, *addr_end_p;
127 skb = *skb_p;
128 iph = skb->nh.iph;
129 th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
130 data = (char *)&th[1];
133 * Hunt irc DCC string, the _shortest_:
135 * strlen("DCC CHAT chat AAAAAAAA P\x01\n")=26
136 * strlen("DCC SCHAT chat AAAAAAAA P\x01\n")=27
137 * strlen("DCC SEND F AAAAAAAA P S\x01\n")=25
138 * strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
139 * strlen("DCC TSEND F AAAAAAAA P S\x01\n")=26
140 * strlen("DCC MOVE F AAAAAAAA P S\x01\n")=25
141 * AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits)
142 * P: bound port (min 1 d )
143 * F: filename (min 1 d )
144 * S: size (min 1 d )
145 * 0x01, \n: terminators
148 data_limit = skb->h.raw + skb->len;
150 while (data < (data_limit - ( 21 + MAXMATCHLEN ) ) )
152 int i;
153 if (memcmp(data,"DCC ",4)) {
154 data ++;
155 continue;
158 dcc_p = data;
159 data += 4; /* point to DCC cmd */
161 for(i=0; i<NUM_DCCPROTO; i++)
164 * go through the table and hunt a match string
167 if( memcmp(data, dccprotos[i].match, dccprotos[i].matchlen ) == 0 )
169 xtra_args = dccprotos[i].xtra_args;
170 data += dccprotos[i].matchlen;
173 * skip next string.
176 while( *data++ != ' ')
179 * must still parse, at least, "AAAAAAAA P\x01\n",
180 * 12 bytes left.
182 if (data > (data_limit-12)) return 0;
185 addr_beg_p = data;
188 * client bound address in dec base
191 s_addr = simple_strtoul(data,&data,10);
192 if (*data++ !=' ')
193 continue;
196 * client bound port in dec base
199 s_port = simple_strtoul(data,&data,10);
200 addr_end_p = data;
203 * should check args consistency?
206 while(xtra_args) {
207 if (*data != ' ')
208 break;
209 data++;
210 simple_strtoul(data,&data,10);
211 xtra_args--;
214 if (xtra_args != 0) continue;
217 * terminators.
220 if (data[0] != 0x01)
221 continue;
222 if (data[1]!='\r' && data[1]!='\n')
223 continue;
226 * Now create an masquerade entry for it
227 * must set NO_DPORT and NO_DADDR because
228 * connection is requested by another client.
231 n_ms = ip_masq_new(IPPROTO_TCP,
232 maddr, 0,
233 htonl(s_addr),htons(s_port),
234 0, 0,
235 IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
236 if (n_ms==NULL)
237 return 0;
240 * Replace the old "address port" with the new one
243 buf_len = sprintf(buf,"%lu %u",
244 ntohl(n_ms->maddr),ntohs(n_ms->mport));
247 * Calculate required delta-offset to keep TCP happy
250 diff = buf_len - (addr_end_p-addr_beg_p);
252 *addr_beg_p = '\0';
253 IP_MASQ_DEBUG(1-debug, "masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p, s_addr,s_port, diff);
256 * No shift.
259 if (diff==0) {
261 * simple case, just copy.
263 memcpy(addr_beg_p,buf,buf_len);
264 } else {
266 *skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC,
267 addr_beg_p, addr_end_p-addr_beg_p,
268 buf, buf_len);
270 ip_masq_listen(n_ms);
271 ip_masq_put(n_ms);
272 return diff;
276 return 0;
281 * Main irc object
282 * You need 1 object per port in case you need
283 * to offer also other used irc ports (6665,6666,etc),
284 * they will share methods but they need own space for
285 * data.
288 struct ip_masq_app ip_masq_irc = {
289 NULL, /* next */
290 "irc", /* name */
291 0, /* type */
292 0, /* n_attach */
293 masq_irc_init_1, /* init_1 */
294 masq_irc_done_1, /* done_1 */
295 masq_irc_out, /* pkt_out */
296 NULL /* pkt_in */
300 * ip_masq_irc initialization
303 __initfunc(int ip_masq_irc_init(void))
305 int i, j;
307 for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
308 if (ports[i]) {
309 if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
310 GFP_KERNEL)) == NULL)
311 return -ENOMEM;
312 memcpy(masq_incarnations[i], &ip_masq_irc, sizeof(struct ip_masq_app));
313 if ((j = register_ip_masq_app(masq_incarnations[i],
314 IPPROTO_TCP,
315 ports[i]))) {
316 return j;
318 IP_MASQ_DEBUG(1-debug,
319 "Irc: loaded support on port[%d] = %d\n",
320 i, ports[i]);
321 } else {
322 /* To be safe, force the incarnation table entry to NULL */
323 masq_incarnations[i] = NULL;
326 return 0;
330 * ip_masq_irc fin.
333 int ip_masq_irc_done(void)
335 int i, j, k;
337 k=0;
338 for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
339 if (masq_incarnations[i]) {
340 if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
341 k = j;
342 } else {
343 kfree(masq_incarnations[i]);
344 masq_incarnations[i] = NULL;
345 IP_MASQ_DEBUG(1-debug, "Irc: unloaded support on port[%d] = %d\n",
346 i, ports[i]);
350 return k;
354 #ifdef MODULE
355 EXPORT_NO_SYMBOLS;
357 int init_module(void)
359 if (ip_masq_irc_init() != 0)
360 return -EIO;
361 return 0;
364 void cleanup_module(void)
366 if (ip_masq_irc_done() != 0)
367 printk(KERN_INFO "ip_masq_irc: can't remove module");
370 #endif /* MODULE */