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