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