]>
Commit | Line | Data |
---|---|---|
2380c486 JR |
1 | diff -NurpP --minimal linux-2.6.21.a/include/linux/netfilter/nf_conntrack_mms.h linux-2.6.21.b/include/linux/netfilter/nf_conntrack_mms.h |
2 | --- linux-2.6.21.a/include/linux/netfilter/nf_conntrack_mms.h 1970-01-01 01:00:00.000000000 +0100 | |
3 | +++ linux-2.6.21.b/include/linux/netfilter/nf_conntrack_mms.h 2007-05-30 11:50:55.000000000 +0200 | |
4 | @@ -0,0 +1,34 @@ | |
5 | +#ifndef _IP_CONNTRACK_MMS_H | |
6 | +#define _IP_CONNTRACK_MMS_H | |
7 | +/* MMS tracking. */ | |
8 | + | |
9 | +#ifdef __KERNEL__ | |
10 | + | |
11 | +#define MMS_PORT 1755 | |
12 | +#define MMS_SRV_MSG_ID 196610 | |
13 | + | |
14 | +#define MMS_SRV_MSG_OFFSET 36 | |
15 | +#define MMS_SRV_UNICODE_STRING_OFFSET 60 | |
16 | +#define MMS_SRV_CHUNKLENLV_OFFSET 16 | |
17 | +#define MMS_SRV_CHUNKLENLM_OFFSET 32 | |
18 | +#define MMS_SRV_MESSAGELENGTH_OFFSET 8 | |
19 | + | |
20 | +/* This structure is per expected connection */ | |
21 | +struct nf_ct_mms_expect { | |
22 | + u_int32_t offset; | |
23 | + u_int32_t len; | |
24 | + u_int32_t padding; | |
25 | + u_int16_t port; | |
26 | +}; | |
27 | + | |
28 | +/* This structure exists only once per master */ | |
29 | +struct nf_ct_mms_master { | |
30 | +}; | |
31 | + | |
32 | +struct nf_conntrack_expect; | |
33 | +extern unsigned int (*nf_nat_mms_hook)(struct sk_buff **pskb, | |
34 | + enum ip_conntrack_info ctinfo, | |
35 | + const struct nf_ct_mms_expect *exp_mms_info, | |
36 | + struct nf_conntrack_expect *exp); | |
37 | +#endif | |
38 | +#endif /* _IP_CONNTRACK_MMS_H */ | |
39 | diff -NurpP --minimal linux-2.6.21.a/include/net/netfilter/nf_conntrack.h linux-2.6.21.b/include/net/netfilter/nf_conntrack.h | |
40 | --- linux-2.6.21.a/include/net/netfilter/nf_conntrack.h 2007-05-30 11:14:07.000000000 +0200 | |
41 | +++ linux-2.6.21.b/include/net/netfilter/nf_conntrack.h 2007-05-30 11:50:55.000000000 +0200 | |
42 | @@ -46,6 +46,7 @@ union nf_conntrack_expect_proto { | |
43 | #include <linux/netfilter/nf_conntrack_h323.h> | |
44 | #include <linux/netfilter/nf_conntrack_sane.h> | |
45 | #include <linux/netfilter/nf_conntrack_sip.h> | |
46 | +#include <linux/netfilter/nf_conntrack_mms.h> | |
47 | ||
48 | /* per conntrack: application helper private data */ | |
49 | union nf_conntrack_help { | |
bd014f2d AM |
50 | @@ -69,6 +69,9 @@ |
51 | #if defined(CONFIG_NF_CONNTRACK_SIP) || defined(CONFIG_NF_CONNTRACK_SIP_MODULE) | |
2380c486 | 52 | struct nf_ct_sip_master ct_sip_info; |
bd014f2d AM |
53 | #endif |
54 | +#if defined(CONFIG_NF_NAT_MMS) || defined(CONFIG_NF_NAT_MMS_MODULE) | |
2380c486 | 55 | + struct nf_ct_mms_master ct_mms_info; |
bd014f2d | 56 | +#endif |
2380c486 JR |
57 | }; |
58 | ||
59 | #include <linux/types.h> | |
60 | diff -NurpP --minimal linux-2.6.21.a/include/net/netfilter/nf_conntrack_mms.h linux-2.6.21.b/include/net/netfilter/nf_conntrack_mms.h | |
61 | --- linux-2.6.21.a/include/net/netfilter/nf_conntrack_mms.h 1970-01-01 01:00:00.000000000 +0100 | |
62 | +++ linux-2.6.21.b/include/net/netfilter/nf_conntrack_mms.h 2007-05-30 11:50:55.000000000 +0200 | |
63 | @@ -0,0 +1,34 @@ | |
64 | +#ifndef _IP_CONNTRACK_MMS_H | |
65 | +#define _IP_CONNTRACK_MMS_H | |
66 | +/* MMS tracking. */ | |
67 | + | |
68 | +#ifdef __KERNEL__ | |
69 | + | |
70 | +#define MMS_PORT 1755 | |
71 | +#define MMS_SRV_MSG_ID 196610 | |
72 | + | |
73 | +#define MMS_SRV_MSG_OFFSET 36 | |
74 | +#define MMS_SRV_UNICODE_STRING_OFFSET 60 | |
75 | +#define MMS_SRV_CHUNKLENLV_OFFSET 16 | |
76 | +#define MMS_SRV_CHUNKLENLM_OFFSET 32 | |
77 | +#define MMS_SRV_MESSAGELENGTH_OFFSET 8 | |
78 | + | |
79 | +/* This structure is per expected connection */ | |
80 | +struct nf_ct_mms_expect { | |
81 | + u_int32_t offset; | |
82 | + u_int32_t len; | |
83 | + u_int32_t padding; | |
84 | + u_int16_t port; | |
85 | +}; | |
86 | + | |
87 | +/* This structure exists only once per master */ | |
88 | +struct nf_ct_mms_master { | |
89 | +}; | |
90 | + | |
91 | +struct nf_conntrack_expect; | |
92 | +extern unsigned int (*nf_nat_mms_hook)(struct sk_buff **pskb, | |
93 | + enum ip_conntrack_info ctinfo, | |
94 | + const struct nf_ct_mms_expect *exp_mms_info, | |
95 | + struct nf_conntrack_expect *exp); | |
96 | +#endif | |
97 | +#endif /* _IP_CONNTRACK_MMS_H */ | |
98 | diff -NurpP --minimal linux-2.6.21.a/net/ipv4/netfilter/Kconfig linux-2.6.21.b/net/ipv4/netfilter/Kconfig | |
99 | --- linux-2.6.21.a/net/ipv4/netfilter/Kconfig 2007-05-30 11:44:12.000000000 +0200 | |
100 | +++ linux-2.6.21.b/net/ipv4/netfilter/Kconfig 2007-05-30 11:50:55.000000000 +0200 | |
101 | @@ -543,6 +543,11 @@ config NF_NAT_H323 | |
102 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | |
103 | default NF_NAT && NF_CONNTRACK_H323 | |
104 | ||
105 | +config NF_NAT_MMS | |
106 | + tristate | |
107 | + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | |
108 | + default NF_NAT && NF_CONNTRACK_MMS | |
109 | + | |
110 | config NF_NAT_SIP | |
111 | tristate | |
112 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | |
113 | @@ -847,5 +852,23 @@ config IP_NF_TARGET_TARPIT | |
114 | hardware or IPs. Any TCP port that you would normally DROP or REJECT | |
115 | can instead become a tarpit. | |
116 | ||
117 | +config IP_NF_NAT_MMS | |
118 | + tristate | |
119 | + depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n | |
120 | + default IP_NF_NAT if IP_NF_MMS=y | |
121 | + default m if IP_NF_MMS=m | |
122 | + | |
123 | +config IP_NF_MMS | |
124 | + tristate 'MMS protocol support' | |
125 | + depends on IP_NF_CONNTRACK | |
126 | + help | |
127 | + Tracking MMS (Microsoft Windows Media Services) connections | |
128 | + could be problematic if random ports are used to send the | |
129 | + streaming content. This option allows users to track streaming | |
130 | + connections over random UDP or TCP ports. | |
131 | + | |
132 | + If you want to compile it as a module, say M here and read | |
133 | + <file:Documentation/modules.txt>. If unsure, say `Y'. | |
134 | + | |
135 | endmenu | |
136 | ||
137 | diff -NurpP --minimal linux-2.6.21.a/net/ipv4/netfilter/Makefile linux-2.6.21.b/net/ipv4/netfilter/Makefile | |
138 | --- linux-2.6.21.a/net/ipv4/netfilter/Makefile 2007-05-30 11:44:12.000000000 +0200 | |
139 | +++ linux-2.6.21.b/net/ipv4/netfilter/Makefile 2007-05-30 11:50:55.000000000 +0200 | |
a1f66529 | 140 | @@ -0,0 +1 @@ |
2380c486 JR |
141 | +obj-$(CONFIG_NF_NAT_MMS) += nf_nat_mms.o |
142 | diff -NurpP --minimal linux-2.6.21.a/net/ipv4/netfilter/nf_nat_mms.c linux-2.6.21.b/net/ipv4/netfilter/nf_nat_mms.c | |
143 | --- linux-2.6.21.a/net/ipv4/netfilter/nf_nat_mms.c 1970-01-01 01:00:00.000000000 +0100 | |
144 | +++ linux-2.6.21.b/net/ipv4/netfilter/nf_nat_mms.c 2007-05-30 11:50:55.000000000 +0200 | |
a1f66529 | 145 | @@ -0,0 +1,202 @@ |
2380c486 JR |
146 | +/* MMS extension for TCP NAT alteration. |
147 | + * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be> | |
148 | + * based on ip_nat_ftp.c and ip_nat_irc.c | |
149 | + * | |
150 | + * ip_nat_mms.c v0.3 2002-09-22 | |
151 | + * | |
152 | + * This program is free software; you can redistribute it and/or | |
153 | + * modify it under the terms of the GNU General Public License | |
154 | + * as published by the Free Software Foundation; either version | |
155 | + * 2 of the License, or (at your option) any later version. | |
156 | + * | |
157 | + * Module load syntax: | |
158 | + * insmod ip_nat_mms.o ports=port1,port2,...port<MAX_PORTS> | |
159 | + * | |
160 | + * Please give the ports of all MMS servers You wish to connect to. | |
161 | + * If you don't specify ports, the default will be TCP port 1755. | |
162 | + * | |
163 | + * More info on MMS protocol, firewalls and NAT: | |
164 | + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp | |
165 | + * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp | |
166 | + * | |
167 | + * The SDP project people are reverse-engineering MMS: | |
168 | + * http://get.to/sdp | |
169 | + * | |
170 | + * 2005-02-13: Harald Welte <laforge@netfilter.org> | |
171 | + * - port to 2.6.x | |
172 | + * - update to work with post 2.6.11 helper API changes | |
173 | + * | |
174 | + * 2007-03-30: Marek Guevara Braun <mguevara@pld-linux.org> | |
175 | + * - port to nf_conntrack | |
176 | + */ | |
177 | + | |
178 | +/* FIXME: issue with UDP & fragmentation with this URL: | |
179 | + http://www.cnn.com/video/world/2002/01/21/jb.shoe.bomb.cafe.cnn.low.asx | |
180 | + may be related to out-of-order first packets: | |
181 | + basically the expectation is set up correctly, then the server sends | |
182 | + a first UDP packet which is fragmented plus arrives out-of-order. | |
183 | + the MASQUERADING firewall with ip_nat_mms loaded responds with | |
184 | + an ICMP unreachable back to the server */ | |
185 | + | |
186 | +#include <linux/module.h> | |
187 | +#include <linux/netfilter_ipv4.h> | |
188 | +#include <linux/ip.h> | |
189 | +#include <linux/tcp.h> | |
190 | +#include <net/tcp.h> | |
191 | +#include <net/netfilter/nf_nat.h> | |
192 | +#include <net/netfilter/nf_nat_helper.h> | |
193 | +#include <net/netfilter/nf_nat_rule.h> | |
194 | +#include <net/netfilter/nf_conntrack_helper.h> | |
195 | +#include <net/netfilter/nf_conntrack_expect.h> | |
196 | +#include <linux/netfilter/nf_conntrack_mms.h> | |
197 | + | |
a1f66529 AM |
198 | +#define NIPQUAD(addr) \ |
199 | + ((unsigned char *)&addr)[0], \ | |
200 | + ((unsigned char *)&addr)[1], \ | |
201 | + ((unsigned char *)&addr)[2], \ | |
202 | + ((unsigned char *)&addr)[3] | |
203 | + | |
2380c486 JR |
204 | +#if 0 |
205 | +#define DEBUGP printk | |
206 | +#define DUMP_BYTES(address, counter) \ | |
207 | +({ \ | |
208 | + int temp_counter; \ | |
209 | + for(temp_counter=0; temp_counter<counter; ++temp_counter) { \ | |
210 | + DEBUGP("%u ", (u8)*(address+temp_counter)); \ | |
211 | + }; \ | |
212 | + DEBUGP("\n"); \ | |
213 | +}) | |
214 | +#else | |
215 | +#define DEBUGP(format, args...) | |
216 | +#define DUMP_BYTES(address, counter) | |
217 | +#endif | |
218 | + | |
219 | +MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>"); | |
220 | +MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) NAT module"); | |
221 | +MODULE_LICENSE("GPL"); | |
222 | + | |
223 | +static unsigned int mms_data_fixup(struct sk_buff **pskb, | |
224 | + enum ip_conntrack_info ctinfo, | |
225 | + const struct nf_ct_mms_expect *ct_mms_info, | |
226 | + struct nf_conntrack_expect *expect) | |
227 | +{ | |
228 | + u_int32_t newip; | |
229 | + struct nf_conn *ct = expect->master; | |
230 | + struct iphdr *iph = ip_hdr(*pskb); | |
231 | + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; | |
232 | + char *data = (char *)tcph + tcph->doff * 4; | |
233 | + int i, j, k, port; | |
234 | + u_int16_t mms_proto; | |
235 | + | |
236 | + u_int32_t *mms_chunkLenLV = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET); | |
237 | + u_int32_t *mms_chunkLenLM = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET); | |
238 | + u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET); | |
239 | + | |
240 | + int zero_padding; | |
241 | + | |
242 | + char buffer[28]; /* "\\255.255.255.255\UDP\65635" * 2 | |
243 | + (for unicode) */ | |
244 | + char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */ | |
245 | + char proto_string[6]; | |
246 | + | |
247 | + /* what was the protocol again ? */ | |
248 | + mms_proto = expect->tuple.dst.protonum; | |
249 | + sprintf(proto_string, "%u", mms_proto); | |
250 | + | |
251 | + DEBUGP("nf_nat_mms: mms_data_fixup: info (seq %u + %u) " | |
252 | + "in %u, proto %s\n", | |
253 | + expect->seq, ct_mms_info->len, ntohl(tcph->seq), | |
254 | + mms_proto == IPPROTO_UDP ? "UDP" | |
255 | + : mms_proto == IPPROTO_TCP ? "TCP":proto_string); | |
256 | + | |
257 | + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; | |
258 | + expect->saved_proto.tcp.port = expect->tuple.dst.u.tcp.port; | |
259 | + expect->expectfn = nf_nat_follow_master; | |
260 | + | |
261 | + /* Alter conntrack's expectations. */ | |
262 | + for (port = ct_mms_info->port; port != 0; port++) { | |
263 | + expect->tuple.dst.u.tcp.port = htons(port); | |
264 | + if (nf_ct_expect_related(expect) == 0) { | |
265 | + DEBUGP("nf_nat_mms: mms_data_fixup: using port %d\n", | |
266 | + port); | |
267 | + break; | |
268 | + } | |
269 | + } | |
270 | + | |
271 | + if (port == 0) | |
272 | + return NF_DROP; | |
273 | + | |
274 | + sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u", | |
275 | + NIPQUAD(newip), | |
276 | + expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP" | |
277 | + : expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string, | |
278 | + port); | |
279 | + DEBUGP("nf_nat_mms: new unicode string=%s\n", buffer); | |
280 | + | |
281 | + memset(unicode_buffer, 0, sizeof(char)*75); | |
282 | + | |
283 | + for (i=0; i<strlen(buffer); ++i) | |
284 | + *(unicode_buffer+i*2)=*(buffer+i); | |
285 | + | |
286 | + DEBUGP("nf_nat_mms: mms_data_fixup: padding: %u len: %u\n", | |
287 | + ct_mms_info->padding, ct_mms_info->len); | |
288 | + DEBUGP("nf_nat_mms: mms_data_fixup: offset: %u\n", | |
289 | + MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len); | |
290 | + DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60); | |
291 | + | |
292 | + /* add end of packet to it */ | |
293 | + for (j=0; j<ct_mms_info->padding; ++j) { | |
294 | + DEBUGP("nf_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n", | |
295 | + i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j)); | |
296 | + *(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j); | |
297 | + } | |
298 | + | |
299 | + /* pad with zeroes at the end ? see explanation of weird math below */ | |
300 | + zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8; | |
301 | + for (k=0; k<zero_padding; ++k) | |
302 | + *(unicode_buffer+i*2+j+k)= (char)0; | |
303 | + | |
304 | + DEBUGP("nf_nat_mms: mms_data_fixup: zero_padding = %u\n", zero_padding); | |
305 | + DEBUGP("nf_nat_mms: original=> chunkLenLV=%u chunkLenLM=%u " | |
306 | + "messageLength=%u\n", *mms_chunkLenLV, *mms_chunkLenLM, | |
307 | + *mms_messageLength); | |
308 | + | |
309 | + /* explanation, before I forget what I did: | |
310 | + strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8; | |
311 | + divide by 8 and add 3 to compute the mms_chunkLenLM field, | |
312 | + but note that things may have to be padded with zeroes to align by 8 | |
313 | + bytes, hence we add 7 and divide by 8 to get the correct length */ | |
314 | + *mms_chunkLenLM = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8); | |
315 | + *mms_chunkLenLV = *mms_chunkLenLM+2; | |
316 | + *mms_messageLength = *mms_chunkLenLV*8; | |
317 | + | |
318 | + DEBUGP("nf_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u" | |
319 | + " messageLength=%u\n", *mms_chunkLenLV, *mms_chunkLenLM, | |
320 | + *mms_messageLength); | |
321 | + | |
322 | + nf_nat_mangle_tcp_packet(*pskb, ct, ctinfo, | |
323 | + ct_mms_info->offset, | |
324 | + ct_mms_info->len + ct_mms_info->padding, | |
325 | + unicode_buffer, strlen(buffer)*2 + | |
326 | + ct_mms_info->padding + zero_padding); | |
327 | + DUMP_BYTES(unicode_buffer, 60); | |
328 | + | |
329 | + return NF_ACCEPT; | |
330 | +} | |
331 | + | |
332 | +static void __exit fini(void) | |
333 | +{ | |
334 | + nf_nat_mms_hook = NULL; | |
335 | + synchronize_net(); | |
336 | +} | |
337 | + | |
338 | +static int __init init(void) | |
339 | +{ | |
340 | + BUG_ON(nf_nat_mms_hook); | |
341 | + nf_nat_mms_hook = &mms_data_fixup; | |
342 | + | |
343 | + return 0; | |
344 | +} | |
345 | + | |
346 | +module_init(init); | |
347 | +module_exit(fini); | |
348 | diff -NurpP --minimal linux-2.6.21.a/net/netfilter/Kconfig linux-2.6.21.b/net/netfilter/Kconfig | |
349 | --- linux-2.6.21.a/net/netfilter/Kconfig 2007-05-30 11:13:04.000000000 +0200 | |
350 | +++ linux-2.6.21.b/net/netfilter/Kconfig 2007-05-30 11:50:55.000000000 +0200 | |
351 | @@ -271,6 +271,18 @@ config NF_CONNTRACK_TFTP | |
352 | ||
353 | To compile it as a module, choose M here. If unsure, say N. | |
354 | ||
355 | +config NF_CONNTRACK_MMS | |
356 | + tristate 'MMS protocol support' | |
357 | + depends on NF_CONNTRACK | |
358 | + help | |
359 | + Tracking MMS (Microsoft Windows Media Services) connections | |
360 | + could be problematic if random ports are used to send the | |
361 | + streaming content. This option allows users to track streaming | |
362 | + connections over random UDP or TCP ports. | |
363 | + | |
364 | + If you want to compile it as a module, say M here and read | |
365 | + <file:Documentation/modules.txt>. If unsure, say `Y'. | |
366 | + | |
367 | config NF_CT_NETLINK | |
368 | tristate 'Connection tracking netlink interface (EXPERIMENTAL)' | |
369 | depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK | |
370 | diff -NurpP --minimal linux-2.6.21.a/net/netfilter/Makefile linux-2.6.21.b/net/netfilter/Makefile | |
371 | --- linux-2.6.21.a/net/netfilter/Makefile 2007-05-30 11:13:04.000000000 +0200 | |
372 | +++ linux-2.6.21.b/net/netfilter/Makefile 2007-05-30 11:50:55.000000000 +0200 | |
373 | @@ -26,6 +26,7 @@ nf_conntrack_h323-objs := nf_conntrack_h | |
374 | obj-$(CONFIG_NF_CONNTRACK_AMANDA) += nf_conntrack_amanda.o | |
375 | obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o | |
376 | obj-$(CONFIG_NF_CONNTRACK_H323) += nf_conntrack_h323.o | |
377 | +obj-$(CONFIG_NF_CONNTRACK_MMS) += nf_conntrack_mms.o | |
378 | obj-$(CONFIG_NF_CONNTRACK_IRC) += nf_conntrack_irc.o | |
379 | obj-$(CONFIG_NF_CONNTRACK_NETBIOS_NS) += nf_conntrack_netbios_ns.o | |
380 | obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_conntrack_pptp.o | |
381 | diff -NurpP --minimal linux-2.6.21.a/net/netfilter/nf_conntrack_mms.c linux-2.6.21.b/net/netfilter/nf_conntrack_mms.c | |
382 | --- linux-2.6.21.a/net/netfilter/nf_conntrack_mms.c 1970-01-01 01:00:00.000000000 +0100 | |
383 | +++ linux-2.6.21.b/net/netfilter/nf_conntrack_mms.c 2007-05-30 11:50:55.000000000 +0200 | |
a1f66529 | 384 | @@ -0,0 +1,375 @@ |
2380c486 JR |
385 | +/* MMS extension for IP connection tracking |
386 | + * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be> | |
387 | + * based on ip_conntrack_ftp.c and ip_conntrack_irc.c | |
388 | + * | |
389 | + * ip_conntrack_mms.c v0.3 2002-09-22 | |
390 | + * | |
391 | + * This program is free software; you can redistribute it and/or | |
392 | + * modify it under the terms of the GNU General Public License | |
393 | + * as published by the Free Software Foundation; either version | |
394 | + * 2 of the License, or (at your option) any later version. | |
395 | + * | |
396 | + * Module load syntax: | |
397 | + * insmod nf_conntrack_mms.o ports=port1,port2,...port<MAX_PORTS> | |
398 | + * | |
399 | + * Please give the ports of all MMS servers You wish to connect to. | |
400 | + * If you don't specify ports, the default will be TCP port 1755. | |
401 | + * | |
402 | + * More info on MMS protocol, firewalls and NAT: | |
403 | + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp | |
404 | + * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp | |
405 | + * | |
406 | + * The SDP project people are reverse-engineering MMS: | |
407 | + * http://get.to/sdp | |
408 | + * | |
409 | + * 2005-02-13: Harald Welte <laforge@netfilter.org> | |
410 | + * - port to 2.6.x | |
411 | + * - update to work with post 2.6.11 helper API changes | |
412 | + * | |
413 | + * 2007-03-30: Marek Guevara Braun <mguevara@pld-linux.org> | |
414 | + * - port to nf_conntrack | |
415 | + */ | |
416 | + | |
417 | + | |
418 | +#include <linux/module.h> | |
419 | +#include <linux/netfilter.h> | |
420 | +#include <linux/ip.h> | |
421 | +#include <linux/ctype.h> | |
422 | +#include <net/checksum.h> | |
423 | +#include <net/tcp.h> | |
424 | + | |
425 | +#include <net/netfilter/nf_conntrack.h> | |
426 | +#include <net/netfilter/nf_conntrack_helper.h> | |
427 | +#include <net/netfilter/nf_conntrack_expect.h> | |
428 | +#include <linux/netfilter/nf_conntrack_mms.h> | |
429 | + | |
430 | +#define MAX_PORTS 8 | |
431 | +static int ports[MAX_PORTS]; | |
432 | +static int ports_c; | |
433 | +module_param_array(ports, int, &ports_c, 0400); | |
434 | +MODULE_PARM_DESC(ports, "port numbers of MMS"); | |
435 | + | |
436 | +static char mms_buffer[65536]; | |
437 | +static DEFINE_SPINLOCK(mms_buffer_lock); | |
438 | + | |
439 | +unsigned int (*nf_nat_mms_hook)(struct sk_buff **pskb, | |
440 | + enum ip_conntrack_info ctinfo, | |
441 | + const struct nf_ct_mms_expect *exp_mms_info, | |
442 | + struct nf_conntrack_expect *exp); | |
443 | +EXPORT_SYMBOL(nf_nat_mms_hook); | |
444 | + | |
445 | +#if 0 | |
446 | +#define DEBUGP printk | |
447 | +#else | |
448 | +#define DEBUGP(format, args...) | |
449 | +#endif | |
450 | + | |
451 | +MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>"); | |
452 | +MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) connection tracking module"); | |
453 | +MODULE_LICENSE("GPL"); | |
454 | + | |
455 | +/* #define isdigit(c) (c >= '0' && c <= '9') */ | |
456 | + | |
457 | +/* copied from drivers/usb/serial/io_edgeport.c - not perfect but will do the trick */ | |
458 | +static void unicode_to_ascii (char *string, short *unicode, int unicode_size) | |
459 | +{ | |
460 | + int i; | |
461 | + for (i = 0; i < unicode_size; ++i) { | |
462 | + string[i] = (char)(unicode[i]); | |
463 | + } | |
464 | + string[unicode_size] = 0x00; | |
465 | +} | |
466 | + | |
467 | +__inline static int atoi(char *s) | |
468 | +{ | |
469 | + int i=0; | |
470 | + while (isdigit(*s)) { | |
471 | + i = i*10 + *(s++) - '0'; | |
472 | + } | |
473 | + return i; | |
474 | +} | |
475 | + | |
476 | +/* convert ip address string like "192.168.0.10" to unsigned int */ | |
477 | +__inline static u_int32_t asciiiptoi(char *s) | |
478 | +{ | |
479 | + unsigned int i, j, k; | |
480 | + | |
481 | + for(i=k=0; k<3; ++k, ++s, i<<=8) { | |
482 | + i+=atoi(s); | |
483 | + for(j=0; (*(++s) != '.') && (j<3); ++j) | |
484 | + ; | |
485 | + } | |
486 | + i+=atoi(s); | |
487 | + return ntohl(i); | |
488 | +} | |
489 | + | |
490 | +int parse_mms(const char *data, | |
491 | + const unsigned int datalen, | |
492 | + u_int32_t *mms_ip, | |
493 | + u_int16_t *mms_proto, | |
494 | + u_int16_t *mms_port, | |
495 | + char **mms_string_b, | |
496 | + char **mms_string_e, | |
497 | + char **mms_padding_e) | |
498 | +{ | |
499 | + int unicode_size, i; | |
500 | + char tempstring[28]; /* "\\255.255.255.255\UDP\65535" */ | |
501 | + char getlengthstring[28]; | |
502 | + | |
503 | + for(unicode_size=0; | |
504 | + (char) *(data+(MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2)) != (char)0; | |
505 | + unicode_size++) | |
506 | + if ((unicode_size == 28) || (MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2 >= datalen)) | |
507 | + return -1; /* out of bounds - incomplete packet */ | |
508 | + | |
509 | + unicode_to_ascii(tempstring, (short *)(data+MMS_SRV_UNICODE_STRING_OFFSET), unicode_size); | |
510 | + DEBUGP("nf_conntrack_mms: offset 60: %s\n", (const char *)(tempstring)); | |
511 | + | |
512 | + /* IP address ? */ | |
513 | + *mms_ip = asciiiptoi(tempstring+2); | |
514 | + | |
0b91b834 | 515 | + i=sprintf(getlengthstring, "%pI4", mms_ip); |
2380c486 JR |
516 | + |
517 | + /* protocol ? */ | |
518 | + if(strncmp(tempstring+3+i, "TCP", 3)==0) | |
519 | + *mms_proto = IPPROTO_TCP; | |
520 | + else if(strncmp(tempstring+3+i, "UDP", 3)==0) | |
521 | + *mms_proto = IPPROTO_UDP; | |
522 | + | |
523 | + /* port ? */ | |
524 | + *mms_port = atoi(tempstring+7+i); | |
525 | + | |
526 | + /* we store a pointer to the beginning of the "\\a.b.c.d\proto\port" | |
527 | + unicode string, one to the end of the string, and one to the end | |
528 | + of the packet, since we must keep track of the number of bytes | |
529 | + between end of the unicode string and the end of packet (padding) */ | |
530 | + *mms_string_b = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET); | |
531 | + *mms_string_e = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET + unicode_size * 2); | |
532 | + *mms_padding_e = (char *)(data + datalen); /* looks funny, doesn't it */ | |
533 | + return 0; | |
534 | +} | |
535 | + | |
536 | + | |
537 | +/* FIXME: This should be in userspace. Later. */ | |
538 | +static int help(struct sk_buff **pskb, | |
539 | + unsigned int protoff, | |
540 | + struct nf_conn *ct, | |
541 | + enum ip_conntrack_info ctinfo) | |
542 | +{ | |
543 | + int ret = NF_DROP; | |
544 | + struct tcphdr _tcph, *th; | |
545 | + char *data, *mb_ptr; | |
546 | + unsigned int datalen, dataoff; | |
547 | + | |
548 | + | |
549 | + //struct tcphdr *tcph = (void *)iph + iph->ihl * 4; | |
550 | + //unsigned int tcplen = len - iph->ihl * 4; | |
551 | + //unsigned int datalen = tcplen - tcph->doff * 4; | |
552 | + int dir = CTINFO2DIR(ctinfo); | |
553 | + struct nf_conntrack_expect *exp; | |
554 | + struct nf_conntrack_tuple *tuple; | |
555 | + struct nf_ct_mms_expect _emmi, *exp_mms_info = &_emmi; | |
556 | + | |
557 | + u_int32_t mms_ip; | |
558 | + u_int16_t mms_proto; | |
559 | + char mms_proto_string[8]; | |
560 | + u_int16_t mms_port; | |
561 | + __be16 port; | |
562 | + char *mms_string_b, *mms_string_e, *mms_padding_e; | |
563 | + typeof(nf_nat_mms_hook) nf_nat_mms; | |
564 | + | |
565 | + /* Until there's been traffic both ways, don't look in packets. */ | |
566 | + if (ctinfo != IP_CT_ESTABLISHED && | |
567 | + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { | |
568 | + DEBUGP("nf_conntrack_mms: Conntrackinfo = %u\n", ctinfo); | |
569 | + return NF_ACCEPT; | |
570 | + } | |
571 | + | |
572 | + /* Not whole TCP header? */ | |
573 | + th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); | |
574 | + if (th == NULL) | |
575 | + return NF_ACCEPT; | |
576 | + | |
577 | + /* No data ? */ | |
578 | + dataoff = protoff + th->doff*4; | |
579 | + if (dataoff >= (*pskb)->len) | |
580 | + return NF_ACCEPT; | |
581 | + | |
582 | + datalen = (*pskb)->len - dataoff; | |
583 | + DEBUGP("nf_conntrack_mms: datalen:%u\n", datalen); | |
584 | + | |
585 | + spin_lock_bh(&mms_buffer_lock); | |
586 | + mb_ptr = skb_header_pointer(*pskb, dataoff, | |
587 | + (*pskb)->len - dataoff, mms_buffer); | |
588 | + BUG_ON(mb_ptr == NULL); | |
589 | + | |
590 | + data = mb_ptr; | |
591 | + | |
592 | +#if 0 | |
593 | + /* Checksum invalid? Ignore. */ | |
594 | + /* FIXME: Source route IP option packets --RR */ | |
595 | + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, | |
596 | + csum_partial((char *)tcph, tcplen, 0))) { | |
597 | + DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", | |
598 | + tcph, tcplen, NIPQUAD(iph->saddr), | |
599 | + NIPQUAD(iph->daddr)); | |
600 | + return NF_ACCEPT; | |
601 | + } | |
602 | +#endif | |
603 | + | |
604 | + /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP | |
605 | + * payload */ | |
606 | + | |
607 | + /* FIXME: There is an issue with only looking at this packet: before | |
608 | + * this packet, the client has already sent a packet to the server with | |
609 | + * the server's hostname according to the client (think of it as the | |
610 | + * "Host: " header in HTTP/1.1). The server will break the connection | |
611 | + * if this doesn't correspond to its own host header. The client can | |
612 | + * also connect to an IP address; if it's the server's IP address, it | |
613 | + * will not break the connection. When doing DNAT on a connection where | |
614 | + * the client uses a server's IP address, the nat module should detect | |
615 | + * this and change this string accordingly to the DNATed address. This | |
616 | + * should probably be done by checking for an IP address, then storing | |
617 | + * it as a member of struct ip_ct_mms_expect and checking for it in | |
618 | + * ip_nat_mms... | |
619 | + */ | |
620 | + if ((MMS_SRV_MSG_OFFSET >= datalen) || | |
621 | + ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) != MMS_SRV_MSG_ID)) | |
622 | + goto out; | |
623 | + | |
624 | + DEBUGP("nf_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", | |
625 | + (u8)*(data+36), (u8)*(data+37), (u8)*(data+38), (u8)*(data+39), | |
626 | + datalen); | |
627 | + if (parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port, | |
628 | + &mms_string_b, &mms_string_e, &mms_padding_e)) | |
629 | + if (net_ratelimit()) | |
630 | + /* FIXME: more verbose debugging ? */ | |
631 | + printk(KERN_WARNING | |
632 | + "nf_conntrack_mms: Unable to parse " | |
633 | + "data payload\n"); | |
634 | + | |
635 | + sprintf(mms_proto_string, "(%u)", mms_proto); | |
636 | + DEBUGP("nf_conntrack_mms: adding %s expectation " | |
637 | + "%u.%u.%u.%u -> %u.%u.%u.%u:%u\n", | |
638 | + mms_proto == IPPROTO_TCP ? "TCP" | |
639 | + : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string, | |
640 | + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), | |
641 | + NIPQUAD(mms_ip), | |
642 | + mms_port); | |
643 | + | |
644 | + /* it's possible that the client will just ask the server to | |
645 | + * tunnel the stream over the same TCP session (from port | |
646 | + * 1755): there's shouldn't be a need to add an expectation in | |
647 | + * that case, but it makes NAT packet mangling so much easier | |
648 | + * */ | |
649 | + | |
650 | + DEBUGP("nf_conntrack_mms: tcph->seq = %u\n", tcph->seq); | |
651 | + | |
652 | + exp = nf_ct_expect_alloc(ct); | |
653 | + if (exp == NULL) { | |
654 | + ret = NF_DROP; | |
655 | + goto out; | |
656 | + } | |
657 | + | |
658 | + exp_mms_info->offset = (mms_string_b - data); | |
659 | + exp_mms_info->len = (mms_string_e - mms_string_b); | |
660 | + exp_mms_info->padding = (mms_padding_e - mms_string_e); | |
661 | + exp_mms_info->port = mms_port; | |
662 | + | |
663 | + DEBUGP("nf_conntrack_mms: wrote info seq=%u (ofs=%u), " | |
664 | + "len=%d, padding=%u\n", exp->seq, (mms_string_e - data), | |
665 | + exp_mms_info->len, exp_mms_info->padding); | |
666 | + | |
667 | + tuple = &ct->tuplehash[!dir].tuple; | |
668 | + port = htons(mms_port); | |
669 | + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, tuple->src.l3num, | |
670 | + NULL, &tuple->dst.u3, | |
671 | + IPPROTO_TCP, NULL, &port); | |
672 | + | |
673 | + nf_nat_mms = rcu_dereference(nf_nat_mms_hook); | |
674 | + if (nf_nat_mms && ct->status & IPS_NAT_MASK) | |
675 | + ret = nf_nat_mms(pskb, ctinfo, exp_mms_info, exp); | |
676 | + else if (nf_ct_expect_related(exp) != 0) | |
677 | + ret = NF_DROP; | |
678 | + nf_ct_expect_put(exp); | |
679 | +/* | |
680 | + exp->tuple = ((struct nf_conntrack_tuple) | |
681 | + { { ct->tuplehash[!dir].tuple.src.u3.ip, { 0 } }, | |
682 | + { mms_ip, | |
683 | + { .tcp = { (__u16) ntohs(mms_port) } }, | |
684 | + mms_proto } } | |
685 | + ); | |
686 | + exp->mask = ((struct nf_conntrack_tuple) | |
687 | + { { 0xFFFFFFFF, { 0 } }, | |
688 | + { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }}); | |
689 | + exp->expectfn = NULL; | |
690 | + exp->master = ct; | |
691 | + | |
692 | + if (nf_nat_mms_hook) | |
693 | + ret = nf_nat_mms_hook(pskb, ctinfo, exp_mms_info, exp); | |
694 | + else if (nf_conntrack_expect_related(exp) != 0) | |
695 | + ret = NF_DROP; | |
696 | + | |
697 | + nf_conntrack_expect_put(exp); | |
698 | +*/ | |
699 | +out: | |
700 | + spin_unlock_bh(&mms_buffer_lock); | |
701 | + return ret; | |
702 | +} | |
703 | + | |
704 | +static struct nf_conntrack_helper mms[MAX_PORTS]; | |
705 | +static char mms_names[MAX_PORTS][10]; | |
706 | +static const struct nf_conntrack_expect_policy mms_exp_policy = { | |
707 | + .max_expected = 1, | |
708 | + .timeout = 120, | |
709 | +}; | |
710 | + | |
711 | +/* Not __exit: called from init() */ | |
712 | +static void fini(void) | |
713 | +{ | |
714 | + int i; | |
715 | + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { | |
716 | + DEBUGP("nf_conntrack_mms: unregistering helper for port %d\n", | |
717 | + ports[i]); | |
718 | + nf_conntrack_helper_unregister(&mms[i]); | |
719 | + } | |
720 | +} | |
721 | + | |
722 | +static int __init init(void) | |
723 | +{ | |
724 | + int i, ret; | |
725 | + char *tmpname; | |
726 | + | |
727 | + if (ports[0] == 0) | |
728 | + ports[0] = MMS_PORT; | |
729 | + | |
730 | + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { | |
731 | + memset(&mms[i], 0, sizeof(struct nf_conntrack_helper)); | |
732 | + mms[i].tuple.src.u.tcp.port = htons(ports[i]); | |
733 | + mms[i].tuple.dst.protonum = IPPROTO_TCP; | |
734 | + mms[i].me = THIS_MODULE; | |
735 | + mms[i].expect_policy = &mms_exp_policy; | |
736 | + mms[i].help = help; | |
737 | + | |
738 | + tmpname = &mms_names[i][0]; | |
739 | + if (ports[i] == MMS_PORT) | |
740 | + sprintf(tmpname, "mms"); | |
741 | + else | |
742 | + sprintf(tmpname, "mms-%d", ports[i]); | |
743 | + mms[i].name = tmpname; | |
744 | + | |
745 | + DEBUGP("nf_conntrack_mms: registering helper for port %d\n", | |
746 | + ports[i]); | |
747 | + ret = nf_conntrack_helper_register(&mms[i]); | |
748 | + | |
749 | + if (ret) { | |
750 | + fini(); | |
751 | + return ret; | |
752 | + } | |
753 | + ports_c++; | |
754 | + } | |
755 | + return 0; | |
756 | +} | |
757 | + | |
758 | +module_init(init); | |
759 | +module_exit(fini); |