Changeset 43311
- Timestamp:
- 2014-11-19T10:21:12+01:00 (3 years ago)
- Location:
- trunk/package/network/utils/xtables-addons/patches
- Files:
-
- 2 deleted
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch
r42256 r43311 236 236 --- /dev/null 237 237 +++ b/extensions/rtsp/nf_conntrack_rtsp.c 238 @@ -0,0 +1,5 19@@238 @@ -0,0 +1,576 @@ 239 239 +/* 240 240 + * RTSP extension for IP connection tracking 241 241 + * (C) 2003 by Tom Marshall <tmarshall at real.com> 242 + * 243 + * 2005-02-13: Harald Welte <laforge at netfilter.org> 244 + * - port to 2.6 245 + * - update to recent post-2.6.11 api changes 246 + * 2006-09-14: Steven Van Acker <deepstar at singularity.be> 247 + * - removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack 248 + * 2007-04-18: Michael Guntsche <mike at it-loops.com> 249 + * - Port to new NF API 250 + * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd 251 + * - fixed rtcp nat mapping and other port mapping fixes 252 + * - simple TEARDOWN request handling 253 + * - codestyle fixes and other less significant bug fixes 254 + * 242 255 + * based on ip_conntrack_irc.c 243 256 + * … … 258 271 + * an expected data channel (default 300 seconds). 259 272 + * 260 + * 2005-02-13: Harald Welte <laforge at netfilter.org>261 + * - port to 2.6262 + * - update to recent post-2.6.11 api changes263 + * 2006-09-14: Steven Van Acker <deepstar at singularity.be>264 + * - removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack265 + * 2007-04-18: Michael Guntsche <mike at it-loops.com>266 + * - Port to new NF API267 273 + */ 268 274 + … … 287 293 + 288 294 +#include <linux/ctype.h> 289 +#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */290 295 + 291 296 +#define MAX_PORTS 8 … … 308 313 +static DEFINE_SPINLOCK(rtsp_buffer_lock); 309 314 + 310 +static struct nf_conntrack_expect_policy rtsp_exp_policy; 315 +static struct nf_conntrack_expect_policy rtsp_exp_policy; 311 316 + 312 317 +unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb, 313 318 + enum ip_conntrack_info ctinfo, 314 + unsigned int matchoff, unsigned int matchlen,struct ip_ct_rtsp_expect* prtspexp, 315 + struct nf_conntrack_expect *exp); 316 +void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); 319 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 320 + unsigned int protoff, 321 +#endif 322 + unsigned int matchoff, unsigned int matchlen, 323 + struct ip_ct_rtsp_expect* prtspexp, 324 + struct nf_conntrack_expect *rtp_exp, 325 + struct nf_conntrack_expect *rtcp_exp); 317 326 + 318 327 +EXPORT_SYMBOL_GPL(nf_nat_rtsp_hook); … … 346 355 +static int 347 356 +rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff, 348 + 349 + 350 + 351 +{ 352 + uint 353 + uint 354 + uint 357 + uint* phdrsoff, uint* phdrslen, 358 + uint* pcseqoff, uint* pcseqlen, 359 + uint* transoff, uint* translen) 360 +{ 361 + uint entitylen = 0; 362 + uint lineoff; 363 + uint linelen; 355 364 + 356 365 + if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) … … 368 377 + break; 369 378 + } 370 + 379 + 371 380 + if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) { 372 381 + *pcseqoff = lineoff; … … 406 415 +static int 407 416 +rtsp_parse_transport(char* ptran, uint tranlen, 408 + 409 +{ 410 + int 411 + uint 417 + struct ip_ct_rtsp_expect* prtspexp) 418 +{ 419 + int rc = 0; 420 + uint off = 0; 412 421 + 413 422 + if (tranlen < 10 || !iseol(ptran[tranlen-1]) || … … 440 449 + u_int16_t port; 441 450 + uint numlen; 442 + 451 + 443 452 + off += 12; 444 453 + numlen = nf_strtou16(ptran+off, &port); … … 492 501 +} 493 502 + 494 +void expected(struct nf_conn *ct, struct nf_conntrack_expect *exp)495 +{496 + typeof(nf_nat_rtsp_hook_expectfn) nf_nat_rtsp_expectfn;497 + nf_nat_rtsp_expectfn = rcu_dereference(nf_nat_rtsp_hook_expectfn);498 + if(nf_nat_rtsp_expectfn && ct->master->status & IPS_NAT_MASK) {499 + nf_nat_rtsp_expectfn(ct,exp);500 + }501 +}502 503 + 503 504 +/*** conntrack functions ***/ … … 507 508 +static inline int 508 509 +help_out(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen, 509 + struct nf_conn *ct, enum ip_conntrack_info ctinfo) 510 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 511 + struct nf_conn *ct, enum ip_conntrack_info ctinfo, 512 + unsigned int protoff) 513 +#else 514 + struct nf_conn *ct, enum ip_conntrack_info ctinfo) 515 +#endif 510 516 +{ 511 517 + struct ip_ct_rtsp_expect expinfo; … … 519 525 + int ret = NF_ACCEPT; 520 526 + 521 + struct nf_conntrack_expect *exp; 527 + struct nf_conntrack_expect *rtp_exp; 528 + struct nf_conntrack_expect *rtcp_exp = NULL; 522 529 + 523 530 + __be16 be_loport; 531 + __be16 be_hiport; 524 532 + 525 533 + typeof(nf_nat_rtsp_hook) nf_nat_rtsp; … … 528 536 + 529 537 + while (dataoff < datalen) { 530 + uint 531 + uint 532 + uint 533 + uint 534 + uint 535 + uint 536 + uint 537 + uint 538 + uint cmdoff = dataoff; 539 + uint hdrsoff = 0; 540 + uint hdrslen = 0; 541 + uint cseqoff = 0; 542 + uint cseqlen = 0; 543 + uint transoff = 0; 544 + uint translen = 0; 545 + uint off; 538 546 + 539 547 + if (!rtsp_parse_message(pdata, datalen, &dataoff, … … 542 550 + &transoff, &translen)) 543 551 + break; /* not a valid message */ 544 + 552 + 553 + if (strncmp(pdata+cmdoff, "TEARDOWN ", 9) == 0) { 554 + pr_debug("teardown handled\n"); 555 + nf_ct_remove_expectations(ct); /* FIXME must be session id aware */ 556 + break; 557 + } 558 + 545 559 + if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0) 546 560 + continue; /* not a SETUP message */ 561 + 547 562 + pr_debug("found a setup message\n"); 548 563 + 549 564 + off = 0; 550 + if(translen) {565 + if(translen) 551 566 + rtsp_parse_transport(pdata+transoff, translen, &expinfo); 552 + }553 567 + 554 568 + if (expinfo.loport == 0) { … … 558 572 + 559 573 + pr_debug("udp transport found, ports=(%d,%hu,%hu)\n", 560 + (int)expinfo.pbtype, expinfo.loport, expinfo.hiport); 561 + 562 + exp = nf_ct_expect_alloc(ct); 563 + if (!exp) { 574 + (int)expinfo.pbtype, expinfo.loport, expinfo.hiport); 575 + 576 + 577 + be_loport = htons(expinfo.loport); 578 + 579 + rtp_exp = nf_ct_expect_alloc(ct); 580 + if (rtp_exp == NULL) { 564 581 + ret = NF_DROP; 565 582 + goto out; 566 583 + } 567 584 + 568 + be_loport = htons(expinfo.loport); 569 + 570 + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), 571 + &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, 572 + IPPROTO_UDP, NULL, &be_loport); 573 + 574 + exp->master = ct; 575 + 576 + exp->expectfn = expected; 577 + exp->flags = 0; 585 + nf_ct_expect_init(rtp_exp, NF_CT_EXPECT_CLASS_DEFAULT, 586 + nf_ct_l3num(ct), 587 + NULL, /* &ct->tuplehash[!dir].tuple.src.u3, */ 588 + &ct->tuplehash[!dir].tuple.dst.u3, 589 + IPPROTO_UDP, NULL, &be_loport); 590 + 591 + rtp_exp->flags = 0; 578 592 + 579 593 + if (expinfo.pbtype == pb_range) { 580 + pr_debug("Changing expectation mask to handle multiple ports\n"); 581 + //exp->mask.dst.u.udp.port = 0xfffe; 582 + } 583 + 584 + pr_debug("expect_related %pI4:%u-%pI4:%u\n", 585 + &exp->tuple.src.u3.ip, 586 + ntohs(exp->tuple.src.u.udp.port), 587 + &exp->tuple.dst.u3.ip, 588 + ntohs(exp->tuple.dst.u.udp.port)); 594 + pr_debug("setup expectation for rtcp\n"); 595 + 596 + be_hiport = htons(expinfo.hiport); 597 + rtcp_exp = nf_ct_expect_alloc(ct); 598 + if (rtcp_exp == NULL) { 599 + ret = NF_DROP; 600 + goto out1; 601 + } 602 + 603 + nf_ct_expect_init(rtcp_exp, NF_CT_EXPECT_CLASS_DEFAULT, 604 + nf_ct_l3num(ct), 605 + NULL, /* &ct->tuplehash[!dir].tuple.src.u3, */ 606 + &ct->tuplehash[!dir].tuple.dst.u3, 607 + IPPROTO_UDP, NULL, &be_hiport); 608 + 609 + rtcp_exp->flags = 0; 610 + 611 + pr_debug("expect_related %pI4:%u-%u-%pI4:%u-%u\n", 612 + &rtp_exp->tuple.src.u3.ip, 613 + ntohs(rtp_exp->tuple.src.u.udp.port), 614 + ntohs(rtcp_exp->tuple.src.u.udp.port), 615 + &rtp_exp->tuple.dst.u3.ip, 616 + ntohs(rtp_exp->tuple.dst.u.udp.port), 617 + ntohs(rtcp_exp->tuple.dst.u.udp.port)); 618 + } else { 619 + pr_debug("expect_related %pI4:%u-%pI4:%u\n", 620 + &rtp_exp->tuple.src.u3.ip, 621 + ntohs(rtp_exp->tuple.src.u.udp.port), 622 + &rtp_exp->tuple.dst.u3.ip, 623 + ntohs(rtp_exp->tuple.dst.u.udp.port)); 624 + } 589 625 + 590 626 + nf_nat_rtsp = rcu_dereference(nf_nat_rtsp_hook); 591 627 + if (nf_nat_rtsp && ct->status & IPS_NAT_MASK) 592 628 + /* pass the request off to the nat helper */ 593 + ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen, &expinfo, exp); 594 + else if (nf_ct_expect_related(exp) != 0) { 595 + pr_info("nf_conntrack_expect_related failed\n"); 596 + ret = NF_DROP; 597 + } 598 + nf_ct_expect_put(exp); 629 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 630 + ret = nf_nat_rtsp(skb, ctinfo, protoff, hdrsoff, hdrslen, 631 + &expinfo, rtp_exp, rtcp_exp); 632 +#else 633 + ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen, 634 + &expinfo, rtp_exp, rtcp_exp); 635 +#endif 636 + else { 637 + if (nf_ct_expect_related(rtp_exp) == 0) { 638 + if (rtcp_exp && nf_ct_expect_related(rtcp_exp) != 0) { 639 + nf_ct_unexpect_related(rtp_exp); 640 + pr_info("nf_conntrack_expect_related failed for rtcp\n"); 641 + ret = NF_DROP; 642 + } 643 + } else { 644 + pr_info("nf_conntrack_expect_related failed for rtp\n"); 645 + ret = NF_DROP; 646 + } 647 + } 648 + if (rtcp_exp) { 649 + nf_ct_expect_put(rtcp_exp); 650 + } 651 +out1: 652 + nf_ct_expect_put(rtp_exp); 599 653 + goto out; 600 654 + } … … 607 661 +static inline int 608 662 +help_in(struct sk_buff *skb, size_t pktlen, 609 + 610 +{ 611 + 663 + struct nf_conn* ct, enum ip_conntrack_info ctinfo) 664 +{ 665 + return NF_ACCEPT; 612 666 +} 613 667 + … … 628 682 + 629 683 + /* Not whole TCP header? */ 630 + th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);684 + th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); 631 685 + 632 686 + if (!th) … … 658 712 + switch (CTINFO2DIR(ctinfo)) { 659 713 + case IP_CT_DIR_ORIGINAL: 714 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 715 + ret = help_out(skb, rb_ptr, datalen, ct, ctinfo, protoff); 716 +#else 660 717 + ret = help_out(skb, rb_ptr, datalen, ct, ctinfo); 718 +#endif 661 719 + break; 662 720 + case IP_CT_DIR_REPLY: … … 705 763 + } 706 764 + 707 + 708 + 765 + rtsp_exp_policy.max_expected = max_outstanding; 766 + rtsp_exp_policy.timeout = setup_timeout; 709 767 + 710 768 + rtsp_buffer = kmalloc(65536, GFP_KERNEL); … … 715 773 + if (ports[0] == 0) { 716 774 + ports[0] = RTSP_PORT; 775 + num_ports = 1; 717 776 + } 718 777 + … … 723 782 + hlpr->tuple.src.u.tcp.port = htons(ports[i]); 724 783 + hlpr->tuple.dst.protonum = IPPROTO_TCP; 725 + //hlpr->mask.src.u.tcp.port = 0xFFFF;726 + //hlpr->mask.dst.protonum = 0xFF;727 784 + hlpr->expect_policy = &rtsp_exp_policy; 728 785 + hlpr->me = THIS_MODULE; … … 735 792 + sprintf(tmpname, "rtsp-%d", i); 736 793 + } 794 + 795 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) 796 + strlcpy(hlpr->name, tmpname, sizeof(hlpr->name)); 797 +#else 737 798 + hlpr->name = tmpname; 738 + 799 +#endif 739 800 + pr_debug("port #%d: %d\n", i, ports[i]); 740 801 + … … 746 807 + return -EBUSY; 747 808 + } 748 + num_ports++;749 809 + } 750 810 + return 0; … … 753 813 +module_init(init); 754 814 +module_exit(fini); 755 +756 +EXPORT_SYMBOL(nf_nat_rtsp_hook_expectfn);757 +758 815 --- /dev/null 759 816 +++ b/extensions/rtsp/nf_conntrack_rtsp.h 760 @@ -0,0 +1, 63@@817 @@ -0,0 +1,72 @@ 761 818 +/* 762 819 + * RTSP extension for IP connection tracking. … … 768 825 + * as published by the Free Software Foundation; either version 769 826 + * 2 of the License, or (at your option) any later version. 770 + */ 827 + * 828 + * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd 829 + * - conditional compilation for kernel 3.7 830 + * - port mapping improvements 831 +*/ 771 832 +#ifndef _IP_CONNTRACK_RTSP_H 772 833 +#define _IP_CONNTRACK_RTSP_H 773 834 + 835 +#include <linux/version.h> 836 + 774 837 +//#define IP_NF_RTSP_DEBUG 1 775 +#define IP_NF_RTSP_VERSION "0. 6.21"838 +#define IP_NF_RTSP_VERSION "0.7" 776 839 + 777 840 +#ifdef __KERNEL__ … … 810 873 + 811 874 +extern unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb, 812 + enum ip_conntrack_info ctinfo, 813 + unsigned int matchoff, unsigned int matchlen, 814 + struct ip_ct_rtsp_expect *prtspexp, 815 + struct nf_conntrack_expect *exp); 816 + 817 +extern void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); 875 + enum ip_conntrack_info ctinfo, 876 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 877 + unsigned int protoff, 878 +#endif 879 + unsigned int matchoff, 880 + unsigned int matchlen, 881 + struct ip_ct_rtsp_expect *prtspexp, 882 + struct nf_conntrack_expect *rtp_exp, 883 + struct nf_conntrack_expect *rtcp_exp); 818 884 + 819 885 +#define RTSP_PORT 554 … … 824 890 --- /dev/null 825 891 +++ b/extensions/rtsp/nf_nat_rtsp.c 826 @@ -0,0 +1, 491@@892 @@ -0,0 +1,617 @@ 827 893 +/* 828 894 + * RTSP extension for TCP NAT alteration 829 895 + * (C) 2003 by Tom Marshall <tmarshall at real.com> 896 + * 897 + * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd 898 + * - fixed rtcp nat mapping and other port mapping fixes 899 + * - fixed system hard lock because of bug in the parser 900 + * - codestyle fixes and less significant fixes 901 + * 830 902 + * based on ip_nat_irc.c 831 903 + * 832 + * 833 + * 834 + * 835 + * 904 + * This program is free software; you can redistribute it and/or 905 + * modify it under the terms of the GNU General Public License 906 + * as published by the Free Software Foundation; either version 907 + * 2 of the License, or (at your option) any later version. 836 908 + * 837 909 + * Module load syntax: 838 + * 839 + * 840 + * 910 + * insmod nf_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS> 911 + * stunaddr=<address> 912 + * destaction=[auto|strip|none] 841 913 + * 842 914 + * If no ports are specified, the default will be port 554 only. … … 858 930 + 859 931 +#include <linux/module.h> 932 +#include <linux/version.h> 860 933 +#include <net/tcp.h> 934 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 935 +# include <net/netfilter/nf_nat.h> 936 +#else 937 +# include <net/netfilter/nf_nat_rule.h> 938 +#endif 861 939 +#include <net/netfilter/nf_nat_helper.h> 862 +#include <net/netfilter/nf_nat_rule.h>863 940 +#include "nf_conntrack_rtsp.h" 864 941 +#include <net/netfilter/nf_conntrack_expect.h> … … 872 949 +#include "netfilter_mime.h" 873 950 + 874 +#include "../compat_xtables.h" 875 + 876 +#define MAX_PORTS 8 877 +#define DSTACT_AUTO 0 878 +#define DSTACT_STRIP 1 879 +#define DSTACT_NONE 2 880 + 881 +static char* stunaddr = NULL; 882 +static char* destaction = NULL; 951 +#define MAX_PORTS 8 952 +#define DSTACT_AUTO 0 953 +#define DSTACT_STRIP 1 954 +#define DSTACT_NONE 2 955 + 956 +static char* stunaddr = NULL; 957 +static char* destaction = NULL; 883 958 + 884 959 +static u_int32_t extip = 0; 885 960 +static int dstact = 0; 961 + 962 +static void nf_nat_rtsp_expected(struct nf_conn* ct, struct nf_conntrack_expect *exp); 886 963 + 887 964 +MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>"); … … 900 977 +get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen) 901 978 +{ 902 + struct iphdr* iph = ip_hdr(skb); 903 + struct tcphdr* tcph = (void *)iph + ip_hdrlen(skb); 904 + 905 + *pptcpdata = (char*)tcph + tcph->doff*4; 906 + *ptcpdatalen = ((char*)skb_transport_header(skb) + skb->len) - *pptcpdata; 907 +} 979 + struct iphdr* iph = ip_hdr(skb); 980 + struct tcphdr* tcph = (void *)iph + ip_hdrlen(skb); 981 + 982 + *pptcpdata = (char*)tcph + tcph->doff*4; 983 + *ptcpdatalen = ((char*)skb_transport_header(skb) + skb->len) - *pptcpdata; 984 +} 985 + 986 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 987 +/* copy of sip_sprintf_addr */ 988 +static int rtsp_sprintf_addr(const struct nf_conn *ct, char *buffer, 989 + const union nf_inet_addr *addr, bool delim) 990 +{ 991 + if (nf_ct_l3num(ct) == NFPROTO_IPV4) { 992 + return sprintf(buffer, "%pI4", &addr->ip); 993 + } else { 994 + if (delim) 995 + return sprintf(buffer, "[%pI6c]", &addr->ip6); 996 + else 997 + return sprintf(buffer, "%pI6c", &addr->ip6); 998 + } 999 +} 1000 +#endif 908 1001 + 909 1002 +/*** nat functions ***/ … … 928 1021 +static int 929 1022 +rtsp_mangle_tran(enum ip_conntrack_info ctinfo, 930 + struct nf_conntrack_expect* exp, 931 + struct ip_ct_rtsp_expect* prtspexp, 932 + struct sk_buff* skb, uint tranoff, uint tranlen) 933 +{ 934 + char* ptcp; 935 + uint tcplen; 936 + char* ptran; 937 + char rbuf1[16]; /* Replacement buffer (one port) */ 938 + uint rbuf1len; /* Replacement len (one port) */ 939 + char rbufa[16]; /* Replacement buffer (all ports) */ 940 + uint rbufalen; /* Replacement len (all ports) */ 941 + u_int32_t newip; 942 + u_int16_t loport, hiport; 943 + uint off = 0; 944 + uint diff; /* Number of bytes we removed */ 945 + 946 + struct nf_conn *ct = exp->master; 947 + struct nf_conntrack_tuple *t; 948 + 949 + char szextaddr[15+1]; 950 + uint extaddrlen; 951 + int is_stun; 952 + 953 + get_skb_tcpdata(skb, &ptcp, &tcplen); 954 + ptran = ptcp+tranoff; 955 + 956 + if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || 957 + tranlen < 10 || !iseol(ptran[tranlen-1]) || 958 + nf_strncasecmp(ptran, "Transport:", 10) != 0) 959 + { 960 + pr_info("sanity check failed\n"); 961 + return 0; 962 + } 963 + off += 10; 964 + SKIP_WSPACE(ptcp+tranoff, tranlen, off); 965 + 966 + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; 967 + t = &exp->tuple; 968 + t->dst.u3.ip = newip; 969 + 970 + extaddrlen = extip ? sprintf(szextaddr, "%pI4", &extip) 971 + : sprintf(szextaddr, "%pI4", &newip); 972 + pr_debug("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto")); 973 + 974 + rbuf1len = rbufalen = 0; 975 + switch (prtspexp->pbtype) 976 + { 977 + case pb_single: 978 + for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ 979 + { 980 + t->dst.u.udp.port = htons(loport); 981 + if (nf_ct_expect_related(exp) == 0) 982 + { 983 + pr_debug("using port %hu\n", loport); 984 + break; 985 + } 986 + } 987 + if (loport != 0) 988 + { 989 + rbuf1len = sprintf(rbuf1, "%hu", loport); 990 + rbufalen = sprintf(rbufa, "%hu", loport); 991 + } 992 + break; 993 + case pb_range: 994 + for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */ 995 + { 996 + t->dst.u.udp.port = htons(loport); 997 + if (nf_ct_expect_related(exp) == 0) 998 + { 999 + hiport = loport + 1; //~exp->mask.dst.u.udp.port; 1000 + pr_debug("using ports %hu-%hu\n", loport, hiport); 1001 + break; 1002 + } 1003 + } 1004 + if (loport != 0) 1005 + { 1006 + rbuf1len = sprintf(rbuf1, "%hu", loport); 1007 + rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1); 1008 + } 1009 + break; 1010 + case pb_discon: 1011 + for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ 1012 + { 1013 + t->dst.u.udp.port = htons(loport); 1014 + if (nf_ct_expect_related(exp) == 0) 1015 + { 1016 + pr_debug("using port %hu (1 of 2)\n", loport); 1017 + break; 1018 + } 1019 + } 1020 + for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */ 1021 + { 1022 + t->dst.u.udp.port = htons(hiport); 1023 + if (nf_ct_expect_related(exp) == 0) 1024 + { 1025 + pr_debug("using port %hu (2 of 2)\n", hiport); 1026 + break; 1027 + } 1028 + } 1029 + if (loport != 0 && hiport != 0) 1030 + { 1031 + rbuf1len = sprintf(rbuf1, "%hu", loport); 1032 + if (hiport == loport+1) 1033 + { 1034 + rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport); 1035 + } 1036 + else 1037 + { 1038 + rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport); 1039 + } 1040 + } 1041 + break; 1042 + } 1043 + 1044 + if (rbuf1len == 0) 1045 + { 1046 + return 0; /* cannot get replacement port(s) */ 1047 + } 1048 + 1049 + /* Transport: tran;field;field=val,tran;field;field=val,... */ 1050 + while (off < tranlen) 1051 + { 1052 + uint saveoff; 1053 + const char* pparamend; 1054 + uint nextparamoff; 1055 + 1056 + pparamend = memchr(ptran+off, ',', tranlen-off); 1057 + pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; 1058 + nextparamoff = pparamend-ptcp; 1059 + 1060 + /* 1061 + * We pass over each param twice. On the first pass, we look for a 1062 + * destination= field. It is handled by the security policy. If it 1063 + * is present, allowed, and equal to our external address, we assume 1064 + * that STUN is being used and we leave the client_port= field alone. 1065 + */ 1066 + is_stun = 0; 1067 + saveoff = off; 1068 + while (off < nextparamoff) 1069 + { 1070 + const char* pfieldend; 1071 + uint nextfieldoff; 1072 + 1073 + pfieldend = memchr(ptran+off, ';', nextparamoff-off); 1074 + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; 1075 + 1076 + if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) 1077 + { 1078 + if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0) 1079 + { 1080 + is_stun = 1; 1081 + } 1082 + if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) 1083 + { 1084 + diff = nextfieldoff-off; 1085 + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 1086 + off, diff, NULL, 0)) 1087 + { 1088 + /* mangle failed, all we can do is bail */ 1089 + nf_ct_unexpect_related(exp); 1090 + return 0; 1091 + } 1092 + get_skb_tcpdata(skb, &ptcp, &tcplen); 1093 + ptran = ptcp+tranoff; 1094 + tranlen -= diff; 1095 + nextparamoff -= diff; 1096 + nextfieldoff -= diff; 1097 + } 1098 + } 1099 + 1100 + off = nextfieldoff; 1101 + } 1102 + if (is_stun) 1103 + { 1104 + continue; 1105 + } 1106 + off = saveoff; 1107 + while (off < nextparamoff) 1108 + { 1109 + const char* pfieldend; 1110 + uint nextfieldoff; 1111 + 1112 + pfieldend = memchr(ptran+off, ';', nextparamoff-off); 1113 + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; 1114 + 1115 + if (strncmp(ptran+off, "client_port=", 12) == 0) 1116 + { 1117 + u_int16_t port; 1118 + uint numlen; 1119 + uint origoff; 1120 + uint origlen; 1121 + char* rbuf = rbuf1; 1122 + uint rbuflen = rbuf1len; 1123 + 1124 + off += 12; 1125 + origoff = (ptran-ptcp)+off; 1126 + origlen = 0; 1127 + numlen = nf_strtou16(ptran+off, &port); 1128 + off += numlen; 1129 + origlen += numlen; 1130 + if (port != prtspexp->loport) 1131 + { 1132 + pr_debug("multiple ports found, port %hu ignored\n", port); 1133 + } 1134 + else 1135 + { 1136 + if (ptran[off] == '-' || ptran[off] == '/') 1137 + { 1138 + off++; 1139 + origlen++; 1140 + numlen = nf_strtou16(ptran+off, &port); 1141 + off += numlen; 1142 + origlen += numlen; 1143 + rbuf = rbufa; 1144 + rbuflen = rbufalen; 1145 + } 1146 + 1147 + /* 1148 + * note we cannot just memcpy() if the sizes are the same. 1149 + * the mangle function does skb resizing, checks for a 1150 + * cloned skb, and updates the checksums. 1151 + * 1152 + * parameter 4 below is offset from start of tcp data. 1153 + */ 1154 + diff = origlen-rbuflen; 1155 + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 1156 + origoff, origlen, rbuf, rbuflen)) 1157 + { 1158 + /* mangle failed, all we can do is bail */ 1159 + nf_ct_unexpect_related(exp); 1160 + return 0; 1161 + } 1162 + get_skb_tcpdata(skb, &ptcp, &tcplen); 1163 + ptran = ptcp+tranoff; 1164 + tranlen -= diff; 1165 + nextparamoff -= diff; 1166 + nextfieldoff -= diff; 1167 + } 1168 + } 1169 + 1170 + off = nextfieldoff; 1171 + } 1172 + 1173 + off = nextparamoff; 1174 + } 1175 + 1176 + return 1; 1023 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1024 + unsigned int protoff, 1025 +#endif 1026 + struct nf_conntrack_expect* rtp_exp, 1027 + struct nf_conntrack_expect* rtcp_exp, 1028 + struct ip_ct_rtsp_expect* prtspexp, 1029 + struct sk_buff* skb, uint tranoff, uint tranlen) 1030 +{ 1031 + char* ptcp; 1032 + uint tcplen; 1033 + char* ptran; 1034 + char rbuf1[16]; /* Replacement buffer (one port) */ 1035 + uint rbuf1len; /* Replacement len (one port) */ 1036 + char rbufa[16]; /* Replacement buffer (all ports) */ 1037 + uint rbufalen; /* Replacement len (all ports) */ 1038 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1039 + union nf_inet_addr newip; 1040 +#else 1041 + u_int32_t newip; 1042 +#endif 1043 + u_int16_t loport, hiport; 1044 + uint off = 0; 1045 + uint diff; /* Number of bytes we removed */ 1046 + 1047 + struct nf_conn *ct = rtp_exp->master; 1048 + /* struct nf_conn *ct = nf_ct_get(skb, &ctinfo); */ 1049 + struct nf_conntrack_tuple *rtp_t; 1050 + 1051 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1052 + char szextaddr[INET6_ADDRSTRLEN]; 1053 +#else 1054 + char szextaddr[INET_ADDRSTRLEN]; 1055 +#endif 1056 + uint extaddrlen; 1057 + int is_stun; 1058 + 1059 + get_skb_tcpdata(skb, &ptcp, &tcplen); 1060 + ptran = ptcp+tranoff; 1061 + 1062 + if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || 1063 + tranlen < 10 || !iseol(ptran[tranlen-1]) || 1064 + nf_strncasecmp(ptran, "Transport:", 10) != 0) { 1065 + pr_info("sanity check failed\n"); 1066 + return 0; 1067 + } 1068 + off += 10; 1069 + SKIP_WSPACE(ptcp+tranoff, tranlen, off); 1070 + 1071 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1072 + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3; 1073 + rtp_t = &rtp_exp->tuple; 1074 + rtp_t->dst.u3 = newip; 1075 + if (rtcp_exp) { 1076 + rtcp_exp->tuple.dst.u3 = newip; 1077 + } 1078 + extaddrlen = rtsp_sprintf_addr(ct, szextaddr, &newip, true); // FIXME handle extip 1079 + pr_debug("stunaddr=%s (auto)\n", szextaddr); 1080 +#else 1081 + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; 1082 + rtp_t = &rtp_exp->tuple; 1083 + rtp_t->dst.u3.ip = newip; 1084 + if (rtcp_exp) { 1085 + rtcp_exp->tuple.dst.u3.ip = newip; 1086 + } 1087 + extaddrlen = extip ? sprintf(szextaddr, "%pI4", &extip) 1088 + : sprintf(szextaddr, "%pI4", &newip); 1089 + pr_debug("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto")); 1090 +#endif 1091 + hiport = 0; 1092 + rbuf1len = rbufalen = 0; 1093 + switch (prtspexp->pbtype) { 1094 + case pb_single: 1095 + for (loport = prtspexp->loport; loport != 0; loport++) { /* XXX: improper wrap? */ 1096 + rtp_t->dst.u.udp.port = htons(loport); 1097 + if (nf_ct_expect_related(rtp_exp) == 0) { 1098 + pr_debug("using port %hu\n", loport); 1099 + break; 1100 + } 1101 + } 1102 + if (loport != 0) { 1103 + rbuf1len = sprintf(rbuf1, "%hu", loport); 1104 + rbufalen = sprintf(rbufa, "%hu", loport); 1105 + } 1106 + break; 1107 + case pb_range: 1108 + for (loport = prtspexp->loport; loport != 0; loport += 2) { /* XXX: improper wrap? */ 1109 + rtp_t->dst.u.udp.port = htons(loport); 1110 + if (nf_ct_expect_related(rtp_exp) != 0) { 1111 + continue; 1112 + } 1113 + hiport = loport + 1; 1114 + rtcp_exp->tuple.dst.u.udp.port = htons(hiport); 1115 + if (nf_ct_expect_related(rtcp_exp) != 0) { 1116 + nf_ct_unexpect_related(rtp_exp); 1117 + continue; 1118 + } 1119 + 1120 + /* FIXME: invalid print in case of ipv6 */ 1121 + pr_debug("nat expect_related %pI4:%u-%u-%pI4:%u-%u\n", 1122 + &rtp_exp->tuple.src.u3.ip, 1123 + ntohs(rtp_exp->tuple.src.u.udp.port), 1124 + ntohs(rtcp_exp->tuple.src.u.udp.port), 1125 + &rtp_exp->tuple.dst.u3.ip, 1126 + ntohs(rtp_exp->tuple.dst.u.udp.port), 1127 + ntohs(rtcp_exp->tuple.dst.u.udp.port)); 1128 + break; 1129 + } 1130 + if (loport != 0) { 1131 + rbuf1len = sprintf(rbuf1, "%hu", loport); 1132 + rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport); 1133 + } 1134 + break; 1135 + case pb_discon: 1136 + for (loport = prtspexp->loport; loport != 0; loport++) { /* XXX: improper wrap? */ 1137 + rtp_t->dst.u.udp.port = htons(loport); 1138 + if (nf_ct_expect_related(rtp_exp) == 0) { 1139 + pr_debug("using port %hu (1 of 2)\n", loport); 1140 + break; 1141 + } 1142 + } 1143 + for (hiport = prtspexp->hiport; hiport != 0; hiport++) { /* XXX: improper wrap? */ 1144 + rtp_t->dst.u.udp.port = htons(hiport); 1145 + if (nf_ct_expect_related(rtp_exp) == 0) { 1146 + pr_debug("using port %hu (2 of 2)\n", hiport); 1147 + break; 1148 + } 1149 + } 1150 + if (loport != 0 && hiport != 0) { 1151 + rbuf1len = sprintf(rbuf1, "%hu", loport); 1152 + rbufalen = sprintf(rbufa, hiport == loport+1 ? 1153 + "%hu-%hu":"%hu/%hu", loport, hiport); 1154 + } 1155 + break; 1156 + } 1157 + 1158 + if (rbuf1len == 0) 1159 + return 0; /* cannot get replacement port(s) */ 1160 + 1161 + /* Transport: tran;field;field=val,tran;field;field=val,... 1162 + `off` is set to the start of Transport value from start of line 1163 + */ 1164 + while (off < tranlen) { 1165 + uint saveoff; 1166 + const char* pparamend; 1167 + uint nextparamoff; 1168 + 1169 + pparamend = memchr(ptran+off, ',', tranlen-off); 1170 + pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; 1171 + nextparamoff = pparamend-ptran; 1172 + 1173 + /* 1174 + * We pass over each param twice. On the first pass, we look for a 1175 + * destination= field. It is handled by the security policy. If it 1176 + * is present, allowed, and equal to our external address, we assume 1177 + * that STUN is being used and we leave the client_port= field alone. 1178 + */ 1179 + is_stun = 0; 1180 + saveoff = off; 1181 + while (off < nextparamoff) { 1182 + const char* pfieldend; 1183 + uint nextfieldoff; 1184 + 1185 + pfieldend = memchr(ptran+off, ';', nextparamoff-off); 1186 + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; 1187 + 1188 + if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) { 1189 + if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0) 1190 + is_stun = 1; 1191 + 1192 + if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) { 1193 + uint dstoff = (ptran-ptcp)+off; 1194 + uint dstlen = nextfieldoff-off; 1195 + char* pdstrep = NULL; 1196 + uint dstreplen = 0; 1197 + diff = dstlen; 1198 + if (dstact == DSTACT_AUTO && !is_stun) { 1199 + pr_debug("RTSP: replace dst addr\n"); 1200 + dstoff += 12; 1201 + dstlen -= 13; 1202 + pdstrep = szextaddr; 1203 + dstreplen = extaddrlen; 1204 + diff = nextfieldoff-off-13-extaddrlen; 1205 + } 1206 + 1207 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1208 + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff, 1209 + dstoff, dstlen, pdstrep, dstreplen)) { 1210 +#else 1211 + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 1212 + dstoff, dstlen, pdstrep, dstreplen)) { 1213 +#endif 1214 + /* mangle failed, all we can do is bail */ 1215 + nf_ct_unexpect_related(rtp_exp); 1216 + if (rtcp_exp) 1217 + nf_ct_unexpect_related(rtcp_exp); 1218 + return 0; 1219 + } 1220 + get_skb_tcpdata(skb, &ptcp, &tcplen); 1221 + ptran = ptcp+tranoff; 1222 + tranlen -= diff; 1223 + nextparamoff -= diff; 1224 + nextfieldoff -= diff; 1225 + } 1226 + } 1227 + 1228 + off = nextfieldoff; 1229 + } 1230 + 1231 + if (is_stun) 1232 + continue; 1233 + 1234 + off = saveoff; 1235 + while (off < nextparamoff) { 1236 + const char* pfieldend; 1237 + uint nextfieldoff; 1238 + 1239 + pfieldend = memchr(ptran+off, ';', nextparamoff-off); 1240 + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; 1241 + 1242 + if (strncmp(ptran+off, "client_port=", 12) == 0) { 1243 + u_int16_t port; 1244 + uint numlen; 1245 + uint origoff; 1246 + uint origlen; 1247 + char* rbuf = rbuf1; 1248 + uint rbuflen = rbuf1len; 1249 + 1250 + off += 12; 1251 + origoff = (ptran-ptcp)+off; 1252 + origlen = 0; 1253 + numlen = nf_strtou16(ptran+off, &port); 1254 + off += numlen; 1255 + origlen += numlen; 1256 + if (port != prtspexp->loport) { 1257 + pr_debug("multiple ports found, port %hu ignored\n", port); 1258 + } else { 1259 + if (ptran[off] == '-' || ptran[off] == '/') { 1260 + off++; 1261 + origlen++; 1262 + numlen = nf_strtou16(ptran+off, &port); 1263 + off += numlen; 1264 + origlen += numlen; 1265 + rbuf = rbufa; 1266 + rbuflen = rbufalen; 1267 + } 1268 + 1269 + /* 1270 + * note we cannot just memcpy() if the sizes are the same. 1271 + * the mangle function does skb resizing, checks for a 1272 + * cloned skb, and updates the checksums. 1273 + * 1274 + * parameter 4 below is offset from start of tcp data. 1275 + */ 1276 + diff = origlen-rbuflen; 1277 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1278 + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff, 1279 + origoff, origlen, rbuf, rbuflen)) { 1280 +#else 1281 + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 1282 + origoff, origlen, rbuf, rbuflen)) { 1283 +#endif 1284 + /* mangle failed, all we can do is bail */ 1285 + nf_ct_unexpect_related(rtp_exp); 1286 + if (rtcp_exp) 1287 + nf_ct_unexpect_related(rtcp_exp); 1288 + return 0; 1289 + } 1290 + get_skb_tcpdata(skb, &ptcp, &tcplen); 1291 + ptran = ptcp+tranoff; 1292 + tranlen -= diff; 1293 + nextparamoff -= diff; 1294 + nextfieldoff -= diff; 1295 + } 1296 + } 1297 + 1298 + off = nextfieldoff; 1299 + } 1300 + 1301 + off = nextparamoff; 1302 + } 1303 + 1304 + return 1; 1177 1305 +} 1178 1306 + 1179 1307 +static uint 1180 1308 +help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo, 1181 + unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp, 1182 + struct nf_conntrack_expect* exp) 1183 +{ 1184 + char* ptcp; 1185 + uint tcplen; 1186 + uint hdrsoff; 1187 + uint hdrslen; 1188 + uint lineoff; 1189 + uint linelen; 1190 + uint off; 1191 + 1192 + //struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; 1193 + //struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4); 1194 + 1195 + get_skb_tcpdata(skb, &ptcp, &tcplen); 1196 + hdrsoff = matchoff;//exp->seq - ntohl(tcph->seq); 1197 + hdrslen = matchlen; 1198 + off = hdrsoff; 1199 + pr_debug("NAT rtsp help_out\n"); 1200 + 1201 + while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) 1202 + { 1203 + if (linelen == 0) 1204 + { 1205 + break; 1206 + } 1207 + if (off > hdrsoff+hdrslen) 1208 + { 1209 + pr_info("!! overrun !!"); 1210 + break; 1211 + } 1212 + pr_debug("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); 1213 + 1214 + if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) 1215 + { 1216 + uint oldtcplen = tcplen; 1217 + pr_debug("hdr: Transport\n"); 1218 + if (!rtsp_mangle_tran(ctinfo, exp, prtspexp, skb, lineoff, linelen)) 1219 + { 1220 + pr_debug("hdr: Transport mangle failed"); 1221 + break; 1222 + } 1223 + get_skb_tcpdata(skb, &ptcp, &tcplen); 1224 + hdrslen -= (oldtcplen-tcplen); 1225 + off -= (oldtcplen-tcplen); 1226 + lineoff -= (oldtcplen-tcplen); 1227 + linelen -= (oldtcplen-tcplen); 1228 + pr_debug("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); 1229 + } 1230 + } 1231 + 1232 + return NF_ACCEPT; 1309 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1310 + unsigned int protoff, 1311 +#endif 1312 + unsigned int matchoff, unsigned int matchlen, 1313 + struct ip_ct_rtsp_expect* prtspexp, 1314 + struct nf_conntrack_expect* rtp_exp, 1315 + struct nf_conntrack_expect* rtcp_exp) 1316 +{ 1317 + char* ptcp; 1318 + uint tcplen; 1319 + uint hdrsoff; 1320 + uint hdrslen; 1321 + uint lineoff; 1322 + uint linelen; 1323 + uint off; 1324 + int dir = CTINFO2DIR(ctinfo); 1325 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1326 + union nf_inet_addr saddr = rtp_exp->master->tuplehash[dir].tuple.src.u3; 1327 +#else 1328 + __be32 saddr = rtp_exp->master->tuplehash[dir].tuple.src.u3.ip; 1329 +#endif 1330 + 1331 + //struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; 1332 + //struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4); 1333 + 1334 + get_skb_tcpdata(skb, &ptcp, &tcplen); 1335 + hdrsoff = matchoff;//exp->seq - ntohl(tcph->seq); 1336 + hdrslen = matchlen; 1337 + off = hdrsoff; 1338 + pr_debug("NAT rtsp help_out\n"); 1339 + 1340 + while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) { 1341 + if (linelen == 0) 1342 + break; 1343 + 1344 + if (off > hdrsoff+hdrslen) { 1345 + pr_info("!! overrun !!"); 1346 + break; 1347 + } 1348 + pr_debug("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); 1349 + 1350 + if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) { 1351 + uint oldtcplen = tcplen; 1352 + pr_debug("hdr: Transport\n"); 1353 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1354 + if (!rtsp_mangle_tran(ctinfo, protoff, rtp_exp, rtcp_exp, 1355 + prtspexp, skb, lineoff, linelen)) { 1356 +#else 1357 + if (!rtsp_mangle_tran(ctinfo, rtp_exp, rtcp_exp, prtspexp, 1358 + skb, lineoff, linelen)) { 1359 +#endif 1360 + pr_debug("hdr: Transport mangle failed"); 1361 + break; 1362 + } 1363 + rtp_exp->expectfn = nf_nat_rtsp_expected; 1364 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1365 + rtp_exp->saved_addr = saddr; 1366 +#else 1367 + rtp_exp->saved_ip = saddr; 1368 +#endif 1369 + rtp_exp->saved_proto.udp.port = htons(prtspexp->loport); 1370 + rtp_exp->dir = !dir; 1371 + if (rtcp_exp) { 1372 + rtcp_exp->expectfn = nf_nat_rtsp_expected; 1373 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1374 + rtcp_exp->saved_addr = saddr; 1375 +#else 1376 + rtcp_exp->saved_ip = saddr; 1377 +#endif 1378 + rtcp_exp->saved_proto.udp.port = htons(prtspexp->hiport); 1379 + rtcp_exp->dir = !dir; 1380 + } 1381 + get_skb_tcpdata(skb, &ptcp, &tcplen); 1382 + hdrslen -= (oldtcplen-tcplen); 1383 + off -= (oldtcplen-tcplen); 1384 + lineoff -= (oldtcplen-tcplen); 1385 + linelen -= (oldtcplen-tcplen); 1386 + pr_debug("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); 1387 + } 1388 + } 1389 + 1390 + return NF_ACCEPT; 1233 1391 +} 1234 1392 + 1235 1393 +static unsigned int 1236 +help(struct sk_buff *skb, enum ip_conntrack_info ctinfo, 1237 + unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp, 1238 + struct nf_conntrack_expect* exp) 1239 +{ 1240 + int dir = CTINFO2DIR(ctinfo); 1241 + int rc = NF_ACCEPT; 1242 + 1243 + switch (dir) 1244 + { 1245 + case IP_CT_DIR_ORIGINAL: 1246 + rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp, exp); 1247 + break; 1248 + case IP_CT_DIR_REPLY: 1249 + pr_debug("unmangle ! %u\n", ctinfo); 1250 + /* XXX: unmangle */ 1251 + rc = NF_ACCEPT; 1252 + break; 1253 + } 1254 + //UNLOCK_BH(&ip_rtsp_lock); 1255 + 1256 + return rc; 1257 +} 1258 + 1259 +static void expected(struct nf_conn* ct, struct nf_conntrack_expect *exp) 1260 +{ 1261 + struct nf_nat_ipv4_multi_range_compat mr; 1262 + u_int32_t newdstip, newsrcip, newip; 1263 + 1264 + struct nf_conn *master = ct->master; 1265 + 1266 + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; 1267 + newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; 1268 + //FIXME (how to port that ?) 1269 + //code from 2.4 : newip = (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC) ? newsrcip : newdstip; 1270 + newip = newdstip; 1271 + 1272 + pr_debug("newsrcip=%pI4, newdstip=%pI4, newip=%pI4\n", 1273 + &newsrcip, &newdstip, &newip); 1274 + 1275 + mr.rangesize = 1; 1276 + // We don't want to manip the per-protocol, just the IPs. 1277 + mr.range[0].flags = NF_NAT_RANGE_MAP_IPS; 1278 + mr.range[0].min_ip = mr.range[0].max_ip = newip; 1279 + 1280 + nf_nat_setup_info(ct, &mr.range[0], NF_NAT_MANIP_DST); 1394 +nf_nat_rtsp(struct sk_buff *skb, enum ip_conntrack_info ctinfo, 1395 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1396 + unsigned int protoff, 1397 +#endif 1398 + unsigned int matchoff, unsigned int matchlen, 1399 + struct ip_ct_rtsp_expect* prtspexp, 1400 + struct nf_conntrack_expect* rtp_exp, 1401 + struct nf_conntrack_expect* rtcp_exp) 1402 +{ 1403 + int dir = CTINFO2DIR(ctinfo); 1404 + int rc = NF_ACCEPT; 1405 + 1406 + switch (dir) { 1407 + case IP_CT_DIR_ORIGINAL: 1408 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1409 + rc = help_out(skb, ctinfo, protoff, matchoff, matchlen, prtspexp, 1410 + rtp_exp, rtcp_exp); 1411 +#else 1412 + rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp, 1413 + rtp_exp, rtcp_exp); 1414 +#endif 1415 + break; 1416 + case IP_CT_DIR_REPLY: 1417 + pr_debug("unmangle ! %u\n", ctinfo); 1418 + /* XXX: unmangle */ 1419 + rc = NF_ACCEPT; 1420 + break; 1421 + } 1422 + //UNLOCK_BH(&ip_rtsp_lock); 1423 + 1424 + return rc; 1425 +} 1426 + 1427 +static void nf_nat_rtsp_expected(struct nf_conn* ct, struct nf_conntrack_expect *exp) 1428 +{ 1429 +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1430 + struct nf_nat_range range; 1431 +#else 1432 + struct nf_nat_ipv4_range range; 1433 +#endif 1434 + 1435 + /* This must be a fresh one. */ 1436 + BUG_ON(ct->status & IPS_NAT_DONE_MASK); 1437 + 1438 + /* For DST manip, map port here to where it's expected. */ 1439 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1440 + range.min_proto = range.max_proto = exp->saved_proto; 1441 + range.min_addr = range.max_addr = exp->saved_addr; 1442 +#else 1443 + range.min = range.max = exp->saved_proto; 1444 + range.min_ip = range.max_ip = exp->saved_ip; 1445 +#endif 1446 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) 1447 + range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); 1448 + nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); 1449 +#else 1450 + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); 1451 + nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); 1452 +#endif 1453 + 1454 + /* Change src to where master sends to, but only if the connection 1455 + * actually came from the same source. */ 1456 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) 1457 + if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3, 1458 + &ct->master->tuplehash[exp->dir].tuple.src.u3)) { 1459 + range.min_addr = range.max_addr 1460 + = ct->master->tuplehash[!exp->dir].tuple.dst.u3; 1461 +#else 1462 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 1463 + ct->master->tuplehash[exp->dir].tuple.src.u3.ip) { 1464 + range.min_ip = range.max_ip 1465 + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; 1466 +#endif 1467 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) 1468 + range.flags = NF_NAT_RANGE_MAP_IPS; 1469 + nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); 1470 +#else 1471 + range.flags = IP_NAT_RANGE_MAP_IPS; 1472 + nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); 1473 +#endif 1474 + } 1281 1475 +} 1282 1476 + … … 1284 1478 +static void __exit fini(void) 1285 1479 +{ 1286 + nf_nat_rtsp_hook = NULL; 1287 + nf_nat_rtsp_hook_expectfn = NULL; 1480 + rcu_assign_pointer(nf_nat_rtsp_hook, NULL); 1288 1481 + synchronize_net(); 1289 1482 +} … … 1294 1487 + 1295 1488 + BUG_ON(nf_nat_rtsp_hook); 1296 + nf_nat_rtsp_hook = help; 1297 + nf_nat_rtsp_hook_expectfn = &expected; 1489 + rcu_assign_pointer(nf_nat_rtsp_hook, nf_nat_rtsp); 1298 1490 + 1299 1491 + if (stunaddr != NULL) … … 1301 1493 + 1302 1494 + if (destaction != NULL) { 1303 + 1495 + if (strcmp(destaction, "auto") == 0) 1304 1496 + dstact = DSTACT_AUTO; 1305 1497 +
Note: See TracChangeset
for help on using the changeset viewer.