1 --- a/net/ipv4/netfilter/Config.in
2 +++ b/net/ipv4/netfilter/Config.in
3 @@ -13,6 +13,7 @@ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ];
4 dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
5 dep_tristate ' Connection tracking flow accounting' CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK
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 ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK
10 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
11 @@ -94,6 +95,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 @@ -47,12 +47,17 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_
28 ifdef CONFIG_IP_NF_IRC
29 export-objs += ip_conntrack_irc.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
37 obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
38 obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
39 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
40 obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
41 +obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
44 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
46 +++ b/net/ipv4/netfilter/ip_conntrack_h323.c
49 + * H.323 'brute force' extension for H.323 connection tracking.
50 + * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
52 + * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
53 + * (http://www.coritel.it/projects/sofia/nat/)
54 + * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
55 + * the unregistered helpers to the conntrack entries.
59 +#include <linux/module.h>
60 +#include <linux/netfilter.h>
61 +#include <linux/ip.h>
62 +#include <net/checksum.h>
65 +#include <linux/netfilter_ipv4/lockhelp.h>
66 +#include <linux/netfilter_ipv4/ip_conntrack.h>
67 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
68 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
69 +#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
70 +#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
72 +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
73 +MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
74 +MODULE_LICENSE("GPL");
76 +DECLARE_LOCK(ip_h323_lock);
77 +struct module *ip_conntrack_h323 = THIS_MODULE;
79 +#define DEBUGP(format, args...)
81 +static int h245_help(const struct iphdr *iph, size_t len,
82 + struct ip_conntrack *ct,
83 + enum ip_conntrack_info ctinfo)
85 + struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
86 + unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
87 + unsigned char *data_limit;
88 + u_int32_t tcplen = len - iph->ihl * 4;
89 + u_int32_t datalen = tcplen - tcph->doff * 4;
90 + int dir = CTINFO2DIR(ctinfo);
91 + struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
92 + struct ip_conntrack_expect expect, *exp = &expect;
93 + struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
94 + u_int16_t data_port;
98 + DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
99 + NIPQUAD(iph->saddr), ntohs(tcph->source),
100 + NIPQUAD(iph->daddr), ntohs(tcph->dest));
102 + /* Can't track connections formed before we registered */
106 + /* Until there's been traffic both ways, don't look in packets. */
107 + if (ctinfo != IP_CT_ESTABLISHED
108 + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
109 + DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
113 + /* Not whole TCP header or too short packet? */
114 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
115 + DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen);
119 + /* Checksum invalid? Ignore. */
120 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
121 + csum_partial((char *)tcph, tcplen, 0))) {
122 + DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
123 + tcph, tcplen, NIPQUAD(iph->saddr),
124 + NIPQUAD(iph->daddr));
128 + data_limit = (unsigned char *) data + datalen;
131 + for (i = 0; data < (data_limit - 5); data++, i++) {
132 + memcpy(&data_ip, data, sizeof(u_int32_t));
133 + if (data_ip == iph->saddr) {
134 + memcpy(&data_port, data + 4, sizeof(u_int16_t));
135 + memset(&expect, 0, sizeof(expect));
136 + /* update the H.225 info */
137 + DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
138 + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
139 + NIPQUAD(iph->saddr), ntohs(data_port));
140 + LOCK_BH(&ip_h323_lock);
141 + info->is_h225 = H225_PORT + 1;
142 + exp_info->port = data_port;
143 + exp_info->dir = dir;
144 + exp_info->offset = i;
146 + exp->seq = ntohl(tcph->seq) + i;
148 + exp->tuple = ((struct ip_conntrack_tuple)
149 + { { ct->tuplehash[!dir].tuple.src.ip,
154 + exp->mask = ((struct ip_conntrack_tuple)
155 + { { 0xFFFFFFFF, { 0 } },
156 + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
158 + exp->expectfn = NULL;
160 + /* Ignore failure; should only happen with NAT */
161 + ip_conntrack_expect_related(ct, exp);
163 + UNLOCK_BH(&ip_h323_lock);
171 +/* H.245 helper is not registered! */
172 +static struct ip_conntrack_helper h245 =
174 + "H.245", /* name */
175 + IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
177 + 8, /* max_ expected */
179 + { { 0, { 0 } }, /* tuple */
180 + { 0, { 0 }, IPPROTO_TCP } },
181 + { { 0, { 0xFFFF } }, /* mask */
182 + { 0, { 0 }, 0xFFFF } },
183 + h245_help /* helper */
186 +static int h225_expect(struct ip_conntrack *ct)
188 + WRITE_LOCK(&ip_conntrack_lock);
189 + ct->helper = &h245;
190 + DEBUGP("h225_expect: helper for %p added\n", ct);
191 + WRITE_UNLOCK(&ip_conntrack_lock);
193 + return NF_ACCEPT; /* unused */
196 +static int h225_help(const struct iphdr *iph, size_t len,
197 + struct ip_conntrack *ct,
198 + enum ip_conntrack_info ctinfo)
200 + struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
201 + unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
202 + unsigned char *data_limit;
203 + u_int32_t tcplen = len - iph->ihl * 4;
204 + u_int32_t datalen = tcplen - tcph->doff * 4;
205 + int dir = CTINFO2DIR(ctinfo);
206 + struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
207 + struct ip_conntrack_expect expect, *exp = &expect;
208 + struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
209 + u_int16_t data_port;
213 + DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
214 + NIPQUAD(iph->saddr), ntohs(tcph->source),
215 + NIPQUAD(iph->daddr), ntohs(tcph->dest));
217 + /* Can't track connections formed before we registered */
221 + /* Until there's been traffic both ways, don't look in packets. */
222 + if (ctinfo != IP_CT_ESTABLISHED
223 + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
224 + DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo);
228 + /* Not whole TCP header or too short packet? */
229 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
230 + DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen);
234 + /* Checksum invalid? Ignore. */
235 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
236 + csum_partial((char *)tcph, tcplen, 0))) {
237 + DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
238 + tcph, tcplen, NIPQUAD(iph->saddr),
239 + NIPQUAD(iph->daddr));
243 + data_limit = (unsigned char *) data + datalen;
246 + for (i = 0; data < (data_limit - 5); data++, i++) {
247 + memcpy(&data_ip, data, sizeof(u_int32_t));
248 + if (data_ip == iph->saddr) {
249 + memcpy(&data_port, data + 4, sizeof(u_int16_t));
250 + if (data_port == tcph->source) {
251 + /* Signal address */
252 + DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n",
253 + NIPQUAD(iph->saddr));
254 + /* Update the H.225 info so that NAT can mangle the address/port
255 + even when we have no expected connection! */
256 +#ifdef CONFIG_IP_NF_NAT_NEEDED
257 + LOCK_BH(&ip_h323_lock);
259 + info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i;
260 + info->offset[IP_CT_DIR_ORIGINAL] = i;
261 + UNLOCK_BH(&ip_h323_lock);
264 + memset(&expect, 0, sizeof(expect));
266 + /* update the H.225 info */
267 + LOCK_BH(&ip_h323_lock);
268 + info->is_h225 = H225_PORT;
269 + exp_info->port = data_port;
270 + exp_info->dir = dir;
271 + exp_info->offset = i;
273 + exp->seq = ntohl(tcph->seq) + i;
275 + exp->tuple = ((struct ip_conntrack_tuple)
276 + { { ct->tuplehash[!dir].tuple.src.ip,
281 + exp->mask = ((struct ip_conntrack_tuple)
282 + { { 0xFFFFFFFF, { 0 } },
283 + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
285 + exp->expectfn = h225_expect;
287 + /* Ignore failure */
288 + ip_conntrack_expect_related(ct, exp);
290 + DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n",
291 + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
292 + NIPQUAD(iph->saddr), ntohs(data_port));
294 + UNLOCK_BH(&ip_h323_lock);
296 +#ifdef CONFIG_IP_NF_NAT_NEEDED
297 + } else if (data_ip == iph->daddr) {
298 + memcpy(&data_port, data + 4, sizeof(u_int16_t));
299 + if (data_port == tcph->dest) {
300 + /* Signal address */
301 + DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n",
302 + NIPQUAD(iph->daddr));
303 + /* Update the H.225 info so that NAT can mangle the address/port
304 + even when we have no expected connection! */
305 + LOCK_BH(&ip_h323_lock);
307 + info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i;
308 + info->offset[IP_CT_DIR_REPLY] = i;
309 + UNLOCK_BH(&ip_h323_lock);
319 +static struct ip_conntrack_helper h225 =
321 + "H.225", /* name */
322 + IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
323 + THIS_MODULE, /* module */
324 + 2, /* max_expected */
326 + { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
327 + { 0, { 0 }, IPPROTO_TCP } },
328 + { { 0, { 0xFFFF } }, /* mask */
329 + { 0, { 0 }, 0xFFFF } },
330 + h225_help /* helper */
333 +static int __init init(void)
335 + return ip_conntrack_helper_register(&h225);
338 +static void __exit fini(void)
340 + /* Unregister H.225 helper */
341 + ip_conntrack_helper_unregister(&h225);
344 +#ifdef CONFIG_IP_NF_NAT_NEEDED
345 +EXPORT_SYMBOL(ip_h323_lock);
351 +++ b/net/ipv4/netfilter/ip_nat_h323.c
354 + * H.323 'brute force' extension for NAT alteration.
355 + * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
357 + * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
358 + * (http://www.coritel.it/projects/sofia/nat.html)
359 + * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
360 + * the unregistered helpers to the conntrack entries.
364 +#include <linux/module.h>
365 +#include <linux/netfilter.h>
366 +#include <linux/ip.h>
367 +#include <net/checksum.h>
368 +#include <net/tcp.h>
370 +#include <linux/netfilter_ipv4/lockhelp.h>
371 +#include <linux/netfilter_ipv4/ip_nat.h>
372 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
373 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
374 +#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
375 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
376 +#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
378 +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
379 +MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
380 +MODULE_LICENSE("GPL");
382 +DECLARE_LOCK_EXTERN(ip_h323_lock);
383 +struct module *ip_nat_h323 = THIS_MODULE;
385 +#define DEBUGP(format, args...)
389 +h225_nat_expected(struct sk_buff **pskb,
390 + unsigned int hooknum,
391 + struct ip_conntrack *ct,
392 + struct ip_nat_info *info);
394 +static unsigned int h225_nat_help(struct ip_conntrack *ct,
395 + struct ip_conntrack_expect *exp,
396 + struct ip_nat_info *info,
397 + enum ip_conntrack_info ctinfo,
398 + unsigned int hooknum,
399 + struct sk_buff **pskb);
401 +static struct ip_nat_helper h245 =
403 + "H.245", /* name */
406 + { { 0, { 0 } }, /* tuple */
407 + { 0, { 0 }, IPPROTO_TCP } },
408 + { { 0, { 0xFFFF } }, /* mask */
409 + { 0, { 0 }, 0xFFFF } },
410 + h225_nat_help, /* helper */
411 + h225_nat_expected /* expectfn */
415 +h225_nat_expected(struct sk_buff **pskb,
416 + unsigned int hooknum,
417 + struct ip_conntrack *ct,
418 + struct ip_nat_info *info)
420 + struct ip_nat_multi_range mr;
421 + u_int32_t newdstip, newsrcip, newip;
423 + struct ip_ct_h225_expect *exp_info;
424 + struct ip_ct_h225_master *master_info;
425 + struct ip_conntrack *master = master_ct(ct);
426 + unsigned int is_h225, ret;
428 + IP_NF_ASSERT(info);
429 + IP_NF_ASSERT(master);
431 + IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
433 + DEBUGP("h225_nat_expected: We have a connection!\n");
434 + master_info = &ct->master->expectant->help.ct_h225_info;
435 + exp_info = &ct->master->help.exp_h225_info;
437 + LOCK_BH(&ip_h323_lock);
439 + DEBUGP("master: ");
440 + DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
441 + DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
442 + DEBUGP("conntrack: ");
443 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
444 + if (exp_info->dir == IP_CT_DIR_ORIGINAL) {
445 + /* Make connection go to the client. */
446 + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
447 + newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
448 + DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n",
449 + NIPQUAD(newsrcip), NIPQUAD(newdstip));
451 + /* Make the connection go to the server */
452 + newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
453 + newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
454 + DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n",
455 + NIPQUAD(newsrcip), NIPQUAD(newdstip));
457 + port = exp_info->port;
458 + is_h225 = master_info->is_h225 == H225_PORT;
459 + UNLOCK_BH(&ip_h323_lock);
461 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
466 + DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
469 + /* We don't want to manip the per-protocol, just the IPs... */
470 + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
471 + mr.range[0].min_ip = mr.range[0].max_ip = newip;
473 + /* ... unless we're doing a MANIP_DST, in which case, make
474 + sure we map to the correct port */
475 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
476 + mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
477 + mr.range[0].min = mr.range[0].max
478 + = ((union ip_conntrack_manip_proto)
482 + ret = ip_nat_setup_info(ct, &mr, hooknum);
485 + DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct);
486 + /* NAT expectfn called with ip_nat_lock write-locked */
487 + info->helper = &h245;
492 +static int h323_signal_address_fixup(struct ip_conntrack *ct,
493 + struct sk_buff **pskb,
494 + enum ip_conntrack_info ctinfo)
496 + struct iphdr *iph = (*pskb)->nh.iph;
497 + struct tcphdr *tcph = (void *)iph + iph->ihl*4;
498 + unsigned char *data;
499 + u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
500 + u_int32_t datalen = tcplen - tcph->doff*4;
501 + struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
504 + u_int8_t buffer[6];
507 + MUST_BE_LOCKED(&ip_h323_lock);
509 + DEBUGP("h323_signal_address_fixup: %s %s\n",
510 + between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
512 + between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
514 + if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
515 + || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)))
518 + DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n",
519 + info->offset[IP_CT_DIR_ORIGINAL],
520 + info->offset[IP_CT_DIR_REPLY],
522 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
523 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
525 + for (i = 0; i < IP_CT_DIR_MAX; i++) {
526 + DEBUGP("h323_signal_address_fixup: %s %s\n",
527 + info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply",
528 + i == IP_CT_DIR_ORIGINAL ? "caller" : "callee");
529 + if (!between(info->seq[i], ntohl(tcph->seq),
530 + ntohl(tcph->seq) + datalen))
532 + if (!between(info->seq[i] + 6, ntohl(tcph->seq),
533 + ntohl(tcph->seq) + datalen)) {
534 + /* Partial retransmisison. It's a cracker being funky. */
535 + if (net_ratelimit()) {
536 + printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
539 + ntohl(tcph->seq) + datalen);
544 + /* Change address inside packet to match way we're mapping
545 + this connection. */
546 + if (i == IP_CT_DIR_ORIGINAL) {
547 + newip = ct->tuplehash[!info->dir].tuple.dst.ip;
548 + port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
550 + newip = ct->tuplehash[!info->dir].tuple.src.ip;
551 + port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
554 + data = (char *) tcph + tcph->doff * 4 + info->offset[i];
556 + DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n",
557 + i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
558 + data[0], data[1], data[2], data[3],
559 + (data[4] << 8 | data[5]));
561 + /* Modify the packet */
562 + memcpy(buffer, &newip, 4);
563 + memcpy(buffer + 4, &port, 2);
564 + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i],
568 + DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n",
569 + i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
570 + data[0], data[1], data[2], data[3],
571 + (data[4] << 8 | data[5]));
577 +static int h323_data_fixup(struct ip_ct_h225_expect *info,
578 + struct ip_conntrack *ct,
579 + struct sk_buff **pskb,
580 + enum ip_conntrack_info ctinfo,
581 + struct ip_conntrack_expect *expect)
585 + u_int8_t buffer[6];
586 + struct ip_conntrack_tuple newtuple;
587 + struct iphdr *iph = (*pskb)->nh.iph;
588 + struct tcphdr *tcph = (void *)iph + iph->ihl*4;
589 + unsigned char *data;
590 + u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
591 + struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info;
594 + MUST_BE_LOCKED(&ip_h323_lock);
595 + DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen);
596 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
597 + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
599 + if (!between(expect->seq + 6, ntohl(tcph->seq),
600 + ntohl(tcph->seq) + tcplen - tcph->doff * 4)) {
601 + /* Partial retransmisison. It's a cracker being funky. */
602 + if (net_ratelimit()) {
603 + printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
606 + ntohl(tcph->seq) + tcplen - tcph->doff * 4);
611 + /* Change address inside packet to match way we're mapping
612 + this connection. */
613 + if (info->dir == IP_CT_DIR_REPLY) {
614 + /* Must be where client thinks server is */
615 + newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
616 + /* Expect something from client->server */
617 + newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
618 + newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
620 + /* Must be where server thinks client is */
621 + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
622 + /* Expect something from server->client */
623 + newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
624 + newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
627 + is_h225 = (master_info->is_h225 == H225_PORT);
630 + newtuple.dst.protonum = IPPROTO_TCP;
631 + newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
633 + newtuple.dst.protonum = IPPROTO_UDP;
634 + newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
637 + /* Try to get same port: if not, try to change it. */
638 + for (port = ntohs(info->port); port != 0; port++) {
640 + newtuple.dst.u.tcp.port = htons(port);
642 + newtuple.dst.u.udp.port = htons(port);
644 + if (ip_conntrack_change_expect(expect, &newtuple) == 0)
648 + DEBUGP("h323_data_fixup: no free port found!\n");
652 + port = htons(port);
654 + data = (char *) tcph + tcph->doff * 4 + info->offset;
656 + DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n",
657 + data[0], data[1], data[2], data[3],
658 + (data[4] << 8 | data[5]));
660 + /* Modify the packet */
661 + memcpy(buffer, &newip, 4);
662 + memcpy(buffer + 4, &port, 2);
663 + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset,
667 + DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n",
668 + data[0], data[1], data[2], data[3],
669 + (data[4] << 8 | data[5]));
674 +static unsigned int h225_nat_help(struct ip_conntrack *ct,
675 + struct ip_conntrack_expect *exp,
676 + struct ip_nat_info *info,
677 + enum ip_conntrack_info ctinfo,
678 + unsigned int hooknum,
679 + struct sk_buff **pskb)
682 + struct ip_ct_h225_expect *exp_info;
684 + /* Only mangle things once: original direction in POST_ROUTING
685 + and reply direction on PRE_ROUTING. */
686 + dir = CTINFO2DIR(ctinfo);
687 + DEBUGP("nat_h323: dir %s at hook %s\n",
688 + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
689 + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
690 + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
691 + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
692 + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
693 + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
694 + DEBUGP("nat_h323: Not touching dir %s at hook %s\n",
695 + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
696 + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
697 + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
698 + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
703 + LOCK_BH(&ip_h323_lock);
704 + if (!h323_signal_address_fixup(ct, pskb, ctinfo)) {
705 + UNLOCK_BH(&ip_h323_lock);
708 + UNLOCK_BH(&ip_h323_lock);
712 + exp_info = &exp->help.exp_h225_info;
714 + LOCK_BH(&ip_h323_lock);
715 + if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) {
716 + UNLOCK_BH(&ip_h323_lock);
719 + UNLOCK_BH(&ip_h323_lock);
724 +static struct ip_nat_helper h225 =
726 + "H.225", /* name */
727 + IP_NAT_HELPER_F_ALWAYS, /* flags */
728 + THIS_MODULE, /* module */
729 + { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
730 + { 0, { 0 }, IPPROTO_TCP } },
731 + { { 0, { 0xFFFF } }, /* mask */
732 + { 0, { 0 }, 0xFFFF } },
733 + h225_nat_help, /* helper */
734 + h225_nat_expected /* expectfn */
737 +static int __init init(void)
741 + ret = ip_nat_helper_register(&h225);
744 + printk("ip_nat_h323: cannot initialize the module!\n");
749 +static void __exit fini(void)
751 + ip_nat_helper_unregister(&h225);
756 --- a/include/linux/netfilter_ipv4/ip_conntrack.h
757 +++ b/include/linux/netfilter_ipv4/ip_conntrack.h
758 @@ -67,6 +67,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_h323.h>
764 /* per expectation: application helper private data */
765 union ip_conntrack_expect_help {
766 @@ -74,6 +75,7 @@ union ip_conntrack_expect_help {
767 struct ip_ct_amanda_expect exp_amanda_info;
768 struct ip_ct_ftp_expect exp_ftp_info;
769 struct ip_ct_irc_expect exp_irc_info;
770 + struct ip_ct_h225_expect exp_h225_info;
772 #ifdef CONFIG_IP_NF_NAT_NEEDED
774 @@ -87,6 +89,7 @@ union ip_conntrack_help {
775 /* insert conntrack helper private data (master) here */
776 struct ip_ct_ftp_master ct_ftp_info;
777 struct ip_ct_irc_master ct_irc_info;
778 + struct ip_ct_h225_master ct_h225_info;
781 #ifdef CONFIG_IP_NF_NAT_NEEDED
783 +++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
785 +#ifndef _IP_CONNTRACK_H323_H
786 +#define _IP_CONNTRACK_H323_H
787 +/* H.323 connection tracking. */
790 +/* Protects H.323 related data */
791 +DECLARE_LOCK_EXTERN(ip_h323_lock);
794 +/* Default H.225 port */
795 +#define H225_PORT 1720
797 +/* This structure is per expected connection */
798 +struct ip_ct_h225_expect {
799 + u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */
800 + enum ip_conntrack_dir dir; /* Direction of the original connection */
801 + unsigned int offset; /* offset of the address in the payload */
804 +/* This structure exists only once per master */
805 +struct ip_ct_h225_master {
806 + int is_h225; /* H.225 or H.245 connection */
807 +#ifdef CONFIG_IP_NF_NAT_NEEDED
808 + enum ip_conntrack_dir dir; /* Direction of the original connection */
809 + u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */
810 + unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */
814 +#endif /* _IP_CONNTRACK_H323_H */