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 %pI4:%hu->%pI4:%hu\n",
124 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
,
125 info
->sig_port
[!dir
]);
126 return set_h225_addr(skb
, data
, 0, &taddr
[i
],
127 &ct
->tuplehash
[!dir
].
129 info
->sig_port
[!dir
]);
130 } else if (addr
.ip
== ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
&&
131 port
== info
->sig_port
[dir
]) {
133 pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
135 &ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
,
136 info
->sig_port
[!dir
]);
137 return set_h225_addr(skb
, data
, 0, &taddr
[i
],
138 &ct
->tuplehash
[!dir
].
140 info
->sig_port
[!dir
]);
148 /****************************************************************************/
149 static int set_ras_addr(struct sk_buff
*skb
, struct nf_conn
*ct
,
150 enum ip_conntrack_info ctinfo
,
151 unsigned char **data
,
152 TransportAddress
*taddr
, int count
)
154 int dir
= CTINFO2DIR(ctinfo
);
157 union nf_inet_addr addr
;
159 for (i
= 0; i
< count
; i
++) {
160 if (get_h225_addr(ct
, *data
, &taddr
[i
], &addr
, &port
) &&
161 addr
.ip
== ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
&&
162 port
== ct
->tuplehash
[dir
].tuple
.src
.u
.udp
.port
) {
163 pr_debug("nf_nat_ras: set rasAddress %pI4:%hu->%pI4:%hu\n",
164 &addr
.ip
, ntohs(port
),
165 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
,
166 ntohs(ct
->tuplehash
[!dir
].tuple
.dst
.u
.udp
.port
));
167 return set_h225_addr(skb
, data
, 0, &taddr
[i
],
168 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
169 ct
->tuplehash
[!dir
].tuple
.
177 /****************************************************************************/
178 static int nat_rtp_rtcp(struct sk_buff
*skb
, struct nf_conn
*ct
,
179 enum ip_conntrack_info ctinfo
,
180 unsigned char **data
, int dataoff
,
181 H245_TransportAddress
*taddr
,
182 __be16 port
, __be16 rtp_port
,
183 struct nf_conntrack_expect
*rtp_exp
,
184 struct nf_conntrack_expect
*rtcp_exp
)
186 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
187 int dir
= CTINFO2DIR(ctinfo
);
189 u_int16_t nated_port
;
191 /* Set expectations for NAT */
192 rtp_exp
->saved_proto
.udp
.port
= rtp_exp
->tuple
.dst
.u
.udp
.port
;
193 rtp_exp
->expectfn
= nf_nat_follow_master
;
195 rtcp_exp
->saved_proto
.udp
.port
= rtcp_exp
->tuple
.dst
.u
.udp
.port
;
196 rtcp_exp
->expectfn
= nf_nat_follow_master
;
197 rtcp_exp
->dir
= !dir
;
199 /* Lookup existing expects */
200 for (i
= 0; i
< H323_RTP_CHANNEL_MAX
; i
++) {
201 if (info
->rtp_port
[i
][dir
] == rtp_port
) {
204 /* Use allocated ports first. This will refresh
206 rtp_exp
->tuple
.dst
.u
.udp
.port
= info
->rtp_port
[i
][dir
];
207 rtcp_exp
->tuple
.dst
.u
.udp
.port
=
208 htons(ntohs(info
->rtp_port
[i
][dir
]) + 1);
210 } else if (info
->rtp_port
[i
][dir
] == 0) {
216 /* Run out of expectations */
217 if (i
>= H323_RTP_CHANNEL_MAX
) {
219 printk("nf_nat_h323: out of expectations\n");
223 /* Try to get a pair of ports. */
224 for (nated_port
= ntohs(rtp_exp
->tuple
.dst
.u
.udp
.port
);
225 nated_port
!= 0; nated_port
+= 2) {
226 rtp_exp
->tuple
.dst
.u
.udp
.port
= htons(nated_port
);
227 if (nf_ct_expect_related(rtp_exp
) == 0) {
228 rtcp_exp
->tuple
.dst
.u
.udp
.port
=
229 htons(nated_port
+ 1);
230 if (nf_ct_expect_related(rtcp_exp
) == 0)
232 nf_ct_unexpect_related(rtp_exp
);
236 if (nated_port
== 0) { /* No port available */
238 printk("nf_nat_h323: out of RTP ports\n");
243 if (set_h245_addr(skb
, data
, dataoff
, taddr
,
244 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
245 htons((port
& htons(1)) ? nated_port
+ 1 :
248 info
->rtp_port
[i
][dir
] = rtp_port
;
249 info
->rtp_port
[i
][!dir
] = htons(nated_port
);
251 nf_ct_unexpect_related(rtp_exp
);
252 nf_ct_unexpect_related(rtcp_exp
);
257 pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n",
258 &rtp_exp
->tuple
.src
.u3
.ip
,
259 ntohs(rtp_exp
->tuple
.src
.u
.udp
.port
),
260 &rtp_exp
->tuple
.dst
.u3
.ip
,
261 ntohs(rtp_exp
->tuple
.dst
.u
.udp
.port
));
262 pr_debug("nf_nat_h323: expect RTCP %pI4:%hu->%pI4:%hu\n",
263 &rtcp_exp
->tuple
.src
.u3
.ip
,
264 ntohs(rtcp_exp
->tuple
.src
.u
.udp
.port
),
265 &rtcp_exp
->tuple
.dst
.u3
.ip
,
266 ntohs(rtcp_exp
->tuple
.dst
.u
.udp
.port
));
271 /****************************************************************************/
272 static int nat_t120(struct sk_buff
*skb
, struct nf_conn
*ct
,
273 enum ip_conntrack_info ctinfo
,
274 unsigned char **data
, int dataoff
,
275 H245_TransportAddress
*taddr
, __be16 port
,
276 struct nf_conntrack_expect
*exp
)
278 int dir
= CTINFO2DIR(ctinfo
);
279 u_int16_t nated_port
= ntohs(port
);
281 /* Set expectations for NAT */
282 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
283 exp
->expectfn
= nf_nat_follow_master
;
286 /* Try to get same port: if not, try to change it. */
287 for (; nated_port
!= 0; nated_port
++) {
288 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
289 if (nf_ct_expect_related(exp
) == 0)
293 if (nated_port
== 0) { /* No port available */
295 printk("nf_nat_h323: out of TCP ports\n");
300 if (set_h245_addr(skb
, data
, dataoff
, taddr
,
301 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
302 htons(nated_port
)) < 0) {
303 nf_ct_unexpect_related(exp
);
307 pr_debug("nf_nat_h323: expect T.120 %pI4:%hu->%pI4:%hu\n",
308 &exp
->tuple
.src
.u3
.ip
,
309 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
310 &exp
->tuple
.dst
.u3
.ip
,
311 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
316 /****************************************************************************/
317 static int nat_h245(struct sk_buff
*skb
, struct nf_conn
*ct
,
318 enum ip_conntrack_info ctinfo
,
319 unsigned char **data
, int dataoff
,
320 TransportAddress
*taddr
, __be16 port
,
321 struct nf_conntrack_expect
*exp
)
323 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
324 int dir
= CTINFO2DIR(ctinfo
);
325 u_int16_t nated_port
= ntohs(port
);
327 /* Set expectations for NAT */
328 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
329 exp
->expectfn
= nf_nat_follow_master
;
332 /* Check existing expects */
333 if (info
->sig_port
[dir
] == port
)
334 nated_port
= ntohs(info
->sig_port
[!dir
]);
336 /* Try to get same port: if not, try to change it. */
337 for (; nated_port
!= 0; nated_port
++) {
338 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
339 if (nf_ct_expect_related(exp
) == 0)
343 if (nated_port
== 0) { /* No port available */
345 printk("nf_nat_q931: out of TCP ports\n");
350 if (set_h225_addr(skb
, data
, dataoff
, taddr
,
351 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
352 htons(nated_port
)) == 0) {
354 info
->sig_port
[dir
] = port
;
355 info
->sig_port
[!dir
] = htons(nated_port
);
357 nf_ct_unexpect_related(exp
);
361 pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n",
362 &exp
->tuple
.src
.u3
.ip
,
363 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
364 &exp
->tuple
.dst
.u3
.ip
,
365 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
370 /****************************************************************************
371 * This conntrack expect function replaces nf_conntrack_q931_expect()
372 * which was set by nf_conntrack_h323.c.
373 ****************************************************************************/
374 static void ip_nat_q931_expect(struct nf_conn
*new,
375 struct nf_conntrack_expect
*this)
377 struct nf_nat_range range
;
379 if (this->tuple
.src
.u3
.ip
!= 0) { /* Only accept calls from GK */
380 nf_nat_follow_master(new, this);
384 /* This must be a fresh one. */
385 BUG_ON(new->status
& IPS_NAT_DONE_MASK
);
387 /* Change src to where master sends to */
388 range
.flags
= IP_NAT_RANGE_MAP_IPS
;
389 range
.min_ip
= range
.max_ip
= new->tuplehash
[!this->dir
].tuple
.src
.u3
.ip
;
390 nf_nat_setup_info(new, &range
, IP_NAT_MANIP_SRC
);
392 /* For DST manip, map port here to where it's expected. */
393 range
.flags
= (IP_NAT_RANGE_MAP_IPS
| IP_NAT_RANGE_PROTO_SPECIFIED
);
394 range
.min
= range
.max
= this->saved_proto
;
395 range
.min_ip
= range
.max_ip
=
396 new->master
->tuplehash
[!this->dir
].tuple
.src
.u3
.ip
;
397 nf_nat_setup_info(new, &range
, IP_NAT_MANIP_DST
);
400 /****************************************************************************/
401 static int nat_q931(struct sk_buff
*skb
, struct nf_conn
*ct
,
402 enum ip_conntrack_info ctinfo
,
403 unsigned char **data
, TransportAddress
*taddr
, int idx
,
404 __be16 port
, struct nf_conntrack_expect
*exp
)
406 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
407 int dir
= CTINFO2DIR(ctinfo
);
408 u_int16_t nated_port
= ntohs(port
);
409 union nf_inet_addr addr
;
411 /* Set expectations for NAT */
412 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
413 exp
->expectfn
= ip_nat_q931_expect
;
416 /* Check existing expects */
417 if (info
->sig_port
[dir
] == port
)
418 nated_port
= ntohs(info
->sig_port
[!dir
]);
420 /* Try to get same port: if not, try to change it. */
421 for (; nated_port
!= 0; nated_port
++) {
422 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
423 if (nf_ct_expect_related(exp
) == 0)
427 if (nated_port
== 0) { /* No port available */
429 printk("nf_nat_ras: out of TCP ports\n");
434 if (set_h225_addr(skb
, data
, 0, &taddr
[idx
],
435 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
436 htons(nated_port
)) == 0) {
438 info
->sig_port
[dir
] = port
;
439 info
->sig_port
[!dir
] = htons(nated_port
);
441 /* Fix for Gnomemeeting */
443 get_h225_addr(ct
, *data
, &taddr
[0], &addr
, &port
) &&
444 (ntohl(addr
.ip
) & 0xff000000) == 0x7f000000) {
445 set_h225_addr(skb
, data
, 0, &taddr
[0],
446 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
447 info
->sig_port
[!dir
]);
450 nf_ct_unexpect_related(exp
);
455 pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n",
456 &exp
->tuple
.src
.u3
.ip
,
457 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
458 &exp
->tuple
.dst
.u3
.ip
,
459 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
464 /****************************************************************************/
465 static void ip_nat_callforwarding_expect(struct nf_conn
*new,
466 struct nf_conntrack_expect
*this)
468 struct nf_nat_range range
;
470 /* This must be a fresh one. */
471 BUG_ON(new->status
& IPS_NAT_DONE_MASK
);
473 /* Change src to where master sends to */
474 range
.flags
= IP_NAT_RANGE_MAP_IPS
;
475 range
.min_ip
= range
.max_ip
= new->tuplehash
[!this->dir
].tuple
.src
.u3
.ip
;
476 nf_nat_setup_info(new, &range
, IP_NAT_MANIP_SRC
);
478 /* For DST manip, map port here to where it's expected. */
479 range
.flags
= (IP_NAT_RANGE_MAP_IPS
| IP_NAT_RANGE_PROTO_SPECIFIED
);
480 range
.min
= range
.max
= this->saved_proto
;
481 range
.min_ip
= range
.max_ip
= this->saved_ip
;
482 nf_nat_setup_info(new, &range
, IP_NAT_MANIP_DST
);
485 /****************************************************************************/
486 static int nat_callforwarding(struct sk_buff
*skb
, struct nf_conn
*ct
,
487 enum ip_conntrack_info ctinfo
,
488 unsigned char **data
, int dataoff
,
489 TransportAddress
*taddr
, __be16 port
,
490 struct nf_conntrack_expect
*exp
)
492 int dir
= CTINFO2DIR(ctinfo
);
493 u_int16_t nated_port
;
495 /* Set expectations for NAT */
496 exp
->saved_ip
= exp
->tuple
.dst
.u3
.ip
;
497 exp
->tuple
.dst
.u3
.ip
= ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
;
498 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
499 exp
->expectfn
= ip_nat_callforwarding_expect
;
502 /* Try to get same port: if not, try to change it. */
503 for (nated_port
= ntohs(port
); nated_port
!= 0; nated_port
++) {
504 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
505 if (nf_ct_expect_related(exp
) == 0)
509 if (nated_port
== 0) { /* No port available */
511 printk("nf_nat_q931: out of TCP ports\n");
516 if (!set_h225_addr(skb
, data
, dataoff
, taddr
,
517 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
518 htons(nated_port
)) == 0) {
519 nf_ct_unexpect_related(exp
);
524 pr_debug("nf_nat_q931: expect Call Forwarding %pI4:%hu->%pI4:%hu\n",
525 &exp
->tuple
.src
.u3
.ip
,
526 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
527 &exp
->tuple
.dst
.u3
.ip
,
528 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
533 /****************************************************************************/
534 static int __init
init(void)
536 BUG_ON(set_h245_addr_hook
!= NULL
);
537 BUG_ON(set_h225_addr_hook
!= NULL
);
538 BUG_ON(set_sig_addr_hook
!= NULL
);
539 BUG_ON(set_ras_addr_hook
!= NULL
);
540 BUG_ON(nat_rtp_rtcp_hook
!= NULL
);
541 BUG_ON(nat_t120_hook
!= NULL
);
542 BUG_ON(nat_h245_hook
!= NULL
);
543 BUG_ON(nat_callforwarding_hook
!= NULL
);
544 BUG_ON(nat_q931_hook
!= NULL
);
546 rcu_assign_pointer(set_h245_addr_hook
, set_h245_addr
);
547 rcu_assign_pointer(set_h225_addr_hook
, set_h225_addr
);
548 rcu_assign_pointer(set_sig_addr_hook
, set_sig_addr
);
549 rcu_assign_pointer(set_ras_addr_hook
, set_ras_addr
);
550 rcu_assign_pointer(nat_rtp_rtcp_hook
, nat_rtp_rtcp
);
551 rcu_assign_pointer(nat_t120_hook
, nat_t120
);
552 rcu_assign_pointer(nat_h245_hook
, nat_h245
);
553 rcu_assign_pointer(nat_callforwarding_hook
, nat_callforwarding
);
554 rcu_assign_pointer(nat_q931_hook
, nat_q931
);
558 /****************************************************************************/
559 static void __exit
fini(void)
561 rcu_assign_pointer(set_h245_addr_hook
, NULL
);
562 rcu_assign_pointer(set_h225_addr_hook
, NULL
);
563 rcu_assign_pointer(set_sig_addr_hook
, NULL
);
564 rcu_assign_pointer(set_ras_addr_hook
, NULL
);
565 rcu_assign_pointer(nat_rtp_rtcp_hook
, NULL
);
566 rcu_assign_pointer(nat_t120_hook
, NULL
);
567 rcu_assign_pointer(nat_h245_hook
, NULL
);
568 rcu_assign_pointer(nat_callforwarding_hook
, NULL
);
569 rcu_assign_pointer(nat_q931_hook
, NULL
);
573 /****************************************************************************/
577 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
578 MODULE_DESCRIPTION("H.323 NAT helper");
579 MODULE_LICENSE("GPL");
580 MODULE_ALIAS("ip_nat_h323");