ee47bf28c82547463629288cc16249bcceb1e20c
[safe/jmp/linux-2.6] / 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/moduleparam.h>
14 #include <linux/tcp.h>
15 #include <net/tcp.h>
16
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>
23
24 /****************************************************************************/
25 static int set_addr(struct sk_buff *skb,
26                     unsigned char **data, int dataoff,
27                     unsigned int addroff, __be32 ip, __be16 port)
28 {
29         enum ip_conntrack_info ctinfo;
30         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
31         struct {
32                 __be32 ip;
33                 __be16 port;
34         } __attribute__ ((__packed__)) buf;
35         const struct tcphdr *th;
36         struct tcphdr _tcph;
37
38         buf.ip = ip;
39         buf.port = port;
40         addroff += dataoff;
41
42         if (ip_hdr(skb)->protocol == IPPROTO_TCP) {
43                 if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
44                                               addroff, sizeof(buf),
45                                               (char *) &buf, sizeof(buf))) {
46                         if (net_ratelimit())
47                                 printk("nf_nat_h323: nf_nat_mangle_tcp_packet"
48                                        " error\n");
49                         return -1;
50                 }
51
52                 /* Relocate data pointer */
53                 th = skb_header_pointer(skb, ip_hdrlen(skb),
54                                         sizeof(_tcph), &_tcph);
55                 if (th == NULL)
56                         return -1;
57                 *data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff;
58         } else {
59                 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
60                                               addroff, sizeof(buf),
61                                               (char *) &buf, sizeof(buf))) {
62                         if (net_ratelimit())
63                                 printk("nf_nat_h323: nf_nat_mangle_udp_packet"
64                                        " error\n");
65                         return -1;
66                 }
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);
71         }
72
73         return 0;
74 }
75
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)
81 {
82         return set_addr(skb, data, dataoff, taddr->ipAddress.ip,
83                         addr->ip, port);
84 }
85
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)
91 {
92         return set_addr(skb, data, dataoff,
93                         taddr->unicastAddress.iPAddress.network,
94                         addr->ip, port);
95 }
96
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)
102 {
103         const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
104         int dir = CTINFO2DIR(ctinfo);
105         int i;
106         __be16 port;
107         union nf_inet_addr addr;
108
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]) {
113                                 /* GW->GK */
114
115                                 /* Fix for Gnomemeeting */
116                                 if (i > 0 &&
117                                     get_h225_addr(ct, *data, &taddr[0],
118                                                   &addr, &port) &&
119                                     (ntohl(addr.ip) & 0xff000000) == 0x7f000000)
120                                         i = 0;
121
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].
129                                                      tuple.dst.u3,
130                                                      info->sig_port[!dir]);
131                         } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
132                                    port == info->sig_port[dir]) {
133                                 /* GK->GW */
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].
141                                                      tuple.src.u3,
142                                                      info->sig_port[!dir]);
143                         }
144                 }
145         }
146
147         return 0;
148 }
149
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)
155 {
156         int dir = CTINFO2DIR(ctinfo);
157         int i;
158         __be16 port;
159         union nf_inet_addr addr;
160
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.
173                                                                 dst.u.udp.port);
174                 }
175         }
176
177         return 0;
178 }
179
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)
188 {
189         struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
190         int dir = CTINFO2DIR(ctinfo);
191         int i;
192         u_int16_t nated_port;
193
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;
197         rtp_exp->dir = !dir;
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;
201
202         /* Lookup existing expects */
203         for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
204                 if (info->rtp_port[i][dir] == rtp_port) {
205                         /* Expected */
206
207                         /* Use allocated ports first. This will refresh
208                          * the expects */
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);
212                         break;
213                 } else if (info->rtp_port[i][dir] == 0) {
214                         /* Not expected */
215                         break;
216                 }
217         }
218
219         /* Run out of expectations */
220         if (i >= H323_RTP_CHANNEL_MAX) {
221                 if (net_ratelimit())
222                         printk("nf_nat_h323: out of expectations\n");
223                 return 0;
224         }
225
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)
234                                 break;
235                         nf_ct_unexpect_related(rtp_exp);
236                 }
237         }
238
239         if (nated_port == 0) {  /* No port available */
240                 if (net_ratelimit())
241                         printk("nf_nat_h323: out of RTP ports\n");
242                 return 0;
243         }
244
245         /* Modify signal */
246         if (set_h245_addr(skb, data, dataoff, taddr,
247                           &ct->tuplehash[!dir].tuple.dst.u3,
248                           htons((port & htons(1)) ? nated_port + 1 :
249                                                     nated_port)) == 0) {
250                 /* Save ports */
251                 info->rtp_port[i][dir] = rtp_port;
252                 info->rtp_port[i][!dir] = htons(nated_port);
253         } else {
254                 nf_ct_unexpect_related(rtp_exp);
255                 nf_ct_unexpect_related(rtcp_exp);
256                 return -1;
257         }
258
259         /* Success */
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));
270
271         return 0;
272 }
273
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)
280 {
281         int dir = CTINFO2DIR(ctinfo);
282         u_int16_t nated_port = ntohs(port);
283
284         /* Set expectations for NAT */
285         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
286         exp->expectfn = nf_nat_follow_master;
287         exp->dir = !dir;
288
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)
293                         break;
294         }
295
296         if (nated_port == 0) {  /* No port available */
297                 if (net_ratelimit())
298                         printk("nf_nat_h323: out of TCP ports\n");
299                 return 0;
300         }
301
302         /* Modify signal */
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);
307                 return -1;
308         }
309
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));
315
316         return 0;
317 }
318
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)
325 {
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);
329
330         /* Set expectations for NAT */
331         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
332         exp->expectfn = nf_nat_follow_master;
333         exp->dir = !dir;
334
335         /* Check existing expects */
336         if (info->sig_port[dir] == port)
337                 nated_port = ntohs(info->sig_port[!dir]);
338
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)
343                         break;
344         }
345
346         if (nated_port == 0) {  /* No port available */
347                 if (net_ratelimit())
348                         printk("nf_nat_q931: out of TCP ports\n");
349                 return 0;
350         }
351
352         /* Modify signal */
353         if (set_h225_addr(skb, data, dataoff, taddr,
354                           &ct->tuplehash[!dir].tuple.dst.u3,
355                           htons(nated_port)) == 0) {
356                 /* Save ports */
357                 info->sig_port[dir] = port;
358                 info->sig_port[!dir] = htons(nated_port);
359         } else {
360                 nf_ct_unexpect_related(exp);
361                 return -1;
362         }
363
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));
369
370         return 0;
371 }
372
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)
379 {
380         struct nf_nat_range range;
381
382         if (this->tuple.src.u3.ip != 0) {       /* Only accept calls from GK */
383                 nf_nat_follow_master(new, this);
384                 return;
385         }
386
387         /* This must be a fresh one. */
388         BUG_ON(new->status & IPS_NAT_DONE_MASK);
389
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);
394
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);
401 }
402
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)
408 {
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;
413
414         /* Set expectations for NAT */
415         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
416         exp->expectfn = ip_nat_q931_expect;
417         exp->dir = !dir;
418
419         /* Check existing expects */
420         if (info->sig_port[dir] == port)
421                 nated_port = ntohs(info->sig_port[!dir]);
422
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)
427                         break;
428         }
429
430         if (nated_port == 0) {  /* No port available */
431                 if (net_ratelimit())
432                         printk("nf_nat_ras: out of TCP ports\n");
433                 return 0;
434         }
435
436         /* Modify signal */
437         if (set_h225_addr(skb, data, 0, &taddr[idx],
438                           &ct->tuplehash[!dir].tuple.dst.u3,
439                           htons(nated_port)) == 0) {
440                 /* Save ports */
441                 info->sig_port[dir] = port;
442                 info->sig_port[!dir] = htons(nated_port);
443
444                 /* Fix for Gnomemeeting */
445                 if (idx > 0 &&
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]);
451                 }
452         } else {
453                 nf_ct_unexpect_related(exp);
454                 return -1;
455         }
456
457         /* Success */
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));
463
464         return 0;
465 }
466
467 /****************************************************************************/
468 static void ip_nat_callforwarding_expect(struct nf_conn *new,
469                                          struct nf_conntrack_expect *this)
470 {
471         struct nf_nat_range range;
472
473         /* This must be a fresh one. */
474         BUG_ON(new->status & IPS_NAT_DONE_MASK);
475
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);
480
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);
486 }
487
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)
494 {
495         int dir = CTINFO2DIR(ctinfo);
496         u_int16_t nated_port;
497
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;
503         exp->dir = !dir;
504
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)
509                         break;
510         }
511
512         if (nated_port == 0) {  /* No port available */
513                 if (net_ratelimit())
514                         printk("nf_nat_q931: out of TCP ports\n");
515                 return 0;
516         }
517
518         /* Modify signal */
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);
523                 return -1;
524         }
525
526         /* Success */
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));
533
534         return 0;
535 }
536
537 /****************************************************************************/
538 static int __init init(void)
539 {
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);
549
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);
559         return 0;
560 }
561
562 /****************************************************************************/
563 static void __exit fini(void)
564 {
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);
574         synchronize_rcu();
575 }
576
577 /****************************************************************************/
578 module_init(init);
579 module_exit(fini);
580
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");