[NETFILTER]: Introduce NF_INET_ hook values
[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         struct tcphdr _tcph, *th;
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_conntrack_address *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_conntrack_address *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         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_conntrack_address 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 "
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].
128                                                      tuple.dst.u3,
129                                                      info->sig_port[!dir]);
130                         } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
131                                    port == info->sig_port[dir]) {
132                                 /* GK->GW */
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].
140                                                      tuple.src.u3,
141                                                      info->sig_port[!dir]);
142                         }
143                 }
144         }
145
146         return 0;
147 }
148
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)
154 {
155         int dir = CTINFO2DIR(ctinfo);
156         int i;
157         __be16 port;
158         union nf_conntrack_address addr;
159
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.
172                                                                 dst.u.udp.port);
173                 }
174         }
175
176         return 0;
177 }
178
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)
187 {
188         struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
189         int dir = CTINFO2DIR(ctinfo);
190         int i;
191         u_int16_t nated_port;
192
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;
196         rtp_exp->dir = !dir;
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;
200
201         /* Lookup existing expects */
202         for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
203                 if (info->rtp_port[i][dir] == rtp_port) {
204                         /* Expected */
205
206                         /* Use allocated ports first. This will refresh
207                          * the expects */
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);
211                         break;
212                 } else if (info->rtp_port[i][dir] == 0) {
213                         /* Not expected */
214                         break;
215                 }
216         }
217
218         /* Run out of expectations */
219         if (i >= H323_RTP_CHANNEL_MAX) {
220                 if (net_ratelimit())
221                         printk("nf_nat_h323: out of expectations\n");
222                 return 0;
223         }
224
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)
233                                 break;
234                         nf_ct_unexpect_related(rtp_exp);
235                 }
236         }
237
238         if (nated_port == 0) {  /* No port available */
239                 if (net_ratelimit())
240                         printk("nf_nat_h323: out of RTP ports\n");
241                 return 0;
242         }
243
244         /* Modify signal */
245         if (set_h245_addr(skb, data, dataoff, taddr,
246                           &ct->tuplehash[!dir].tuple.dst.u3,
247                           htons((port & htons(1)) ? nated_port + 1 :
248                                                     nated_port)) == 0) {
249                 /* Save ports */
250                 info->rtp_port[i][dir] = rtp_port;
251                 info->rtp_port[i][!dir] = htons(nated_port);
252         } else {
253                 nf_ct_unexpect_related(rtp_exp);
254                 nf_ct_unexpect_related(rtcp_exp);
255                 return -1;
256         }
257
258         /* Success */
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));
269
270         return 0;
271 }
272
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)
279 {
280         int dir = CTINFO2DIR(ctinfo);
281         u_int16_t nated_port = ntohs(port);
282
283         /* Set expectations for NAT */
284         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
285         exp->expectfn = nf_nat_follow_master;
286         exp->dir = !dir;
287
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)
292                         break;
293         }
294
295         if (nated_port == 0) {  /* No port available */
296                 if (net_ratelimit())
297                         printk("nf_nat_h323: out of TCP ports\n");
298                 return 0;
299         }
300
301         /* Modify signal */
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);
306                 return -1;
307         }
308
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));
314
315         return 0;
316 }
317
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)
324 {
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);
328
329         /* Set expectations for NAT */
330         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
331         exp->expectfn = nf_nat_follow_master;
332         exp->dir = !dir;
333
334         /* Check existing expects */
335         if (info->sig_port[dir] == port)
336                 nated_port = ntohs(info->sig_port[!dir]);
337
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)
342                         break;
343         }
344
345         if (nated_port == 0) {  /* No port available */
346                 if (net_ratelimit())
347                         printk("nf_nat_q931: out of TCP ports\n");
348                 return 0;
349         }
350
351         /* Modify signal */
352         if (set_h225_addr(skb, data, dataoff, taddr,
353                           &ct->tuplehash[!dir].tuple.dst.u3,
354                           htons(nated_port)) == 0) {
355                 /* Save ports */
356                 info->sig_port[dir] = port;
357                 info->sig_port[!dir] = htons(nated_port);
358         } else {
359                 nf_ct_unexpect_related(exp);
360                 return -1;
361         }
362
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));
368
369         return 0;
370 }
371
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)
378 {
379         struct nf_nat_range range;
380
381         if (this->tuple.src.u3.ip != 0) {       /* Only accept calls from GK */
382                 nf_nat_follow_master(new, this);
383                 return;
384         }
385
386         /* This must be a fresh one. */
387         BUG_ON(new->status & IPS_NAT_DONE_MASK);
388
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;
392
393         /* hook doesn't matter, but it has to do source manip */
394         nf_nat_setup_info(new, &range, NF_INET_POST_ROUTING);
395
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;
401
402         /* hook doesn't matter, but it has to do destination manip */
403         nf_nat_setup_info(new, &range, NF_INET_PRE_ROUTING);
404 }
405
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)
411 {
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;
416
417         /* Set expectations for NAT */
418         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
419         exp->expectfn = ip_nat_q931_expect;
420         exp->dir = !dir;
421
422         /* Check existing expects */
423         if (info->sig_port[dir] == port)
424                 nated_port = ntohs(info->sig_port[!dir]);
425
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)
430                         break;
431         }
432
433         if (nated_port == 0) {  /* No port available */
434                 if (net_ratelimit())
435                         printk("nf_nat_ras: out of TCP ports\n");
436                 return 0;
437         }
438
439         /* Modify signal */
440         if (set_h225_addr(skb, data, 0, &taddr[idx],
441                           &ct->tuplehash[!dir].tuple.dst.u3,
442                           htons(nated_port)) == 0) {
443                 /* Save ports */
444                 info->sig_port[dir] = port;
445                 info->sig_port[!dir] = htons(nated_port);
446
447                 /* Fix for Gnomemeeting */
448                 if (idx > 0 &&
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]);
454                 }
455         } else {
456                 nf_ct_unexpect_related(exp);
457                 return -1;
458         }
459
460         /* Success */
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));
466
467         return 0;
468 }
469
470 /****************************************************************************/
471 static void ip_nat_callforwarding_expect(struct nf_conn *new,
472                                          struct nf_conntrack_expect *this)
473 {
474         struct nf_nat_range range;
475
476         /* This must be a fresh one. */
477         BUG_ON(new->status & IPS_NAT_DONE_MASK);
478
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;
482
483         /* hook doesn't matter, but it has to do source manip */
484         nf_nat_setup_info(new, &range, NF_INET_POST_ROUTING);
485
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;
490
491         /* hook doesn't matter, but it has to do destination manip */
492         nf_nat_setup_info(new, &range, NF_INET_PRE_ROUTING);
493 }
494
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)
501 {
502         int dir = CTINFO2DIR(ctinfo);
503         u_int16_t nated_port;
504
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;
510         exp->dir = !dir;
511
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)
516                         break;
517         }
518
519         if (nated_port == 0) {  /* No port available */
520                 if (net_ratelimit())
521                         printk("nf_nat_q931: out of TCP ports\n");
522                 return 0;
523         }
524
525         /* Modify signal */
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);
530                 return -1;
531         }
532
533         /* Success */
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));
540
541         return 0;
542 }
543
544 /****************************************************************************/
545 static int __init init(void)
546 {
547         BUG_ON(set_h245_addr_hook != NULL);
548         BUG_ON(set_h225_addr_hook != NULL);
549         BUG_ON(set_sig_addr_hook != NULL);
550         BUG_ON(set_ras_addr_hook != NULL);
551         BUG_ON(nat_rtp_rtcp_hook != NULL);
552         BUG_ON(nat_t120_hook != NULL);
553         BUG_ON(nat_h245_hook != NULL);
554         BUG_ON(nat_callforwarding_hook != NULL);
555         BUG_ON(nat_q931_hook != NULL);
556
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);
566         return 0;
567 }
568
569 /****************************************************************************/
570 static void __exit fini(void)
571 {
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);
581         synchronize_rcu();
582 }
583
584 /****************************************************************************/
585 module_init(init);
586 module_exit(fini);
587
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");