1 --- a/net/ipv4/netfilter/Config.in
2 +++ b/net/ipv4/netfilter/Config.in
3 @@ -15,6 +15,7 @@ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ];
4 dep_tristate ' Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES
5 dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
6 dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
7 + dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK
10 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
11 @@ -110,6 +111,13 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ];
12 define_tristate CONFIG_IP_NF_NAT_AMANDA $CONFIG_IP_NF_NAT
15 + if [ "$CONFIG_IP_NF_H323" = "m" ]; then
16 + define_tristate CONFIG_IP_NF_NAT_H323 m
18 + if [ "$CONFIG_IP_NF_H323" = "y" ]; then
19 + define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT
22 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
23 dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
25 --- a/net/ipv4/netfilter/Makefile
26 +++ b/net/ipv4/netfilter/Makefile
27 @@ -53,6 +53,10 @@ obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack
28 ifdef CONFIG_IP_NF_NAT_PPTP
29 export-objs += ip_conntrack_pptp.o
31 +obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
32 +ifdef CONFIG_IP_NF_NAT_H323
33 + export-objs += ip_conntrack_h323.o
38 @@ -62,6 +66,7 @@ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ft
39 obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
40 obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
41 obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
42 +obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
45 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
47 +++ b/net/ipv4/netfilter/ip_conntrack_h323.c
50 + * H.323 'brute force' extension for H.323 connection tracking.
51 + * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
53 + * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
54 + * (http://www.coritel.it/projects/sofia/nat/)
55 + * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
56 + * the unregistered helpers to the conntrack entries.
60 +#include <linux/module.h>
61 +#include <linux/netfilter.h>
62 +#include <linux/ip.h>
63 +#include <net/checksum.h>
66 +#include <linux/netfilter_ipv4/lockhelp.h>
67 +#include <linux/netfilter_ipv4/ip_conntrack.h>
68 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
69 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
70 +#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
71 +#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
73 +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
74 +MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
75 +MODULE_LICENSE("GPL");
77 +DECLARE_LOCK(ip_h323_lock);
78 +struct module *ip_conntrack_h323 = THIS_MODULE;
80 +#define DEBUGP(format, args...)
82 +static int h245_help(const struct iphdr *iph, size_t len,
83 + struct ip_conntrack *ct,
84 + enum ip_conntrack_info ctinfo)
86 + struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
87 + unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
88 + unsigned char *data_limit;
89 + u_int32_t tcplen = len - iph->ihl * 4;
90 + u_int32_t datalen = tcplen - tcph->doff * 4;
91 + int dir = CTINFO2DIR(ctinfo);
92 + struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
93 + struct ip_conntrack_expect expect, *exp = &expect;
94 + struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
95 + u_int16_t data_port;
99 + DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
100 + NIPQUAD(iph->saddr), ntohs(tcph->source),
101 + NIPQUAD(iph->daddr), ntohs(tcph->dest));
103 + /* Can't track connections formed before we registered */
107 + /* Until there's been traffic both ways, don't look in packets. */
108 + if (ctinfo != IP_CT_ESTABLISHED
109 + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
110 + DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
114 + /* Not whole TCP header or too short packet? */
115 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
116 + DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen);
120 + /* Checksum invalid? Ignore. */
121 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
122 + csum_partial((char *)tcph, tcplen, 0))) {
123 + DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
124 + tcph, tcplen, NIPQUAD(iph->saddr),
125 + NIPQUAD(iph->daddr));
129 + data_limit = (unsigned char *) data + datalen;
132 + for (i = 0; data < (data_limit - 5); data++, i++) {
133 + memcpy(&data_ip, data, sizeof(u_int32_t));
134 + if (data_ip == iph->saddr) {
135 + memcpy(&data_port, data + 4, sizeof(u_int16_t));
136 + memset(&expect, 0, sizeof(expect));
137 + /* update the H.225 info */
138 + DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
139 + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
140 + NIPQUAD(iph->saddr), ntohs(data_port));
141 + LOCK_BH(&ip_h323_lock);
142 + info->is_h225 = H225_PORT + 1;
143 + exp_info->port = data_port;
144 + exp_info->dir = dir;
145 + exp_info->offset = i;
147 + exp->seq = ntohl(tcph->seq) + i;
149 + exp->tuple = ((struct ip_conntrack_tuple)
150 + { { ct->tuplehash[!dir].tuple.src.ip,
155 + exp->mask = ((struct ip_conntrack_tuple)
156 + { { 0xFFFFFFFF, { 0 } },
157 + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
159 + exp->expectfn = NULL;
161 + /* Ignore failure; should only happen with NAT */
162 + ip_conntrack_expect_related(ct, exp);
164 + UNLOCK_BH(&ip_h323_lock);
172 +/* H.245 helper is not registered! */
173 +static struct ip_conntrack_helper h245 =
175 + "H.245", /* name */
176 + IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
178 + 8, /* max_ expected */
180 + { { 0, { 0 } }, /* tuple */
181 + { 0, { 0 }, IPPROTO_TCP } },
182 + { { 0, { 0xFFFF } }, /* mask */
183 + { 0, { 0 }, 0xFFFF } },
184 + h245_help /* helper */
187 +static int h225_expect(struct ip_conntrack *ct)
189 + WRITE_LOCK(&ip_conntrack_lock);
190 + ct->helper = &h245;
191 + DEBUGP("h225_expect: helper for %p added\n", ct);
192 + WRITE_UNLOCK(&ip_conntrack_lock);
194 + return NF_ACCEPT; /* unused */
197 +static int h225_help(const struct iphdr *iph, size_t len,
198 + struct ip_conntrack *ct,
199 + enum ip_conntrack_info ctinfo)
201 + struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
202 + unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
203 + unsigned char *data_limit;
204 + u_int32_t tcplen = len - iph->ihl * 4;
205 + u_int32_t datalen = tcplen - tcph->doff * 4;
206 + int dir = CTINFO2DIR(ctinfo);
207 + struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
208 + struct ip_conntrack_expect expect, *exp = &expect;
209 + struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
210 + u_int16_t data_port;
214 + DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
215 + NIPQUAD(iph->saddr), ntohs(tcph->source),
216 + NIPQUAD(iph->daddr), ntohs(tcph->dest));
218 + /* Can't track connections formed before we registered */
222 + /* Until there's been traffic both ways, don't look in packets. */
223 + if (ctinfo != IP_CT_ESTABLISHED
224 + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
225 + DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo);
229 + /* Not whole TCP header or too short packet? */
230 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
231 + DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen);
235 + /* Checksum invalid? Ignore. */
236 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
237 + csum_partial((char *)tcph, tcplen, 0))) {
238 + DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
239 + tcph, tcplen, NIPQUAD(iph->saddr),
240 + NIPQUAD(iph->daddr));
244 + data_limit = (unsigned char *) data + datalen;
247 + for (i = 0; data < (data_limit - 5); data++, i++) {
248 + memcpy(&data_ip, data, sizeof(u_int32_t));
249 + if (data_ip == iph->saddr) {
250 + memcpy(&data_port, data + 4, sizeof(u_int16_t));
251 + if (data_port == tcph->source) {
252 + /* Signal address */
253 + DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n",
254 + NIPQUAD(iph->saddr));
255 + /* Update the H.225 info so that NAT can mangle the address/port
256 + even when we have no expected connection! */
257 +#ifdef CONFIG_IP_NF_NAT_NEEDED
258 + LOCK_BH(&ip_h323_lock);
260 + info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i;
261 + info->offset[IP_CT_DIR_ORIGINAL] = i;
262 + UNLOCK_BH(&ip_h323_lock);
265 + memset(&expect, 0, sizeof(expect));
267 + /* update the H.225 info */
268 + LOCK_BH(&ip_h323_lock);
269 + info->is_h225 = H225_PORT;
270 + exp_info->port = data_port;
271 + exp_info->dir = dir;
272 + exp_info->offset = i;
274 + exp->seq = ntohl(tcph->seq) + i;
276 + exp->tuple = ((struct ip_conntrack_tuple)
277 + { { ct->tuplehash[!dir].tuple.src.ip,
282 + exp->mask = ((struct ip_conntrack_tuple)
283 + { { 0xFFFFFFFF, { 0 } },
284 + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
286 + exp->expectfn = h225_expect;
288 + /* Ignore failure */
289 + ip_conntrack_expect_related(ct, exp);
291 + DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n",
292 + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
293 + NIPQUAD(iph->saddr), ntohs(data_port));
295 + UNLOCK_BH(&ip_h323_lock);
297 +#ifdef CONFIG_IP_NF_NAT_NEEDED
298 + } else if (data_ip == iph->daddr) {
299 + memcpy(&data_port, data + 4, sizeof(u_int16_t));
300 + if (data_port == tcph->dest) {
301 + /* Signal address */
302 + DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n",
303 + NIPQUAD(iph->daddr));
304 + /* Update the H.225 info so that NAT can mangle the address/port
305 + even when we have no expected connection! */
306 + LOCK_BH(&ip_h323_lock);
308 + info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i;
309 + info->offset[IP_CT_DIR_REPLY] = i;
310 + UNLOCK_BH(&ip_h323_lock);
320 +static struct ip_conntrack_helper h225 =
322 + "H.225", /* name */
323 + IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
324 + THIS_MODULE, /* module */
325 + 2, /* max_expected */
327 + { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
328 + { 0, { 0 }, IPPROTO_TCP } },
329 + { { 0, { 0xFFFF } }, /* mask */
330 + { 0, { 0 }, 0xFFFF } },
331 + h225_help /* helper */
334 +static int __init init(void)
336 + return ip_conntrack_helper_register(&h225);
339 +static void __exit fini(void)
341 + /* Unregister H.225 helper */
342 + ip_conntrack_helper_unregister(&h225);
345 +#ifdef CONFIG_IP_NF_NAT_NEEDED
346 +EXPORT_SYMBOL(ip_h323_lock);
352 +++ b/net/ipv4/netfilter/ip_nat_h323.c
355 + * H.323 'brute force' extension for NAT alteration.
356 + * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
358 + * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
359 + * (http://www.coritel.it/projects/sofia/nat.html)
360 + * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
361 + * the unregistered helpers to the conntrack entries.
365 +#include <linux/module.h>
366 +#include <linux/netfilter.h>
367 +#include <linux/ip.h>
368 +#include <net/checksum.h>
369 +#include <net/tcp.h>
371 +#include <linux/netfilter_ipv4/lockhelp.h>
372 +#include <linux/netfilter_ipv4/ip_nat.h>
373 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
374 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
375 +#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
376 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
377 +#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
379 +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
380 +MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
381 +MODULE_LICENSE("GPL");
383 +DECLARE_LOCK_EXTERN(ip_h323_lock);
384 +struct module *ip_nat_h323 = THIS_MODULE;
386 +#define DEBUGP(format, args...)
390 +h225_nat_expected(struct sk_buff **pskb,
391 + unsigned int hooknum,
392 + struct ip_conntrack *ct,
393 + struct ip_nat_info *info);
395 +static unsigned int h225_nat_help(struct ip_conntrack *ct,
396 + struct ip_conntrack_expect *exp,
397 + struct ip_nat_info *info,
398 + enum ip_conntrack_info ctinfo,
399 + unsigned int hooknum,
400 + struct sk_buff **pskb);
402 +static struct ip_nat_helper h245 =
404 + "H.245", /* name */
407 + { { 0, { 0 } }, /* tuple */
408 + { 0, { 0 }, IPPROTO_TCP } },
409 + { { 0, { 0xFFFF } }, /* mask */
410 + { 0, { 0 }, 0xFFFF } },
411 + h225_nat_help, /* helper */
412 + h225_nat_expected /* expectfn */
416 +h225_nat_expected(struct sk_buff **pskb,
417 + unsigned int hooknum,
418 + struct ip_conntrack *ct,
419 + struct ip_nat_info *info)
421 + struct ip_nat_multi_range mr;
422 + u_int32_t newdstip, newsrcip, newip;
424 + struct ip_ct_h225_expect *exp_info;
425 + struct ip_ct_h225_master *master_info;
426 + struct ip_conntrack *master = master_ct(ct);
427 + unsigned int is_h225, ret;
429 + IP_NF_ASSERT(info);
430 + IP_NF_ASSERT(master);
432 + IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
434 + DEBUGP("h225_nat_expected: We have a connection!\n");
435 + master_info = &ct->master->expectant->help.ct_h225_info;
436 + exp_info = &ct->master->help.exp_h225_info;
438 + LOCK_BH(&ip_h323_lock);
440 + DEBUGP("master: ");
441 + DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
442 + DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
443 + DEBUGP("conntrack: ");
444 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
445 + if (exp_info->dir == IP_CT_DIR_ORIGINAL) {
446 + /* Make connection go to the client. */
447 + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
448 + newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
449 + DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n",
450 + NIPQUAD(newsrcip), NIPQUAD(newdstip));
452 + /* Make the connection go to the server */
453 + newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
454 + newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
455 + DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n",
456 + NIPQUAD(newsrcip), NIPQUAD(newdstip));
458 + port = exp_info->port;
459 + is_h225 = master_info->is_h225 == H225_PORT;
460 + UNLOCK_BH(&ip_h323_lock);
462 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
467 + DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
470 + /* We don't want to manip the per-protocol, just the IPs... */
471 + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
472 + mr.range[0].min_ip = mr.range[0].max_ip = newip;
474 + /* ... unless we're doing a MANIP_DST, in which case, make
475 + sure we map to the correct port */
476 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
477 + mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
478 + mr.range[0].min = mr.range[0].max
479 + = ((union ip_conntrack_manip_proto)
483 + ret = ip_nat_setup_info(ct, &mr, hooknum);
486 + DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct);
487 + /* NAT expectfn called with ip_nat_lock write-locked */
488 + info->helper = &h245;
493 +static int h323_signal_address_fixup(struct ip_conntrack *ct,
494 + struct sk_buff **pskb,
495 + enum ip_conntrack_info ctinfo)
497 + struct iphdr *iph = (*pskb)->nh.iph;
498 + struct tcphdr *tcph = (void *)iph + iph->ihl*4;
499 + unsigned char *data;
500 + u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
501 + u_int32_t datalen = tcplen - tcph->doff*4;
502 + struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
505 + u_int8_t buffer[6];
508 + MUST_BE_LOCKED(&ip_h323_lock);
510 + DEBUGP("h323_signal_address_fixup: %s %s\n",
511 + between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
513 + between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
515 + if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
516 + || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)))
519 + DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n",
520 + info->offset[IP_CT_DIR_ORIGINAL],
521 + info->offset[IP_CT_DIR_REPLY],
523 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
524 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
526 + for (i = 0; i < IP_CT_DIR_MAX; i++) {
527 + DEBUGP("h323_signal_address_fixup: %s %s\n",
528 + info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply",
529 + i == IP_CT_DIR_ORIGINAL ? "caller" : "callee");
530 + if (!between(info->seq[i], ntohl(tcph->seq),
531 + ntohl(tcph->seq) + datalen))
533 + if (!between(info->seq[i] + 6, ntohl(tcph->seq),
534 + ntohl(tcph->seq) + datalen)) {
535 + /* Partial retransmisison. It's a cracker being funky. */
536 + if (net_ratelimit()) {
537 + printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
540 + ntohl(tcph->seq) + datalen);
545 + /* Change address inside packet to match way we're mapping
546 + this connection. */
547 + if (i == IP_CT_DIR_ORIGINAL) {
548 + newip = ct->tuplehash[!info->dir].tuple.dst.ip;
549 + port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
551 + newip = ct->tuplehash[!info->dir].tuple.src.ip;
552 + port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
555 + data = (char *) tcph + tcph->doff * 4 + info->offset[i];
557 + DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n",
558 + i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
559 + data[0], data[1], data[2], data[3],
560 + (data[4] << 8 | data[5]));
562 + /* Modify the packet */
563 + memcpy(buffer, &newip, 4);
564 + memcpy(buffer + 4, &port, 2);
565 + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i],
569 + DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n",
570 + i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
571 + data[0], data[1], data[2], data[3],
572 + (data[4] << 8 | data[5]));
578 +static int h323_data_fixup(struct ip_ct_h225_expect *info,
579 + struct ip_conntrack *ct,
580 + struct sk_buff **pskb,
581 + enum ip_conntrack_info ctinfo,
582 + struct ip_conntrack_expect *expect)
586 + u_int8_t buffer[6];
587 + struct ip_conntrack_tuple newtuple;
588 + struct iphdr *iph = (*pskb)->nh.iph;
589 + struct tcphdr *tcph = (void *)iph + iph->ihl*4;
590 + unsigned char *data;
591 + u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
592 + struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info;
595 + MUST_BE_LOCKED(&ip_h323_lock);
596 + DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen);
597 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
598 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
600 + if (!between(expect->seq + 6, ntohl(tcph->seq),
601 + ntohl(tcph->seq) + tcplen - tcph->doff * 4)) {
602 + /* Partial retransmisison. It's a cracker being funky. */
603 + if (net_ratelimit()) {
604 + printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
607 + ntohl(tcph->seq) + tcplen - tcph->doff * 4);
612 + /* Change address inside packet to match way we're mapping
613 + this connection. */
614 + if (info->dir == IP_CT_DIR_REPLY) {
615 + /* Must be where client thinks server is */
616 + newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
617 + /* Expect something from client->server */
618 + newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
619 + newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
621 + /* Must be where server thinks client is */
622 + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
623 + /* Expect something from server->client */
624 + newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
625 + newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
628 + is_h225 = (master_info->is_h225 == H225_PORT);
631 + newtuple.dst.protonum = IPPROTO_TCP;
632 + newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
634 + newtuple.dst.protonum = IPPROTO_UDP;
635 + newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
638 + /* Try to get same port: if not, try to change it. */
639 + for (port = ntohs(info->port); port != 0; port++) {
641 + newtuple.dst.u.tcp.port = htons(port);
643 + newtuple.dst.u.udp.port = htons(port);
645 + if (ip_conntrack_change_expect(expect, &newtuple) == 0)
649 + DEBUGP("h323_data_fixup: no free port found!\n");
653 + port = htons(port);
655 + data = (char *) tcph + tcph->doff * 4 + info->offset;
657 + DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n",
658 + data[0], data[1], data[2], data[3],
659 + (data[4] << 8 | data[5]));
661 + /* Modify the packet */
662 + memcpy(buffer, &newip, 4);
663 + memcpy(buffer + 4, &port, 2);
664 + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset,
668 + DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n",
669 + data[0], data[1], data[2], data[3],
670 + (data[4] << 8 | data[5]));
675 +static unsigned int h225_nat_help(struct ip_conntrack *ct,
676 + struct ip_conntrack_expect *exp,
677 + struct ip_nat_info *info,
678 + enum ip_conntrack_info ctinfo,
679 + unsigned int hooknum,
680 + struct sk_buff **pskb)
683 + struct ip_ct_h225_expect *exp_info;
685 + /* Only mangle things once: original direction in POST_ROUTING
686 + and reply direction on PRE_ROUTING. */
687 + dir = CTINFO2DIR(ctinfo);
688 + DEBUGP("nat_h323: dir %s at hook %s\n",
689 + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
690 + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
691 + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
692 + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
693 + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
694 + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
695 + DEBUGP("nat_h323: Not touching 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" : "???");
704 + LOCK_BH(&ip_h323_lock);
705 + if (!h323_signal_address_fixup(ct, pskb, ctinfo)) {
706 + UNLOCK_BH(&ip_h323_lock);
709 + UNLOCK_BH(&ip_h323_lock);
713 + exp_info = &exp->help.exp_h225_info;
715 + LOCK_BH(&ip_h323_lock);
716 + if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) {
717 + UNLOCK_BH(&ip_h323_lock);
720 + UNLOCK_BH(&ip_h323_lock);
725 +static struct ip_nat_helper h225 =
727 + "H.225", /* name */
728 + IP_NAT_HELPER_F_ALWAYS, /* flags */
729 + THIS_MODULE, /* module */
730 + { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
731 + { 0, { 0 }, IPPROTO_TCP } },
732 + { { 0, { 0xFFFF } }, /* mask */
733 + { 0, { 0 }, 0xFFFF } },
734 + h225_nat_help, /* helper */
735 + h225_nat_expected /* expectfn */
738 +static int __init init(void)
742 + ret = ip_nat_helper_register(&h225);
745 + printk("ip_nat_h323: cannot initialize the module!\n");
750 +static void __exit fini(void)
752 + ip_nat_helper_unregister(&h225);
757 --- a/include/linux/netfilter_ipv4/ip_conntrack.h
758 +++ b/include/linux/netfilter_ipv4/ip_conntrack.h
759 @@ -71,6 +71,7 @@ union ip_conntrack_expect_proto {
760 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
761 #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
762 #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
763 +#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
765 /* per expectation: application helper private data */
766 union ip_conntrack_expect_help {
767 @@ -79,6 +80,7 @@ union ip_conntrack_expect_help {
768 struct ip_ct_ftp_expect exp_ftp_info;
769 struct ip_ct_irc_expect exp_irc_info;
770 struct ip_ct_pptp_expect exp_pptp_info;
771 + struct ip_ct_h225_expect exp_h225_info;
773 #ifdef CONFIG_IP_NF_NAT_NEEDED
775 @@ -93,6 +95,7 @@ union ip_conntrack_help {
776 struct ip_ct_ftp_master ct_ftp_info;
777 struct ip_ct_irc_master ct_irc_info;
778 struct ip_ct_pptp_master ct_pptp_info;
779 + struct ip_ct_h225_master ct_h225_info;
782 #ifdef CONFIG_IP_NF_NAT_NEEDED
784 +++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
786 +#ifndef _IP_CONNTRACK_H323_H
787 +#define _IP_CONNTRACK_H323_H
788 +/* H.323 connection tracking. */
791 +/* Protects H.323 related data */
792 +DECLARE_LOCK_EXTERN(ip_h323_lock);
795 +/* Default H.225 port */
796 +#define H225_PORT 1720
798 +/* This structure is per expected connection */
799 +struct ip_ct_h225_expect {
800 + u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */
801 + enum ip_conntrack_dir dir; /* Direction of the original connection */
802 + unsigned int offset; /* offset of the address in the payload */
805 +/* This structure exists only once per master */
806 +struct ip_ct_h225_master {
807 + int is_h225; /* H.225 or H.245 connection */
808 +#ifdef CONFIG_IP_NF_NAT_NEEDED
809 + enum ip_conntrack_dir dir; /* Direction of the original connection */
810 + u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */
811 + unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */
815 +#endif /* _IP_CONNTRACK_H323_H */