Root/target/linux/generic-2.4/patches/613-netfilter_nat_h323.patch

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
8 fi
9 
10 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
11@@ -80,6 +81,13 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ];
12           define_tristate CONFIG_IP_NF_NAT_AMANDA $CONFIG_IP_NF_NAT
13         fi
14       fi
15+ if [ "$CONFIG_IP_NF_H323" = "m" ]; then
16+ define_tristate CONFIG_IP_NF_NAT_H323 m
17+ else
18+ if [ "$CONFIG_IP_NF_H323" = "y" ]; then
19+ define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT
20+ fi
21+ fi
22       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
23         dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
24       fi
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
30 endif
31+obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
32+ifdef CONFIG_IP_NF_NAT_H323
33+ export-objs += ip_conntrack_h323.o
34+endif
35 
36 # NAT helpers
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
42 
43 # generic IP tables
44 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
45--- /dev/null
46+++ b/net/ipv4/netfilter/ip_conntrack_h323.c
47@@ -0,0 +1,302 @@
48+/*
49+ * H.323 'brute force' extension for H.323 connection tracking.
50+ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
51+ *
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.
56+ */
57+
58+
59+#include <linux/module.h>
60+#include <linux/netfilter.h>
61+#include <linux/ip.h>
62+#include <net/checksum.h>
63+#include <net/tcp.h>
64+
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>
71+
72+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
73+MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
74+MODULE_LICENSE("GPL");
75+
76+DECLARE_LOCK(ip_h323_lock);
77+struct module *ip_conntrack_h323 = THIS_MODULE;
78+
79+#define DEBUGP(format, args...)
80+
81+static int h245_help(const struct iphdr *iph, size_t len,
82+ struct ip_conntrack *ct,
83+ enum ip_conntrack_info ctinfo)
84+{
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;
95+ u_int32_t data_ip;
96+ unsigned int i;
97+
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));
101+
102+ /* Can't track connections formed before we registered */
103+ if (!info)
104+ return NF_ACCEPT;
105+
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);
110+ return NF_ACCEPT;
111+ }
112+
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);
116+ return NF_ACCEPT;
117+ }
118+
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));
125+ return NF_ACCEPT;
126+ }
127+
128+ data_limit = (unsigned char *) data + datalen;
129+ /* bytes: 0123 45
130+ ipadrr port */
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;
145+
146+ exp->seq = ntohl(tcph->seq) + i;
147+
148+ exp->tuple = ((struct ip_conntrack_tuple)
149+ { { ct->tuplehash[!dir].tuple.src.ip,
150+ { 0 } },
151+ { data_ip,
152+ { data_port },
153+ IPPROTO_UDP }});
154+ exp->mask = ((struct ip_conntrack_tuple)
155+ { { 0xFFFFFFFF, { 0 } },
156+ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
157+
158+ exp->expectfn = NULL;
159+
160+ /* Ignore failure; should only happen with NAT */
161+ ip_conntrack_expect_related(ct, exp);
162+
163+ UNLOCK_BH(&ip_h323_lock);
164+ }
165+ }
166+
167+ return NF_ACCEPT;
168+
169+}
170+
171+/* H.245 helper is not registered! */
172+static struct ip_conntrack_helper h245 =
173+ { { NULL, NULL },
174+ "H.245", /* name */
175+ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
176+ NULL, /* module */
177+ 8, /* max_ expected */
178+ 240, /* timeout */
179+ { { 0, { 0 } }, /* tuple */
180+ { 0, { 0 }, IPPROTO_TCP } },
181+ { { 0, { 0xFFFF } }, /* mask */
182+ { 0, { 0 }, 0xFFFF } },
183+ h245_help /* helper */
184+ };
185+
186+static int h225_expect(struct ip_conntrack *ct)
187+{
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);
192+
193+ return NF_ACCEPT; /* unused */
194+}
195+
196+static int h225_help(const struct iphdr *iph, size_t len,
197+ struct ip_conntrack *ct,
198+ enum ip_conntrack_info ctinfo)
199+{
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;
210+ u_int32_t data_ip;
211+ unsigned int i;
212+
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));
216+
217+ /* Can't track connections formed before we registered */
218+ if (!info)
219+ return NF_ACCEPT;
220+
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);
225+ return NF_ACCEPT;
226+ }
227+
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);
231+ return NF_ACCEPT;
232+ }
233+
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));
240+ return NF_ACCEPT;
241+ }
242+
243+ data_limit = (unsigned char *) data + datalen;
244+ /* bytes: 0123 45
245+ ipadrr port */
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);
258+ info->dir = dir;
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);
262+#endif
263+ } else {
264+ memset(&expect, 0, sizeof(expect));
265+
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;
272+
273+ exp->seq = ntohl(tcph->seq) + i;
274+
275+ exp->tuple = ((struct ip_conntrack_tuple)
276+ { { ct->tuplehash[!dir].tuple.src.ip,
277+ { 0 } },
278+ { data_ip,
279+ { data_port },
280+ IPPROTO_TCP }});
281+ exp->mask = ((struct ip_conntrack_tuple)
282+ { { 0xFFFFFFFF, { 0 } },
283+ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
284+
285+ exp->expectfn = h225_expect;
286+
287+ /* Ignore failure */
288+ ip_conntrack_expect_related(ct, exp);
289+
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));
293+
294+ UNLOCK_BH(&ip_h323_lock);
295+ }
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);
306+ info->dir = dir;
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);
310+ }
311+#endif
312+ }
313+ }
314+
315+ return NF_ACCEPT;
316+
317+}
318+
319+static struct ip_conntrack_helper h225 =
320+ { { NULL, NULL },
321+ "H.225", /* name */
322+ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
323+ THIS_MODULE, /* module */
324+ 2, /* max_expected */
325+ 240, /* timeout */
326+ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
327+ { 0, { 0 }, IPPROTO_TCP } },
328+ { { 0, { 0xFFFF } }, /* mask */
329+ { 0, { 0 }, 0xFFFF } },
330+ h225_help /* helper */
331+ };
332+
333+static int __init init(void)
334+{
335+ return ip_conntrack_helper_register(&h225);
336+}
337+
338+static void __exit fini(void)
339+{
340+ /* Unregister H.225 helper */
341+ ip_conntrack_helper_unregister(&h225);
342+}
343+
344+#ifdef CONFIG_IP_NF_NAT_NEEDED
345+EXPORT_SYMBOL(ip_h323_lock);
346+#endif
347+
348+module_init(init);
349+module_exit(fini);
350--- /dev/null
351+++ b/net/ipv4/netfilter/ip_nat_h323.c
352@@ -0,0 +1,403 @@
353+/*
354+ * H.323 'brute force' extension for NAT alteration.
355+ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
356+ *
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.
361+ */
362+
363+
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>
369+
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>
377+
378+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
379+MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
380+MODULE_LICENSE("GPL");
381+
382+DECLARE_LOCK_EXTERN(ip_h323_lock);
383+struct module *ip_nat_h323 = THIS_MODULE;
384+
385+#define DEBUGP(format, args...)
386+
387+
388+static unsigned int
389+h225_nat_expected(struct sk_buff **pskb,
390+ unsigned int hooknum,
391+ struct ip_conntrack *ct,
392+ struct ip_nat_info *info);
393+
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);
400+
401+static struct ip_nat_helper h245 =
402+ { { NULL, NULL },
403+ "H.245", /* name */
404+ 0, /* flags */
405+ NULL, /* module */
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 */
412+ };
413+
414+static unsigned int
415+h225_nat_expected(struct sk_buff **pskb,
416+ unsigned int hooknum,
417+ struct ip_conntrack *ct,
418+ struct ip_nat_info *info)
419+{
420+ struct ip_nat_multi_range mr;
421+ u_int32_t newdstip, newsrcip, newip;
422+ u_int16_t port;
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;
427+
428+ IP_NF_ASSERT(info);
429+ IP_NF_ASSERT(master);
430+
431+ IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
432+
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;
436+
437+ LOCK_BH(&ip_h323_lock);
438+
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));
450+ } else {
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));
456+ }
457+ port = exp_info->port;
458+ is_h225 = master_info->is_h225 == H225_PORT;
459+ UNLOCK_BH(&ip_h323_lock);
460+
461+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
462+ newip = newsrcip;
463+ else
464+ newip = newdstip;
465+
466+ DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
467+
468+ mr.rangesize = 1;
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;
472+
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)
479+ { port });
480+ }
481+
482+ ret = ip_nat_setup_info(ct, &mr, hooknum);
483+
484+ if (is_h225) {
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;
488+ }
489+ return ret;
490+}
491+
492+static int h323_signal_address_fixup(struct ip_conntrack *ct,
493+ struct sk_buff **pskb,
494+ enum ip_conntrack_info ctinfo)
495+{
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;
502+ u_int32_t newip;
503+ u_int16_t port;
504+ u_int8_t buffer[6];
505+ int i;
506+
507+ MUST_BE_LOCKED(&ip_h323_lock);
508+
509+ DEBUGP("h323_signal_address_fixup: %s %s\n",
510+ between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
511+ ? "yes" : "no",
512+ between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
513+ ? "yes" : "no");
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)))
516+ return 1;
517+
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],
521+ tcplen);
522+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
523+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
524+
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))
531+ continue;
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",
537+ info->seq[i],
538+ ntohl(tcph->seq),
539+ ntohl(tcph->seq) + datalen);
540+ }
541+ return 0;
542+ }
543+
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;
549+ } else {
550+ newip = ct->tuplehash[!info->dir].tuple.src.ip;
551+ port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
552+ }
553+
554+ data = (char *) tcph + tcph->doff * 4 + info->offset[i];
555+
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]));
560+
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],
565+ 6, buffer, 6))
566+ return 0;
567+
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]));
572+ }
573+
574+ return 1;
575+}
576+
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)
582+{
583+ u_int32_t newip;
584+ u_int16_t port;
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;
592+ int is_h225;
593+
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);
598+
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",
604+ expect->seq,
605+ ntohl(tcph->seq),
606+ ntohl(tcph->seq) + tcplen - tcph->doff * 4);
607+ }
608+ return 0;
609+ }
610+
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;
619+ } else {
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;
625+ }
626+
627+ is_h225 = (master_info->is_h225 == H225_PORT);
628+
629+ if (is_h225) {
630+ newtuple.dst.protonum = IPPROTO_TCP;
631+ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
632+ } else {
633+ newtuple.dst.protonum = IPPROTO_UDP;
634+ newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
635+ }
636+
637+ /* Try to get same port: if not, try to change it. */
638+ for (port = ntohs(info->port); port != 0; port++) {
639+ if (is_h225)
640+ newtuple.dst.u.tcp.port = htons(port);
641+ else
642+ newtuple.dst.u.udp.port = htons(port);
643+
644+ if (ip_conntrack_change_expect(expect, &newtuple) == 0)
645+ break;
646+ }
647+ if (port == 0) {
648+ DEBUGP("h323_data_fixup: no free port found!\n");
649+ return 0;
650+ }
651+
652+ port = htons(port);
653+
654+ data = (char *) tcph + tcph->doff * 4 + info->offset;
655+
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]));
659+
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,
664+ 6, buffer, 6))
665+ return 0;
666+
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]));
670+
671+ return 1;
672+}
673+
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)
680+{
681+ int dir;
682+ struct ip_ct_h225_expect *exp_info;
683+
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" : "???");
699+ return NF_ACCEPT;
700+ }
701+
702+ if (!exp) {
703+ LOCK_BH(&ip_h323_lock);
704+ if (!h323_signal_address_fixup(ct, pskb, ctinfo)) {
705+ UNLOCK_BH(&ip_h323_lock);
706+ return NF_DROP;
707+ }
708+ UNLOCK_BH(&ip_h323_lock);
709+ return NF_ACCEPT;
710+ }
711+
712+ exp_info = &exp->help.exp_h225_info;
713+
714+ LOCK_BH(&ip_h323_lock);
715+ if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) {
716+ UNLOCK_BH(&ip_h323_lock);
717+ return NF_DROP;
718+ }
719+ UNLOCK_BH(&ip_h323_lock);
720+
721+ return NF_ACCEPT;
722+}
723+
724+static struct ip_nat_helper h225 =
725+ { { NULL, NULL },
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 */
735+ };
736+
737+static int __init init(void)
738+{
739+ int ret;
740+
741+ ret = ip_nat_helper_register(&h225);
742+
743+ if (ret != 0)
744+ printk("ip_nat_h323: cannot initialize the module!\n");
745+
746+ return ret;
747+}
748+
749+static void __exit fini(void)
750+{
751+ ip_nat_helper_unregister(&h225);
752+}
753+
754+module_init(init);
755+module_exit(fini);
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 {
759 
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>
763 
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;
771 
772 #ifdef CONFIG_IP_NF_NAT_NEEDED
773     union {
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;
779 };
780 
781 #ifdef CONFIG_IP_NF_NAT_NEEDED
782--- /dev/null
783+++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
784@@ -0,0 +1,30 @@
785+#ifndef _IP_CONNTRACK_H323_H
786+#define _IP_CONNTRACK_H323_H
787+/* H.323 connection tracking. */
788+
789+#ifdef __KERNEL__
790+/* Protects H.323 related data */
791+DECLARE_LOCK_EXTERN(ip_h323_lock);
792+#endif
793+
794+/* Default H.225 port */
795+#define H225_PORT 1720
796+
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 */
802+};
803+
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 */
811+#endif
812+};
813+
814+#endif /* _IP_CONNTRACK_H323_H */
815

Archive Download this file



interactive