2 * IP_MASQ_IRC irc masquerading module
5 * Version: @(#)ip_masq_irc.c 0.03 97/11/30
7 * Author: Juan Jose Ciarlante
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)
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()
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
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
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>
52 #include <linux/init.h>
53 #include <net/protocol.h>
55 #include <net/ip_masq.h>
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
];
67 #ifdef CONFIG_IP_MASQ_DEBUG
69 MODULE_PARM(debug
, "i");
72 MODULE_PARM(ports
, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS
) "i");
76 * List of supported DCC protocols
79 #define NUM_DCCPROTO 5
88 struct dccproto dccprotos
[NUM_DCCPROTO
] = {
98 masq_irc_init_1 (struct ip_masq_app
*mapp
, struct ip_masq
*ms
)
105 masq_irc_done_1 (struct ip_masq_app
*mapp
, struct ip_masq
*ms
)
112 masq_irc_out (struct ip_masq_app
*mapp
, struct ip_masq
*ms
, struct sk_buff
**skb_p
, __u32 maddr
)
117 char *data
, *data_limit
;
120 struct ip_masq
*n_ms
;
121 char buf
[20]; /* "m_addr m_port" (dec base)*/
124 int xtra_args
= 0; /* extra int args wanted after addr */
125 char *dcc_p
, *addr_beg_p
, *addr_end_p
;
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 )
145 * 0x01, \n: terminators
148 data_limit
= skb
->h
.raw
+ skb
->len
;
150 while (data
< (data_limit
- ( 21 + MAXMATCHLEN
) ) )
153 if (memcmp(data
,"DCC ",4)) {
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
;
176 while( *data
++ != ' ')
179 * must still parse, at least, "AAAAAAAA P\x01\n",
182 if (data
> (data_limit
-12)) return 0;
188 * client bound address in dec base
191 s_addr
= simple_strtoul(data
,&data
,10);
196 * client bound port in dec base
199 s_port
= simple_strtoul(data
,&data
,10);
203 * should check args consistency?
210 simple_strtoul(data
,&data
,10);
214 if (xtra_args
!= 0) continue;
222 if (data
[1]!='\r' && data
[1]!='\n')
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
,
233 htonl(s_addr
),htons(s_port
),
235 IP_MASQ_F_NO_DPORT
|IP_MASQ_F_NO_DADDR
);
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
);
253 IP_MASQ_DEBUG(1-debug
, "masq_irc_out(): '%s' %X:%X detected (diff=%d)\n", dcc_p
, s_addr
,s_port
, diff
);
261 * simple case, just copy.
263 memcpy(addr_beg_p
,buf
,buf_len
);
266 *skb_p
= ip_masq_skb_replace(skb
, GFP_ATOMIC
,
267 addr_beg_p
, addr_end_p
-addr_beg_p
,
270 ip_masq_listen(n_ms
);
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
288 struct ip_masq_app ip_masq_irc
= {
293 masq_irc_init_1
, /* init_1 */
294 masq_irc_done_1
, /* done_1 */
295 masq_irc_out
, /* pkt_out */
300 * ip_masq_irc initialization
303 __initfunc(int ip_masq_irc_init(void))
307 for (i
=0; (i
<MAX_MASQ_APP_PORTS
); i
++) {
309 if ((masq_incarnations
[i
] = kmalloc(sizeof(struct ip_masq_app
),
310 GFP_KERNEL
)) == NULL
)
312 memcpy(masq_incarnations
[i
], &ip_masq_irc
, sizeof(struct ip_masq_app
));
313 if ((j
= register_ip_masq_app(masq_incarnations
[i
],
318 IP_MASQ_DEBUG(1-debug
,
319 "Irc: loaded support on port[%d] = %d\n",
322 /* To be safe, force the incarnation table entry to NULL */
323 masq_incarnations
[i
] = NULL
;
333 int ip_masq_irc_done(void)
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
]))) {
343 kfree(masq_incarnations
[i
]);
344 masq_incarnations
[i
] = NULL
;
345 IP_MASQ_DEBUG(1-debug
, "Irc: unloaded support on port[%d] = %d\n",
357 int init_module(void)
359 if (ip_masq_irc_init() != 0)
364 void cleanup_module(void)
366 if (ip_masq_irc_done() != 0)
367 printk(KERN_INFO
"ip_masq_irc: can't remove module");