diff options
author | Patrick McHardy <kaber@trash.net> | 2006-12-03 01:09:06 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-12-03 01:09:06 -0500 |
commit | 869f37d8e48f3911eb70f38a994feaa8f8380008 (patch) | |
tree | 7aa184a20f289f3e4c5d5bba81d8d3df15688059 | |
parent | f587de0e2feb9eb9b94f98d0a7b7437e4d6617b4 (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.h | 15 | ||||
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 5 | ||||
-rw-r--r-- | net/ipv4/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_irc.c | 101 | ||||
-rw-r--r-- | net/netfilter/Kconfig | 15 | ||||
-rw-r--r-- | net/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_irc.c | 281 |
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 | |||
8 | extern 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 | ||
503 | config NF_NAT_IRC | ||
504 | tristate | ||
505 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | ||
506 | default NF_NAT && NF_CONNTRACK_IRC | ||
507 | |||
503 | config IP_NF_NAT_TFTP | 508 | config 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 | |||
53 | obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o | 53 | obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o |
54 | obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o | 54 | obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o |
55 | obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o | 55 | obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o |
56 | obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o | ||
56 | 57 | ||
57 | # generic IP tables | 58 | # generic IP tables |
58 | obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o | 59 | obj-$(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 | |||
31 | MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); | ||
32 | MODULE_DESCRIPTION("IRC (DCC) NAT helper"); | ||
33 | MODULE_LICENSE("GPL"); | ||
34 | MODULE_ALIAS("ip_nat_irc"); | ||
35 | |||
36 | static 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 | |||
78 | static void __exit nf_nat_irc_fini(void) | ||
79 | { | ||
80 | rcu_assign_pointer(nf_nat_irc_hook, NULL); | ||
81 | synchronize_rcu(); | ||
82 | } | ||
83 | |||
84 | static 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. */ | ||
92 | static 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 | } | ||
98 | module_param_call(ports, warn_set, NULL, NULL, 0); | ||
99 | |||
100 | module_init(nf_nat_irc_init); | ||
101 | module_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 | ||
182 | config 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 | |||
182 | config NF_CT_NETLINK | 197 | config 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 | |||
25 | obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o | 25 | obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o |
26 | obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o | 26 | obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o |
27 | obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o | 27 | obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o |
28 | obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o | ||
28 | 29 | ||
29 | # generic X tables | 30 | # generic X tables |
30 | obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o | 31 | obj-$(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 | ||
24 | static unsigned short ports[MAX_PORTS]; | ||
25 | static int ports_c; | ||
26 | static unsigned int max_dcc_channels = 8; | ||
27 | static unsigned int dcc_timeout __read_mostly = 300; | ||
28 | /* This is slow, but it's simple. --RR */ | ||
29 | static char *irc_buffer; | ||
30 | static DEFINE_SPINLOCK(irc_buffer_lock); | ||
31 | |||
32 | unsigned 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; | ||
37 | EXPORT_SYMBOL_GPL(nf_nat_irc_hook); | ||
38 | |||
39 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
40 | MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | MODULE_ALIAS("ip_conntrack_irc"); | ||
43 | |||
44 | module_param_array(ports, ushort, &ports_c, 0400); | ||
45 | MODULE_PARM_DESC(ports, "port numbers of IRC servers"); | ||
46 | module_param(max_dcc_channels, uint, 0400); | ||
47 | MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per " | ||
48 | "IRC session"); | ||
49 | module_param(dcc_timeout, uint, 0400); | ||
50 | MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); | ||
51 | |||
52 | static 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 | */ | ||
74 | static 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 | |||
98 | static 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 | |||
215 | static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly; | ||
216 | static char irc_names[MAX_PORTS][sizeof("irc-65535")] __read_mostly; | ||
217 | |||
218 | static void nf_conntrack_irc_fini(void); | ||
219 | |||
220 | static 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 */ | ||
271 | static 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 | |||
280 | module_init(nf_conntrack_irc_init); | ||
281 | module_exit(nf_conntrack_irc_fini); | ||