merge r17552 to 8.09
[openwrt/svn-archive/archive.git] / target / linux / generic-2.4 / patches / 613-netfilter_nat_h323.patch
1 Index: linux-2.4.35.4/net/ipv4/netfilter/Config.in
2 ===================================================================
3 --- linux-2.4.35.4.orig/net/ipv4/netfilter/Config.in 2009-06-06 22:34:34.000000000 +0000
4 +++ linux-2.4.35.4/net/ipv4/netfilter/Config.in 2009-06-06 22:37:34.000000000 +0000
5 @@ -13,6 +13,7 @@
6 dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
7 dep_tristate ' Connection tracking flow accounting' CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK
8 dep_tristate ' Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES
9 + dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK
10 fi
11
12 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
13 @@ -94,6 +95,13 @@
14 define_tristate CONFIG_IP_NF_NAT_AMANDA $CONFIG_IP_NF_NAT
15 fi
16 fi
17 + if [ "$CONFIG_IP_NF_H323" = "m" ]; then
18 + define_tristate CONFIG_IP_NF_NAT_H323 m
19 + else
20 + if [ "$CONFIG_IP_NF_H323" = "y" ]; then
21 + define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT
22 + fi
23 + fi
24 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
25 dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
26 fi
27 Index: linux-2.4.35.4/net/ipv4/netfilter/Makefile
28 ===================================================================
29 --- linux-2.4.35.4.orig/net/ipv4/netfilter/Makefile 2009-06-06 22:34:34.000000000 +0000
30 +++ linux-2.4.35.4/net/ipv4/netfilter/Makefile 2009-06-06 22:46:32.000000000 +0000
31 @@ -47,12 +47,17 @@
32 ifdef CONFIG_IP_NF_IRC
33 export-objs += ip_conntrack_irc.o
34 endif
35 +obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
36 +ifdef CONFIG_IP_NF_NAT_H323
37 + export-objs += ip_conntrack_h323.o
38 +endif
39
40 # NAT helpers
41 obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
42 obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
43 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
44 obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
45 +obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
46
47 # generic IP tables
48 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
49 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_h323.c
50 ===================================================================
51 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
52 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_h323.c 2009-06-06 22:34:50.000000000 +0000
53 @@ -0,0 +1,302 @@
54 +/*
55 + * H.323 'brute force' extension for H.323 connection tracking.
56 + * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
57 + *
58 + * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
59 + * (http://www.coritel.it/projects/sofia/nat/)
60 + * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
61 + * the unregistered helpers to the conntrack entries.
62 + */
63 +
64 +
65 +#include <linux/module.h>
66 +#include <linux/netfilter.h>
67 +#include <linux/ip.h>
68 +#include <net/checksum.h>
69 +#include <net/tcp.h>
70 +
71 +#include <linux/netfilter_ipv4/lockhelp.h>
72 +#include <linux/netfilter_ipv4/ip_conntrack.h>
73 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
74 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
75 +#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
76 +#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
77 +
78 +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
79 +MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
80 +MODULE_LICENSE("GPL");
81 +
82 +DECLARE_LOCK(ip_h323_lock);
83 +struct module *ip_conntrack_h323 = THIS_MODULE;
84 +
85 +#define DEBUGP(format, args...)
86 +
87 +static int h245_help(const struct iphdr *iph, size_t len,
88 + struct ip_conntrack *ct,
89 + enum ip_conntrack_info ctinfo)
90 +{
91 + struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
92 + unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
93 + unsigned char *data_limit;
94 + u_int32_t tcplen = len - iph->ihl * 4;
95 + u_int32_t datalen = tcplen - tcph->doff * 4;
96 + int dir = CTINFO2DIR(ctinfo);
97 + struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
98 + struct ip_conntrack_expect expect, *exp = &expect;
99 + struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
100 + u_int16_t data_port;
101 + u_int32_t data_ip;
102 + unsigned int i;
103 +
104 + DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
105 + NIPQUAD(iph->saddr), ntohs(tcph->source),
106 + NIPQUAD(iph->daddr), ntohs(tcph->dest));
107 +
108 + /* Can't track connections formed before we registered */
109 + if (!info)
110 + return NF_ACCEPT;
111 +
112 + /* Until there's been traffic both ways, don't look in packets. */
113 + if (ctinfo != IP_CT_ESTABLISHED
114 + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
115 + DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
116 + return NF_ACCEPT;
117 + }
118 +
119 + /* Not whole TCP header or too short packet? */
120 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
121 + DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen);
122 + return NF_ACCEPT;
123 + }
124 +
125 + /* Checksum invalid? Ignore. */
126 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
127 + csum_partial((char *)tcph, tcplen, 0))) {
128 + DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
129 + tcph, tcplen, NIPQUAD(iph->saddr),
130 + NIPQUAD(iph->daddr));
131 + return NF_ACCEPT;
132 + }
133 +
134 + data_limit = (unsigned char *) data + datalen;
135 + /* bytes: 0123 45
136 + ipadrr port */
137 + for (i = 0; data < (data_limit - 5); data++, i++) {
138 + memcpy(&data_ip, data, sizeof(u_int32_t));
139 + if (data_ip == iph->saddr) {
140 + memcpy(&data_port, data + 4, sizeof(u_int16_t));
141 + memset(&expect, 0, sizeof(expect));
142 + /* update the H.225 info */
143 + DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
144 + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
145 + NIPQUAD(iph->saddr), ntohs(data_port));
146 + LOCK_BH(&ip_h323_lock);
147 + info->is_h225 = H225_PORT + 1;
148 + exp_info->port = data_port;
149 + exp_info->dir = dir;
150 + exp_info->offset = i;
151 +
152 + exp->seq = ntohl(tcph->seq) + i;
153 +
154 + exp->tuple = ((struct ip_conntrack_tuple)
155 + { { ct->tuplehash[!dir].tuple.src.ip,
156 + { 0 } },
157 + { data_ip,
158 + { data_port },
159 + IPPROTO_UDP }});
160 + exp->mask = ((struct ip_conntrack_tuple)
161 + { { 0xFFFFFFFF, { 0 } },
162 + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
163 +
164 + exp->expectfn = NULL;
165 +
166 + /* Ignore failure; should only happen with NAT */
167 + ip_conntrack_expect_related(ct, exp);
168 +
169 + UNLOCK_BH(&ip_h323_lock);
170 + }
171 + }
172 +
173 + return NF_ACCEPT;
174 +
175 +}
176 +
177 +/* H.245 helper is not registered! */
178 +static struct ip_conntrack_helper h245 =
179 + { { NULL, NULL },
180 + "H.245", /* name */
181 + IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
182 + NULL, /* module */
183 + 8, /* max_ expected */
184 + 240, /* timeout */
185 + { { 0, { 0 } }, /* tuple */
186 + { 0, { 0 }, IPPROTO_TCP } },
187 + { { 0, { 0xFFFF } }, /* mask */
188 + { 0, { 0 }, 0xFFFF } },
189 + h245_help /* helper */
190 + };
191 +
192 +static int h225_expect(struct ip_conntrack *ct)
193 +{
194 + WRITE_LOCK(&ip_conntrack_lock);
195 + ct->helper = &h245;
196 + DEBUGP("h225_expect: helper for %p added\n", ct);
197 + WRITE_UNLOCK(&ip_conntrack_lock);
198 +
199 + return NF_ACCEPT; /* unused */
200 +}
201 +
202 +static int h225_help(const struct iphdr *iph, size_t len,
203 + struct ip_conntrack *ct,
204 + enum ip_conntrack_info ctinfo)
205 +{
206 + struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
207 + unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
208 + unsigned char *data_limit;
209 + u_int32_t tcplen = len - iph->ihl * 4;
210 + u_int32_t datalen = tcplen - tcph->doff * 4;
211 + int dir = CTINFO2DIR(ctinfo);
212 + struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
213 + struct ip_conntrack_expect expect, *exp = &expect;
214 + struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
215 + u_int16_t data_port;
216 + u_int32_t data_ip;
217 + unsigned int i;
218 +
219 + DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
220 + NIPQUAD(iph->saddr), ntohs(tcph->source),
221 + NIPQUAD(iph->daddr), ntohs(tcph->dest));
222 +
223 + /* Can't track connections formed before we registered */
224 + if (!info)
225 + return NF_ACCEPT;
226 +
227 + /* Until there's been traffic both ways, don't look in packets. */
228 + if (ctinfo != IP_CT_ESTABLISHED
229 + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
230 + DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo);
231 + return NF_ACCEPT;
232 + }
233 +
234 + /* Not whole TCP header or too short packet? */
235 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
236 + DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen);
237 + return NF_ACCEPT;
238 + }
239 +
240 + /* Checksum invalid? Ignore. */
241 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
242 + csum_partial((char *)tcph, tcplen, 0))) {
243 + DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
244 + tcph, tcplen, NIPQUAD(iph->saddr),
245 + NIPQUAD(iph->daddr));
246 + return NF_ACCEPT;
247 + }
248 +
249 + data_limit = (unsigned char *) data + datalen;
250 + /* bytes: 0123 45
251 + ipadrr port */
252 + for (i = 0; data < (data_limit - 5); data++, i++) {
253 + memcpy(&data_ip, data, sizeof(u_int32_t));
254 + if (data_ip == iph->saddr) {
255 + memcpy(&data_port, data + 4, sizeof(u_int16_t));
256 + if (data_port == tcph->source) {
257 + /* Signal address */
258 + DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n",
259 + NIPQUAD(iph->saddr));
260 + /* Update the H.225 info so that NAT can mangle the address/port
261 + even when we have no expected connection! */
262 +#ifdef CONFIG_IP_NF_NAT_NEEDED
263 + LOCK_BH(&ip_h323_lock);
264 + info->dir = dir;
265 + info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i;
266 + info->offset[IP_CT_DIR_ORIGINAL] = i;
267 + UNLOCK_BH(&ip_h323_lock);
268 +#endif
269 + } else {
270 + memset(&expect, 0, sizeof(expect));
271 +
272 + /* update the H.225 info */
273 + LOCK_BH(&ip_h323_lock);
274 + info->is_h225 = H225_PORT;
275 + exp_info->port = data_port;
276 + exp_info->dir = dir;
277 + exp_info->offset = i;
278 +
279 + exp->seq = ntohl(tcph->seq) + i;
280 +
281 + exp->tuple = ((struct ip_conntrack_tuple)
282 + { { ct->tuplehash[!dir].tuple.src.ip,
283 + { 0 } },
284 + { data_ip,
285 + { data_port },
286 + IPPROTO_TCP }});
287 + exp->mask = ((struct ip_conntrack_tuple)
288 + { { 0xFFFFFFFF, { 0 } },
289 + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
290 +
291 + exp->expectfn = h225_expect;
292 +
293 + /* Ignore failure */
294 + ip_conntrack_expect_related(ct, exp);
295 +
296 + DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n",
297 + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
298 + NIPQUAD(iph->saddr), ntohs(data_port));
299 +
300 + UNLOCK_BH(&ip_h323_lock);
301 + }
302 +#ifdef CONFIG_IP_NF_NAT_NEEDED
303 + } else if (data_ip == iph->daddr) {
304 + memcpy(&data_port, data + 4, sizeof(u_int16_t));
305 + if (data_port == tcph->dest) {
306 + /* Signal address */
307 + DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n",
308 + NIPQUAD(iph->daddr));
309 + /* Update the H.225 info so that NAT can mangle the address/port
310 + even when we have no expected connection! */
311 + LOCK_BH(&ip_h323_lock);
312 + info->dir = dir;
313 + info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i;
314 + info->offset[IP_CT_DIR_REPLY] = i;
315 + UNLOCK_BH(&ip_h323_lock);
316 + }
317 +#endif
318 + }
319 + }
320 +
321 + return NF_ACCEPT;
322 +
323 +}
324 +
325 +static struct ip_conntrack_helper h225 =
326 + { { NULL, NULL },
327 + "H.225", /* name */
328 + IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
329 + THIS_MODULE, /* module */
330 + 2, /* max_expected */
331 + 240, /* timeout */
332 + { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
333 + { 0, { 0 }, IPPROTO_TCP } },
334 + { { 0, { 0xFFFF } }, /* mask */
335 + { 0, { 0 }, 0xFFFF } },
336 + h225_help /* helper */
337 + };
338 +
339 +static int __init init(void)
340 +{
341 + return ip_conntrack_helper_register(&h225);
342 +}
343 +
344 +static void __exit fini(void)
345 +{
346 + /* Unregister H.225 helper */
347 + ip_conntrack_helper_unregister(&h225);
348 +}
349 +
350 +#ifdef CONFIG_IP_NF_NAT_NEEDED
351 +EXPORT_SYMBOL(ip_h323_lock);
352 +#endif
353 +
354 +module_init(init);
355 +module_exit(fini);
356 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_h323.c
357 ===================================================================
358 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
359 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_h323.c 2009-06-06 22:34:50.000000000 +0000
360 @@ -0,0 +1,403 @@
361 +/*
362 + * H.323 'brute force' extension for NAT alteration.
363 + * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
364 + *
365 + * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
366 + * (http://www.coritel.it/projects/sofia/nat.html)
367 + * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
368 + * the unregistered helpers to the conntrack entries.
369 + */
370 +
371 +
372 +#include <linux/module.h>
373 +#include <linux/netfilter.h>
374 +#include <linux/ip.h>
375 +#include <net/checksum.h>
376 +#include <net/tcp.h>
377 +
378 +#include <linux/netfilter_ipv4/lockhelp.h>
379 +#include <linux/netfilter_ipv4/ip_nat.h>
380 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
381 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
382 +#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
383 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
384 +#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
385 +
386 +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
387 +MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
388 +MODULE_LICENSE("GPL");
389 +
390 +DECLARE_LOCK_EXTERN(ip_h323_lock);
391 +struct module *ip_nat_h323 = THIS_MODULE;
392 +
393 +#define DEBUGP(format, args...)
394 +
395 +
396 +static unsigned int
397 +h225_nat_expected(struct sk_buff **pskb,
398 + unsigned int hooknum,
399 + struct ip_conntrack *ct,
400 + struct ip_nat_info *info);
401 +
402 +static unsigned int h225_nat_help(struct ip_conntrack *ct,
403 + struct ip_conntrack_expect *exp,
404 + struct ip_nat_info *info,
405 + enum ip_conntrack_info ctinfo,
406 + unsigned int hooknum,
407 + struct sk_buff **pskb);
408 +
409 +static struct ip_nat_helper h245 =
410 + { { NULL, NULL },
411 + "H.245", /* name */
412 + 0, /* flags */
413 + NULL, /* module */
414 + { { 0, { 0 } }, /* tuple */
415 + { 0, { 0 }, IPPROTO_TCP } },
416 + { { 0, { 0xFFFF } }, /* mask */
417 + { 0, { 0 }, 0xFFFF } },
418 + h225_nat_help, /* helper */
419 + h225_nat_expected /* expectfn */
420 + };
421 +
422 +static unsigned int
423 +h225_nat_expected(struct sk_buff **pskb,
424 + unsigned int hooknum,
425 + struct ip_conntrack *ct,
426 + struct ip_nat_info *info)
427 +{
428 + struct ip_nat_multi_range mr;
429 + u_int32_t newdstip, newsrcip, newip;
430 + u_int16_t port;
431 + struct ip_ct_h225_expect *exp_info;
432 + struct ip_ct_h225_master *master_info;
433 + struct ip_conntrack *master = master_ct(ct);
434 + unsigned int is_h225, ret;
435 +
436 + IP_NF_ASSERT(info);
437 + IP_NF_ASSERT(master);
438 +
439 + IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
440 +
441 + DEBUGP("h225_nat_expected: We have a connection!\n");
442 + master_info = &ct->master->expectant->help.ct_h225_info;
443 + exp_info = &ct->master->help.exp_h225_info;
444 +
445 + LOCK_BH(&ip_h323_lock);
446 +
447 + DEBUGP("master: ");
448 + DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
449 + DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
450 + DEBUGP("conntrack: ");
451 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
452 + if (exp_info->dir == IP_CT_DIR_ORIGINAL) {
453 + /* Make connection go to the client. */
454 + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
455 + newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
456 + DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n",
457 + NIPQUAD(newsrcip), NIPQUAD(newdstip));
458 + } else {
459 + /* Make the connection go to the server */
460 + newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
461 + newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
462 + DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n",
463 + NIPQUAD(newsrcip), NIPQUAD(newdstip));
464 + }
465 + port = exp_info->port;
466 + is_h225 = master_info->is_h225 == H225_PORT;
467 + UNLOCK_BH(&ip_h323_lock);
468 +
469 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
470 + newip = newsrcip;
471 + else
472 + newip = newdstip;
473 +
474 + DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
475 +
476 + mr.rangesize = 1;
477 + /* We don't want to manip the per-protocol, just the IPs... */
478 + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
479 + mr.range[0].min_ip = mr.range[0].max_ip = newip;
480 +
481 + /* ... unless we're doing a MANIP_DST, in which case, make
482 + sure we map to the correct port */
483 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
484 + mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
485 + mr.range[0].min = mr.range[0].max
486 + = ((union ip_conntrack_manip_proto)
487 + { port });
488 + }
489 +
490 + ret = ip_nat_setup_info(ct, &mr, hooknum);
491 +
492 + if (is_h225) {
493 + DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct);
494 + /* NAT expectfn called with ip_nat_lock write-locked */
495 + info->helper = &h245;
496 + }
497 + return ret;
498 +}
499 +
500 +static int h323_signal_address_fixup(struct ip_conntrack *ct,
501 + struct sk_buff **pskb,
502 + enum ip_conntrack_info ctinfo)
503 +{
504 + struct iphdr *iph = (*pskb)->nh.iph;
505 + struct tcphdr *tcph = (void *)iph + iph->ihl*4;
506 + unsigned char *data;
507 + u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
508 + u_int32_t datalen = tcplen - tcph->doff*4;
509 + struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
510 + u_int32_t newip;
511 + u_int16_t port;
512 + u_int8_t buffer[6];
513 + int i;
514 +
515 + MUST_BE_LOCKED(&ip_h323_lock);
516 +
517 + DEBUGP("h323_signal_address_fixup: %s %s\n",
518 + between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
519 + ? "yes" : "no",
520 + between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
521 + ? "yes" : "no");
522 + if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
523 + || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)))
524 + return 1;
525 +
526 + DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n",
527 + info->offset[IP_CT_DIR_ORIGINAL],
528 + info->offset[IP_CT_DIR_REPLY],
529 + tcplen);
530 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
531 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
532 +
533 + for (i = 0; i < IP_CT_DIR_MAX; i++) {
534 + DEBUGP("h323_signal_address_fixup: %s %s\n",
535 + info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply",
536 + i == IP_CT_DIR_ORIGINAL ? "caller" : "callee");
537 + if (!between(info->seq[i], ntohl(tcph->seq),
538 + ntohl(tcph->seq) + datalen))
539 + continue;
540 + if (!between(info->seq[i] + 6, ntohl(tcph->seq),
541 + ntohl(tcph->seq) + datalen)) {
542 + /* Partial retransmisison. It's a cracker being funky. */
543 + if (net_ratelimit()) {
544 + printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
545 + info->seq[i],
546 + ntohl(tcph->seq),
547 + ntohl(tcph->seq) + datalen);
548 + }
549 + return 0;
550 + }
551 +
552 + /* Change address inside packet to match way we're mapping
553 + this connection. */
554 + if (i == IP_CT_DIR_ORIGINAL) {
555 + newip = ct->tuplehash[!info->dir].tuple.dst.ip;
556 + port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
557 + } else {
558 + newip = ct->tuplehash[!info->dir].tuple.src.ip;
559 + port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
560 + }
561 +
562 + data = (char *) tcph + tcph->doff * 4 + info->offset[i];
563 +
564 + DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n",
565 + i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
566 + data[0], data[1], data[2], data[3],
567 + (data[4] << 8 | data[5]));
568 +
569 + /* Modify the packet */
570 + memcpy(buffer, &newip, 4);
571 + memcpy(buffer + 4, &port, 2);
572 + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i],
573 + 6, buffer, 6))
574 + return 0;
575 +
576 + DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n",
577 + i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
578 + data[0], data[1], data[2], data[3],
579 + (data[4] << 8 | data[5]));
580 + }
581 +
582 + return 1;
583 +}
584 +
585 +static int h323_data_fixup(struct ip_ct_h225_expect *info,
586 + struct ip_conntrack *ct,
587 + struct sk_buff **pskb,
588 + enum ip_conntrack_info ctinfo,
589 + struct ip_conntrack_expect *expect)
590 +{
591 + u_int32_t newip;
592 + u_int16_t port;
593 + u_int8_t buffer[6];
594 + struct ip_conntrack_tuple newtuple;
595 + struct iphdr *iph = (*pskb)->nh.iph;
596 + struct tcphdr *tcph = (void *)iph + iph->ihl*4;
597 + unsigned char *data;
598 + u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
599 + struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info;
600 + int is_h225;
601 +
602 + MUST_BE_LOCKED(&ip_h323_lock);
603 + DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen);
604 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
605 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
606 +
607 + if (!between(expect->seq + 6, ntohl(tcph->seq),
608 + ntohl(tcph->seq) + tcplen - tcph->doff * 4)) {
609 + /* Partial retransmisison. It's a cracker being funky. */
610 + if (net_ratelimit()) {
611 + printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
612 + expect->seq,
613 + ntohl(tcph->seq),
614 + ntohl(tcph->seq) + tcplen - tcph->doff * 4);
615 + }
616 + return 0;
617 + }
618 +
619 + /* Change address inside packet to match way we're mapping
620 + this connection. */
621 + if (info->dir == IP_CT_DIR_REPLY) {
622 + /* Must be where client thinks server is */
623 + newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
624 + /* Expect something from client->server */
625 + newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
626 + newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
627 + } else {
628 + /* Must be where server thinks client is */
629 + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
630 + /* Expect something from server->client */
631 + newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
632 + newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
633 + }
634 +
635 + is_h225 = (master_info->is_h225 == H225_PORT);
636 +
637 + if (is_h225) {
638 + newtuple.dst.protonum = IPPROTO_TCP;
639 + newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
640 + } else {
641 + newtuple.dst.protonum = IPPROTO_UDP;
642 + newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
643 + }
644 +
645 + /* Try to get same port: if not, try to change it. */
646 + for (port = ntohs(info->port); port != 0; port++) {
647 + if (is_h225)
648 + newtuple.dst.u.tcp.port = htons(port);
649 + else
650 + newtuple.dst.u.udp.port = htons(port);
651 +
652 + if (ip_conntrack_change_expect(expect, &newtuple) == 0)
653 + break;
654 + }
655 + if (port == 0) {
656 + DEBUGP("h323_data_fixup: no free port found!\n");
657 + return 0;
658 + }
659 +
660 + port = htons(port);
661 +
662 + data = (char *) tcph + tcph->doff * 4 + info->offset;
663 +
664 + DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n",
665 + data[0], data[1], data[2], data[3],
666 + (data[4] << 8 | data[5]));
667 +
668 + /* Modify the packet */
669 + memcpy(buffer, &newip, 4);
670 + memcpy(buffer + 4, &port, 2);
671 + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset,
672 + 6, buffer, 6))
673 + return 0;
674 +
675 + DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n",
676 + data[0], data[1], data[2], data[3],
677 + (data[4] << 8 | data[5]));
678 +
679 + return 1;
680 +}
681 +
682 +static unsigned int h225_nat_help(struct ip_conntrack *ct,
683 + struct ip_conntrack_expect *exp,
684 + struct ip_nat_info *info,
685 + enum ip_conntrack_info ctinfo,
686 + unsigned int hooknum,
687 + struct sk_buff **pskb)
688 +{
689 + int dir;
690 + struct ip_ct_h225_expect *exp_info;
691 +
692 + /* Only mangle things once: original direction in POST_ROUTING
693 + and reply direction on PRE_ROUTING. */
694 + dir = CTINFO2DIR(ctinfo);
695 + DEBUGP("nat_h323: dir %s at hook %s\n",
696 + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
697 + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
698 + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
699 + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
700 + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
701 + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
702 + DEBUGP("nat_h323: Not touching dir %s at hook %s\n",
703 + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
704 + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
705 + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
706 + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
707 + return NF_ACCEPT;
708 + }
709 +
710 + if (!exp) {
711 + LOCK_BH(&ip_h323_lock);
712 + if (!h323_signal_address_fixup(ct, pskb, ctinfo)) {
713 + UNLOCK_BH(&ip_h323_lock);
714 + return NF_DROP;
715 + }
716 + UNLOCK_BH(&ip_h323_lock);
717 + return NF_ACCEPT;
718 + }
719 +
720 + exp_info = &exp->help.exp_h225_info;
721 +
722 + LOCK_BH(&ip_h323_lock);
723 + if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) {
724 + UNLOCK_BH(&ip_h323_lock);
725 + return NF_DROP;
726 + }
727 + UNLOCK_BH(&ip_h323_lock);
728 +
729 + return NF_ACCEPT;
730 +}
731 +
732 +static struct ip_nat_helper h225 =
733 + { { NULL, NULL },
734 + "H.225", /* name */
735 + IP_NAT_HELPER_F_ALWAYS, /* flags */
736 + THIS_MODULE, /* module */
737 + { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
738 + { 0, { 0 }, IPPROTO_TCP } },
739 + { { 0, { 0xFFFF } }, /* mask */
740 + { 0, { 0 }, 0xFFFF } },
741 + h225_nat_help, /* helper */
742 + h225_nat_expected /* expectfn */
743 + };
744 +
745 +static int __init init(void)
746 +{
747 + int ret;
748 +
749 + ret = ip_nat_helper_register(&h225);
750 +
751 + if (ret != 0)
752 + printk("ip_nat_h323: cannot initialize the module!\n");
753 +
754 + return ret;
755 +}
756 +
757 +static void __exit fini(void)
758 +{
759 + ip_nat_helper_unregister(&h225);
760 +}
761 +
762 +module_init(init);
763 +module_exit(fini);
764 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack.h
765 ===================================================================
766 --- linux-2.4.35.4.orig/include/linux/netfilter_ipv4/ip_conntrack.h 2009-06-06 22:06:48.000000000 +0000
767 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack.h 2009-06-06 22:53:09.000000000 +0000
768 @@ -67,6 +67,7 @@
769
770 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
771 #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
772 +#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
773
774 /* per expectation: application helper private data */
775 union ip_conntrack_expect_help {
776 @@ -74,6 +75,7 @@
777 struct ip_ct_amanda_expect exp_amanda_info;
778 struct ip_ct_ftp_expect exp_ftp_info;
779 struct ip_ct_irc_expect exp_irc_info;
780 + struct ip_ct_h225_expect exp_h225_info;
781
782 #ifdef CONFIG_IP_NF_NAT_NEEDED
783 union {
784 @@ -87,6 +89,7 @@
785 /* insert conntrack helper private data (master) here */
786 struct ip_ct_ftp_master ct_ftp_info;
787 struct ip_ct_irc_master ct_irc_info;
788 + struct ip_ct_h225_master ct_h225_info;
789 };
790
791 #ifdef CONFIG_IP_NF_NAT_NEEDED
792 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack_h323.h
793 ===================================================================
794 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
795 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2009-06-06 22:34:50.000000000 +0000
796 @@ -0,0 +1,30 @@
797 +#ifndef _IP_CONNTRACK_H323_H
798 +#define _IP_CONNTRACK_H323_H
799 +/* H.323 connection tracking. */
800 +
801 +#ifdef __KERNEL__
802 +/* Protects H.323 related data */
803 +DECLARE_LOCK_EXTERN(ip_h323_lock);
804 +#endif
805 +
806 +/* Default H.225 port */
807 +#define H225_PORT 1720
808 +
809 +/* This structure is per expected connection */
810 +struct ip_ct_h225_expect {
811 + u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */
812 + enum ip_conntrack_dir dir; /* Direction of the original connection */
813 + unsigned int offset; /* offset of the address in the payload */
814 +};
815 +
816 +/* This structure exists only once per master */
817 +struct ip_ct_h225_master {
818 + int is_h225; /* H.225 or H.245 connection */
819 +#ifdef CONFIG_IP_NF_NAT_NEEDED
820 + enum ip_conntrack_dir dir; /* Direction of the original connection */
821 + u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */
822 + unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */
823 +#endif
824 +};
825 +
826 +#endif /* _IP_CONNTRACK_H323_H */