Merge HEAD from ../linux-2.6
[pandora-kernel.git] / net / ipv4 / netfilter / ip_nat_helper_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  * Changes:
12  *      2006-02-01 - initial version 0.1
13  *
14  *      2006-02-20 - version 0.2
15  *        1. Changed source format to follow kernel conventions
16  *        2. Deleted some unnecessary structures
17  *        3. Minor fixes
18  *
19  *      2006-03-10 - version 0.3
20  *        1. Added support for multiple TPKTs in one packet (suggested by
21  *           Patrick McHardy)
22  *        2. Added support for non-linear skb (based on Patrick McHardy's patch)
23  *        3. Eliminated unnecessary return code
24  *
25  *      2006-03-15 - version 0.4
26  *        1. Added support for T.120 channels
27  *        2. Added parameter gkrouted_only (suggested by Patrick McHardy)
28  */
29
30 #include <linux/module.h>
31 #include <linux/netfilter_ipv4.h>
32 #include <linux/netfilter.h>
33 #include <linux/ip.h>
34 #include <linux/tcp.h>
35 #include <linux/moduleparam.h>
36 #include <net/tcp.h>
37 #include <linux/netfilter_ipv4/ip_nat.h>
38 #include <linux/netfilter_ipv4/ip_nat_helper.h>
39 #include <linux/netfilter_ipv4/ip_nat_rule.h>
40 #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
41 #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
42 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
43
44 #include "ip_conntrack_helper_h323_asn1.h"
45
46 #if 0
47 #define DEBUGP printk
48 #else
49 #define DEBUGP(format, args...)
50 #endif
51
52 extern int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
53                          u_int32_t * ip, u_int16_t * port);
54 extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
55                          u_int32_t * ip, u_int16_t * port);
56 extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
57                                      struct ip_conntrack_expect *this);
58 extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
59                                      struct ip_conntrack_expect *this);
60 extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
61                                   unsigned char **data, int dataoff,
62                                   H245_TransportAddress * addr,
63                                   u_int32_t ip, u_int16_t port);
64 extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
65                                   unsigned char **data, int dataoff,
66                                   TransportAddress * addr,
67                                   u_int32_t ip, u_int16_t port);
68 extern int (*set_sig_addr_hook) (struct sk_buff ** pskb,
69                                  struct ip_conntrack * ct,
70                                  enum ip_conntrack_info ctinfo,
71                                  unsigned char **data,
72                                  TransportAddress * addr, int count);
73 extern int (*set_ras_addr_hook) (struct sk_buff ** pskb,
74                                  struct ip_conntrack * ct,
75                                  enum ip_conntrack_info ctinfo,
76                                  unsigned char **data,
77                                  TransportAddress * addr, int count);
78 extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
79                                  struct ip_conntrack * ct,
80                                  enum ip_conntrack_info ctinfo,
81                                  unsigned char **data, int dataoff,
82                                  H245_TransportAddress * addr,
83                                  u_int16_t port, u_int16_t rtp_port,
84                                  struct ip_conntrack_expect * rtp_exp,
85                                  struct ip_conntrack_expect * rtcp_exp);
86 extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
87                              enum ip_conntrack_info ctinfo,
88                              unsigned char **data, int dataoff,
89                              H245_TransportAddress * addr, u_int16_t port,
90                              struct ip_conntrack_expect * exp);
91 extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
92                              enum ip_conntrack_info ctinfo,
93                              unsigned char **data, int dataoff,
94                              TransportAddress * addr, u_int16_t port,
95                              struct ip_conntrack_expect * exp);
96 extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
97                              enum ip_conntrack_info ctinfo,
98                              unsigned char **data, TransportAddress * addr,
99                              int idx, u_int16_t port,
100                              struct ip_conntrack_expect * exp);
101
102
103 /****************************************************************************/
104 static int set_addr(struct sk_buff **pskb,
105                     unsigned char **data, int dataoff,
106                     unsigned int addroff, u_int32_t ip, u_int16_t port)
107 {
108         enum ip_conntrack_info ctinfo;
109         struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo);
110         struct {
111                 u_int32_t ip;
112                 u_int16_t port;
113         } __attribute__ ((__packed__)) buf;
114         struct tcphdr _tcph, *th;
115
116         buf.ip = ip;
117         buf.port = htons(port);
118         addroff += dataoff;
119
120         if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
121                 if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
122                                               addroff, sizeof(buf),
123                                               (char *) &buf, sizeof(buf))) {
124                         if (net_ratelimit())
125                                 printk("ip_nat_h323: ip_nat_mangle_tcp_packet"
126                                        " error\n");
127                         return -1;
128                 }
129
130                 /* Relocate data pointer */
131                 th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
132                                         sizeof(_tcph), &_tcph);
133                 if (th == NULL)
134                         return -1;
135                 *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
136                     th->doff * 4 + dataoff;
137         } else {
138                 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
139                                               addroff, sizeof(buf),
140                                               (char *) &buf, sizeof(buf))) {
141                         if (net_ratelimit())
142                                 printk("ip_nat_h323: ip_nat_mangle_udp_packet"
143                                        " error\n");
144                         return -1;
145                 }
146                 /* ip_nat_mangle_udp_packet uses skb_make_writable() to copy
147                  * or pull everything in a linear buffer, so we can safely
148                  * use the skb pointers now */
149                 *data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
150                     sizeof(struct udphdr);
151         }
152
153         return 0;
154 }
155
156 /****************************************************************************/
157 static int set_h225_addr(struct sk_buff **pskb,
158                          unsigned char **data, int dataoff,
159                          TransportAddress * addr,
160                          u_int32_t ip, u_int16_t port)
161 {
162         return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port);
163 }
164
165 /****************************************************************************/
166 static int set_h245_addr(struct sk_buff **pskb,
167                          unsigned char **data, int dataoff,
168                          H245_TransportAddress * addr,
169                          u_int32_t ip, u_int16_t port)
170 {
171         return set_addr(pskb, data, dataoff,
172                         addr->unicastAddress.iPAddress.network, ip, port);
173 }
174
175 /****************************************************************************/
176 static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
177                         enum ip_conntrack_info ctinfo,
178                         unsigned char **data,
179                         TransportAddress * addr, int count)
180 {
181         struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
182         int dir = CTINFO2DIR(ctinfo);
183         int i;
184         u_int32_t ip;
185         u_int16_t port;
186
187         for (i = 0; i < count; i++) {
188                 if (get_h225_addr(*data, &addr[i], &ip, &port)) {
189                         if (ip == ct->tuplehash[dir].tuple.src.ip &&
190                             port == info->sig_port[dir]) {
191                                 /* GW->GK */
192
193                                 /* Fix for Gnomemeeting */
194                                 if (i > 0 &&
195                                     get_h225_addr(*data, &addr[0],
196                                                   &ip, &port) &&
197                                     (ntohl(ip) & 0xff000000) == 0x7f000000)
198                                         i = 0;
199
200                                 DEBUGP
201                                     ("ip_nat_ras: set signal address "
202                                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
203                                      NIPQUAD(ip), port,
204                                      NIPQUAD(ct->tuplehash[!dir].tuple.dst.
205                                              ip), info->sig_port[!dir]);
206                                 return set_h225_addr(pskb, data, 0, &addr[i],
207                                                      ct->tuplehash[!dir].
208                                                      tuple.dst.ip,
209                                                      info->sig_port[!dir]);
210                         } else if (ip == ct->tuplehash[dir].tuple.dst.ip &&
211                                    port == info->sig_port[dir]) {
212                                 /* GK->GW */
213                                 DEBUGP
214                                     ("ip_nat_ras: set signal address "
215                                      "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
216                                      NIPQUAD(ip), port,
217                                      NIPQUAD(ct->tuplehash[!dir].tuple.src.
218                                              ip), info->sig_port[!dir]);
219                                 return set_h225_addr(pskb, data, 0, &addr[i],
220                                                      ct->tuplehash[!dir].
221                                                      tuple.src.ip,
222                                                      info->sig_port[!dir]);
223                         }
224                 }
225         }
226
227         return 0;
228 }
229
230 /****************************************************************************/
231 static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
232                         enum ip_conntrack_info ctinfo,
233                         unsigned char **data,
234                         TransportAddress * addr, int count)
235 {
236         int dir = CTINFO2DIR(ctinfo);
237         int i;
238         u_int32_t ip;
239         u_int16_t port;
240
241         for (i = 0; i < count; i++) {
242                 if (get_h225_addr(*data, &addr[i], &ip, &port) &&
243                     ip == ct->tuplehash[dir].tuple.src.ip &&
244                     port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) {
245                         DEBUGP("ip_nat_ras: set rasAddress "
246                                "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
247                                NIPQUAD(ip), port,
248                                NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
249                                ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
250                                      port));
251                         return set_h225_addr(pskb, data, 0, &addr[i],
252                                              ct->tuplehash[!dir].tuple.dst.ip,
253                                              ntohs(ct->tuplehash[!dir].tuple.
254                                                    dst.u.udp.port));
255                 }
256         }
257
258         return 0;
259 }
260
261 /****************************************************************************/
262 static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
263                         enum ip_conntrack_info ctinfo,
264                         unsigned char **data, int dataoff,
265                         H245_TransportAddress * addr,
266                         u_int16_t port, u_int16_t rtp_port,
267                         struct ip_conntrack_expect *rtp_exp,
268                         struct ip_conntrack_expect *rtcp_exp)
269 {
270         struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
271         int dir = CTINFO2DIR(ctinfo);
272         int i;
273         u_int16_t nated_port;
274
275         /* Set expectations for NAT */
276         rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
277         rtp_exp->expectfn = ip_nat_follow_master;
278         rtp_exp->dir = !dir;
279         rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
280         rtcp_exp->expectfn = ip_nat_follow_master;
281         rtcp_exp->dir = !dir;
282
283         /* Lookup existing expects */
284         for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
285                 if (info->rtp_port[i][dir] == rtp_port) {
286                         /* Expected */
287
288                         /* Use allocated ports first. This will refresh
289                          * the expects */
290                         rtp_exp->tuple.dst.u.udp.port =
291                             htons(info->rtp_port[i][dir]);
292                         rtcp_exp->tuple.dst.u.udp.port =
293                             htons(info->rtp_port[i][dir] + 1);
294                         break;
295                 } else if (info->rtp_port[i][dir] == 0) {
296                         /* Not expected */
297                         break;
298                 }
299         }
300
301         /* Run out of expectations */
302         if (i >= H323_RTP_CHANNEL_MAX) {
303                 if (net_ratelimit())
304                         printk("ip_nat_h323: out of expectations\n");
305                 return 0;
306         }
307
308         /* Try to get a pair of ports. */
309         for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
310              nated_port != 0; nated_port += 2) {
311                 rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
312                 if (ip_conntrack_expect_related(rtp_exp) == 0) {
313                         rtcp_exp->tuple.dst.u.udp.port =
314                             htons(nated_port + 1);
315                         if (ip_conntrack_expect_related(rtcp_exp) == 0)
316                                 break;
317                         ip_conntrack_unexpect_related(rtp_exp);
318                 }
319         }
320
321         if (nated_port == 0) {  /* No port available */
322                 if (net_ratelimit())
323                         printk("ip_nat_h323: out of RTP ports\n");
324                 return 0;
325         }
326
327         /* Modify signal */
328         if (set_h245_addr(pskb, data, dataoff, addr,
329                           ct->tuplehash[!dir].tuple.dst.ip,
330                           (port & 1) ? nated_port + 1 : nated_port) == 0) {
331                 /* Save ports */
332                 info->rtp_port[i][dir] = rtp_port;
333                 info->rtp_port[i][!dir] = nated_port;
334         } else {
335                 ip_conntrack_unexpect_related(rtp_exp);
336                 ip_conntrack_unexpect_related(rtcp_exp);
337                 return -1;
338         }
339
340         /* Success */
341         DEBUGP("ip_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
342                NIPQUAD(rtp_exp->tuple.src.ip),
343                ntohs(rtp_exp->tuple.src.u.udp.port),
344                NIPQUAD(rtp_exp->tuple.dst.ip),
345                ntohs(rtp_exp->tuple.dst.u.udp.port));
346         DEBUGP("ip_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
347                NIPQUAD(rtcp_exp->tuple.src.ip),
348                ntohs(rtcp_exp->tuple.src.u.udp.port),
349                NIPQUAD(rtcp_exp->tuple.dst.ip),
350                ntohs(rtcp_exp->tuple.dst.u.udp.port));
351
352         return 0;
353 }
354
355 /****************************************************************************/
356 static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct,
357                     enum ip_conntrack_info ctinfo,
358                     unsigned char **data, int dataoff,
359                     H245_TransportAddress * addr, u_int16_t port,
360                     struct ip_conntrack_expect *exp)
361 {
362         int dir = CTINFO2DIR(ctinfo);
363         u_int16_t nated_port = port;
364
365         /* Set expectations for NAT */
366         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
367         exp->expectfn = ip_nat_follow_master;
368         exp->dir = !dir;
369
370         /* Try to get same port: if not, try to change it. */
371         for (; nated_port != 0; nated_port++) {
372                 exp->tuple.dst.u.tcp.port = htons(nated_port);
373                 if (ip_conntrack_expect_related(exp) == 0)
374                         break;
375         }
376
377         if (nated_port == 0) {  /* No port available */
378                 if (net_ratelimit())
379                         printk("ip_nat_h323: out of TCP ports\n");
380                 return 0;
381         }
382
383         /* Modify signal */
384         if (set_h245_addr(pskb, data, dataoff, addr,
385                           ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) {
386                 ip_conntrack_unexpect_related(exp);
387                 return -1;
388         }
389
390         DEBUGP("ip_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
391                NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
392                NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
393
394         return 0;
395 }
396
397 /****************************************************************************
398  * This conntrack expect function replaces ip_conntrack_h245_expect()
399  * which was set by ip_conntrack_helper_h323.c. It calls both
400  * ip_nat_follow_master() and ip_conntrack_h245_expect()
401  ****************************************************************************/
402 static void ip_nat_h245_expect(struct ip_conntrack *new,
403                                struct ip_conntrack_expect *this)
404 {
405         ip_nat_follow_master(new, this);
406         ip_conntrack_h245_expect(new, this);
407 }
408
409 /****************************************************************************/
410 static int nat_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
411                     enum ip_conntrack_info ctinfo,
412                     unsigned char **data, int dataoff,
413                     TransportAddress * addr, u_int16_t port,
414                     struct ip_conntrack_expect *exp)
415 {
416         struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
417         int dir = CTINFO2DIR(ctinfo);
418         u_int16_t nated_port = port;
419
420         /* Set expectations for NAT */
421         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
422         exp->expectfn = ip_nat_h245_expect;
423         exp->dir = !dir;
424
425         /* Check existing expects */
426         if (info->sig_port[dir] == port)
427                 nated_port = info->sig_port[!dir];
428
429         /* Try to get same port: if not, try to change it. */
430         for (; nated_port != 0; nated_port++) {
431                 exp->tuple.dst.u.tcp.port = htons(nated_port);
432                 if (ip_conntrack_expect_related(exp) == 0)
433                         break;
434         }
435
436         if (nated_port == 0) {  /* No port available */
437                 if (net_ratelimit())
438                         printk("ip_nat_q931: out of TCP ports\n");
439                 return 0;
440         }
441
442         /* Modify signal */
443         if (set_h225_addr(pskb, data, dataoff, addr,
444                           ct->tuplehash[!dir].tuple.dst.ip,
445                           nated_port) == 0) {
446                 /* Save ports */
447                 info->sig_port[dir] = port;
448                 info->sig_port[!dir] = nated_port;
449         } else {
450                 ip_conntrack_unexpect_related(exp);
451                 return -1;
452         }
453
454         DEBUGP("ip_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
455                NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
456                NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
457
458         return 0;
459 }
460
461 /****************************************************************************
462  * This conntrack expect function replaces ip_conntrack_q931_expect()
463  * which was set by ip_conntrack_helper_h323.c.
464  ****************************************************************************/
465 static void ip_nat_q931_expect(struct ip_conntrack *new,
466                                struct ip_conntrack_expect *this)
467 {
468         struct ip_nat_range range;
469
470         if (this->tuple.src.ip != 0) {  /* Only accept calls from GK */
471                 ip_nat_follow_master(new, this);
472                 goto out;
473         }
474
475         /* This must be a fresh one. */
476         BUG_ON(new->status & IPS_NAT_DONE_MASK);
477
478         /* Change src to where master sends to */
479         range.flags = IP_NAT_RANGE_MAP_IPS;
480         range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip;
481
482         /* hook doesn't matter, but it has to do source manip */
483         ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
484
485         /* For DST manip, map port here to where it's expected. */
486         range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
487         range.min = range.max = this->saved_proto;
488         range.min_ip = range.max_ip =
489             new->master->tuplehash[!this->dir].tuple.src.ip;
490
491         /* hook doesn't matter, but it has to do destination manip */
492         ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
493
494       out:
495         ip_conntrack_q931_expect(new, this);
496 }
497
498 /****************************************************************************/
499 static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
500                     enum ip_conntrack_info ctinfo,
501                     unsigned char **data, TransportAddress * addr, int idx,
502                     u_int16_t port, struct ip_conntrack_expect *exp)
503 {
504         struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
505         int dir = CTINFO2DIR(ctinfo);
506         u_int16_t nated_port = port;
507         u_int32_t ip;
508
509         /* Set expectations for NAT */
510         exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
511         exp->expectfn = ip_nat_q931_expect;
512         exp->dir = !dir;
513
514         /* Check existing expects */
515         if (info->sig_port[dir] == port)
516                 nated_port = info->sig_port[!dir];
517
518         /* Try to get same port: if not, try to change it. */
519         for (; nated_port != 0; nated_port++) {
520                 exp->tuple.dst.u.tcp.port = htons(nated_port);
521                 if (ip_conntrack_expect_related(exp) == 0)
522                         break;
523         }
524
525         if (nated_port == 0) {  /* No port available */
526                 if (net_ratelimit())
527                         printk("ip_nat_ras: out of TCP ports\n");
528                 return 0;
529         }
530
531         /* Modify signal */
532         if (set_h225_addr(pskb, data, 0, &addr[idx],
533                           ct->tuplehash[!dir].tuple.dst.ip,
534                           nated_port) == 0) {
535                 /* Save ports */
536                 info->sig_port[dir] = port;
537                 info->sig_port[!dir] = nated_port;
538
539                 /* Fix for Gnomemeeting */
540                 if (idx > 0 &&
541                     get_h225_addr(*data, &addr[0], &ip, &port) &&
542                     (ntohl(ip) & 0xff000000) == 0x7f000000) {
543                         set_h225_addr_hook(pskb, data, 0, &addr[0],
544                                            ct->tuplehash[!dir].tuple.dst.ip,
545                                            info->sig_port[!dir]);
546                 }
547         } else {
548                 ip_conntrack_unexpect_related(exp);
549                 return -1;
550         }
551
552         /* Success */
553         DEBUGP("ip_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
554                NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
555                NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
556
557         return 0;
558 }
559
560 /****************************************************************************/
561 static int __init init(void)
562 {
563         BUG_ON(set_h245_addr_hook != NULL);
564         BUG_ON(set_h225_addr_hook != NULL);
565         BUG_ON(set_sig_addr_hook != NULL);
566         BUG_ON(set_ras_addr_hook != NULL);
567         BUG_ON(nat_rtp_rtcp_hook != NULL);
568         BUG_ON(nat_t120_hook != NULL);
569         BUG_ON(nat_h245_hook != NULL);
570         BUG_ON(nat_q931_hook != NULL);
571
572         set_h245_addr_hook = set_h245_addr;
573         set_h225_addr_hook = set_h225_addr;
574         set_sig_addr_hook = set_sig_addr;
575         set_ras_addr_hook = set_ras_addr;
576         nat_rtp_rtcp_hook = nat_rtp_rtcp;
577         nat_t120_hook = nat_t120;
578         nat_h245_hook = nat_h245;
579         nat_q931_hook = nat_q931;
580
581         DEBUGP("ip_nat_h323: init success\n");
582         return 0;
583 }
584
585 /****************************************************************************/
586 static void __exit fini(void)
587 {
588         set_h245_addr_hook = NULL;
589         set_h225_addr_hook = NULL;
590         set_sig_addr_hook = NULL;
591         set_ras_addr_hook = NULL;
592         nat_rtp_rtcp_hook = NULL;
593         nat_t120_hook = NULL;
594         nat_h245_hook = NULL;
595         nat_q931_hook = NULL;
596         synchronize_net();
597 }
598
599 /****************************************************************************/
600 module_init(init);
601 module_exit(fini);
602
603 MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
604 MODULE_DESCRIPTION("H.323 NAT helper");
605 MODULE_LICENSE("GPL");