linux/net/ipv4/netfilter/nf_nat_h323.c
<<
>>
Prefs
   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/****************************************************************************/
  25static 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/****************************************************************************/
  76static 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/****************************************************************************/
  86static 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/****************************************************************************/
  97static 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/****************************************************************************/
 150static 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/****************************************************************************/
 180static 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/****************************************************************************/
 274static 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/****************************************************************************/
 319static 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 ****************************************************************************/
 376static 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_IP_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_IP_PRE_ROUTING);
 404}
 405
 406/****************************************************************************/
 407static 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/****************************************************************************/
 471static 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_IP_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_IP_PRE_ROUTING);
 493}
 494
 495/****************************************************************************/
 496static 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/****************************************************************************/
 545static 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/****************************************************************************/
 570static 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/****************************************************************************/
 585module_init(init);
 586module_exit(fini);
 587
 588MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
 589MODULE_DESCRIPTION("H.323 NAT helper");
 590MODULE_LICENSE("GPL");
 591MODULE_ALIAS("ip_nat_h323");
 592