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>
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
19 * 2006-03-10 - version 0.3
20 * 1. Added support for multiple TPKTs in one packet (suggested by
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>
34 #include <linux/tcp.h>
35 #include <linux/moduleparam.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"
49 #define DEBUGP(format, args...)
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
,
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
,
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
);
113 } __attribute__ ((__packed__
)) buf
;
114 struct tcphdr _tcph
, *th
;
117 buf
.port
= htons(port
);
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
))) {
125 printk("ip_nat_h323: ip_nat_mangle_tcp_packet"
130 /* Relocate data pointer */
131 th
= skb_header_pointer(*pskb
, (*pskb
)->nh
.iph
->ihl
* 4,
132 sizeof(_tcph
), &_tcph
);
135 *data
= (*pskb
)->data
+ (*pskb
)->nh
.iph
->ihl
* 4 +
136 th
->doff
* 4 + dataoff
;
138 if (!ip_nat_mangle_udp_packet(pskb
, ct
, ctinfo
,
139 addroff
, sizeof(buf
),
140 (char *) &buf
, sizeof(buf
))) {
142 printk("ip_nat_h323: ip_nat_mangle_udp_packet"
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
);
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
);
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
]) {
193 /* Fix for Gnomemeeting */
195 get_h225_addr(*data
, &addr
[0],
197 (ntohl(ip
) & 0xff000000) == 0x7f000000)
201 ("ip_nat_ras: set signal address "
202 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
204 NIPQUAD(ct
->tuplehash
[!dir
].tuple
.dst
.
205 ip
), info
->sig_port
[!dir
]);
206 return set_h225_addr(pskb
, data
, 0, &addr
[i
],
209 info
->sig_port
[!dir
]);
210 } else if (ip
== ct
->tuplehash
[dir
].tuple
.dst
.ip
&&
211 port
== info
->sig_port
[dir
]) {
214 ("ip_nat_ras: set signal address "
215 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
217 NIPQUAD(ct
->tuplehash
[!dir
].tuple
.src
.
218 ip
), info
->sig_port
[!dir
]);
219 return set_h225_addr(pskb
, data
, 0, &addr
[i
],
222 info
->sig_port
[!dir
]);
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
);
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",
248 NIPQUAD(ct
->tuplehash
[!dir
].tuple
.dst
.ip
),
249 ntohs(ct
->tuplehash
[!dir
].tuple
.dst
.u
.udp
.
251 return set_h225_addr(pskb
, data
, 0, &addr
[i
],
252 ct
->tuplehash
[!dir
].tuple
.dst
.ip
,
253 ntohs(ct
->tuplehash
[!dir
].tuple
.
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
);
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
;
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
) {
288 /* Use allocated ports first. This will refresh
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);
295 } else if (info
->rtp_port
[i
][dir
] == 0) {
301 /* Run out of expectations */
302 if (i
>= H323_RTP_CHANNEL_MAX
) {
304 printk("ip_nat_h323: out of expectations\n");
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)
317 ip_conntrack_unexpect_related(rtp_exp
);
321 if (nated_port
== 0) { /* No port available */
323 printk("ip_nat_h323: out of RTP ports\n");
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) {
332 info
->rtp_port
[i
][dir
] = rtp_port
;
333 info
->rtp_port
[i
][!dir
] = nated_port
;
335 ip_conntrack_unexpect_related(rtp_exp
);
336 ip_conntrack_unexpect_related(rtcp_exp
);
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
));
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
;
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)
377 if (nated_port
== 0) { /* No port available */
379 printk("ip_nat_h323: out of TCP ports\n");
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
);
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
));
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
;
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)
436 if (nated_port
== 0) { /* No port available */
438 printk("ip_nat_q931: out of TCP ports\n");
443 if (set_h225_addr(pskb
, data
, dataoff
, addr
,
444 ct
->tuplehash
[!dir
].tuple
.dst
.ip
,
447 info
->sig_port
[dir
] = port
;
448 info
->sig_port
[!dir
] = nated_port
;
450 ip_conntrack_unexpect_related(exp
);
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
));
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);
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
);
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
;
509 /* Set expectations for NAT */
510 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
511 exp
->expectfn
= ip_nat_q931_expect
;
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)
525 if (nated_port
== 0) { /* No port available */
527 printk("ip_nat_ras: out of TCP ports\n");
532 if (set_h225_addr(pskb
, data
, 0, &addr
[idx
],
533 ct
->tuplehash
[!dir
].tuple
.dst
.ip
,
536 info
->sig_port
[dir
] = port
;
537 info
->sig_port
[!dir
] = nated_port
;
539 /* Fix for Gnomemeeting */
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
]);
548 ip_conntrack_unexpect_related(exp
);
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
));
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");
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
;
599 /****************************************************************************/
603 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
604 MODULE_DESCRIPTION("H.323 NAT helper");
605 MODULE_LICENSE("GPL");