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/moduleparam.h>
14 #include <linux/tcp.h>
17 #include <net/netfilter/nf_nat.h>
18 #include <net/netfilter/nf_nat_helper.h>
19 #include <net/netfilter/nf_nat_rule.h>
20 #include <net/netfilter/nf_conntrack_helper.h>
21 #include <net/netfilter/nf_conntrack_expect.h>
22 #include <linux/netfilter/nf_conntrack_h323.h>
24 /****************************************************************************/
25 static int set_addr(struct sk_buff
*skb
,
26 unsigned char **data
, int dataoff
,
27 unsigned int addroff
, __be32 ip
, __be16 port
)
29 enum ip_conntrack_info ctinfo
;
30 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
34 } __attribute__ ((__packed__
)) buf
;
35 const struct tcphdr
*th
;
42 if (ip_hdr(skb
)->protocol
== IPPROTO_TCP
) {
43 if (!nf_nat_mangle_tcp_packet(skb
, ct
, ctinfo
,
45 (char *) &buf
, sizeof(buf
))) {
47 printk("nf_nat_h323: nf_nat_mangle_tcp_packet"
52 /* Relocate data pointer */
53 th
= skb_header_pointer(skb
, ip_hdrlen(skb
),
54 sizeof(_tcph
), &_tcph
);
57 *data
= skb
->data
+ ip_hdrlen(skb
) + th
->doff
* 4 + dataoff
;
59 if (!nf_nat_mangle_udp_packet(skb
, ct
, ctinfo
,
61 (char *) &buf
, sizeof(buf
))) {
63 printk("nf_nat_h323: nf_nat_mangle_udp_packet"
67 /* nf_nat_mangle_udp_packet uses skb_make_writable() to copy
68 * or pull everything in a linear buffer, so we can safely
69 * use the skb pointers now */
70 *data
= skb
->data
+ ip_hdrlen(skb
) + sizeof(struct udphdr
);
76 /****************************************************************************/
77 static int set_h225_addr(struct sk_buff
*skb
,
78 unsigned char **data
, int dataoff
,
79 TransportAddress
*taddr
,
80 union nf_inet_addr
*addr
, __be16 port
)
82 return set_addr(skb
, data
, dataoff
, taddr
->ipAddress
.ip
,
86 /****************************************************************************/
87 static int set_h245_addr(struct sk_buff
*skb
,
88 unsigned char **data
, int dataoff
,
89 H245_TransportAddress
*taddr
,
90 union nf_inet_addr
*addr
, __be16 port
)
92 return set_addr(skb
, data
, dataoff
,
93 taddr
->unicastAddress
.iPAddress
.network
,
97 /****************************************************************************/
98 static int set_sig_addr(struct sk_buff
*skb
, struct nf_conn
*ct
,
99 enum ip_conntrack_info ctinfo
,
100 unsigned char **data
,
101 TransportAddress
*taddr
, int count
)
103 const struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
104 int dir
= CTINFO2DIR(ctinfo
);
107 union nf_inet_addr addr
;
109 for (i
= 0; i
< count
; i
++) {
110 if (get_h225_addr(ct
, *data
, &taddr
[i
], &addr
, &port
)) {
111 if (addr
.ip
== ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
&&
112 port
== info
->sig_port
[dir
]) {
115 /* Fix for Gnomemeeting */
117 get_h225_addr(ct
, *data
, &taddr
[0],
119 (ntohl(addr
.ip
) & 0xff000000) == 0x7f000000)
122 pr_debug("nf_nat_ras: set signal address "
123 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
124 NIPQUAD(addr
.ip
), port
,
125 NIPQUAD(ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
),
126 info
->sig_port
[!dir
]);
127 return set_h225_addr(skb
, data
, 0, &taddr
[i
],
128 &ct
->tuplehash
[!dir
].
130 info
->sig_port
[!dir
]);
131 } else if (addr
.ip
== ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
&&
132 port
== info
->sig_port
[dir
]) {
134 pr_debug("nf_nat_ras: set signal address "
135 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
136 NIPQUAD(addr
.ip
), port
,
137 NIPQUAD(ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
),
138 info
->sig_port
[!dir
]);
139 return set_h225_addr(skb
, data
, 0, &taddr
[i
],
140 &ct
->tuplehash
[!dir
].
142 info
->sig_port
[!dir
]);
150 /****************************************************************************/
151 static int set_ras_addr(struct sk_buff
*skb
, struct nf_conn
*ct
,
152 enum ip_conntrack_info ctinfo
,
153 unsigned char **data
,
154 TransportAddress
*taddr
, int count
)
156 int dir
= CTINFO2DIR(ctinfo
);
159 union nf_inet_addr addr
;
161 for (i
= 0; i
< count
; i
++) {
162 if (get_h225_addr(ct
, *data
, &taddr
[i
], &addr
, &port
) &&
163 addr
.ip
== ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
&&
164 port
== ct
->tuplehash
[dir
].tuple
.src
.u
.udp
.port
) {
165 pr_debug("nf_nat_ras: set rasAddress "
166 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
167 NIPQUAD(addr
.ip
), ntohs(port
),
168 NIPQUAD(ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
),
169 ntohs(ct
->tuplehash
[!dir
].tuple
.dst
.u
.udp
.port
));
170 return set_h225_addr(skb
, data
, 0, &taddr
[i
],
171 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
172 ct
->tuplehash
[!dir
].tuple
.
180 /****************************************************************************/
181 static int nat_rtp_rtcp(struct sk_buff
*skb
, struct nf_conn
*ct
,
182 enum ip_conntrack_info ctinfo
,
183 unsigned char **data
, int dataoff
,
184 H245_TransportAddress
*taddr
,
185 __be16 port
, __be16 rtp_port
,
186 struct nf_conntrack_expect
*rtp_exp
,
187 struct nf_conntrack_expect
*rtcp_exp
)
189 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
190 int dir
= CTINFO2DIR(ctinfo
);
192 u_int16_t nated_port
;
194 /* Set expectations for NAT */
195 rtp_exp
->saved_proto
.udp
.port
= rtp_exp
->tuple
.dst
.u
.udp
.port
;
196 rtp_exp
->expectfn
= nf_nat_follow_master
;
198 rtcp_exp
->saved_proto
.udp
.port
= rtcp_exp
->tuple
.dst
.u
.udp
.port
;
199 rtcp_exp
->expectfn
= nf_nat_follow_master
;
200 rtcp_exp
->dir
= !dir
;
202 /* Lookup existing expects */
203 for (i
= 0; i
< H323_RTP_CHANNEL_MAX
; i
++) {
204 if (info
->rtp_port
[i
][dir
] == rtp_port
) {
207 /* Use allocated ports first. This will refresh
209 rtp_exp
->tuple
.dst
.u
.udp
.port
= info
->rtp_port
[i
][dir
];
210 rtcp_exp
->tuple
.dst
.u
.udp
.port
=
211 htons(ntohs(info
->rtp_port
[i
][dir
]) + 1);
213 } else if (info
->rtp_port
[i
][dir
] == 0) {
219 /* Run out of expectations */
220 if (i
>= H323_RTP_CHANNEL_MAX
) {
222 printk("nf_nat_h323: out of expectations\n");
226 /* Try to get a pair of ports. */
227 for (nated_port
= ntohs(rtp_exp
->tuple
.dst
.u
.udp
.port
);
228 nated_port
!= 0; nated_port
+= 2) {
229 rtp_exp
->tuple
.dst
.u
.udp
.port
= htons(nated_port
);
230 if (nf_ct_expect_related(rtp_exp
) == 0) {
231 rtcp_exp
->tuple
.dst
.u
.udp
.port
=
232 htons(nated_port
+ 1);
233 if (nf_ct_expect_related(rtcp_exp
) == 0)
235 nf_ct_unexpect_related(rtp_exp
);
239 if (nated_port
== 0) { /* No port available */
241 printk("nf_nat_h323: out of RTP ports\n");
246 if (set_h245_addr(skb
, data
, dataoff
, taddr
,
247 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
248 htons((port
& htons(1)) ? nated_port
+ 1 :
251 info
->rtp_port
[i
][dir
] = rtp_port
;
252 info
->rtp_port
[i
][!dir
] = htons(nated_port
);
254 nf_ct_unexpect_related(rtp_exp
);
255 nf_ct_unexpect_related(rtcp_exp
);
260 pr_debug("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
261 NIPQUAD(rtp_exp
->tuple
.src
.u3
.ip
),
262 ntohs(rtp_exp
->tuple
.src
.u
.udp
.port
),
263 NIPQUAD(rtp_exp
->tuple
.dst
.u3
.ip
),
264 ntohs(rtp_exp
->tuple
.dst
.u
.udp
.port
));
265 pr_debug("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
266 NIPQUAD(rtcp_exp
->tuple
.src
.u3
.ip
),
267 ntohs(rtcp_exp
->tuple
.src
.u
.udp
.port
),
268 NIPQUAD(rtcp_exp
->tuple
.dst
.u3
.ip
),
269 ntohs(rtcp_exp
->tuple
.dst
.u
.udp
.port
));
274 /****************************************************************************/
275 static int nat_t120(struct sk_buff
*skb
, struct nf_conn
*ct
,
276 enum ip_conntrack_info ctinfo
,
277 unsigned char **data
, int dataoff
,
278 H245_TransportAddress
*taddr
, __be16 port
,
279 struct nf_conntrack_expect
*exp
)
281 int dir
= CTINFO2DIR(ctinfo
);
282 u_int16_t nated_port
= ntohs(port
);
284 /* Set expectations for NAT */
285 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
286 exp
->expectfn
= nf_nat_follow_master
;
289 /* Try to get same port: if not, try to change it. */
290 for (; nated_port
!= 0; nated_port
++) {
291 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
292 if (nf_ct_expect_related(exp
) == 0)
296 if (nated_port
== 0) { /* No port available */
298 printk("nf_nat_h323: out of TCP ports\n");
303 if (set_h245_addr(skb
, data
, dataoff
, taddr
,
304 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
305 htons(nated_port
)) < 0) {
306 nf_ct_unexpect_related(exp
);
310 pr_debug("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
311 NIPQUAD(exp
->tuple
.src
.u3
.ip
),
312 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
313 NIPQUAD(exp
->tuple
.dst
.u3
.ip
),
314 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
319 /****************************************************************************/
320 static int nat_h245(struct sk_buff
*skb
, struct nf_conn
*ct
,
321 enum ip_conntrack_info ctinfo
,
322 unsigned char **data
, int dataoff
,
323 TransportAddress
*taddr
, __be16 port
,
324 struct nf_conntrack_expect
*exp
)
326 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
327 int dir
= CTINFO2DIR(ctinfo
);
328 u_int16_t nated_port
= ntohs(port
);
330 /* Set expectations for NAT */
331 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
332 exp
->expectfn
= nf_nat_follow_master
;
335 /* Check existing expects */
336 if (info
->sig_port
[dir
] == port
)
337 nated_port
= ntohs(info
->sig_port
[!dir
]);
339 /* Try to get same port: if not, try to change it. */
340 for (; nated_port
!= 0; nated_port
++) {
341 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
342 if (nf_ct_expect_related(exp
) == 0)
346 if (nated_port
== 0) { /* No port available */
348 printk("nf_nat_q931: out of TCP ports\n");
353 if (set_h225_addr(skb
, data
, dataoff
, taddr
,
354 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
355 htons(nated_port
)) == 0) {
357 info
->sig_port
[dir
] = port
;
358 info
->sig_port
[!dir
] = htons(nated_port
);
360 nf_ct_unexpect_related(exp
);
364 pr_debug("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
365 NIPQUAD(exp
->tuple
.src
.u3
.ip
),
366 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
367 NIPQUAD(exp
->tuple
.dst
.u3
.ip
),
368 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
373 /****************************************************************************
374 * This conntrack expect function replaces nf_conntrack_q931_expect()
375 * which was set by nf_conntrack_h323.c.
376 ****************************************************************************/
377 static void ip_nat_q931_expect(struct nf_conn
*new,
378 struct nf_conntrack_expect
*this)
380 struct nf_nat_range range
;
382 if (this->tuple
.src
.u3
.ip
!= 0) { /* Only accept calls from GK */
383 nf_nat_follow_master(new, this);
387 /* This must be a fresh one. */
388 BUG_ON(new->status
& IPS_NAT_DONE_MASK
);
390 /* Change src to where master sends to */
391 range
.flags
= IP_NAT_RANGE_MAP_IPS
;
392 range
.min_ip
= range
.max_ip
= new->tuplehash
[!this->dir
].tuple
.src
.u3
.ip
;
393 nf_nat_setup_info(new, &range
, IP_NAT_MANIP_SRC
);
395 /* For DST manip, map port here to where it's expected. */
396 range
.flags
= (IP_NAT_RANGE_MAP_IPS
| IP_NAT_RANGE_PROTO_SPECIFIED
);
397 range
.min
= range
.max
= this->saved_proto
;
398 range
.min_ip
= range
.max_ip
=
399 new->master
->tuplehash
[!this->dir
].tuple
.src
.u3
.ip
;
400 nf_nat_setup_info(new, &range
, IP_NAT_MANIP_DST
);
403 /****************************************************************************/
404 static int nat_q931(struct sk_buff
*skb
, struct nf_conn
*ct
,
405 enum ip_conntrack_info ctinfo
,
406 unsigned char **data
, TransportAddress
*taddr
, int idx
,
407 __be16 port
, struct nf_conntrack_expect
*exp
)
409 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
410 int dir
= CTINFO2DIR(ctinfo
);
411 u_int16_t nated_port
= ntohs(port
);
412 union nf_inet_addr addr
;
414 /* Set expectations for NAT */
415 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
416 exp
->expectfn
= ip_nat_q931_expect
;
419 /* Check existing expects */
420 if (info
->sig_port
[dir
] == port
)
421 nated_port
= ntohs(info
->sig_port
[!dir
]);
423 /* Try to get same port: if not, try to change it. */
424 for (; nated_port
!= 0; nated_port
++) {
425 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
426 if (nf_ct_expect_related(exp
) == 0)
430 if (nated_port
== 0) { /* No port available */
432 printk("nf_nat_ras: out of TCP ports\n");
437 if (set_h225_addr(skb
, data
, 0, &taddr
[idx
],
438 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
439 htons(nated_port
)) == 0) {
441 info
->sig_port
[dir
] = port
;
442 info
->sig_port
[!dir
] = htons(nated_port
);
444 /* Fix for Gnomemeeting */
446 get_h225_addr(ct
, *data
, &taddr
[0], &addr
, &port
) &&
447 (ntohl(addr
.ip
) & 0xff000000) == 0x7f000000) {
448 set_h225_addr(skb
, data
, 0, &taddr
[0],
449 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
450 info
->sig_port
[!dir
]);
453 nf_ct_unexpect_related(exp
);
458 pr_debug("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
459 NIPQUAD(exp
->tuple
.src
.u3
.ip
),
460 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
461 NIPQUAD(exp
->tuple
.dst
.u3
.ip
),
462 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
467 /****************************************************************************/
468 static void ip_nat_callforwarding_expect(struct nf_conn
*new,
469 struct nf_conntrack_expect
*this)
471 struct nf_nat_range range
;
473 /* This must be a fresh one. */
474 BUG_ON(new->status
& IPS_NAT_DONE_MASK
);
476 /* Change src to where master sends to */
477 range
.flags
= IP_NAT_RANGE_MAP_IPS
;
478 range
.min_ip
= range
.max_ip
= new->tuplehash
[!this->dir
].tuple
.src
.u3
.ip
;
479 nf_nat_setup_info(new, &range
, IP_NAT_MANIP_SRC
);
481 /* For DST manip, map port here to where it's expected. */
482 range
.flags
= (IP_NAT_RANGE_MAP_IPS
| IP_NAT_RANGE_PROTO_SPECIFIED
);
483 range
.min
= range
.max
= this->saved_proto
;
484 range
.min_ip
= range
.max_ip
= this->saved_ip
;
485 nf_nat_setup_info(new, &range
, IP_NAT_MANIP_DST
);
488 /****************************************************************************/
489 static int nat_callforwarding(struct sk_buff
*skb
, struct nf_conn
*ct
,
490 enum ip_conntrack_info ctinfo
,
491 unsigned char **data
, int dataoff
,
492 TransportAddress
*taddr
, __be16 port
,
493 struct nf_conntrack_expect
*exp
)
495 int dir
= CTINFO2DIR(ctinfo
);
496 u_int16_t nated_port
;
498 /* Set expectations for NAT */
499 exp
->saved_ip
= exp
->tuple
.dst
.u3
.ip
;
500 exp
->tuple
.dst
.u3
.ip
= ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
;
501 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
502 exp
->expectfn
= ip_nat_callforwarding_expect
;
505 /* Try to get same port: if not, try to change it. */
506 for (nated_port
= ntohs(port
); nated_port
!= 0; nated_port
++) {
507 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
508 if (nf_ct_expect_related(exp
) == 0)
512 if (nated_port
== 0) { /* No port available */
514 printk("nf_nat_q931: out of TCP ports\n");
519 if (!set_h225_addr(skb
, data
, dataoff
, taddr
,
520 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
521 htons(nated_port
)) == 0) {
522 nf_ct_unexpect_related(exp
);
527 pr_debug("nf_nat_q931: expect Call Forwarding "
528 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
529 NIPQUAD(exp
->tuple
.src
.u3
.ip
),
530 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
531 NIPQUAD(exp
->tuple
.dst
.u3
.ip
),
532 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
537 /****************************************************************************/
538 static int __init
init(void)
540 BUG_ON(set_h245_addr_hook
!= NULL
);
541 BUG_ON(set_h225_addr_hook
!= NULL
);
542 BUG_ON(set_sig_addr_hook
!= NULL
);
543 BUG_ON(set_ras_addr_hook
!= NULL
);
544 BUG_ON(nat_rtp_rtcp_hook
!= NULL
);
545 BUG_ON(nat_t120_hook
!= NULL
);
546 BUG_ON(nat_h245_hook
!= NULL
);
547 BUG_ON(nat_callforwarding_hook
!= NULL
);
548 BUG_ON(nat_q931_hook
!= NULL
);
550 rcu_assign_pointer(set_h245_addr_hook
, set_h245_addr
);
551 rcu_assign_pointer(set_h225_addr_hook
, set_h225_addr
);
552 rcu_assign_pointer(set_sig_addr_hook
, set_sig_addr
);
553 rcu_assign_pointer(set_ras_addr_hook
, set_ras_addr
);
554 rcu_assign_pointer(nat_rtp_rtcp_hook
, nat_rtp_rtcp
);
555 rcu_assign_pointer(nat_t120_hook
, nat_t120
);
556 rcu_assign_pointer(nat_h245_hook
, nat_h245
);
557 rcu_assign_pointer(nat_callforwarding_hook
, nat_callforwarding
);
558 rcu_assign_pointer(nat_q931_hook
, nat_q931
);
562 /****************************************************************************/
563 static void __exit
fini(void)
565 rcu_assign_pointer(set_h245_addr_hook
, NULL
);
566 rcu_assign_pointer(set_h225_addr_hook
, NULL
);
567 rcu_assign_pointer(set_sig_addr_hook
, NULL
);
568 rcu_assign_pointer(set_ras_addr_hook
, NULL
);
569 rcu_assign_pointer(nat_rtp_rtcp_hook
, NULL
);
570 rcu_assign_pointer(nat_t120_hook
, NULL
);
571 rcu_assign_pointer(nat_h245_hook
, NULL
);
572 rcu_assign_pointer(nat_callforwarding_hook
, NULL
);
573 rcu_assign_pointer(nat_q931_hook
, NULL
);
577 /****************************************************************************/
581 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
582 MODULE_DESCRIPTION("H.323 NAT helper");
583 MODULE_LICENSE("GPL");
584 MODULE_ALIAS("ip_nat_h323");