[NETFILTER]: Add H.323 conntrack/NAT helper
[linux-2.6/suspend2-2.6.18.git] / net / ipv4 / netfilter / ip_nat_helper_h323.c
bloba0bc883928c09d4b7a5531af474820ce12ead663
1 /*
2 * H.323 extension for NAT alteration.
4 * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
6 * This source code is licensed under General Public License version 2.
8 * Based on the 'brute force' H.323 NAT module by
9 * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
11 * Changes:
12 * 2006-02-01 - initial version 0.1
14 * 2006-02-20 - version 0.2
15 * 1. Changed source format to follow kernel conventions
16 * 2. Deleted some unnecessary structures
17 * 3. Minor fixes
19 * 2006-03-10 - version 0.3
20 * 1. Added support for multiple TPKTs in one packet (suggested by
21 * Patrick McHardy)
22 * 2. Added support for non-linear skb (based on Patrick McHardy's patch)
23 * 3. Eliminated unnecessary return code
25 * 2006-03-15 - version 0.4
26 * 1. Added support for T.120 channels
27 * 2. Added parameter gkrouted_only (suggested by Patrick McHardy)
30 #include <linux/module.h>
31 #include <linux/netfilter_ipv4.h>
32 #include <linux/netfilter.h>
33 #include <linux/ip.h>
34 #include <linux/tcp.h>
35 #include <linux/moduleparam.h>
36 #include <net/tcp.h>
37 #include <linux/netfilter_ipv4/ip_nat.h>
38 #include <linux/netfilter_ipv4/ip_nat_helper.h>
39 #include <linux/netfilter_ipv4/ip_nat_rule.h>
40 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
41 #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
42 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
44 #include "ip_conntrack_helper_h323_asn1.h"
46 #if 0
47 #define DEBUGP printk
48 #else
49 #define DEBUGP(format, args...)
50 #endif
52 extern int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
53 u_int32_t * ip, u_int16_t * port);
54 extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
55 u_int32_t * ip, u_int16_t * port);
56 extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
57 struct ip_conntrack_expect *this);
58 extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
59 struct ip_conntrack_expect *this);
60 extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
61 unsigned char **data, int dataoff,
62 H245_TransportAddress * addr,
63 u_int32_t ip, u_int16_t port);
64 extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
65 unsigned char **data, int dataoff,
66 TransportAddress * addr,
67 u_int32_t ip, u_int16_t port);
68 extern int (*set_sig_addr_hook) (struct sk_buff ** pskb,
69 struct ip_conntrack * ct,
70 enum ip_conntrack_info ctinfo,
71 unsigned char **data,
72 TransportAddress * addr, int count);
73 extern int (*set_ras_addr_hook) (struct sk_buff ** pskb,
74 struct ip_conntrack * ct,
75 enum ip_conntrack_info ctinfo,
76 unsigned char **data,
77 TransportAddress * addr, int count);
78 extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
79 struct ip_conntrack * ct,
80 enum ip_conntrack_info ctinfo,
81 unsigned char **data, int dataoff,
82 H245_TransportAddress * addr,
83 u_int16_t port, u_int16_t rtp_port,
84 struct ip_conntrack_expect * rtp_exp,
85 struct ip_conntrack_expect * rtcp_exp);
86 extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
87 enum ip_conntrack_info ctinfo,
88 unsigned char **data, int dataoff,
89 H245_TransportAddress * addr, u_int16_t port,
90 struct ip_conntrack_expect * exp);
91 extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
92 enum ip_conntrack_info ctinfo,
93 unsigned char **data, int dataoff,
94 TransportAddress * addr, u_int16_t port,
95 struct ip_conntrack_expect * exp);
96 extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
97 enum ip_conntrack_info ctinfo,
98 unsigned char **data, TransportAddress * addr,
99 int idx, u_int16_t port,
100 struct ip_conntrack_expect * exp);
103 /****************************************************************************/
104 static int set_addr(struct sk_buff **pskb,
105 unsigned char **data, int dataoff,
106 unsigned int addroff, u_int32_t ip, u_int16_t port)
108 enum ip_conntrack_info ctinfo;
109 struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo);
110 struct {
111 u_int32_t ip;
112 u_int16_t port;
113 } __attribute__ ((__packed__)) buf;
114 struct tcphdr _tcph, *th;
116 buf.ip = ip;
117 buf.port = htons(port);
118 addroff += dataoff;
120 if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
121 if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
122 addroff, sizeof(buf),
123 (char *) &buf, sizeof(buf))) {
124 if (net_ratelimit())
125 printk("ip_nat_h323: ip_nat_mangle_tcp_packet"
126 " error\n");
127 return -1;
130 /* Relocate data pointer */
131 th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
132 sizeof(_tcph), &_tcph);
133 if (th == NULL)
134 return -1;
135 *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
136 th->doff * 4 + dataoff;
137 } else {
138 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
139 addroff, sizeof(buf),
140 (char *) &buf, sizeof(buf))) {
141 if (net_ratelimit())
142 printk("ip_nat_h323: ip_nat_mangle_udp_packet"
143 " error\n");
144 return -1;
146 /* ip_nat_mangle_udp_packet uses skb_make_writable() to copy
147 * or pull everything in a linear buffer, so we can safely
148 * use the skb pointers now */
149 *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
150 sizeof(struct udphdr);
153 return 0;
156 /****************************************************************************/
157 static int set_h225_addr(struct sk_buff **pskb,
158 unsigned char **data, int dataoff,
159 TransportAddress * addr,
160 u_int32_t ip, u_int16_t port)
162 return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port);
165 /****************************************************************************/
166 static int set_h245_addr(struct sk_buff **pskb,
167 unsigned char **data, int dataoff,
168 H245_TransportAddress * addr,
169 u_int32_t ip, u_int16_t port)
171 return set_addr(pskb, data, dataoff,
172 addr->unicastAddress.iPAddress.network, ip, port);
175 /****************************************************************************/
176 static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
177 enum ip_conntrack_info ctinfo,
178 unsigned char **data,
179 TransportAddress * addr, int count)
181 struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
182 int dir = CTINFO2DIR(ctinfo);
183 int i;
184 u_int32_t ip;
185 u_int16_t port;
187 for (i = 0; i < count; i++) {
188 if (get_h225_addr(*data, &addr[i], &ip, &port)) {
189 if (ip == ct->tuplehash[dir].tuple.src.ip &&
190 port == info->sig_port[dir]) {
191 /* GW->GK */
193 /* Fix for Gnomemeeting */
194 if (i > 0 &&
195 get_h225_addr(*data, &addr[0],
196 &ip, &port) &&
197 (ntohl(ip) & 0xff000000) == 0x7f000000)
198 i = 0;
200 DEBUGP
201 ("ip_nat_ras: set signal address "
202 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
203 NIPQUAD(ip), port,
204 NIPQUAD(ct->tuplehash[!dir].tuple.dst.
205 ip), info->sig_port[!dir]);
206 return set_h225_addr(pskb, data, 0, &addr[i],
207 ct->tuplehash[!dir].
208 tuple.dst.ip,
209 info->sig_port[!dir]);
210 } else if (ip == ct->tuplehash[dir].tuple.dst.ip &&
211 port == info->sig_port[dir]) {
212 /* GK->GW */
213 DEBUGP
214 ("ip_nat_ras: set signal address "
215 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
216 NIPQUAD(ip), port,
217 NIPQUAD(ct->tuplehash[!dir].tuple.src.
218 ip), info->sig_port[!dir]);
219 return set_h225_addr(pskb, data, 0, &addr[i],
220 ct->tuplehash[!dir].
221 tuple.src.ip,
222 info->sig_port[!dir]);
227 return 0;
230 /****************************************************************************/
231 static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
232 enum ip_conntrack_info ctinfo,
233 unsigned char **data,
234 TransportAddress * addr, int count)
236 int dir = CTINFO2DIR(ctinfo);
237 int i;
238 u_int32_t ip;
239 u_int16_t port;
241 for (i = 0; i < count; i++) {
242 if (get_h225_addr(*data, &addr[i], &ip, &port) &&
243 ip == ct->tuplehash[dir].tuple.src.ip &&
244 port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) {
245 DEBUGP("ip_nat_ras: set rasAddress "
246 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
247 NIPQUAD(ip), port,
248 NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
249 ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
250 port));
251 return set_h225_addr(pskb, data, 0, &addr[i],
252 ct->tuplehash[!dir].tuple.dst.ip,
253 ntohs(ct->tuplehash[!dir].tuple.
254 dst.u.udp.port));
258 return 0;
261 /****************************************************************************/
262 static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
263 enum ip_conntrack_info ctinfo,
264 unsigned char **data, int dataoff,
265 H245_TransportAddress * addr,
266 u_int16_t port, u_int16_t rtp_port,
267 struct ip_conntrack_expect *rtp_exp,
268 struct ip_conntrack_expect *rtcp_exp)
270 struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
271 int dir = CTINFO2DIR(ctinfo);
272 int i;
273 u_int16_t nated_port;
275 /* Set expectations for NAT */
276 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
277 rtp_exp->expectfn = ip_nat_follow_master;
278 rtp_exp->dir = !dir;
279 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
280 rtcp_exp->expectfn = ip_nat_follow_master;
281 rtcp_exp->dir = !dir;
283 /* Lookup existing expects */
284 for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
285 if (info->rtp_port[i][dir] == rtp_port) {
286 /* Expected */
288 /* Use allocated ports first. This will refresh
289 * the expects */
290 rtp_exp->tuple.dst.u.udp.port =
291 htons(info->rtp_port[i][dir]);
292 rtcp_exp->tuple.dst.u.udp.port =
293 htons(info->rtp_port[i][dir] + 1);
294 break;
295 } else if (info->rtp_port[i][dir] == 0) {
296 /* Not expected */
297 break;
301 /* Run out of expectations */
302 if (i >= H323_RTP_CHANNEL_MAX) {
303 if (net_ratelimit())
304 printk("ip_nat_h323: out of expectations\n");
305 return 0;
308 /* Try to get a pair of ports. */
309 for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
310 nated_port != 0; nated_port += 2) {
311 rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
312 if (ip_conntrack_expect_related(rtp_exp) == 0) {
313 rtcp_exp->tuple.dst.u.udp.port =
314 htons(nated_port + 1);
315 if (ip_conntrack_expect_related(rtcp_exp) == 0)
316 break;
317 ip_conntrack_unexpect_related(rtp_exp);
321 if (nated_port == 0) { /* No port available */
322 if (net_ratelimit())
323 printk("ip_nat_h323: out of RTP ports\n");
324 return 0;
327 /* Modify signal */
328 if (set_h245_addr(pskb, data, dataoff, addr,
329 ct->tuplehash[!dir].tuple.dst.ip,
330 (port & 1) ? nated_port + 1 : nated_port) == 0) {
331 /* Save ports */
332 info->rtp_port[i][dir] = rtp_port;
333 info->rtp_port[i][!dir] = nated_port;
334 } else {
335 ip_conntrack_unexpect_related(rtp_exp);
336 ip_conntrack_unexpect_related(rtcp_exp);
337 return -1;
340 /* Success */
341 DEBUGP("ip_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
342 NIPQUAD(rtp_exp->tuple.src.ip),
343 ntohs(rtp_exp->tuple.src.u.udp.port),
344 NIPQUAD(rtp_exp->tuple.dst.ip),
345 ntohs(rtp_exp->tuple.dst.u.udp.port));
346 DEBUGP("ip_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
347 NIPQUAD(rtcp_exp->tuple.src.ip),
348 ntohs(rtcp_exp->tuple.src.u.udp.port),
349 NIPQUAD(rtcp_exp->tuple.dst.ip),
350 ntohs(rtcp_exp->tuple.dst.u.udp.port));
352 return 0;
355 /****************************************************************************/
356 static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct,
357 enum ip_conntrack_info ctinfo,
358 unsigned char **data, int dataoff,
359 H245_TransportAddress * addr, u_int16_t port,
360 struct ip_conntrack_expect *exp)
362 int dir = CTINFO2DIR(ctinfo);
363 u_int16_t nated_port = port;
365 /* Set expectations for NAT */
366 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
367 exp->expectfn = ip_nat_follow_master;
368 exp->dir = !dir;
370 /* Try to get same port: if not, try to change it. */
371 for (; nated_port != 0; nated_port++) {
372 exp->tuple.dst.u.tcp.port = htons(nated_port);
373 if (ip_conntrack_expect_related(exp) == 0)
374 break;
377 if (nated_port == 0) { /* No port available */
378 if (net_ratelimit())
379 printk("ip_nat_h323: out of TCP ports\n");
380 return 0;
383 /* Modify signal */
384 if (set_h245_addr(pskb, data, dataoff, addr,
385 ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) {
386 ip_conntrack_unexpect_related(exp);
387 return -1;
390 DEBUGP("ip_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
391 NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
392 NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
394 return 0;
397 /****************************************************************************
398 * This conntrack expect function replaces ip_conntrack_h245_expect()
399 * which was set by ip_conntrack_helper_h323.c. It calls both
400 * ip_nat_follow_master() and ip_conntrack_h245_expect()
401 ****************************************************************************/
402 static void ip_nat_h245_expect(struct ip_conntrack *new,
403 struct ip_conntrack_expect *this)
405 ip_nat_follow_master(new, this);
406 ip_conntrack_h245_expect(new, this);
409 /****************************************************************************/
410 static int nat_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
411 enum ip_conntrack_info ctinfo,
412 unsigned char **data, int dataoff,
413 TransportAddress * addr, u_int16_t port,
414 struct ip_conntrack_expect *exp)
416 struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
417 int dir = CTINFO2DIR(ctinfo);
418 u_int16_t nated_port = port;
420 /* Set expectations for NAT */
421 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
422 exp->expectfn = ip_nat_h245_expect;
423 exp->dir = !dir;
425 /* Check existing expects */
426 if (info->sig_port[dir] == port)
427 nated_port = info->sig_port[!dir];
429 /* Try to get same port: if not, try to change it. */
430 for (; nated_port != 0; nated_port++) {
431 exp->tuple.dst.u.tcp.port = htons(nated_port);
432 if (ip_conntrack_expect_related(exp) == 0)
433 break;
436 if (nated_port == 0) { /* No port available */
437 if (net_ratelimit())
438 printk("ip_nat_q931: out of TCP ports\n");
439 return 0;
442 /* Modify signal */
443 if (set_h225_addr(pskb, data, dataoff, addr,
444 ct->tuplehash[!dir].tuple.dst.ip,
445 nated_port) == 0) {
446 /* Save ports */
447 info->sig_port[dir] = port;
448 info->sig_port[!dir] = nated_port;
449 } else {
450 ip_conntrack_unexpect_related(exp);
451 return -1;
454 DEBUGP("ip_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
455 NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
456 NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
458 return 0;
461 /****************************************************************************
462 * This conntrack expect function replaces ip_conntrack_q931_expect()
463 * which was set by ip_conntrack_helper_h323.c.
464 ****************************************************************************/
465 static void ip_nat_q931_expect(struct ip_conntrack *new,
466 struct ip_conntrack_expect *this)
468 struct ip_nat_range range;
470 if (this->tuple.src.ip != 0) { /* Only accept calls from GK */
471 ip_nat_follow_master(new, this);
472 goto out;
475 /* This must be a fresh one. */
476 BUG_ON(new->status & IPS_NAT_DONE_MASK);
478 /* Change src to where master sends to */
479 range.flags = IP_NAT_RANGE_MAP_IPS;
480 range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip;
482 /* hook doesn't matter, but it has to do source manip */
483 ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
485 /* For DST manip, map port here to where it's expected. */
486 range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
487 range.min = range.max = this->saved_proto;
488 range.min_ip = range.max_ip =
489 new->master->tuplehash[!this->dir].tuple.src.ip;
491 /* hook doesn't matter, but it has to do destination manip */
492 ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
494 out:
495 ip_conntrack_q931_expect(new, this);
498 /****************************************************************************/
499 static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
500 enum ip_conntrack_info ctinfo,
501 unsigned char **data, TransportAddress * addr, int idx,
502 u_int16_t port, struct ip_conntrack_expect *exp)
504 struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
505 int dir = CTINFO2DIR(ctinfo);
506 u_int16_t nated_port = port;
507 u_int32_t ip;
509 /* Set expectations for NAT */
510 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
511 exp->expectfn = ip_nat_q931_expect;
512 exp->dir = !dir;
514 /* Check existing expects */
515 if (info->sig_port[dir] == port)
516 nated_port = info->sig_port[!dir];
518 /* Try to get same port: if not, try to change it. */
519 for (; nated_port != 0; nated_port++) {
520 exp->tuple.dst.u.tcp.port = htons(nated_port);
521 if (ip_conntrack_expect_related(exp) == 0)
522 break;
525 if (nated_port == 0) { /* No port available */
526 if (net_ratelimit())
527 printk("ip_nat_ras: out of TCP ports\n");
528 return 0;
531 /* Modify signal */
532 if (set_h225_addr(pskb, data, 0, &addr[idx],
533 ct->tuplehash[!dir].tuple.dst.ip,
534 nated_port) == 0) {
535 /* Save ports */
536 info->sig_port[dir] = port;
537 info->sig_port[!dir] = nated_port;
539 /* Fix for Gnomemeeting */
540 if (idx > 0 &&
541 get_h225_addr(*data, &addr[0], &ip, &port) &&
542 (ntohl(ip) & 0xff000000) == 0x7f000000) {
543 set_h225_addr_hook(pskb, data, 0, &addr[0],
544 ct->tuplehash[!dir].tuple.dst.ip,
545 info->sig_port[!dir]);
547 } else {
548 ip_conntrack_unexpect_related(exp);
549 return -1;
552 /* Success */
553 DEBUGP("ip_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
554 NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
555 NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
557 return 0;
560 /****************************************************************************/
561 static int __init init(void)
563 BUG_ON(set_h245_addr_hook != NULL);
564 BUG_ON(set_h225_addr_hook != NULL);
565 BUG_ON(set_sig_addr_hook != NULL);
566 BUG_ON(set_ras_addr_hook != NULL);
567 BUG_ON(nat_rtp_rtcp_hook != NULL);
568 BUG_ON(nat_t120_hook != NULL);
569 BUG_ON(nat_h245_hook != NULL);
570 BUG_ON(nat_q931_hook != NULL);
572 set_h245_addr_hook = set_h245_addr;
573 set_h225_addr_hook = set_h225_addr;
574 set_sig_addr_hook = set_sig_addr;
575 set_ras_addr_hook = set_ras_addr;
576 nat_rtp_rtcp_hook = nat_rtp_rtcp;
577 nat_t120_hook = nat_t120;
578 nat_h245_hook = nat_h245;
579 nat_q931_hook = nat_q931;
581 DEBUGP("ip_nat_h323: init success\n");
582 return 0;
585 /****************************************************************************/
586 static void __exit fini(void)
588 set_h245_addr_hook = NULL;
589 set_h225_addr_hook = NULL;
590 set_sig_addr_hook = NULL;
591 set_ras_addr_hook = NULL;
592 nat_rtp_rtcp_hook = NULL;
593 nat_t120_hook = NULL;
594 nat_h245_hook = NULL;
595 nat_q931_hook = NULL;
596 synchronize_net();
599 /****************************************************************************/
600 module_init(init);
601 module_exit(fini);
603 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
604 MODULE_DESCRIPTION("H.323 NAT helper");
605 MODULE_LICENSE("GPL");