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