Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nf_nat_h323.c
Go to the documentation of this file.
1 /*
2  * H.323 extension for NAT alteration.
3  *
4  * Copyright (c) 2006 Jing Min Zhao <[email protected]>
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 <[email protected]>
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>
21 
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)
26 {
27  enum ip_conntrack_info ctinfo;
28  struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
29  struct {
30  __be32 ip;
31  __be16 port;
32  } __attribute__ ((__packed__)) buf;
34  struct tcphdr _tcph;
35 
36  buf.ip = ip;
37  buf.port = port;
38  addroff += dataoff;
39 
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");
45  return -1;
46  }
47 
48  /* Relocate data pointer */
49  th = skb_header_pointer(skb, ip_hdrlen(skb),
50  sizeof(_tcph), &_tcph);
51  if (th == NULL)
52  return -1;
53  *data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff;
54  } else {
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");
59  return -1;
60  }
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);
65  }
66 
67  return 0;
68 }
69 
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)
75 {
76  return set_addr(skb, protoff, data, dataoff, taddr->ipAddress.ip,
77  addr->ip, port);
78 }
79 
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)
85 {
86  return set_addr(skb, protoff, data, dataoff,
88  addr->ip, port);
89 }
90 
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)
96 {
97  const struct nf_ct_h323_master *info = nfct_help_data(ct);
98  int dir = CTINFO2DIR(ctinfo);
99  int i;
100  __be16 port;
101  union nf_inet_addr addr;
102 
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]) {
107  /* GW->GK */
108 
109  /* Fix for Gnomemeeting */
110  if (i > 0 &&
111  get_h225_addr(ct, *data, &taddr[0],
112  &addr, &port) &&
113  (ntohl(addr.ip) & 0xff000000) == 0x7f000000)
114  i = 0;
115 
116  pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
117  &addr.ip, port,
118  &ct->tuplehash[!dir].tuple.dst.u3.ip,
119  info->sig_port[!dir]);
120  return set_h225_addr(skb, protoff, data, 0,
121  &taddr[i],
122  &ct->tuplehash[!dir].
123  tuple.dst.u3,
124  info->sig_port[!dir]);
125  } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
126  port == info->sig_port[dir]) {
127  /* GK->GW */
128  pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
129  &addr.ip, port,
130  &ct->tuplehash[!dir].tuple.src.u3.ip,
131  info->sig_port[!dir]);
132  return set_h225_addr(skb, protoff, data, 0,
133  &taddr[i],
134  &ct->tuplehash[!dir].
135  tuple.src.u3,
136  info->sig_port[!dir]);
137  }
138  }
139  }
140 
141  return 0;
142 }
143 
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)
149 {
150  int dir = CTINFO2DIR(ctinfo);
151  int i;
152  __be16 port;
153  union nf_inet_addr addr;
154 
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.
166  dst.u.udp.port);
167  }
168  }
169 
170  return 0;
171 }
172 
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)
181 {
182  struct nf_ct_h323_master *info = nfct_help_data(ct);
183  int dir = CTINFO2DIR(ctinfo);
184  int i;
185  u_int16_t nated_port;
186 
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;
190  rtp_exp->dir = !dir;
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;
194 
195  /* Lookup existing expects */
196  for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
197  if (info->rtp_port[i][dir] == rtp_port) {
198  /* Expected */
199 
200  /* Use allocated ports first. This will refresh
201  * the expects */
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);
205  break;
206  } else if (info->rtp_port[i][dir] == 0) {
207  /* Not expected */
208  break;
209  }
210  }
211 
212  /* Run out of expectations */
213  if (i >= H323_RTP_CHANNEL_MAX) {
214  net_notice_ratelimited("nf_nat_h323: out of expectations\n");
215  return 0;
216  }
217 
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) {
221  int ret;
222 
223  rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
224  ret = nf_ct_expect_related(rtp_exp);
225  if (ret == 0) {
226  rtcp_exp->tuple.dst.u.udp.port =
227  htons(nated_port + 1);
228  ret = nf_ct_expect_related(rtcp_exp);
229  if (ret == 0)
230  break;
231  else if (ret != -EBUSY) {
232  nf_ct_unexpect_related(rtp_exp);
233  nated_port = 0;
234  break;
235  }
236  } else if (ret != -EBUSY) {
237  nated_port = 0;
238  break;
239  }
240  }
241 
242  if (nated_port == 0) { /* No port available */
243  net_notice_ratelimited("nf_nat_h323: out of RTP ports\n");
244  return 0;
245  }
246 
247  /* Modify signal */
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 :
251  nated_port)) == 0) {
252  /* Save ports */
253  info->rtp_port[i][dir] = rtp_port;
254  info->rtp_port[i][!dir] = htons(nated_port);
255  } else {
256  nf_ct_unexpect_related(rtp_exp);
257  nf_ct_unexpect_related(rtcp_exp);
258  return -1;
259  }
260 
261  /* Success */
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));
272 
273  return 0;
274 }
275 
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)
282 {
283  int dir = CTINFO2DIR(ctinfo);
284  u_int16_t nated_port = ntohs(port);
285 
286  /* Set expectations for NAT */
287  exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
289  exp->dir = !dir;
290 
291  /* Try to get same port: if not, try to change it. */
292  for (; nated_port != 0; nated_port++) {
293  int ret;
294 
295  exp->tuple.dst.u.tcp.port = htons(nated_port);
296  ret = nf_ct_expect_related(exp);
297  if (ret == 0)
298  break;
299  else if (ret != -EBUSY) {
300  nated_port = 0;
301  break;
302  }
303  }
304 
305  if (nated_port == 0) { /* No port available */
306  net_notice_ratelimited("nf_nat_h323: out of TCP ports\n");
307  return 0;
308  }
309 
310  /* Modify signal */
311  if (set_h245_addr(skb, protoff, data, dataoff, taddr,
312  &ct->tuplehash[!dir].tuple.dst.u3,
313  htons(nated_port)) < 0) {
315  return -1;
316  }
317 
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));
323 
324  return 0;
325 }
326 
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)
333 {
334  struct nf_ct_h323_master *info = nfct_help_data(ct);
335  int dir = CTINFO2DIR(ctinfo);
336  u_int16_t nated_port = ntohs(port);
337 
338  /* Set expectations for NAT */
339  exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
341  exp->dir = !dir;
342 
343  /* Check existing expects */
344  if (info->sig_port[dir] == port)
345  nated_port = ntohs(info->sig_port[!dir]);
346 
347  /* Try to get same port: if not, try to change it. */
348  for (; nated_port != 0; nated_port++) {
349  int ret;
350 
351  exp->tuple.dst.u.tcp.port = htons(nated_port);
352  ret = nf_ct_expect_related(exp);
353  if (ret == 0)
354  break;
355  else if (ret != -EBUSY) {
356  nated_port = 0;
357  break;
358  }
359  }
360 
361  if (nated_port == 0) { /* No port available */
362  net_notice_ratelimited("nf_nat_q931: out of TCP ports\n");
363  return 0;
364  }
365 
366  /* Modify signal */
367  if (set_h225_addr(skb, protoff, data, dataoff, taddr,
368  &ct->tuplehash[!dir].tuple.dst.u3,
369  htons(nated_port)) == 0) {
370  /* Save ports */
371  info->sig_port[dir] = port;
372  info->sig_port[!dir] = htons(nated_port);
373  } else {
375  return -1;
376  }
377 
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));
383 
384  return 0;
385 }
386 
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)
393 {
394  struct nf_nat_range range;
395 
396  if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */
397  nf_nat_follow_master(new, this);
398  return;
399  }
400 
401  /* This must be a fresh one. */
402  BUG_ON(new->status & IPS_NAT_DONE_MASK);
403 
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;
409 
410  /* For DST manip, map port here to where it's expected. */
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;
416 }
417 
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)
424 {
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;
429 
430  /* Set expectations for NAT */
431  exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
432  exp->expectfn = ip_nat_q931_expect;
433  exp->dir = !dir;
434 
435  /* Check existing expects */
436  if (info->sig_port[dir] == port)
437  nated_port = ntohs(info->sig_port[!dir]);
438 
439  /* Try to get same port: if not, try to change it. */
440  for (; nated_port != 0; nated_port++) {
441  int ret;
442 
443  exp->tuple.dst.u.tcp.port = htons(nated_port);
444  ret = nf_ct_expect_related(exp);
445  if (ret == 0)
446  break;
447  else if (ret != -EBUSY) {
448  nated_port = 0;
449  break;
450  }
451  }
452 
453  if (nated_port == 0) { /* No port available */
454  net_notice_ratelimited("nf_nat_ras: out of TCP ports\n");
455  return 0;
456  }
457 
458  /* Modify signal */
459  if (set_h225_addr(skb, protoff, data, 0, &taddr[idx],
460  &ct->tuplehash[!dir].tuple.dst.u3,
461  htons(nated_port)) == 0) {
462  /* Save ports */
463  info->sig_port[dir] = port;
464  info->sig_port[!dir] = htons(nated_port);
465 
466  /* Fix for Gnomemeeting */
467  if (idx > 0 &&
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]);
473  }
474  } else {
476  return -1;
477  }
478 
479  /* Success */
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));
485 
486  return 0;
487 }
488 
489 /****************************************************************************/
490 static void ip_nat_callforwarding_expect(struct nf_conn *new,
491  struct nf_conntrack_expect *this)
492 {
493  struct nf_nat_range range;
494 
495  /* This must be a fresh one. */
496  BUG_ON(new->status & IPS_NAT_DONE_MASK);
497 
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;
503 
504  /* For DST manip, map port here to where it's expected. */
506  range.min_proto = range.max_proto = this->saved_proto;
507  range.min_addr = range.max_addr = this->saved_addr;
509 }
510 
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)
518 {
519  int dir = CTINFO2DIR(ctinfo);
520  u_int16_t nated_port;
521 
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;
527  exp->dir = !dir;
528 
529  /* Try to get same port: if not, try to change it. */
530  for (nated_port = ntohs(port); nated_port != 0; nated_port++) {
531  int ret;
532 
533  exp->tuple.dst.u.tcp.port = htons(nated_port);
534  ret = nf_ct_expect_related(exp);
535  if (ret == 0)
536  break;
537  else if (ret != -EBUSY) {
538  nated_port = 0;
539  break;
540  }
541  }
542 
543  if (nated_port == 0) { /* No port available */
544  net_notice_ratelimited("nf_nat_q931: out of TCP ports\n");
545  return 0;
546  }
547 
548  /* Modify signal */
549  if (!set_h225_addr(skb, protoff, data, dataoff, taddr,
550  &ct->tuplehash[!dir].tuple.dst.u3,
551  htons(nated_port)) == 0) {
553  return -1;
554  }
555 
556  /* Success */
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));
562 
563  return 0;
564 }
565 
566 static struct nf_ct_helper_expectfn q931_nat = {
567  .name = "Q.931",
568  .expectfn = ip_nat_q931_expect,
569 };
570 
571 static struct nf_ct_helper_expectfn callforwarding_nat = {
572  .name = "callforwarding",
573  .expectfn = ip_nat_callforwarding_expect,
574 };
575 
576 /****************************************************************************/
577 static int __init init(void)
578 {
588 
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);
599  nf_ct_helper_expectfn_register(&callforwarding_nat);
600  return 0;
601 }
602 
603 /****************************************************************************/
604 static void __exit fini(void)
605 {
616  nf_ct_helper_expectfn_unregister(&callforwarding_nat);
617  synchronize_rcu();
618 }
619 
620 /****************************************************************************/
622 module_exit(fini);
623 
624 MODULE_AUTHOR("Jing Min Zhao <[email protected]>");
625 MODULE_DESCRIPTION("H.323 NAT helper");
626 MODULE_LICENSE("GPL");
627 MODULE_ALIAS("ip_nat_h323");