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 struct tcphdr _tcph
, *th
;
41 if (ip_hdr(skb
)->protocol
== IPPROTO_TCP
) {
42 if (!nf_nat_mangle_tcp_packet(skb
, ct
, ctinfo
,
44 (char *) &buf
, sizeof(buf
))) {
46 printk("nf_nat_h323: nf_nat_mangle_tcp_packet"
51 /* Relocate data pointer */
52 th
= skb_header_pointer(skb
, ip_hdrlen(skb
),
53 sizeof(_tcph
), &_tcph
);
56 *data
= skb
->data
+ ip_hdrlen(skb
) + th
->doff
* 4 + dataoff
;
58 if (!nf_nat_mangle_udp_packet(skb
, ct
, ctinfo
,
60 (char *) &buf
, sizeof(buf
))) {
62 printk("nf_nat_h323: nf_nat_mangle_udp_packet"
66 /* nf_nat_mangle_udp_packet uses skb_make_writable() to copy
67 * or pull everything in a linear buffer, so we can safely
68 * use the skb pointers now */
69 *data
= skb
->data
+ ip_hdrlen(skb
) + sizeof(struct udphdr
);
75 /****************************************************************************/
76 static int set_h225_addr(struct sk_buff
*skb
,
77 unsigned char **data
, int dataoff
,
78 TransportAddress
*taddr
,
79 union nf_conntrack_address
*addr
, __be16 port
)
81 return set_addr(skb
, data
, dataoff
, taddr
->ipAddress
.ip
,
85 /****************************************************************************/
86 static int set_h245_addr(struct sk_buff
*skb
,
87 unsigned char **data
, int dataoff
,
88 H245_TransportAddress
*taddr
,
89 union nf_conntrack_address
*addr
, __be16 port
)
91 return set_addr(skb
, data
, dataoff
,
92 taddr
->unicastAddress
.iPAddress
.network
,
96 /****************************************************************************/
97 static int set_sig_addr(struct sk_buff
*skb
, struct nf_conn
*ct
,
98 enum ip_conntrack_info ctinfo
,
100 TransportAddress
*taddr
, int count
)
102 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
103 int dir
= CTINFO2DIR(ctinfo
);
106 union nf_conntrack_address addr
;
108 for (i
= 0; i
< count
; i
++) {
109 if (get_h225_addr(ct
, *data
, &taddr
[i
], &addr
, &port
)) {
110 if (addr
.ip
== ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
&&
111 port
== info
->sig_port
[dir
]) {
114 /* Fix for Gnomemeeting */
116 get_h225_addr(ct
, *data
, &taddr
[0],
118 (ntohl(addr
.ip
) & 0xff000000) == 0x7f000000)
121 pr_debug("nf_nat_ras: set signal address "
122 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
123 NIPQUAD(addr
.ip
), port
,
124 NIPQUAD(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 "
134 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
135 NIPQUAD(addr
.ip
), port
,
136 NIPQUAD(ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
),
137 info
->sig_port
[!dir
]);
138 return set_h225_addr(skb
, data
, 0, &taddr
[i
],
139 &ct
->tuplehash
[!dir
].
141 info
->sig_port
[!dir
]);
149 /****************************************************************************/
150 static int set_ras_addr(struct sk_buff
*skb
, struct nf_conn
*ct
,
151 enum ip_conntrack_info ctinfo
,
152 unsigned char **data
,
153 TransportAddress
*taddr
, int count
)
155 int dir
= CTINFO2DIR(ctinfo
);
158 union nf_conntrack_address addr
;
160 for (i
= 0; i
< count
; i
++) {
161 if (get_h225_addr(ct
, *data
, &taddr
[i
], &addr
, &port
) &&
162 addr
.ip
== ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
&&
163 port
== ct
->tuplehash
[dir
].tuple
.src
.u
.udp
.port
) {
164 pr_debug("nf_nat_ras: set rasAddress "
165 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
166 NIPQUAD(addr
.ip
), ntohs(port
),
167 NIPQUAD(ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
),
168 ntohs(ct
->tuplehash
[!dir
].tuple
.dst
.u
.udp
.port
));
169 return set_h225_addr(skb
, data
, 0, &taddr
[i
],
170 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
171 ct
->tuplehash
[!dir
].tuple
.
179 /****************************************************************************/
180 static int nat_rtp_rtcp(struct sk_buff
*skb
, struct nf_conn
*ct
,
181 enum ip_conntrack_info ctinfo
,
182 unsigned char **data
, int dataoff
,
183 H245_TransportAddress
*taddr
,
184 __be16 port
, __be16 rtp_port
,
185 struct nf_conntrack_expect
*rtp_exp
,
186 struct nf_conntrack_expect
*rtcp_exp
)
188 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
189 int dir
= CTINFO2DIR(ctinfo
);
191 u_int16_t nated_port
;
193 /* Set expectations for NAT */
194 rtp_exp
->saved_proto
.udp
.port
= rtp_exp
->tuple
.dst
.u
.udp
.port
;
195 rtp_exp
->expectfn
= nf_nat_follow_master
;
197 rtcp_exp
->saved_proto
.udp
.port
= rtcp_exp
->tuple
.dst
.u
.udp
.port
;
198 rtcp_exp
->expectfn
= nf_nat_follow_master
;
199 rtcp_exp
->dir
= !dir
;
201 /* Lookup existing expects */
202 for (i
= 0; i
< H323_RTP_CHANNEL_MAX
; i
++) {
203 if (info
->rtp_port
[i
][dir
] == rtp_port
) {
206 /* Use allocated ports first. This will refresh
208 rtp_exp
->tuple
.dst
.u
.udp
.port
= info
->rtp_port
[i
][dir
];
209 rtcp_exp
->tuple
.dst
.u
.udp
.port
=
210 htons(ntohs(info
->rtp_port
[i
][dir
]) + 1);
212 } else if (info
->rtp_port
[i
][dir
] == 0) {
218 /* Run out of expectations */
219 if (i
>= H323_RTP_CHANNEL_MAX
) {
221 printk("nf_nat_h323: out of expectations\n");
225 /* Try to get a pair of ports. */
226 for (nated_port
= ntohs(rtp_exp
->tuple
.dst
.u
.udp
.port
);
227 nated_port
!= 0; nated_port
+= 2) {
228 rtp_exp
->tuple
.dst
.u
.udp
.port
= htons(nated_port
);
229 if (nf_ct_expect_related(rtp_exp
) == 0) {
230 rtcp_exp
->tuple
.dst
.u
.udp
.port
=
231 htons(nated_port
+ 1);
232 if (nf_ct_expect_related(rtcp_exp
) == 0)
234 nf_ct_unexpect_related(rtp_exp
);
238 if (nated_port
== 0) { /* No port available */
240 printk("nf_nat_h323: out of RTP ports\n");
245 if (set_h245_addr(skb
, data
, dataoff
, taddr
,
246 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
247 htons((port
& htons(1)) ? nated_port
+ 1 :
250 info
->rtp_port
[i
][dir
] = rtp_port
;
251 info
->rtp_port
[i
][!dir
] = htons(nated_port
);
253 nf_ct_unexpect_related(rtp_exp
);
254 nf_ct_unexpect_related(rtcp_exp
);
259 pr_debug("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
260 NIPQUAD(rtp_exp
->tuple
.src
.u3
.ip
),
261 ntohs(rtp_exp
->tuple
.src
.u
.udp
.port
),
262 NIPQUAD(rtp_exp
->tuple
.dst
.u3
.ip
),
263 ntohs(rtp_exp
->tuple
.dst
.u
.udp
.port
));
264 pr_debug("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
265 NIPQUAD(rtcp_exp
->tuple
.src
.u3
.ip
),
266 ntohs(rtcp_exp
->tuple
.src
.u
.udp
.port
),
267 NIPQUAD(rtcp_exp
->tuple
.dst
.u3
.ip
),
268 ntohs(rtcp_exp
->tuple
.dst
.u
.udp
.port
));
273 /****************************************************************************/
274 static int nat_t120(struct sk_buff
*skb
, struct nf_conn
*ct
,
275 enum ip_conntrack_info ctinfo
,
276 unsigned char **data
, int dataoff
,
277 H245_TransportAddress
*taddr
, __be16 port
,
278 struct nf_conntrack_expect
*exp
)
280 int dir
= CTINFO2DIR(ctinfo
);
281 u_int16_t nated_port
= ntohs(port
);
283 /* Set expectations for NAT */
284 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
285 exp
->expectfn
= nf_nat_follow_master
;
288 /* Try to get same port: if not, try to change it. */
289 for (; nated_port
!= 0; nated_port
++) {
290 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
291 if (nf_ct_expect_related(exp
) == 0)
295 if (nated_port
== 0) { /* No port available */
297 printk("nf_nat_h323: out of TCP ports\n");
302 if (set_h245_addr(skb
, data
, dataoff
, taddr
,
303 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
304 htons(nated_port
)) < 0) {
305 nf_ct_unexpect_related(exp
);
309 pr_debug("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
310 NIPQUAD(exp
->tuple
.src
.u3
.ip
),
311 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
312 NIPQUAD(exp
->tuple
.dst
.u3
.ip
),
313 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
318 /****************************************************************************/
319 static int nat_h245(struct sk_buff
*skb
, struct nf_conn
*ct
,
320 enum ip_conntrack_info ctinfo
,
321 unsigned char **data
, int dataoff
,
322 TransportAddress
*taddr
, __be16 port
,
323 struct nf_conntrack_expect
*exp
)
325 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
326 int dir
= CTINFO2DIR(ctinfo
);
327 u_int16_t nated_port
= ntohs(port
);
329 /* Set expectations for NAT */
330 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
331 exp
->expectfn
= nf_nat_follow_master
;
334 /* Check existing expects */
335 if (info
->sig_port
[dir
] == port
)
336 nated_port
= ntohs(info
->sig_port
[!dir
]);
338 /* Try to get same port: if not, try to change it. */
339 for (; nated_port
!= 0; nated_port
++) {
340 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
341 if (nf_ct_expect_related(exp
) == 0)
345 if (nated_port
== 0) { /* No port available */
347 printk("nf_nat_q931: out of TCP ports\n");
352 if (set_h225_addr(skb
, data
, dataoff
, taddr
,
353 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
354 htons(nated_port
)) == 0) {
356 info
->sig_port
[dir
] = port
;
357 info
->sig_port
[!dir
] = htons(nated_port
);
359 nf_ct_unexpect_related(exp
);
363 pr_debug("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
364 NIPQUAD(exp
->tuple
.src
.u3
.ip
),
365 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
366 NIPQUAD(exp
->tuple
.dst
.u3
.ip
),
367 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
372 /****************************************************************************
373 * This conntrack expect function replaces nf_conntrack_q931_expect()
374 * which was set by nf_conntrack_h323.c.
375 ****************************************************************************/
376 static void ip_nat_q931_expect(struct nf_conn
*new,
377 struct nf_conntrack_expect
*this)
379 struct nf_nat_range range
;
381 if (this->tuple
.src
.u3
.ip
!= 0) { /* Only accept calls from GK */
382 nf_nat_follow_master(new, this);
386 /* This must be a fresh one. */
387 BUG_ON(new->status
& IPS_NAT_DONE_MASK
);
389 /* Change src to where master sends to */
390 range
.flags
= IP_NAT_RANGE_MAP_IPS
;
391 range
.min_ip
= range
.max_ip
= new->tuplehash
[!this->dir
].tuple
.src
.u3
.ip
;
393 /* hook doesn't matter, but it has to do source manip */
394 nf_nat_setup_info(new, &range
, NF_IP_POST_ROUTING
);
396 /* For DST manip, map port here to where it's expected. */
397 range
.flags
= (IP_NAT_RANGE_MAP_IPS
| IP_NAT_RANGE_PROTO_SPECIFIED
);
398 range
.min
= range
.max
= this->saved_proto
;
399 range
.min_ip
= range
.max_ip
=
400 new->master
->tuplehash
[!this->dir
].tuple
.src
.u3
.ip
;
402 /* hook doesn't matter, but it has to do destination manip */
403 nf_nat_setup_info(new, &range
, NF_IP_PRE_ROUTING
);
406 /****************************************************************************/
407 static int nat_q931(struct sk_buff
*skb
, struct nf_conn
*ct
,
408 enum ip_conntrack_info ctinfo
,
409 unsigned char **data
, TransportAddress
*taddr
, int idx
,
410 __be16 port
, struct nf_conntrack_expect
*exp
)
412 struct nf_ct_h323_master
*info
= &nfct_help(ct
)->help
.ct_h323_info
;
413 int dir
= CTINFO2DIR(ctinfo
);
414 u_int16_t nated_port
= ntohs(port
);
415 union nf_conntrack_address addr
;
417 /* Set expectations for NAT */
418 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
419 exp
->expectfn
= ip_nat_q931_expect
;
422 /* Check existing expects */
423 if (info
->sig_port
[dir
] == port
)
424 nated_port
= ntohs(info
->sig_port
[!dir
]);
426 /* Try to get same port: if not, try to change it. */
427 for (; nated_port
!= 0; nated_port
++) {
428 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
429 if (nf_ct_expect_related(exp
) == 0)
433 if (nated_port
== 0) { /* No port available */
435 printk("nf_nat_ras: out of TCP ports\n");
440 if (set_h225_addr(skb
, data
, 0, &taddr
[idx
],
441 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
442 htons(nated_port
)) == 0) {
444 info
->sig_port
[dir
] = port
;
445 info
->sig_port
[!dir
] = htons(nated_port
);
447 /* Fix for Gnomemeeting */
449 get_h225_addr(ct
, *data
, &taddr
[0], &addr
, &port
) &&
450 (ntohl(addr
.ip
) & 0xff000000) == 0x7f000000) {
451 set_h225_addr(skb
, data
, 0, &taddr
[0],
452 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
453 info
->sig_port
[!dir
]);
456 nf_ct_unexpect_related(exp
);
461 pr_debug("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
462 NIPQUAD(exp
->tuple
.src
.u3
.ip
),
463 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
464 NIPQUAD(exp
->tuple
.dst
.u3
.ip
),
465 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
470 /****************************************************************************/
471 static void ip_nat_callforwarding_expect(struct nf_conn
*new,
472 struct nf_conntrack_expect
*this)
474 struct nf_nat_range range
;
476 /* This must be a fresh one. */
477 BUG_ON(new->status
& IPS_NAT_DONE_MASK
);
479 /* Change src to where master sends to */
480 range
.flags
= IP_NAT_RANGE_MAP_IPS
;
481 range
.min_ip
= range
.max_ip
= new->tuplehash
[!this->dir
].tuple
.src
.u3
.ip
;
483 /* hook doesn't matter, but it has to do source manip */
484 nf_nat_setup_info(new, &range
, NF_IP_POST_ROUTING
);
486 /* For DST manip, map port here to where it's expected. */
487 range
.flags
= (IP_NAT_RANGE_MAP_IPS
| IP_NAT_RANGE_PROTO_SPECIFIED
);
488 range
.min
= range
.max
= this->saved_proto
;
489 range
.min_ip
= range
.max_ip
= this->saved_ip
;
491 /* hook doesn't matter, but it has to do destination manip */
492 nf_nat_setup_info(new, &range
, NF_IP_PRE_ROUTING
);
495 /****************************************************************************/
496 static int nat_callforwarding(struct sk_buff
*skb
, struct nf_conn
*ct
,
497 enum ip_conntrack_info ctinfo
,
498 unsigned char **data
, int dataoff
,
499 TransportAddress
*taddr
, __be16 port
,
500 struct nf_conntrack_expect
*exp
)
502 int dir
= CTINFO2DIR(ctinfo
);
503 u_int16_t nated_port
;
505 /* Set expectations for NAT */
506 exp
->saved_ip
= exp
->tuple
.dst
.u3
.ip
;
507 exp
->tuple
.dst
.u3
.ip
= ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
;
508 exp
->saved_proto
.tcp
.port
= exp
->tuple
.dst
.u
.tcp
.port
;
509 exp
->expectfn
= ip_nat_callforwarding_expect
;
512 /* Try to get same port: if not, try to change it. */
513 for (nated_port
= ntohs(port
); nated_port
!= 0; nated_port
++) {
514 exp
->tuple
.dst
.u
.tcp
.port
= htons(nated_port
);
515 if (nf_ct_expect_related(exp
) == 0)
519 if (nated_port
== 0) { /* No port available */
521 printk("nf_nat_q931: out of TCP ports\n");
526 if (!set_h225_addr(skb
, data
, dataoff
, taddr
,
527 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
,
528 htons(nated_port
)) == 0) {
529 nf_ct_unexpect_related(exp
);
534 pr_debug("nf_nat_q931: expect Call Forwarding "
535 "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
536 NIPQUAD(exp
->tuple
.src
.u3
.ip
),
537 ntohs(exp
->tuple
.src
.u
.tcp
.port
),
538 NIPQUAD(exp
->tuple
.dst
.u3
.ip
),
539 ntohs(exp
->tuple
.dst
.u
.tcp
.port
));
544 /****************************************************************************/
545 static int __init
init(void)
547 BUG_ON(rcu_dereference(set_h245_addr_hook
) != NULL
);
548 BUG_ON(rcu_dereference(set_h225_addr_hook
) != NULL
);
549 BUG_ON(rcu_dereference(set_sig_addr_hook
) != NULL
);
550 BUG_ON(rcu_dereference(set_ras_addr_hook
) != NULL
);
551 BUG_ON(rcu_dereference(nat_rtp_rtcp_hook
) != NULL
);
552 BUG_ON(rcu_dereference(nat_t120_hook
) != NULL
);
553 BUG_ON(rcu_dereference(nat_h245_hook
) != NULL
);
554 BUG_ON(rcu_dereference(nat_callforwarding_hook
) != NULL
);
555 BUG_ON(rcu_dereference(nat_q931_hook
) != NULL
);
557 rcu_assign_pointer(set_h245_addr_hook
, set_h245_addr
);
558 rcu_assign_pointer(set_h225_addr_hook
, set_h225_addr
);
559 rcu_assign_pointer(set_sig_addr_hook
, set_sig_addr
);
560 rcu_assign_pointer(set_ras_addr_hook
, set_ras_addr
);
561 rcu_assign_pointer(nat_rtp_rtcp_hook
, nat_rtp_rtcp
);
562 rcu_assign_pointer(nat_t120_hook
, nat_t120
);
563 rcu_assign_pointer(nat_h245_hook
, nat_h245
);
564 rcu_assign_pointer(nat_callforwarding_hook
, nat_callforwarding
);
565 rcu_assign_pointer(nat_q931_hook
, nat_q931
);
569 /****************************************************************************/
570 static void __exit
fini(void)
572 rcu_assign_pointer(set_h245_addr_hook
, NULL
);
573 rcu_assign_pointer(set_h225_addr_hook
, NULL
);
574 rcu_assign_pointer(set_sig_addr_hook
, NULL
);
575 rcu_assign_pointer(set_ras_addr_hook
, NULL
);
576 rcu_assign_pointer(nat_rtp_rtcp_hook
, NULL
);
577 rcu_assign_pointer(nat_t120_hook
, NULL
);
578 rcu_assign_pointer(nat_h245_hook
, NULL
);
579 rcu_assign_pointer(nat_callforwarding_hook
, NULL
);
580 rcu_assign_pointer(nat_q931_hook
, NULL
);
584 /****************************************************************************/
588 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
589 MODULE_DESCRIPTION("H.323 NAT helper");
590 MODULE_LICENSE("GPL");
591 MODULE_ALIAS("ip_nat_h323");