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