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 #include <linux/module.h>
13 #include <linux/tcp.h>
16 #include <net/netfilter/nf_nat.h>
17 #include <net/netfilter/nf_nat_helper.h>
18 #include <net/netfilter/nf_conntrack_helper.h>
19 #include <net/netfilter/nf_conntrack_expect.h>
20 #include <linux/netfilter/nf_conntrack_h323.h>
22 /****************************************************************************/
23 static int set_addr(struct sk_buff
*skb
, unsigned int protoff
,
24 unsigned char **data
, int dataoff
,
25 unsigned int addroff
, __be32 ip
, __be16 port
)
27 enum ip_conntrack_info ctinfo
;
28 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
32 } __attribute__ ((__packed__
)) buf
;
33 const struct tcphdr
*th
;
40 if (ip_hdr(skb
)->protocol
== IPPROTO_TCP
) {
41 if (!nf_nat_mangle_tcp_packet(skb
, ct
, ctinfo
,
42 protoff
, addroff
, sizeof(buf
),
43 (char *) &buf
, sizeof(buf
))) {
44 net_notice_ratelimited("nf_nat_h323: nf_nat_mangle_tcp_packet error\n");
48 /* Relocate data pointer */
49 th
= skb_header_pointer(skb
, ip_hdrlen(skb
),
50 sizeof(_tcph
), &_tcph
);
53 *data
= skb
->data
+ ip_hdrlen(skb
) + th
->doff
* 4 + dataoff
;
55 if (!nf_nat_mangle_udp_packet(skb
, ct
, ctinfo
,
56 protoff
, addroff
, sizeof(buf
),
57 (char *) &buf
, sizeof(buf
))) {
58 net_notice_ratelimited("nf_nat_h323: nf_nat_mangle_udp_packet error\n");
61 /* nf_nat_mangle_udp_packet uses skb_make_writable() to copy
62 * or pull everything in a linear buffer, so we can safely
63 * use the skb pointers now */
64 *data
= skb
->data
+ ip_hdrlen(skb
) + sizeof(struct udphdr
);
70 /****************************************************************************/
71 static int set_h225_addr(struct sk_buff
*skb
, unsigned int protoff
,
72 unsigned char **data
, int dataoff
,
73 TransportAddress
*taddr
,
74 union nf_inet_addr
*addr
, __be16 port
)
76 return set_addr(skb
, protoff
, data
, dataoff
, taddr
->ipAddress
.ip
,
80 /****************************************************************************/
81 static int set_h245_addr(struct sk_buff
*skb
, unsigned protoff
,
82 unsigned char **data
, int dataoff
,
83 H245_TransportAddress
*taddr
,
84 union nf_inet_addr
*addr
, __be16 port
)
86 return set_addr(skb
, protoff
, data
, dataoff
,
87 taddr
->unicastAddress
.iPAddress
.network
,
91 /****************************************************************************/
92 static int set_sig_addr(struct sk_buff
*skb
, struct nf_conn
*ct
,
93 enum ip_conntrack_info ctinfo
,
94 unsigned int protoff
, unsigned char **data
,
95 TransportAddress
*taddr
, int count
)
97 const struct nf_ct_h323_master
*info
= nfct_help_data(ct
);
98 int dir
= CTINFO2DIR(ctinfo
);
101 union nf_inet_addr addr
;
103 for (i
= 0; i
< count
; i
++) {
104 if (get_h225_addr(ct
, *data
, &taddr
[i
], &addr
, &port
)) {
105 if (addr
.ip
== ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
&&
106 port
== info
->sig_port
[dir
]) {
109 /* Fix for Gnomemeeting */
111 get_h225_addr(ct
, *data
, &taddr
[0],
113 (ntohl(addr
.ip
) & 0xff000000) == 0x7f000000)
116 pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
118 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
,
119 info
->sig_port
[!dir
]);
120 return set_h225_addr(skb
, protoff
, data
, 0,
122 &ct
->tuplehash
[!dir
].
124 info
->sig_port
[!dir
]);
125 } else if (addr
.ip
== ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
&&
126 port
== info
->sig_port
[dir
]) {
128 pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
130 &ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
,
131 info
->sig_port
[!dir
]);
132 return set_h225_addr(skb
, protoff
, data
, 0,
134 &ct
->tuplehash
[!dir
].
136 info
->sig_port
[!dir
]);
144 /****************************************************************************/
145 static int set_ras_addr(struct sk_buff
*skb
, struct nf_conn
*ct
,
146 enum ip_conntrack_info ctinfo
,
147 unsigned int protoff
, unsigned char **data
,
148 TransportAddress
*taddr
, int count
)
150 int dir
= CTINFO2DIR(ctinfo
);
153 union nf_inet_addr addr
;
155 for (i
= 0; i
< count
; i
++) {
156 if (get_h225_addr(ct
, *data
, &taddr
[i
], &addr
, &port
) &&
157 addr
.ip
== ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
&&
158 port
== ct
->tuplehash
[dir
].tuple
.src
.u
.udp
.port
) {
159 pr_debug("nf_nat_ras: set rasAddress %pI4:%hu->%pI4:%hu\n",
160 &addr
.ip
, ntohs(port
),
161 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
,
162 ntohs(ct
->tuplehash
[!dir
].tuple
.dst
.u
.udp
.port
));
163 return set_h225_addr(skb
, protoff
, data
, 0, &taddr
[i
],
164 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
165 ct
->tuplehash
[!dir
].tuple
.
173 /****************************************************************************/
174 static int nat_rtp_rtcp(struct sk_buff
*skb
, struct nf_conn
*ct
,
175 enum ip_conntrack_info ctinfo
,
176 unsigned int protoff
, unsigned char **data
, int dataoff
,
177 H245_TransportAddress
*taddr
,
178 __be16 port
, __be16 rtp_port
,
179 struct nf_conntrack_expect
*rtp_exp
,
180 struct nf_conntrack_expect
*rtcp_exp
)
182 struct nf_ct_h323_master
*info
= nfct_help_data(ct
);
183 int dir
= CTINFO2DIR(ctinfo
);
185 u_int16_t nated_port
;
187 /* Set expectations for NAT */
188 rtp_exp
->saved_proto
.udp
.port
= rtp_exp
->tuple
.dst
.u
.udp
.port
;
189 rtp_exp
->expectfn
= nf_nat_follow_master
;
191 rtcp_exp
->saved_proto
.udp
.port
= rtcp_exp
->tuple
.dst
.u
.udp
.port
;
192 rtcp_exp
->expectfn
= nf_nat_follow_master
;
193 rtcp_exp
->dir
= !dir
;
195 /* Lookup existing expects */
196 for (i
= 0; i
< H323_RTP_CHANNEL_MAX
; i
++) {
197 if (info
->rtp_port
[i
][dir
] == rtp_port
) {
200 /* Use allocated ports first. This will refresh
202 rtp_exp
->tuple
.dst
.u
.udp
.port
= info
->rtp_port
[i
][dir
];
203 rtcp_exp
->tuple
.dst
.u
.udp
.port
=
204 htons(ntohs(info
->rtp_port
[i
][dir
]) + 1);
206 } else if (info
->rtp_port
[i
][dir
] == 0) {
212 /* Run out of expectations */
213 if (i
>= H323_RTP_CHANNEL_MAX
) {
214 net_notice_ratelimited("nf_nat_h323: out of expectations\n");
218 /* Try to get a pair of ports. */
219 for (nated_port
= ntohs(rtp_exp
->tuple
.dst
.u
.udp
.port
);
220 nated_port
!= 0; nated_port
+= 2) {
223 rtp_exp
->tuple
.dst
.u
.udp
.port
= htons(nated_port
);
224 ret
= nf_ct_expect_related(rtp_exp
);
226 rtcp_exp
->tuple
.dst
.u
.udp
.port
=
227 htons(nated_port
+ 1);
228 ret
= nf_ct_expect_related(rtcp_exp
);
231 else if (ret
!= -EBUSY
) {
232 nf_ct_unexpect_related(rtp_exp
);
236 } else if (ret
!= -EBUSY
) {
242 if (nated_port
== 0) { /* No port available */
243 net_notice_ratelimited("nf_nat_h323: out of RTP ports\n");
248 if (set_h245_addr(skb
, protoff
, data
, dataoff
, taddr
,
249 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
250 htons((port
& htons(1)) ? nated_port
+ 1 :
253 info
->rtp_port
[i
][dir
] = rtp_port
;
254 info
->rtp_port
[i
][!dir
] = htons(nated_port
);
256 nf_ct_unexpect_related(rtp_exp
);
257 nf_ct_unexpect_related(rtcp_exp
);
262 pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n",
263 &rtp_exp
->tuple
.src
.u3
.ip
,
264 ntohs(rtp_exp
->tuple
.src
.u
.udp
.port
),
265 &rtp_exp
->tuple
.dst
.u3
.ip
,
266 ntohs(rtp_exp
->tuple
.dst
.u
.udp
.port
));
267 pr_debug("nf_nat_h323: expect RTCP %pI4:%hu->%pI4:%hu\n",
268 &rtcp_exp
->tuple
.src
.u3
.ip
,
269 ntohs(rtcp_exp
->tuple
.src
.u
.udp
.port
),
270 &rtcp_exp
->tuple
.dst
.u3
.ip
,
271 ntohs(rtcp_exp
->tuple
.dst
.u
.udp
.port
));
276 /****************************************************************************/
277 static int nat_t120(struct sk_buff
*skb
, struct nf_conn
*ct
,
278 enum ip_conntrack_info ctinfo
,
279 unsigned int protoff
, unsigned char **data
, int dataoff
,
280 H245_TransportAddress
*taddr
, __be16 port
,
281 struct nf_conntrack_expect
*exp
)
283 int dir
= CTINFO2DIR(ctinfo
);
284 u_int16_t nated_port
= ntohs(port
);
286 /* Set expectations for NAT */
287 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
288 exp
->expectfn
= nf_nat_follow_master
;
291 /* Try to get same port: if not, try to change it. */
292 for (; nated_port
!= 0; nated_port
++) {
295 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
296 ret
= nf_ct_expect_related(exp
);
299 else if (ret
!= -EBUSY
) {
305 if (nated_port
== 0) { /* No port available */
306 net_notice_ratelimited("nf_nat_h323: out of TCP ports\n");
311 if (set_h245_addr(skb
, protoff
, data
, dataoff
, taddr
,
312 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
313 htons(nated_port
)) < 0) {
314 nf_ct_unexpect_related(exp
);
318 pr_debug("nf_nat_h323: expect T.120 %pI4:%hu->%pI4:%hu\n",
319 &exp
->tuple
.src
.u3
.ip
,
320 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
321 &exp
->tuple
.dst
.u3
.ip
,
322 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
327 /****************************************************************************/
328 static int nat_h245(struct sk_buff
*skb
, struct nf_conn
*ct
,
329 enum ip_conntrack_info ctinfo
,
330 unsigned int protoff
, unsigned char **data
, int dataoff
,
331 TransportAddress
*taddr
, __be16 port
,
332 struct nf_conntrack_expect
*exp
)
334 struct nf_ct_h323_master
*info
= nfct_help_data(ct
);
335 int dir
= CTINFO2DIR(ctinfo
);
336 u_int16_t nated_port
= ntohs(port
);
338 /* Set expectations for NAT */
339 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
340 exp
->expectfn
= nf_nat_follow_master
;
343 /* Check existing expects */
344 if (info
->sig_port
[dir
] == port
)
345 nated_port
= ntohs(info
->sig_port
[!dir
]);
347 /* Try to get same port: if not, try to change it. */
348 for (; nated_port
!= 0; nated_port
++) {
351 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
352 ret
= nf_ct_expect_related(exp
);
355 else if (ret
!= -EBUSY
) {
361 if (nated_port
== 0) { /* No port available */
362 net_notice_ratelimited("nf_nat_q931: out of TCP ports\n");
367 if (set_h225_addr(skb
, protoff
, data
, dataoff
, taddr
,
368 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
369 htons(nated_port
)) == 0) {
371 info
->sig_port
[dir
] = port
;
372 info
->sig_port
[!dir
] = htons(nated_port
);
374 nf_ct_unexpect_related(exp
);
378 pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n",
379 &exp
->tuple
.src
.u3
.ip
,
380 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
381 &exp
->tuple
.dst
.u3
.ip
,
382 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
387 /****************************************************************************
388 * This conntrack expect function replaces nf_conntrack_q931_expect()
389 * which was set by nf_conntrack_h323.c.
390 ****************************************************************************/
391 static void ip_nat_q931_expect(struct nf_conn
*new,
392 struct nf_conntrack_expect
*this)
394 struct nf_nat_range range
;
396 if (this->tuple
.src
.u3
.ip
!= 0) { /* Only accept calls from GK */
397 nf_nat_follow_master(new, this);
401 /* This must be a fresh one. */
402 BUG_ON(new->status
& IPS_NAT_DONE_MASK
);
404 /* Change src to where master sends to */
405 range
.flags
= NF_NAT_RANGE_MAP_IPS
;
406 range
.min_addr
= range
.max_addr
=
407 new->tuplehash
[!this->dir
].tuple
.src
.u3
;
408 nf_nat_setup_info(new, &range
, NF_NAT_MANIP_SRC
);
410 /* For DST manip, map port here to where it's expected. */
411 range
.flags
= (NF_NAT_RANGE_MAP_IPS
| NF_NAT_RANGE_PROTO_SPECIFIED
);
412 range
.min_proto
= range
.max_proto
= this->saved_proto
;
413 range
.min_addr
= range
.max_addr
=
414 new->master
->tuplehash
[!this->dir
].tuple
.src
.u3
;
415 nf_nat_setup_info(new, &range
, NF_NAT_MANIP_DST
);
418 /****************************************************************************/
419 static int nat_q931(struct sk_buff
*skb
, struct nf_conn
*ct
,
420 enum ip_conntrack_info ctinfo
,
421 unsigned int protoff
, unsigned char **data
,
422 TransportAddress
*taddr
, int idx
,
423 __be16 port
, struct nf_conntrack_expect
*exp
)
425 struct nf_ct_h323_master
*info
= nfct_help_data(ct
);
426 int dir
= CTINFO2DIR(ctinfo
);
427 u_int16_t nated_port
= ntohs(port
);
428 union nf_inet_addr addr
;
430 /* Set expectations for NAT */
431 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
432 exp
->expectfn
= ip_nat_q931_expect
;
435 /* Check existing expects */
436 if (info
->sig_port
[dir
] == port
)
437 nated_port
= ntohs(info
->sig_port
[!dir
]);
439 /* Try to get same port: if not, try to change it. */
440 for (; nated_port
!= 0; nated_port
++) {
443 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
444 ret
= nf_ct_expect_related(exp
);
447 else if (ret
!= -EBUSY
) {
453 if (nated_port
== 0) { /* No port available */
454 net_notice_ratelimited("nf_nat_ras: out of TCP ports\n");
459 if (set_h225_addr(skb
, protoff
, data
, 0, &taddr
[idx
],
460 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
461 htons(nated_port
)) == 0) {
463 info
->sig_port
[dir
] = port
;
464 info
->sig_port
[!dir
] = htons(nated_port
);
466 /* Fix for Gnomemeeting */
468 get_h225_addr(ct
, *data
, &taddr
[0], &addr
, &port
) &&
469 (ntohl(addr
.ip
) & 0xff000000) == 0x7f000000) {
470 set_h225_addr(skb
, protoff
, data
, 0, &taddr
[0],
471 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
472 info
->sig_port
[!dir
]);
475 nf_ct_unexpect_related(exp
);
480 pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n",
481 &exp
->tuple
.src
.u3
.ip
,
482 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
483 &exp
->tuple
.dst
.u3
.ip
,
484 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
489 /****************************************************************************/
490 static void ip_nat_callforwarding_expect(struct nf_conn
*new,
491 struct nf_conntrack_expect
*this)
493 struct nf_nat_range range
;
495 /* This must be a fresh one. */
496 BUG_ON(new->status
& IPS_NAT_DONE_MASK
);
498 /* Change src to where master sends to */
499 range
.flags
= NF_NAT_RANGE_MAP_IPS
;
500 range
.min_addr
= range
.max_addr
=
501 new->tuplehash
[!this->dir
].tuple
.src
.u3
;
502 nf_nat_setup_info(new, &range
, NF_NAT_MANIP_SRC
);
504 /* For DST manip, map port here to where it's expected. */
505 range
.flags
= (NF_NAT_RANGE_MAP_IPS
| NF_NAT_RANGE_PROTO_SPECIFIED
);
506 range
.min_proto
= range
.max_proto
= this->saved_proto
;
507 range
.min_addr
= range
.max_addr
= this->saved_addr
;
508 nf_nat_setup_info(new, &range
, NF_NAT_MANIP_DST
);
511 /****************************************************************************/
512 static int nat_callforwarding(struct sk_buff
*skb
, struct nf_conn
*ct
,
513 enum ip_conntrack_info ctinfo
,
514 unsigned int protoff
,
515 unsigned char **data
, int dataoff
,
516 TransportAddress
*taddr
, __be16 port
,
517 struct nf_conntrack_expect
*exp
)
519 int dir
= CTINFO2DIR(ctinfo
);
520 u_int16_t nated_port
;
522 /* Set expectations for NAT */
523 exp
->saved_addr
= exp
->tuple
.dst
.u3
;
524 exp
->tuple
.dst
.u3
.ip
= ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
;
525 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
526 exp
->expectfn
= ip_nat_callforwarding_expect
;
529 /* Try to get same port: if not, try to change it. */
530 for (nated_port
= ntohs(port
); nated_port
!= 0; nated_port
++) {
533 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
534 ret
= nf_ct_expect_related(exp
);
537 else if (ret
!= -EBUSY
) {
543 if (nated_port
== 0) { /* No port available */
544 net_notice_ratelimited("nf_nat_q931: out of TCP ports\n");
549 if (!set_h225_addr(skb
, protoff
, data
, dataoff
, taddr
,
550 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
551 htons(nated_port
)) == 0) {
552 nf_ct_unexpect_related(exp
);
557 pr_debug("nf_nat_q931: expect Call Forwarding %pI4:%hu->%pI4:%hu\n",
558 &exp
->tuple
.src
.u3
.ip
,
559 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
560 &exp
->tuple
.dst
.u3
.ip
,
561 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
566 static struct nf_ct_helper_expectfn q931_nat
= {
568 .expectfn
= ip_nat_q931_expect
,
571 static struct nf_ct_helper_expectfn callforwarding_nat
= {
572 .name
= "callforwarding",
573 .expectfn
= ip_nat_callforwarding_expect
,
576 /****************************************************************************/
577 static int __init
init(void)
579 BUG_ON(set_h245_addr_hook
!= NULL
);
580 BUG_ON(set_h225_addr_hook
!= NULL
);
581 BUG_ON(set_sig_addr_hook
!= NULL
);
582 BUG_ON(set_ras_addr_hook
!= NULL
);
583 BUG_ON(nat_rtp_rtcp_hook
!= NULL
);
584 BUG_ON(nat_t120_hook
!= NULL
);
585 BUG_ON(nat_h245_hook
!= NULL
);
586 BUG_ON(nat_callforwarding_hook
!= NULL
);
587 BUG_ON(nat_q931_hook
!= NULL
);
589 RCU_INIT_POINTER(set_h245_addr_hook
, set_h245_addr
);
590 RCU_INIT_POINTER(set_h225_addr_hook
, set_h225_addr
);
591 RCU_INIT_POINTER(set_sig_addr_hook
, set_sig_addr
);
592 RCU_INIT_POINTER(set_ras_addr_hook
, set_ras_addr
);
593 RCU_INIT_POINTER(nat_rtp_rtcp_hook
, nat_rtp_rtcp
);
594 RCU_INIT_POINTER(nat_t120_hook
, nat_t120
);
595 RCU_INIT_POINTER(nat_h245_hook
, nat_h245
);
596 RCU_INIT_POINTER(nat_callforwarding_hook
, nat_callforwarding
);
597 RCU_INIT_POINTER(nat_q931_hook
, nat_q931
);
598 nf_ct_helper_expectfn_register(&q931_nat
);
599 nf_ct_helper_expectfn_register(&callforwarding_nat
);
603 /****************************************************************************/
604 static void __exit
fini(void)
606 RCU_INIT_POINTER(set_h245_addr_hook
, NULL
);
607 RCU_INIT_POINTER(set_h225_addr_hook
, NULL
);
608 RCU_INIT_POINTER(set_sig_addr_hook
, NULL
);
609 RCU_INIT_POINTER(set_ras_addr_hook
, NULL
);
610 RCU_INIT_POINTER(nat_rtp_rtcp_hook
, NULL
);
611 RCU_INIT_POINTER(nat_t120_hook
, NULL
);
612 RCU_INIT_POINTER(nat_h245_hook
, NULL
);
613 RCU_INIT_POINTER(nat_callforwarding_hook
, NULL
);
614 RCU_INIT_POINTER(nat_q931_hook
, NULL
);
615 nf_ct_helper_expectfn_unregister(&q931_nat
);
616 nf_ct_helper_expectfn_unregister(&callforwarding_nat
);
620 /****************************************************************************/
624 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
625 MODULE_DESCRIPTION("H.323 NAT helper");
626 MODULE_LICENSE("GPL");
627 MODULE_ALIAS("ip_nat_h323");