d4c061874f8fcc1b47454332271a81f83f66359e
[linux-2.6.git] / net / ipv4 / netfilter / nf_nat_h323.c
1 /*
2  * H.323 extension for NAT alteration.
3  *
4  * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
5  *
6  * This source code is licensed under General Public License version 2.
7  *
8  * Based on the 'brute force' H.323 NAT module by
9  * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
10  */
11
12 #include <linux/module.h>
13 #include <linux/tcp.h>
14 #include <net/tcp.h>
15
16 #include <net/netfilter/nf_nat.h>
17 #include <net/netfilter/nf_nat_helper.h>
18 #include <net/netfilter/nf_nat_rule.h>
19 #include <net/netfilter/nf_conntrack_helper.h>
20 #include <net/netfilter/nf_conntrack_expect.h>
21 #include <linux/netfilter/nf_conntrack_h323.h>
22
23 /****************************************************************************/
24 static int set_addr(struct sk_buff *skb,
25                     unsigned char **data, int dataoff,
26                     unsigned int addroff, __be32 ip, __be16 port)
27 {
28         enum ip_conntrack_info ctinfo;
29         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
30         struct {
31                 __be32 ip;
32                 __be16 port;
33         } __attribute__ ((__packed__)) buf;
34         const struct tcphdr *th;
35         struct tcphdr _tcph;
36
37         buf.ip = ip;
38         buf.port = port;
39         addroff += dataoff;
40
41         if (ip_hdr(skb)->protocol == IPPROTO_TCP) {
42                 if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
43                                               addroff, sizeof(buf),
44                                               (char *) &buf, sizeof(buf))) {
45                         if (net_ratelimit())
46                                 printk("nf_nat_h323: nf_nat_mangle_tcp_packet"
47                                        " error\n");
48                         return -1;
49                 }
50
51                 /* Relocate data pointer */
52                 th = skb_header_pointer(skb, ip_hdrlen(skb),
53                                         sizeof(_tcph), &_tcph);
54                 if (th == NULL)
55                         return -1;
56                 *data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff;
57         } else {
58                 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
59                                               addroff, sizeof(buf),
60                                               (char *) &buf, sizeof(buf))) {
61                         if (net_ratelimit())
62                                 printk("nf_nat_h323: nf_nat_mangle_udp_packet"
63                                        " error\n");
64                         return -1;
65                 }
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);
70         }
71
72         return 0;
73 }
74
75 /****************************************************************************/
76 static int set_h225_addr(struct sk_buff *skb,
77                          unsigned char **data, int dataoff,
78                          TransportAddress *taddr,
79                          union nf_inet_addr *addr, __be16 port)
80 {
81         return set_addr(skb, data, dataoff, taddr->ipAddress.ip,
82                         addr->ip, port);
83 }
84
85 /****************************************************************************/
86 static int set_h245_addr(struct sk_buff *skb,
87                          unsigned char **data, int dataoff,
88                          H245_TransportAddress *taddr,
89                          union nf_inet_addr *addr, __be16 port)
90 {
91         return set_addr(skb, data, dataoff,
92                         taddr->unicastAddress.iPAddress.network,
93                         addr->ip, port);
94 }
95
96 /****************************************************************************/
97 static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
98                         enum ip_conntrack_info ctinfo,
99                         unsigned char **data,
100                         TransportAddress *taddr, int count)
101 {
102         const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
103         int dir = CTINFO2DIR(ctinfo);
104         int i;
105         __be16 port;
106         union nf_inet_addr addr;
107
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]) {
112                                 /* GW->GK */
113
114                                 /* Fix for Gnomemeeting */
115                                 if (i > 0 &&
116                                     get_h225_addr(ct, *data, &taddr[0],
117                                                   &addr, &port) &&
118                                     (ntohl(addr.ip) & 0xff000000) == 0x7f000000)
119                                         i = 0;
120
121                                 pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
122                                          &addr.ip, port,
123                                          &ct->tuplehash[!dir].tuple.dst.u3.ip,
124                                          info->sig_port[!dir]);
125                                 return set_h225_addr(skb, data, 0, &taddr[i],
126                                                      &ct->tuplehash[!dir].
127                                                      tuple.dst.u3,
128                                                      info->sig_port[!dir]);
129                         } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
130                                    port == info->sig_port[dir]) {
131                                 /* GK->GW */
132                                 pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
133                                          &addr.ip, port,
134                                          &ct->tuplehash[!dir].tuple.src.u3.ip,
135                                          info->sig_port[!dir]);
136                                 return set_h225_addr(skb, data, 0, &taddr[i],
137                                                      &ct->tuplehash[!dir].
138                                                      tuple.src.u3,
139                                                      info->sig_port[!dir]);
140                         }
141                 }
142         }
143
144         return 0;
145 }
146
147 /****************************************************************************/
148 static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
149                         enum ip_conntrack_info ctinfo,
150                         unsigned char **data,
151                         TransportAddress *taddr, int count)
152 {
153         int dir = CTINFO2DIR(ctinfo);
154         int i;
155         __be16 port;
156         union nf_inet_addr addr;
157
158         for (i = 0; i < count; i++) {
159                 if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
160                     addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
161                     port == ct->tuplehash[dir].tuple.src.u.udp.port) {
162                         pr_debug("nf_nat_ras: set rasAddress %pI4:%hu->%pI4:%hu\n",
163                                  &addr.ip, ntohs(port),
164                                  &ct->tuplehash[!dir].tuple.dst.u3.ip,
165                                  ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port));
166                         return set_h225_addr(skb, data, 0, &taddr[i],
167                                              &ct->tuplehash[!dir].tuple.dst.u3,
168                                              ct->tuplehash[!dir].tuple.
169                                                                 dst.u.udp.port);
170                 }
171         }
172
173         return 0;
174 }
175
176 /****************************************************************************/
177 static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
178                         enum ip_conntrack_info ctinfo,
179                         unsigned char **data, int dataoff,
180                         H245_TransportAddress *taddr,
181                         __be16 port, __be16 rtp_port,
182                         struct nf_conntrack_expect *rtp_exp,
183                         struct nf_conntrack_expect *rtcp_exp)
184 {
185         struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
186         int dir = CTINFO2DIR(ctinfo);
187         int i;
188         u_int16_t nated_port;
189
190         /* Set expectations for NAT */
191         rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
192         rtp_exp->expectfn = nf_nat_follow_master;
193         rtp_exp->dir = !dir;
194         rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
195         rtcp_exp->expectfn = nf_nat_follow_master;
196         rtcp_exp->dir = !dir;
197
198         /* Lookup existing expects */
199         for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
200                 if (info->rtp_port[i][dir] == rtp_port) {
201                         /* Expected */
202
203                         /* Use allocated ports first. This will refresh
204                          * the expects */
205                         rtp_exp->tuple.dst.u.udp.port = info->rtp_port[i][dir];
206                         rtcp_exp->tuple.dst.u.udp.port =
207                             htons(ntohs(info->rtp_port[i][dir]) + 1);
208                         break;
209                 } else if (info->rtp_port[i][dir] == 0) {
210                         /* Not expected */
211                         break;
212                 }
213         }
214
215         /* Run out of expectations */
216         if (i >= H323_RTP_CHANNEL_MAX) {
217                 if (net_ratelimit())
218                         printk("nf_nat_h323: out of expectations\n");
219                 return 0;
220         }
221
222         /* Try to get a pair of ports. */
223         for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
224              nated_port != 0; nated_port += 2) {
225                 rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
226                 if (nf_ct_expect_related(rtp_exp) == 0) {
227                         rtcp_exp->tuple.dst.u.udp.port =
228                             htons(nated_port + 1);
229                         if (nf_ct_expect_related(rtcp_exp) == 0)
230                                 break;
231                         nf_ct_unexpect_related(rtp_exp);
232                 }
233         }
234
235         if (nated_port == 0) {  /* No port available */
236                 if (net_ratelimit())
237                         printk("nf_nat_h323: out of RTP ports\n");
238                 return 0;
239         }
240
241         /* Modify signal */
242         if (set_h245_addr(skb, data, dataoff, taddr,
243                           &ct->tuplehash[!dir].tuple.dst.u3,
244                           htons((port & htons(1)) ? nated_port + 1 :
245                                                     nated_port)) == 0) {
246                 /* Save ports */
247                 info->rtp_port[i][dir] = rtp_port;
248                 info->rtp_port[i][!dir] = htons(nated_port);
249         } else {
250                 nf_ct_unexpect_related(rtp_exp);
251                 nf_ct_unexpect_related(rtcp_exp);
252                 return -1;
253         }
254
255         /* Success */
256         pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n",
257                  &rtp_exp->tuple.src.u3.ip,
258                  ntohs(rtp_exp->tuple.src.u.udp.port),
259                  &rtp_exp->tuple.dst.u3.ip,
260                  ntohs(rtp_exp->tuple.dst.u.udp.port));
261         pr_debug("nf_nat_h323: expect RTCP %pI4:%hu->%pI4:%hu\n",
262                  &rtcp_exp->tuple.src.u3.ip,
263                  ntohs(rtcp_exp->tuple.src.u.udp.port),
264                  &rtcp_exp->tuple.dst.u3.ip,
265                  ntohs(rtcp_exp->tuple.dst.u.udp.port));
266
267         return 0;
268 }
269
270 /****************************************************************************/
271 static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
272                     enum ip_conntrack_info ctinfo,
273                     unsigned char **data, int dataoff,
274                     H245_TransportAddress *taddr, __be16 port,
275                     struct nf_conntrack_expect *exp)
276 {
277         int dir = CTINFO2DIR(ctinfo);
278         u_int16_t nated_port = ntohs(port);
279
280         /* Set expectations for NAT */
281         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
282         exp->expectfn = nf_nat_follow_master;
283         exp->dir = !dir;
284
285         /* Try to get same port: if not, try to change it. */
286         for (; nated_port != 0; nated_port++) {
287                 exp->tuple.dst.u.tcp.port = htons(nated_port);
288                 if (nf_ct_expect_related(exp) == 0)
289                         break;
290         }
291
292         if (nated_port == 0) {  /* No port available */
293                 if (net_ratelimit())
294                         printk("nf_nat_h323: out of TCP ports\n");
295                 return 0;
296         }
297
298         /* Modify signal */
299         if (set_h245_addr(skb, data, dataoff, taddr,
300                           &ct->tuplehash[!dir].tuple.dst.u3,
301                           htons(nated_port)) < 0) {
302                 nf_ct_unexpect_related(exp);
303                 return -1;
304         }
305
306         pr_debug("nf_nat_h323: expect T.120 %pI4:%hu->%pI4:%hu\n",
307                  &exp->tuple.src.u3.ip,
308                  ntohs(exp->tuple.src.u.tcp.port),
309                  &exp->tuple.dst.u3.ip,
310                  ntohs(exp->tuple.dst.u.tcp.port));
311
312         return 0;
313 }
314
315 /****************************************************************************/
316 static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
317                     enum ip_conntrack_info ctinfo,
318                     unsigned char **data, int dataoff,
319                     TransportAddress *taddr, __be16 port,
320                     struct nf_conntrack_expect *exp)
321 {
322         struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
323         int dir = CTINFO2DIR(ctinfo);
324         u_int16_t nated_port = ntohs(port);
325
326         /* Set expectations for NAT */
327         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
328         exp->expectfn = nf_nat_follow_master;
329         exp->dir = !dir;
330
331         /* Check existing expects */
332         if (info->sig_port[dir] == port)
333                 nated_port = ntohs(info->sig_port[!dir]);
334
335         /* Try to get same port: if not, try to change it. */
336         for (; nated_port != 0; nated_port++) {
337                 exp->tuple.dst.u.tcp.port = htons(nated_port);
338                 if (nf_ct_expect_related(exp) == 0)
339                         break;
340         }
341
342         if (nated_port == 0) {  /* No port available */
343                 if (net_ratelimit())
344                         printk("nf_nat_q931: out of TCP ports\n");
345                 return 0;
346         }
347
348         /* Modify signal */
349         if (set_h225_addr(skb, data, dataoff, taddr,
350                           &ct->tuplehash[!dir].tuple.dst.u3,
351                           htons(nated_port)) == 0) {
352                 /* Save ports */
353                 info->sig_port[dir] = port;
354                 info->sig_port[!dir] = htons(nated_port);
355         } else {
356                 nf_ct_unexpect_related(exp);
357                 return -1;
358         }
359
360         pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n",
361                  &exp->tuple.src.u3.ip,
362                  ntohs(exp->tuple.src.u.tcp.port),
363                  &exp->tuple.dst.u3.ip,
364                  ntohs(exp->tuple.dst.u.tcp.port));
365
366         return 0;
367 }
368
369 /****************************************************************************
370  * This conntrack expect function replaces nf_conntrack_q931_expect()
371  * which was set by nf_conntrack_h323.c.
372  ****************************************************************************/
373 static void ip_nat_q931_expect(struct nf_conn *new,
374                                struct nf_conntrack_expect *this)
375 {
376         struct nf_nat_range range;
377
378         if (this->tuple.src.u3.ip != 0) {       /* Only accept calls from GK */
379                 nf_nat_follow_master(new, this);
380                 return;
381         }
382
383         /* This must be a fresh one. */
384         BUG_ON(new->status & IPS_NAT_DONE_MASK);
385
386         /* Change src to where master sends to */
387         range.flags = IP_NAT_RANGE_MAP_IPS;
388         range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
389         nf_nat_setup_info(new, &range, IP_NAT_MANIP_SRC);
390
391         /* For DST manip, map port here to where it's expected. */
392         range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
393         range.min = range.max = this->saved_proto;
394         range.min_ip = range.max_ip =
395             new->master->tuplehash[!this->dir].tuple.src.u3.ip;
396         nf_nat_setup_info(new, &range, IP_NAT_MANIP_DST);
397 }
398
399 /****************************************************************************/
400 static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
401                     enum ip_conntrack_info ctinfo,
402                     unsigned char **data, TransportAddress *taddr, int idx,
403                     __be16 port, struct nf_conntrack_expect *exp)
404 {
405         struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
406         int dir = CTINFO2DIR(ctinfo);
407         u_int16_t nated_port = ntohs(port);
408         union nf_inet_addr addr;
409
410         /* Set expectations for NAT */
411         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
412         exp->expectfn = ip_nat_q931_expect;
413         exp->dir = !dir;
414
415         /* Check existing expects */
416         if (info->sig_port[dir] == port)
417                 nated_port = ntohs(info->sig_port[!dir]);
418
419         /* Try to get same port: if not, try to change it. */
420         for (; nated_port != 0; nated_port++) {
421                 exp->tuple.dst.u.tcp.port = htons(nated_port);
422                 if (nf_ct_expect_related(exp) == 0)
423                         break;
424         }
425
426         if (nated_port == 0) {  /* No port available */
427                 if (net_ratelimit())
428                         printk("nf_nat_ras: out of TCP ports\n");
429                 return 0;
430         }
431
432         /* Modify signal */
433         if (set_h225_addr(skb, data, 0, &taddr[idx],
434                           &ct->tuplehash[!dir].tuple.dst.u3,
435                           htons(nated_port)) == 0) {
436                 /* Save ports */
437                 info->sig_port[dir] = port;
438                 info->sig_port[!dir] = htons(nated_port);
439
440                 /* Fix for Gnomemeeting */
441                 if (idx > 0 &&
442                     get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
443                     (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
444                         set_h225_addr(skb, data, 0, &taddr[0],
445                                       &ct->tuplehash[!dir].tuple.dst.u3,
446                                       info->sig_port[!dir]);
447                 }
448         } else {
449                 nf_ct_unexpect_related(exp);
450                 return -1;
451         }
452
453         /* Success */
454         pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n",
455                  &exp->tuple.src.u3.ip,
456                  ntohs(exp->tuple.src.u.tcp.port),
457                  &exp->tuple.dst.u3.ip,
458                  ntohs(exp->tuple.dst.u.tcp.port));
459
460         return 0;
461 }
462
463 /****************************************************************************/
464 static void ip_nat_callforwarding_expect(struct nf_conn *new,
465                                          struct nf_conntrack_expect *this)
466 {
467         struct nf_nat_range range;
468
469         /* This must be a fresh one. */
470         BUG_ON(new->status & IPS_NAT_DONE_MASK);
471
472         /* Change src to where master sends to */
473         range.flags = IP_NAT_RANGE_MAP_IPS;
474         range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
475         nf_nat_setup_info(new, &range, IP_NAT_MANIP_SRC);
476
477         /* For DST manip, map port here to where it's expected. */
478         range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
479         range.min = range.max = this->saved_proto;
480         range.min_ip = range.max_ip = this->saved_ip;
481         nf_nat_setup_info(new, &range, IP_NAT_MANIP_DST);
482 }
483
484 /****************************************************************************/
485 static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
486                               enum ip_conntrack_info ctinfo,
487                               unsigned char **data, int dataoff,
488                               TransportAddress *taddr, __be16 port,
489                               struct nf_conntrack_expect *exp)
490 {
491         int dir = CTINFO2DIR(ctinfo);
492         u_int16_t nated_port;
493
494         /* Set expectations for NAT */
495         exp->saved_ip = exp->tuple.dst.u3.ip;
496         exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
497         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
498         exp->expectfn = ip_nat_callforwarding_expect;
499         exp->dir = !dir;
500
501         /* Try to get same port: if not, try to change it. */
502         for (nated_port = ntohs(port); nated_port != 0; nated_port++) {
503                 exp->tuple.dst.u.tcp.port = htons(nated_port);
504                 if (nf_ct_expect_related(exp) == 0)
505                         break;
506         }
507
508         if (nated_port == 0) {  /* No port available */
509                 if (net_ratelimit())
510                         printk("nf_nat_q931: out of TCP ports\n");
511                 return 0;
512         }
513
514         /* Modify signal */
515         if (!set_h225_addr(skb, data, dataoff, taddr,
516                            &ct->tuplehash[!dir].tuple.dst.u3,
517                            htons(nated_port)) == 0) {
518                 nf_ct_unexpect_related(exp);
519                 return -1;
520         }
521
522         /* Success */
523         pr_debug("nf_nat_q931: expect Call Forwarding %pI4:%hu->%pI4:%hu\n",
524                  &exp->tuple.src.u3.ip,
525                  ntohs(exp->tuple.src.u.tcp.port),
526                  &exp->tuple.dst.u3.ip,
527                  ntohs(exp->tuple.dst.u.tcp.port));
528
529         return 0;
530 }
531
532 /****************************************************************************/
533 static int __init init(void)
534 {
535         BUG_ON(set_h245_addr_hook != NULL);
536         BUG_ON(set_h225_addr_hook != NULL);
537         BUG_ON(set_sig_addr_hook != NULL);
538         BUG_ON(set_ras_addr_hook != NULL);
539         BUG_ON(nat_rtp_rtcp_hook != NULL);
540         BUG_ON(nat_t120_hook != NULL);
541         BUG_ON(nat_h245_hook != NULL);
542         BUG_ON(nat_callforwarding_hook != NULL);
543         BUG_ON(nat_q931_hook != NULL);
544
545         rcu_assign_pointer(set_h245_addr_hook, set_h245_addr);
546         rcu_assign_pointer(set_h225_addr_hook, set_h225_addr);
547         rcu_assign_pointer(set_sig_addr_hook, set_sig_addr);
548         rcu_assign_pointer(set_ras_addr_hook, set_ras_addr);
549         rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp);
550         rcu_assign_pointer(nat_t120_hook, nat_t120);
551         rcu_assign_pointer(nat_h245_hook, nat_h245);
552         rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding);
553         rcu_assign_pointer(nat_q931_hook, nat_q931);
554         return 0;
555 }
556
557 /****************************************************************************/
558 static void __exit fini(void)
559 {
560         rcu_assign_pointer(set_h245_addr_hook, NULL);
561         rcu_assign_pointer(set_h225_addr_hook, NULL);
562         rcu_assign_pointer(set_sig_addr_hook, NULL);
563         rcu_assign_pointer(set_ras_addr_hook, NULL);
564         rcu_assign_pointer(nat_rtp_rtcp_hook, NULL);
565         rcu_assign_pointer(nat_t120_hook, NULL);
566         rcu_assign_pointer(nat_h245_hook, NULL);
567         rcu_assign_pointer(nat_callforwarding_hook, NULL);
568         rcu_assign_pointer(nat_q931_hook, NULL);
569         synchronize_rcu();
570 }
571
572 /****************************************************************************/
573 module_init(init);
574 module_exit(fini);
575
576 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
577 MODULE_DESCRIPTION("H.323 NAT helper");
578 MODULE_LICENSE("GPL");
579 MODULE_ALIAS("ip_nat_h323");