summaryrefslogtreecommitdiffstats
path: root/target/linux/generic-2.4/patches/615-netfilter_nat_mms.patch
blob: 3871d5939527c3ed81477ca59d2fbf3e07af8fb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.new/net/ipv4/netfilter/Config.in
--- linux-2.4.32/net/ipv4/netfilter/Config.in	2006-03-01 01:12:48.268947944 +0100
+++ linux-2.4.32.new/net/ipv4/netfilter/Config.in	2006-03-01 01:14:53.455916632 +0100
@@ -17,6 +17,7 @@
   dep_tristate '   PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
   dep_tristate '  H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK
   dep_tristate '  RTSP protocol support' CONFIG_IP_NF_RTSP $CONFIG_IP_NF_CONNTRACK
+  dep_tristate '  MMS protocol support' CONFIG_IP_NF_MMS $CONFIG_IP_NF_CONNTRACK
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -127,6 +128,13 @@
          define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT
        fi
       fi
+      if [ "$CONFIG_IP_NF_MMS" = "m" ]; then
+       define_tristate CONFIG_IP_NF_NAT_MMS m
+      else
+       if [ "$CONFIG_IP_NF_MMS" = "y" ]; then
+         define_tristate CONFIG_IP_NF_NAT_MMS $CONFIG_IP_NF_NAT
+       fi
+      fi
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
         dep_tristate '    Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
       fi
diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32.new/net/ipv4/netfilter/Makefile
--- linux-2.4.32/net/ipv4/netfilter/Makefile	2006-03-01 01:12:48.270947640 +0100
+++ linux-2.4.32.new/net/ipv4/netfilter/Makefile	2006-03-01 01:15:25.263081208 +0100
@@ -61,6 +61,10 @@
 ifdef CONFIG_IP_NF_NAT_RTSP
        export-objs += ip_conntrack_rtsp.o
 endif
+obj-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms.o
+ifdef CONFIG_IP_NF_NAT_MMS
+       export-objs += ip_conntrack_mms.o
+endif
 
 
 
@@ -73,6 +77,7 @@
 obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
 obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
 obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o
+obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o
 
 # generic IP tables 
 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_mms.c
--- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_mms.c	2006-03-01 01:13:32.991149136 +0100
@@ -0,0 +1,292 @@
+/* MMS extension for IP connection tracking
+ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
+ * based on ip_conntrack_ftp.c and ip_conntrack_irc.c
+ *
+ * ip_conntrack_mms.c v0.3 2002-09-22
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ *      Module load syntax:
+ *      insmod ip_conntrack_mms.o ports=port1,port2,...port<MAX_PORTS>
+ *
+ *      Please give the ports of all MMS servers You wish to connect to.
+ *      If you don't specify ports, the default will be TCP port 1755.
+ *
+ *      More info on MMS protocol, firewalls and NAT:
+ *      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp
+ *      http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp
+ *
+ *      The SDP project people are reverse-engineering MMS:
+ *      http://get.to/sdp
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <linux/ctype.h>
+#include <net/checksum.h>
+#include <net/tcp.h>
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
+
+DECLARE_LOCK(ip_mms_lock);
+struct module *ip_conntrack_mms = THIS_MODULE;
+
+#define MAX_PORTS 8
+static int ports[MAX_PORTS];
+static int ports_c;
+#ifdef MODULE_PARM
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
+#endif
+
+#define DEBUGP(format, args...)
+
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+EXPORT_SYMBOL(ip_mms_lock);
+#endif
+
+MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
+MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) connection tracking module");
+MODULE_LICENSE("GPL");
+
+/* #define isdigit(c) (c >= '0' && c <= '9') */
+
+/* copied from drivers/usb/serial/io_edgeport.c - not perfect but will do the trick */
+static void unicode_to_ascii (char *string, short *unicode, int unicode_size)
+{
+	int i;
+	for (i = 0; i < unicode_size; ++i) {
+		string[i] = (char)(unicode[i]);
+	}
+	string[unicode_size] = 0x00;
+}
+
+__inline static int atoi(char *s) 
+{
+	int i=0;
+	while (isdigit(*s)) {
+		i = i*10 + *(s++) - '0';
+	}
+	return i;
+}
+
+/* convert ip address string like "192.168.0.10" to unsigned int */
+__inline static u_int32_t asciiiptoi(char *s)
+{
+	unsigned int i, j, k;
+
+	for(i=k=0; k<3; ++k, ++s, i<<=8) {
+		i+=atoi(s);
+		for(j=0; (*(++s) != '.') && (j<3); ++j)
+			;
+	}
+	i+=atoi(s);
+	return ntohl(i);
+}
+
+int parse_mms(const char *data, 
+	      const unsigned int datalen,
+	      u_int32_t *mms_ip,
+	      u_int16_t *mms_proto,
+	      u_int16_t *mms_port,
+	      char **mms_string_b,
+	      char **mms_string_e,
+	      char **mms_padding_e)
+{
+	int unicode_size, i;
+	char tempstring[28];       /* "\\255.255.255.255\UDP\65535" */
+	char getlengthstring[28];
+	
+	for(unicode_size=0; 
+	    (char) *(data+(MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2)) != (char)0;
+	    unicode_size++)
+		if ((unicode_size == 28) || (MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2 >= datalen)) 
+			return -1; /* out of bounds - incomplete packet */
+	
+	unicode_to_ascii(tempstring, (short *)(data+MMS_SRV_UNICODE_STRING_OFFSET), unicode_size);
+	DEBUGP("ip_conntrack_mms: offset 60: %s\n", (const char *)(tempstring));
+	
+	/* IP address ? */
+	*mms_ip = asciiiptoi(tempstring+2);
+	
+	i=sprintf(getlengthstring, "%u.%u.%u.%u", HIPQUAD(*mms_ip));
+		
+	/* protocol ? */
+	if(strncmp(tempstring+3+i, "TCP", 3)==0)
+		*mms_proto = IPPROTO_TCP;
+	else if(strncmp(tempstring+3+i, "UDP", 3)==0)
+		*mms_proto = IPPROTO_UDP;
+
+	/* port ? */
+	*mms_port = atoi(tempstring+7+i);
+
+	/* we store a pointer to the beginning of the "\\a.b.c.d\proto\port" 
+	   unicode string, one to the end of the string, and one to the end 
+	   of the packet, since we must keep track of the number of bytes 
+	   between end of the unicode string and the end of packet (padding) */
+	*mms_string_b  = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET);
+	*mms_string_e  = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET + unicode_size * 2);
+	*mms_padding_e = (char *)(data + datalen); /* looks funny, doesn't it */
+	return 0;
+}
+
+
+static int help(const struct iphdr *iph, size_t len,
+		struct ip_conntrack *ct,
+		enum ip_conntrack_info ctinfo)
+{
+	/* tcplen not negative guaranteed by ip_conntrack_tcp.c */
+	struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
+	const char *data = (const char *)tcph + tcph->doff * 4;
+	unsigned int tcplen = len - iph->ihl * 4;
+	unsigned int datalen = tcplen - tcph->doff * 4;
+	int dir = CTINFO2DIR(ctinfo);
+	struct ip_conntrack_expect expect, *exp = &expect; 
+	struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info;
+	
+	u_int32_t mms_ip;
+	u_int16_t mms_proto;
+	char mms_proto_string[8];
+	u_int16_t mms_port;
+	char *mms_string_b, *mms_string_e, *mms_padding_e;
+	     
+	/* Until there's been traffic both ways, don't look in packets. */
+	if (ctinfo != IP_CT_ESTABLISHED
+	    && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
+		DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo);
+		return NF_ACCEPT;
+	}
+
+	/* Not whole TCP header? */
+	if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) {
+		DEBUGP("ip_conntrack_mms: tcplen = %u\n", (unsigned)tcplen);
+		return NF_ACCEPT;
+	}
+
+	/* Checksum invalid?  Ignore. */
+	if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
+	    csum_partial((char *)tcph, tcplen, 0))) {
+		DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
+		       tcph, tcplen, NIPQUAD(iph->saddr),
+		       NIPQUAD(iph->daddr));
+		return NF_ACCEPT;
+	}
+	
+	/* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */
+	if( (MMS_SRV_MSG_OFFSET < datalen) && 
+	    ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) {
+		DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", 
+		       (u8)*(data+36), (u8)*(data+37), 
+		       (u8)*(data+38), (u8)*(data+39),
+		       datalen);
+		if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port,
+		             &mms_string_b, &mms_string_e, &mms_padding_e))
+			if(net_ratelimit())
+				printk(KERN_WARNING
+				       "ip_conntrack_mms: Unable to parse data payload\n");
+
+		memset(&expect, 0, sizeof(expect));
+
+		sprintf(mms_proto_string, "(%u)", mms_proto);
+		DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n",
+		       mms_proto == IPPROTO_TCP ? "TCP"
+		       : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string,
+		       NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
+		       NIPQUAD(mms_ip),
+		       mms_port);
+		
+		/* it's possible that the client will just ask the server to tunnel
+		   the stream over the same TCP session (from port 1755): there's 
+		   shouldn't be a need to add an expectation in that case, but it
+		   makes NAT packet mangling so much easier */
+		LOCK_BH(&ip_mms_lock);
+
+		DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq);
+		
+		exp->seq = ntohl(tcph->seq) + (mms_string_b - data);
+		exp_mms_info->len     = (mms_string_e  - mms_string_b);
+		exp_mms_info->padding = (mms_padding_e - mms_string_e);
+		exp_mms_info->port    = mms_port;
+		
+		DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n",
+		       exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding);
+		
+		exp->tuple = ((struct ip_conntrack_tuple)
+		              { { ct->tuplehash[!dir].tuple.src.ip, { 0 } },
+		              { mms_ip,
+		                { (__u16) ntohs(mms_port) },
+		                mms_proto } }
+		             );
+		exp->mask  = ((struct ip_conntrack_tuple)
+		             { { 0xFFFFFFFF, { 0 } },
+		               { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+		exp->expectfn = NULL;
+		ip_conntrack_expect_related(ct, &expect);
+		UNLOCK_BH(&ip_mms_lock);
+	}
+
+	return NF_ACCEPT;
+}
+
+static struct ip_conntrack_helper mms[MAX_PORTS];
+static char mms_names[MAX_PORTS][10];
+
+/* Not __exit: called from init() */
+static void fini(void)
+{
+	int i;
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+		DEBUGP("ip_conntrack_mms: unregistering helper for port %d\n",
+				ports[i]);
+		ip_conntrack_helper_unregister(&mms[i]);
+	}
+}
+
+static int __init init(void)
+{
+	int i, ret;
+	char *tmpname;
+
+	if (ports[0] == 0)
+		ports[0] = MMS_PORT;
+
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+		memset(&mms[i], 0, sizeof(struct ip_conntrack_helper));
+		mms[i].tuple.src.u.tcp.port = htons(ports[i]);
+		mms[i].tuple.dst.protonum = IPPROTO_TCP;
+		mms[i].mask.src.u.tcp.port = 0xFFFF;
+		mms[i].mask.dst.protonum = 0xFFFF;
+		mms[i].max_expected = 1;
+		mms[i].timeout = 0;
+		mms[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
+		mms[i].me = THIS_MODULE;
+		mms[i].help = help;
+
+		tmpname = &mms_names[i][0];
+		if (ports[i] == MMS_PORT)
+			sprintf(tmpname, "mms");
+		else
+			sprintf(tmpname, "mms-%d", ports[i]);
+		mms[i].name = tmpname;
+
+		DEBUGP("ip_conntrack_mms: registering helper for port %d\n", 
+				ports[i]);
+		ret = ip_conntrack_helper_register(&mms[i]);
+
+		if (ret) {
+			fini();
+			return ret;
+		}
+		ports_c++;
+	}
+	return 0;
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c linux-2.4.32.new/net/ipv4/netfilter/ip_nat_mms.c
--- linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32.new/net/ipv4/netfilter/ip_nat_mms.c	2006-03-01 01:13:32.992148984 +0100
@@ -0,0 +1,330 @@
+/* MMS extension for TCP NAT alteration.
+ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
+ * based on ip_nat_ftp.c and ip_nat_irc.c
+ *
+ * ip_nat_mms.c v0.3 2002-09-22
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ *      Module load syntax:
+ *      insmod ip_nat_mms.o ports=port1,port2,...port<MAX_PORTS>
+ *
+ *      Please give the ports of all MMS servers You wish to connect to.
+ *      If you don't specify ports, the default will be TCP port 1755.
+ *
+ *      More info on MMS protocol, firewalls and NAT:
+ *      http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp
+ *      http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp
+ *
+ *      The SDP project people are reverse-engineering MMS:
+ *      http://get.to/sdp
+ */
+
+
+#include <linux/module.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+
+#define DEBUGP(format, args...)
+#define DUMP_BYTES(address, counter)
+
+#define MAX_PORTS 8
+static int ports[MAX_PORTS];
+static int ports_c = 0;
+
+#ifdef MODULE_PARM
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
+#endif
+
+MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
+MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) NAT module");
+MODULE_LICENSE("GPL");
+
+DECLARE_LOCK_EXTERN(ip_mms_lock);
+
+
+static int mms_data_fixup(const struct ip_ct_mms_expect *ct_mms_info,
+                          struct ip_conntrack *ct,
+                          struct sk_buff **pskb,
+                          enum ip_conntrack_info ctinfo,
+                          struct ip_conntrack_expect *expect)
+{
+	u_int32_t newip;
+	struct ip_conntrack_tuple t;
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
+	char *data = (char *)tcph + tcph->doff * 4;
+	int i, j, k, port;
+	u_int16_t mms_proto;
+
+	u_int32_t *mms_chunkLenLV    = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET);
+	u_int32_t *mms_chunkLenLM    = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET);
+	u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET);
+
+	int zero_padding;
+
+	char buffer[28];         /* "\\255.255.255.255\UDP\65635" * 2 (for unicode) */
+	char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */
+	char proto_string[6];
+	
+	MUST_BE_LOCKED(&ip_mms_lock);
+
+	/* what was the protocol again ? */
+	mms_proto = expect->tuple.dst.protonum;
+	sprintf(proto_string, "%u", mms_proto);
+	
+	DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) in %u, proto %s\n",
+	       expect->seq, ct_mms_info->len, ntohl(tcph->seq),
+	       mms_proto == IPPROTO_UDP ? "UDP"
+	       : mms_proto == IPPROTO_TCP ? "TCP":proto_string);
+	
+	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
+
+	/* Alter conntrack's expectations. */
+	t = expect->tuple;
+	t.dst.ip = newip;
+	for (port = ct_mms_info->port; port != 0; port++) {
+		t.dst.u.tcp.port = htons(port);
+		if (ip_conntrack_change_expect(expect, &t) == 0) {
+			DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n", port);
+			break;
+		}
+	}
+	
+	if(port == 0)
+		return 0;
+
+	sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u",
+	        NIPQUAD(newip),
+		expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP"
+		: expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string,
+		port);
+	DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer);
+	
+	memset(unicode_buffer, 0, sizeof(char)*75);
+
+	for (i=0; i<strlen(buffer); ++i)
+		*(unicode_buffer+i*2)=*(buffer+i);
+	
+	DEBUGP("ip_nat_mms: mms_data_fixup: padding: %u len: %u\n", ct_mms_info->padding, ct_mms_info->len);
+	DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n", MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len);
+	DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60);
+	
+	/* add end of packet to it */
+	for (j=0; j<ct_mms_info->padding; ++j) {
+		DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n", 
+		       i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j));
+		*(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j);
+	}
+
+	/* pad with zeroes at the end ? see explanation of weird math below */
+	zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8;
+	for (k=0; k<zero_padding; ++k)
+		*(unicode_buffer+i*2+j+k)= (char)0;
+	
+	DEBUGP("ip_nat_mms: mms_data_fixup: zero_padding = %u\n", zero_padding);
+	DEBUGP("ip_nat_mms: original=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n",
+	       *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength);
+	
+	/* explanation, before I forget what I did:
+	   strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8;
+	   divide by 8 and add 3 to compute the mms_chunkLenLM field,
+	   but note that things may have to be padded with zeroes to align by 8 
+	   bytes, hence we add 7 and divide by 8 to get the correct length */ 
+	*mms_chunkLenLM    = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8);
+	*mms_chunkLenLV    = *mms_chunkLenLM+2;
+	*mms_messageLength = *mms_chunkLenLV*8;
+	
+	DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n",
+	       *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength);
+	
+	ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
+	                         expect->seq - ntohl(tcph->seq),
+	                         ct_mms_info->len + ct_mms_info->padding, unicode_buffer,
+	                         strlen(buffer)*2 + ct_mms_info->padding + zero_padding);
+	DUMP_BYTES(unicode_buffer, 60);
+	
+	return 1;
+}
+
+static unsigned int
+mms_nat_expected(struct sk_buff **pskb,
+                 unsigned int hooknum,
+                 struct ip_conntrack *ct,
+                 struct ip_nat_info *info)
+{
+	struct ip_nat_multi_range mr;
+	u_int32_t newdstip, newsrcip, newip;
+
+	struct ip_conntrack *master = master_ct(ct);
+
+	IP_NF_ASSERT(info);
+	IP_NF_ASSERT(master);
+
+	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
+
+	DEBUGP("ip_nat_mms: mms_nat_expected: We have a connection!\n");
+
+	newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+	newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+	DEBUGP("ip_nat_mms: mms_nat_expected: hook %s: newsrc->newdst %u.%u.%u.%u->%u.%u.%u.%u\n",
+	       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+	       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+	       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???",
+	       NIPQUAD(newsrcip), NIPQUAD(newdstip));
+
+	if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
+		newip = newsrcip;
+	else
+		newip = newdstip;
+
+	DEBUGP("ip_nat_mms: mms_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
+
+	mr.rangesize = 1;
+	/* We don't want to manip the per-protocol, just the IPs. */
+	mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
+	mr.range[0].min_ip = mr.range[0].max_ip = newip;
+
+	return ip_nat_setup_info(ct, &mr, hooknum);
+}
+
+
+static unsigned int mms_nat_help(struct ip_conntrack *ct,
+			 struct ip_conntrack_expect *exp,
+			 struct ip_nat_info *info,
+			 enum ip_conntrack_info ctinfo,
+			 unsigned int hooknum,
+			 struct sk_buff **pskb)
+{
+	struct iphdr *iph = (*pskb)->nh.iph;
+	struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
+	unsigned int datalen;
+	int dir;
+	struct ip_ct_mms_expect *ct_mms_info;
+
+	if (!exp)
+		DEBUGP("ip_nat_mms: no exp!!");
+
+	ct_mms_info = &exp->help.exp_mms_info;
+	
+	/* Only mangle things once: original direction in POST_ROUTING
+	   and reply direction on PRE_ROUTING. */
+	dir = CTINFO2DIR(ctinfo);
+	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
+	    ||(hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
+		DEBUGP("ip_nat_mms: mms_nat_help: not touching dir %s at hook %s\n",
+		       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+		       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+		       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+		       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
+		return NF_ACCEPT;
+	}
+	DEBUGP("ip_nat_mms: mms_nat_help: beyond not touching (dir %s at hook %s)\n",
+	       dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+	       hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+	       : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+	       : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
+	
+	datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
+	
+	DEBUGP("ip_nat_mms: mms_nat_help: %u+%u=%u %u %u\n", exp->seq, ct_mms_info->len,
+	       exp->seq + ct_mms_info->len,
+	       ntohl(tcph->seq),
+	       ntohl(tcph->seq) + datalen);
+	
+	LOCK_BH(&ip_mms_lock);
+	/* Check wether the whole IP/proto/port pattern is carried in the payload */
+	if (between(exp->seq + ct_mms_info->len,
+	    ntohl(tcph->seq),
+	    ntohl(tcph->seq) + datalen)) {
+		if (!mms_data_fixup(ct_mms_info, ct, pskb, ctinfo, exp)) {
+			UNLOCK_BH(&ip_mms_lock);
+			return NF_DROP;
+		}
+	} else {
+		/* Half a match?  This means a partial retransmisison.
+		   It's a cracker being funky. */
+		if (net_ratelimit()) {
+			printk("ip_nat_mms: partial packet %u/%u in %u/%u\n",
+			       exp->seq, ct_mms_info->len,
+			       ntohl(tcph->seq),
+			       ntohl(tcph->seq) + datalen);
+		}
+		UNLOCK_BH(&ip_mms_lock);
+		return NF_DROP;
+	}
+	UNLOCK_BH(&ip_mms_lock);
+	
+	return NF_ACCEPT;
+}
+
+static struct ip_nat_helper mms[MAX_PORTS];
+static char mms_names[MAX_PORTS][10];
+
+/* Not __exit: called from init() */
+static void fini(void)
+{
+	int i;
+
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+		DEBUGP("ip_nat_mms: unregistering helper for port %d\n", ports[i]);
+		ip_nat_helper_unregister(&mms[i]);
+	}
+}
+
+static int __init init(void)
+{
+	int i, ret = 0;
+	char *tmpname;
+
+	if (ports[0] == 0)
+		ports[0] = MMS_PORT;
+
+	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
+
+		memset(&mms[i], 0, sizeof(struct ip_nat_helper));
+
+		mms[i].tuple.dst.protonum = IPPROTO_TCP;
+		mms[i].tuple.src.u.tcp.port = htons(ports[i]);
+		mms[i].mask.dst.protonum = 0xFFFF;
+		mms[i].mask.src.u.tcp.port = 0xFFFF;
+		mms[i].help = mms_nat_help;
+		mms[i].me = THIS_MODULE;
+		mms[i].flags = 0;
+		mms[i].expect = mms_nat_expected;
+
+		tmpname = &mms_names[i][0];
+		if (ports[i] == MMS_PORT)
+			sprintf(tmpname, "mms");
+		else
+			sprintf(tmpname, "mms-%d", i);
+		mms[i].name = tmpname;
+
+		DEBUGP("ip_nat_mms: register helper for port %d\n",
+				ports[i]);
+		ret = ip_nat_helper_register(&mms[i]);
+
+		if (ret) {
+			printk("ip_nat_mms: error registering "
+			       "helper for port %d\n", ports[i]);
+			fini();
+			return ret;
+		}
+		ports_c++;
+	}
+
+	return ret;
+}
+
+module_init(init);
+module_exit(fini);
diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h	2006-03-01 01:12:47.910002512 +0100
+++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h	2006-03-01 01:16:16.710260048 +0100
@@ -73,6 +73,7 @@
 #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
 #include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
 
 /* per expectation: application helper private data */
 union ip_conntrack_expect_help {
@@ -83,6 +84,7 @@
 	struct ip_ct_pptp_expect exp_pptp_info;
 	struct ip_ct_h225_expect exp_h225_info;
 	struct ip_ct_rtsp_expect exp_rtsp_info;
+	struct ip_ct_mms_expect exp_mms_info;
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
 	union {
@@ -99,6 +101,7 @@
 	struct ip_ct_pptp_master ct_pptp_info;
 	struct ip_ct_h225_master ct_h225_info;
 	struct ip_ct_rtsp_master ct_rtsp_info;
+	struct ip_ct_mms_master ct_mms_info;
 };
 
 #ifdef CONFIG_IP_NF_NAT_NEEDED
diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_mms.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_mms.h
--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_mms.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_mms.h	2006-03-01 01:13:32.993148832 +0100
@@ -0,0 +1,31 @@
+#ifndef _IP_CONNTRACK_MMS_H
+#define _IP_CONNTRACK_MMS_H
+/* MMS tracking. */
+
+#ifdef __KERNEL__
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+DECLARE_LOCK_EXTERN(ip_mms_lock);
+
+#define MMS_PORT                         1755
+#define MMS_SRV_MSG_ID                   196610
+
+#define MMS_SRV_MSG_OFFSET               36
+#define MMS_SRV_UNICODE_STRING_OFFSET    60
+#define MMS_SRV_CHUNKLENLV_OFFSET        16
+#define MMS_SRV_CHUNKLENLM_OFFSET        32
+#define MMS_SRV_MESSAGELENGTH_OFFSET     8
+#endif
+
+/* This structure is per expected connection */
+struct ip_ct_mms_expect {
+	u_int32_t len;
+	u_int32_t padding;
+	u_int16_t port;
+};
+
+/* This structure exists only once per master */
+struct ip_ct_mms_master {
+};
+
+#endif /* _IP_CONNTRACK_MMS_H */