aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2006-12-03 01:09:06 -0500
committerDavid S. Miller <davem@davemloft.net>2006-12-03 01:09:06 -0500
commit869f37d8e48f3911eb70f38a994feaa8f8380008 (patch)
tree7aa184a20f289f3e4c5d5bba81d8d3df15688059
parentf587de0e2feb9eb9b94f98d0a7b7437e4d6617b4 (diff)
[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port
Add nf_conntrack port of the IRC conntrack/NAT helper. Since DCC doesn't support IPv6 yet, the helper is still IPv4 only. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netfilter/nf_conntrack_irc.h15
-rw-r--r--net/ipv4/netfilter/Kconfig5
-rw-r--r--net/ipv4/netfilter/Makefile1
-rw-r--r--net/ipv4/netfilter/nf_nat_irc.c101
-rw-r--r--net/netfilter/Kconfig15
-rw-r--r--net/netfilter/Makefile1
-rw-r--r--net/netfilter/nf_conntrack_irc.c281
7 files changed, 419 insertions, 0 deletions
diff --git a/include/linux/netfilter/nf_conntrack_irc.h b/include/linux/netfilter/nf_conntrack_irc.h
new file mode 100644
index 000000000000..2ab6b8255911
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_irc.h
@@ -0,0 +1,15 @@
1#ifndef _NF_CONNTRACK_IRC_H
2#define _NF_CONNTRACK_IRC_H
3
4#ifdef __KERNEL__
5
6#define IRC_PORT 6667
7
8extern unsigned int (*nf_nat_irc_hook)(struct sk_buff **pskb,
9 enum ip_conntrack_info ctinfo,
10 unsigned int matchoff,
11 unsigned int matchlen,
12 struct nf_conntrack_expect *exp);
13
14#endif /* __KERNEL__ */
15#endif /* _NF_CONNTRACK_IRC_H */
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index e14156d1122e..4555f721dfc1 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -500,6 +500,11 @@ config IP_NF_NAT_IRC
500 default IP_NF_NAT if IP_NF_IRC=y 500 default IP_NF_NAT if IP_NF_IRC=y
501 default m if IP_NF_IRC=m 501 default m if IP_NF_IRC=m
502 502
503config NF_NAT_IRC
504 tristate
505 depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
506 default NF_NAT && NF_CONNTRACK_IRC
507
503config IP_NF_NAT_TFTP 508config IP_NF_NAT_TFTP
504 tristate 509 tristate
505 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n 510 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index bdaba4700e3b..56733c370327 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o
53obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o 53obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
54obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o 54obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
55obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o 55obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
56obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o
56 57
57# generic IP tables 58# generic IP tables
58obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o 59obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c
new file mode 100644
index 000000000000..9b8c0daea744
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_irc.c
@@ -0,0 +1,101 @@
1/* IRC extension for TCP NAT alteration.
2 *
3 * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2004 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
5 * based on a copy of RR's ip_nat_ftp.c
6 *
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.
11 */
12
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/tcp.h>
16#include <linux/kernel.h>
17
18#include <net/netfilter/nf_nat.h>
19#include <net/netfilter/nf_nat_helper.h>
20#include <net/netfilter/nf_nat_rule.h>
21#include <net/netfilter/nf_conntrack_helper.h>
22#include <net/netfilter/nf_conntrack_expect.h>
23#include <linux/netfilter/nf_conntrack_irc.h>
24
25#if 0
26#define DEBUGP printk
27#else
28#define DEBUGP(format, args...)
29#endif
30
31MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
32MODULE_DESCRIPTION("IRC (DCC) NAT helper");
33MODULE_LICENSE("GPL");
34MODULE_ALIAS("ip_nat_irc");
35
36static unsigned int help(struct sk_buff **pskb,
37 enum ip_conntrack_info ctinfo,
38 unsigned int matchoff,
39 unsigned int matchlen,
40 struct nf_conntrack_expect *exp)
41{
42 char buffer[sizeof("4294967296 65635")];
43 u_int32_t ip;
44 u_int16_t port;
45 unsigned int ret;
46
47 DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
48 expect->seq, exp_irc_info->len, ntohl(tcph->seq));
49
50 /* Reply comes from server. */
51 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
52 exp->dir = IP_CT_DIR_REPLY;
53 exp->expectfn = nf_nat_follow_master;
54
55 /* Try to get same port: if not, try to change it. */
56 for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
57 exp->tuple.dst.u.tcp.port = htons(port);
58 if (nf_conntrack_expect_related(exp) == 0)
59 break;
60 }
61
62 if (port == 0)
63 return NF_DROP;
64
65 ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip);
66 sprintf(buffer, "%u %u", ip, port);
67 DEBUGP("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n",
68 buffer, NIPQUAD(ip), port);
69
70 ret = nf_nat_mangle_tcp_packet(pskb, exp->master, ctinfo,
71 matchoff, matchlen, buffer,
72 strlen(buffer));
73 if (ret != NF_ACCEPT)
74 nf_conntrack_unexpect_related(exp);
75 return ret;
76}
77
78static void __exit nf_nat_irc_fini(void)
79{
80 rcu_assign_pointer(nf_nat_irc_hook, NULL);
81 synchronize_rcu();
82}
83
84static int __init nf_nat_irc_init(void)
85{
86 BUG_ON(rcu_dereference(nf_nat_irc_hook));
87 rcu_assign_pointer(nf_nat_irc_hook, help);
88 return 0;
89}
90
91/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */
92static int warn_set(const char *val, struct kernel_param *kp)
93{
94 printk(KERN_INFO KBUILD_MODNAME
95 ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
96 return 0;
97}
98module_param_call(ports, warn_set, NULL, NULL, 0);
99
100module_init(nf_nat_irc_init);
101module_exit(nf_nat_irc_fini);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index d8f3451c95b6..bd50897d8fbb 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -179,6 +179,21 @@ config NF_CONNTRACK_H323
179 179
180 To compile it as a module, choose M here. If unsure, say N. 180 To compile it as a module, choose M here. If unsure, say N.
181 181
182config NF_CONNTRACK_IRC
183 tristate "IRC protocol support (EXPERIMENTAL)"
184 depends on EXPERIMENTAL && NF_CONNTRACK
185 help
186 There is a commonly-used extension to IRC called
187 Direct Client-to-Client Protocol (DCC). This enables users to send
188 files to each other, and also chat to each other without the need
189 of a server. DCC Sending is used anywhere you send files over IRC,
190 and DCC Chat is most commonly used by Eggdrop bots. If you are
191 using NAT, this extension will enable you to send files and initiate
192 chats. Note that you do NOT need this extension to get files or
193 have others initiate chats, or everything else in IRC.
194
195 To compile it as a module, choose M here. If unsure, say N.
196
182config NF_CT_NETLINK 197config NF_CT_NETLINK
183 tristate 'Connection tracking netlink interface (EXPERIMENTAL)' 198 tristate 'Connection tracking netlink interface (EXPERIMENTAL)'
184 depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK 199 depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 69b554576b6b..343fd4896406 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -25,6 +25,7 @@ nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o
25obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o 25obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o
26obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o 26obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
27obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o 27obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o
28obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o
28 29
29# generic X tables 30# generic X tables
30obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o 31obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
new file mode 100644
index 000000000000..ed01db634399
--- /dev/null
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -0,0 +1,281 @@
1/* IRC extension for IP connection tracking, Version 1.21
2 * (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
3 * based on RR's ip_conntrack_ftp.c
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 */
10
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/skbuff.h>
14#include <linux/in.h>
15#include <linux/tcp.h>
16#include <linux/netfilter.h>
17
18#include <net/netfilter/nf_conntrack.h>
19#include <net/netfilter/nf_conntrack_expect.h>
20#include <net/netfilter/nf_conntrack_helper.h>
21#include <linux/netfilter/nf_conntrack_irc.h>
22
23#define MAX_PORTS 8
24static unsigned short ports[MAX_PORTS];
25static int ports_c;
26static unsigned int max_dcc_channels = 8;
27static unsigned int dcc_timeout __read_mostly = 300;
28/* This is slow, but it's simple. --RR */
29static char *irc_buffer;
30static DEFINE_SPINLOCK(irc_buffer_lock);
31
32unsigned int (*nf_nat_irc_hook)(struct sk_buff **pskb,
33 enum ip_conntrack_info ctinfo,
34 unsigned int matchoff,
35 unsigned int matchlen,
36 struct nf_conntrack_expect *exp) __read_mostly;
37EXPORT_SYMBOL_GPL(nf_nat_irc_hook);
38
39MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
40MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
41MODULE_LICENSE("GPL");
42MODULE_ALIAS("ip_conntrack_irc");
43
44module_param_array(ports, ushort, &ports_c, 0400);
45MODULE_PARM_DESC(ports, "port numbers of IRC servers");
46module_param(max_dcc_channels, uint, 0400);
47MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per "
48 "IRC session");
49module_param(dcc_timeout, uint, 0400);
50MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
51
52static const char *dccprotos[] = {
53 "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT "
54};
55
56#define MINMATCHLEN 5
57
58#if 0
59#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \
60 __FILE__, __FUNCTION__ , ## args)
61#else
62#define DEBUGP(format, args...)
63#endif
64
65/* tries to get the ip_addr and port out of a dcc command
66 * return value: -1 on failure, 0 on success
67 * data pointer to first byte of DCC command data
68 * data_end pointer to last byte of dcc command data
69 * ip returns parsed ip of dcc command
70 * port returns parsed port of dcc command
71 * ad_beg_p returns pointer to first byte of addr data
72 * ad_end_p returns pointer to last byte of addr data
73 */
74static int parse_dcc(char *data, char *data_end, u_int32_t *ip,
75 u_int16_t *port, char **ad_beg_p, char **ad_end_p)
76{
77 /* at least 12: "AAAAAAAA P\1\n" */
78 while (*data++ != ' ')
79 if (data > data_end - 12)
80 return -1;
81
82 *ad_beg_p = data;
83 *ip = simple_strtoul(data, &data, 10);
84
85 /* skip blanks between ip and port */
86 while (*data == ' ') {
87 if (data >= data_end)
88 return -1;
89 data++;
90 }
91
92 *port = simple_strtoul(data, &data, 10);
93 *ad_end_p = data;
94
95 return 0;
96}
97
98static int help(struct sk_buff **pskb, unsigned int protoff,
99 struct nf_conn *ct, enum ip_conntrack_info ctinfo)
100{
101 unsigned int dataoff;
102 struct tcphdr _tcph, *th;
103 char *data, *data_limit, *ib_ptr;
104 int dir = CTINFO2DIR(ctinfo);
105 struct nf_conntrack_expect *exp;
106 struct nf_conntrack_tuple *tuple;
107 u_int32_t dcc_ip;
108 u_int16_t dcc_port;
109 __be16 port;
110 int i, ret = NF_ACCEPT;
111 char *addr_beg_p, *addr_end_p;
112 typeof(nf_nat_irc_hook) nf_nat_irc;
113
114 /* If packet is coming from IRC server */
115 if (dir == IP_CT_DIR_REPLY)
116 return NF_ACCEPT;
117
118 /* Until there's been traffic both ways, don't look in packets. */
119 if (ctinfo != IP_CT_ESTABLISHED &&
120 ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
121 return NF_ACCEPT;
122
123 /* Not a full tcp header? */
124 th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph);
125 if (th == NULL)
126 return NF_ACCEPT;
127
128 /* No data? */
129 dataoff = protoff + th->doff*4;
130 if (dataoff >= (*pskb)->len)
131 return NF_ACCEPT;
132
133 spin_lock_bh(&irc_buffer_lock);
134 ib_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff,
135 irc_buffer);
136 BUG_ON(ib_ptr == NULL);
137
138 data = ib_ptr;
139 data_limit = ib_ptr + (*pskb)->len - dataoff;
140
141 /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
142 * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
143 while (data < data_limit - (19 + MINMATCHLEN)) {
144 if (memcmp(data, "\1DCC ", 5)) {
145 data++;
146 continue;
147 }
148 data += 5;
149 /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */
150
151 DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
152 NIPQUAD(iph->saddr), ntohs(th->source),
153 NIPQUAD(iph->daddr), ntohs(th->dest));
154
155 for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
156 if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
157 /* no match */
158 continue;
159 }
160 data += strlen(dccprotos[i]);
161 DEBUGP("DCC %s detected\n", dccprotos[i]);
162
163 /* we have at least
164 * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid
165 * data left (== 14/13 bytes) */
166 if (parse_dcc((char *)data, data_limit, &dcc_ip,
167 &dcc_port, &addr_beg_p, &addr_end_p)) {
168 DEBUGP("unable to parse dcc command\n");
169 continue;
170 }
171 DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
172 HIPQUAD(dcc_ip), dcc_port);
173
174 /* dcc_ip can be the internal OR external (NAT'ed) IP */
175 tuple = &ct->tuplehash[dir].tuple;
176 if (tuple->src.u3.ip != htonl(dcc_ip) &&
177 tuple->dst.u3.ip != htonl(dcc_ip)) {
178 if (net_ratelimit())
179 printk(KERN_WARNING
180 "Forged DCC command from "
181 "%u.%u.%u.%u: %u.%u.%u.%u:%u\n",
182 NIPQUAD(tuple->src.u3.ip),
183 HIPQUAD(dcc_ip), dcc_port);
184 continue;
185 }
186
187 exp = nf_conntrack_expect_alloc(ct);
188 if (exp == NULL) {
189 ret = NF_DROP;
190 goto out;
191 }
192 tuple = &ct->tuplehash[!dir].tuple;
193 port = htons(dcc_port);
194 nf_conntrack_expect_init(exp, tuple->src.l3num,
195 NULL, &tuple->dst.u3,
196 IPPROTO_TCP, NULL, &port);
197
198 nf_nat_irc = rcu_dereference(nf_nat_irc_hook);
199 if (nf_nat_irc && ct->status & IPS_NAT_MASK)
200 ret = nf_nat_irc(pskb, ctinfo,
201 addr_beg_p - ib_ptr,
202 addr_end_p - addr_beg_p,
203 exp);
204 else if (nf_conntrack_expect_related(exp) != 0)
205 ret = NF_DROP;
206 nf_conntrack_expect_put(exp);
207 goto out;
208 }
209 }
210 out:
211 spin_unlock_bh(&irc_buffer_lock);
212 return ret;
213}
214
215static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly;
216static char irc_names[MAX_PORTS][sizeof("irc-65535")] __read_mostly;
217
218static void nf_conntrack_irc_fini(void);
219
220static int __init nf_conntrack_irc_init(void)
221{
222 int i, ret;
223 char *tmpname;
224
225 if (max_dcc_channels < 1) {
226 printk("nf_ct_irc: max_dcc_channels must not be zero\n");
227 return -EINVAL;
228 }
229
230 irc_buffer = kmalloc(65536, GFP_KERNEL);
231 if (!irc_buffer)
232 return -ENOMEM;
233
234 /* If no port given, default to standard irc port */
235 if (ports_c == 0)
236 ports[ports_c++] = IRC_PORT;
237
238 for (i = 0; i < ports_c; i++) {
239 irc[i].tuple.src.l3num = AF_INET;
240 irc[i].tuple.src.u.tcp.port = htons(ports[i]);
241 irc[i].tuple.dst.protonum = IPPROTO_TCP;
242 irc[i].mask.src.l3num = 0xFFFF;
243 irc[i].mask.src.u.tcp.port = htons(0xFFFF);
244 irc[i].mask.dst.protonum = 0xFF;
245 irc[i].max_expected = max_dcc_channels;
246 irc[i].timeout = dcc_timeout;
247 irc[i].me = THIS_MODULE;
248 irc[i].help = help;
249
250 tmpname = &irc_names[i][0];
251 if (ports[i] == IRC_PORT)
252 sprintf(tmpname, "irc");
253 else
254 sprintf(tmpname, "irc-%u", i);
255 irc[i].name = tmpname;
256
257 ret = nf_conntrack_helper_register(&irc[i]);
258 if (ret) {
259 printk("nf_ct_irc: failed to register helper "
260 "for pf: %u port: %u\n",
261 irc[i].tuple.src.l3num, ports[i]);
262 nf_conntrack_irc_fini();
263 return ret;
264 }
265 }
266 return 0;
267}
268
269/* This function is intentionally _NOT_ defined as __exit, because
270 * it is needed by the init function */
271static void nf_conntrack_irc_fini(void)
272{
273 int i;
274
275 for (i = 0; i < ports_c; i++)
276 nf_conntrack_helper_unregister(&irc[i]);
277 kfree(irc_buffer);
278}
279
280module_init(nf_conntrack_irc_init);
281module_exit(nf_conntrack_irc_fini);