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