From: Florian Fainelli Date: Wed, 12 Apr 2006 16:15:41 +0000 (+0000) Subject: Add SIP connection tracking helpers. Update 2.6 kernel configuration to build SIP... X-Git-Tag: reboot~30842 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=19e37cab1585f14d8e2b5a593074432ea99c4bf9;p=oweals%2Fopenwrt.git Add SIP connection tracking helpers. Update 2.6 kernel configuration to build SIP connection tracking helper Add informations in menuconfig SVN-Revision: 3627 --- diff --git a/openwrt/target/linux/Config.in b/openwrt/target/linux/Config.in index 87cd436ddb..65d9a3e0b0 100644 --- a/openwrt/target/linux/Config.in +++ b/openwrt/target/linux/Config.in @@ -230,6 +230,8 @@ config BR2_PACKAGE_KMOD_IPT_NAT_EXTRA * ip_nat_proto_gre * ip_conntrack_pptp * ip_nat_pptp + * ip_conntrack_sip + * ip_nat_sip * ip_nat_snmp_basic * ip_conntrack_tftp diff --git a/openwrt/target/linux/aruba-2.6/config b/openwrt/target/linux/aruba-2.6/config index d7e4e53b22..386272371a 100644 --- a/openwrt/target/linux/aruba-2.6/config +++ b/openwrt/target/linux/aruba-2.6/config @@ -312,7 +312,8 @@ CONFIG_IP_NF_IRC=m # CONFIG_IP_NF_NETBIOS_NS is not set CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_AMANDA=m -# CONFIG_IP_NF_PPTP is not set +CONFIG_IP_NF_PPTP=m +CONFIG_IP_NF_SIP=m CONFIG_IP_NF_QUEUE=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_IPRANGE=m @@ -347,6 +348,8 @@ CONFIG_IP_NF_NAT_IRC=m CONFIG_IP_NF_NAT_FTP=y CONFIG_IP_NF_NAT_TFTP=m CONFIG_IP_NF_NAT_AMANDA=m +CONFIG_IP_NF_NAT_PPTP=m +CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_MANGLE=y CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_ECN=m diff --git a/openwrt/target/linux/au1000-2.6/config b/openwrt/target/linux/au1000-2.6/config index be9db372a5..37dac8ed26 100644 --- a/openwrt/target/linux/au1000-2.6/config +++ b/openwrt/target/linux/au1000-2.6/config @@ -339,6 +339,7 @@ CONFIG_IP_NF_IRC=y CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_AMANDA=m CONFIG_IP_NF_PPTP=m +CONFIG_IP_NF_SIP=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_IPRANGE=m @@ -375,6 +376,7 @@ CONFIG_IP_NF_NAT_FTP=y CONFIG_IP_NF_NAT_TFTP=m CONFIG_IP_NF_NAT_AMANDA=m CONFIG_IP_NF_NAT_PPTP=m +CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_MANGLE=y CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_ECN=m diff --git a/openwrt/target/linux/brcm-2.6/config b/openwrt/target/linux/brcm-2.6/config index 725ffbb03b..a916628c42 100644 --- a/openwrt/target/linux/brcm-2.6/config +++ b/openwrt/target/linux/brcm-2.6/config @@ -354,6 +354,7 @@ CONFIG_IP_NF_IRC=y CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_AMANDA=m CONFIG_IP_NF_PPTP=m +CONFIG_IP_NF_SIP=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_IPRANGE=m @@ -390,6 +391,7 @@ CONFIG_IP_NF_NAT_FTP=y CONFIG_IP_NF_NAT_TFTP=m CONFIG_IP_NF_NAT_AMANDA=m CONFIG_IP_NF_NAT_PPTP=m +CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_MANGLE=y CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_ECN=m diff --git a/openwrt/target/linux/generic-2.6/patches/107-netfilter_nat_sip.patch b/openwrt/target/linux/generic-2.6/patches/107-netfilter_nat_sip.patch new file mode 100644 index 0000000000..6640118f20 --- /dev/null +++ b/openwrt/target/linux/generic-2.6/patches/107-netfilter_nat_sip.patch @@ -0,0 +1,830 @@ +diff -urN linux-2.6.16.4/net/ipv4/netfilter/ip_conntrack_sip.c linux-2.6.16.4.new/net/ipv4/netfilter/ip_conntrack_sip.c +--- linux-2.6.16.4/net/ipv4/netfilter/ip_conntrack_sip.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16.4.new/net/ipv4/netfilter/ip_conntrack_sip.c 2006-04-12 17:31:44.000000000 +0200 +@@ -0,0 +1,414 @@ ++/* SIP extension for IP connection tracking. ++ * ++ * (C) 2005 by Christian Hentschel ++ * based on RR's ip_conntrack_ftp.c and other modules. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hentschel "); ++MODULE_DESCRIPTION("SIP connection tracking helper"); ++ ++static DEFINE_SPINLOCK(sipbf_lock); ++ ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_c; ++module_param_array(ports, int, &ports_c, 0400); ++MODULE_PARM_DESC(ports, " port numbers of sip servers"); ++ ++static unsigned int sip_timeout = SIP_TIMEOUT; ++ ++module_param(sip_timeout, int, 0600); ++MODULE_PARM_DESC(sip_timeout, "timeout for the master sip session"); ++ ++unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack *ct, ++ const char **dptr); ++EXPORT_SYMBOL_GPL(ip_nat_sip_hook); ++ ++unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *exp, ++ const char *dptr); ++EXPORT_SYMBOL_GPL(ip_nat_sdp_hook); ++ ++int ct_sip_get_info(const char *dptr, size_t dlen, ++ unsigned int *matchoff, ++ unsigned int *matchlen, ++ struct sip_header_nfo *hnfo); ++EXPORT_SYMBOL(ct_sip_get_info); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++static int digits_len(const char *dptr, const char *limit, int *shift); ++static int epaddr_len(const char *dptr, const char *limit, int *shift); ++static int skp_digits_len(const char *dptr, const char *limit, int *shift); ++static int skp_epaddr_len(const char *dptr, const char *limit, int *shift); ++ ++struct sip_header_nfo ct_sip_hdrs[] = { ++ { /* Via header */ ++ "Via:", sizeof("Via:") - 1, ++ "\r\nv:", sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */ ++ "UDP ", sizeof("UDP ") - 1, ++ epaddr_len ++ }, ++ { /* Contact header */ ++ "Contact:", sizeof("Contact:") - 1, ++ "\r\nm:", sizeof("\r\nm:") - 1, ++ "sip:", sizeof("sip:") - 1, ++ skp_epaddr_len ++ }, ++ { /* Content length header */ ++ "Content-Length:", sizeof("Content-Length:") - 1, ++ "\r\nl:", sizeof("\r\nl:") - 1, ++ ":", sizeof(":") - 1, ++ skp_digits_len ++ }, ++ { /* SDP media info */ ++ "\nm=", sizeof("\nm=") - 1, ++ "\rm=", sizeof("\rm=") - 1, ++ "audio ", sizeof("audio ") - 1, ++ digits_len ++ }, ++ { /* SDP owner address*/ ++ "\no=", sizeof("\no=") - 1, ++ "\ro=", sizeof("\ro=") - 1, ++ "IN IP4 ", sizeof("IN IP4 ") - 1, ++ epaddr_len ++ }, ++ { /* SDP connection info */ ++ "\nc=", sizeof("\nc=") - 1, ++ "\rc=", sizeof("\rc=") - 1, ++ "IN IP4 ", sizeof("IN IP4 ") - 1, ++ epaddr_len ++ }, ++ { /* Requests headers */ ++ "sip:", sizeof("sip:") - 1, ++ "sip:", sizeof("sip:") - 1, /* yes, i know.. ;) */ ++ "@", sizeof("@") - 1, ++ epaddr_len ++ }, ++ { /* SDP version header */ ++ "\nv=", sizeof("\nv=") - 1, ++ "\rv=", sizeof("\rv=") - 1, ++ "=", sizeof("=") - 1, ++ digits_len ++ } ++}; ++EXPORT_SYMBOL(ct_sip_hdrs); ++ ++ ++static int digits_len(const char *dptr, const char *limit, int *shift) ++{ ++ int len = 0; ++ while (dptr <= limit && isdigit(*dptr)) { ++ dptr++; ++ len++; ++ } ++ return len; ++} ++ ++/* get digits lenght, skiping blank spaces. */ ++static int skp_digits_len(const char *dptr, const char *limit, int *shift) ++{ ++ for (; dptr <= limit && *dptr == ' '; dptr++) ++ (*shift)++; ++ ++ return digits_len(dptr, limit, shift); ++} ++ ++/* Simple ipaddr parser.. */ ++static int parse_ipaddr(const char *cp, const char **endp, ++ uint32_t *ipaddr, const char *limit) ++{ ++ unsigned long int val; ++ int i, digit = 0; ++ ++ for (i = 0, *ipaddr = 0; cp <= limit && i < 4; i++) { ++ digit = 0; ++ if (!isdigit(*cp)) ++ break; ++ ++ val = simple_strtoul(cp, (char **)&cp, 10); ++ if (val > 0xFF) ++ return -1; ++ ++ ((uint8_t *)ipaddr)[i] = val; ++ digit = 1; ++ ++ if (*cp != '.') ++ break; ++ cp++; ++ } ++ if (!digit) ++ return -1; ++ ++ if (endp) ++ *endp = cp; ++ ++ return 0; ++} ++ ++/* skip ip address. returns it lenght. */ ++static int epaddr_len(const char *dptr, const char *limit, int *shift) ++{ ++ const char *aux = dptr; ++ uint32_t ip; ++ ++ if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) { ++ DEBUGP("ip: %s parse failed.!\n", dptr); ++ return 0; ++ } ++ ++ /* Port number */ ++ if (*dptr == ':') { ++ dptr++; ++ dptr += digits_len(dptr, limit, shift); ++ } ++ return dptr - aux; ++} ++ ++/* get address lenght, skiping user info. */ ++static int skp_epaddr_len(const char *dptr, const char *limit, int *shift) ++{ ++ for (; dptr <= limit && *dptr != '@'; dptr++) ++ (*shift)++; ++ ++ if (*dptr == '@') { ++ dptr++; ++ (*shift)++; ++ return epaddr_len(dptr, limit, shift); ++ } ++ return 0; ++} ++ ++/* Returns 0 if not found, -1 error parsing. */ ++int ct_sip_get_info(const char *dptr, size_t dlen, ++ unsigned int *matchoff, ++ unsigned int *matchlen, ++ struct sip_header_nfo *hnfo) ++{ ++ const char *limit, *aux, *k = dptr; ++ int shift = 0; ++ ++ limit = dptr + (dlen - hnfo->lnlen); ++ ++ while (dptr <= limit) { ++ if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && ++ (strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) ++ { ++ dptr++; ++ continue; ++ } ++ aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, ++ ct_sip_lnlen(dptr, limit)); ++ if (!aux) { ++ DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, hnfo->lname); ++ return -1; ++ } ++ aux += hnfo->ln_strlen; ++ ++ *matchlen = hnfo->match_len(aux, limit, &shift); ++ if (!*matchlen) ++ return -1; ++ ++ *matchoff = (aux - k) + shift; ++ ++ DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname, *matchlen); ++ return 1; ++ } ++ DEBUGP("%s header not found.\n", hnfo->lname); ++ return 0; ++} ++ ++static int set_expected_rtp(struct sk_buff **pskb, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo, ++ uint32_t ipaddr, uint16_t port, ++ const char *dptr) ++{ ++ struct ip_conntrack_expect *exp; ++ int ret; ++ ++ exp = ip_conntrack_expect_alloc(ct); ++ if (exp == NULL) ++ return NF_DROP; ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip, { 0 } }, ++ { ipaddr, { .udp = { htons(port) } }, IPPROTO_UDP }}); ++ ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { .udp = { 0xFFFF } }, 0xFF }}); ++ ++ exp->expectfn = NULL; ++ ++ if (ip_nat_sdp_hook) ++ ret = ip_nat_sdp_hook(pskb, ctinfo, exp, dptr); ++ else { ++ if (ip_conntrack_expect_related(exp) != 0) ++ ret = NF_DROP; ++ else ++ ret = NF_ACCEPT; ++ } ++ ip_conntrack_expect_put(exp); ++ ++ return ret; ++} ++ ++static int sip_help(struct sk_buff **pskb, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ unsigned int dataoff, datalen; ++ const char *dptr; ++ int ret = NF_ACCEPT; ++ int matchoff, matchlen; ++ uint32_t ipaddr; ++ uint16_t port; ++ ++ /* No Data ? */ ++ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); ++ if (dataoff >= (*pskb)->len) { ++ DEBUGP("skb->len = %u\n", (*pskb)->len); ++ return NF_ACCEPT; ++ } ++ ++ ip_ct_refresh(ct, *pskb, sip_timeout * HZ); ++ ++ spin_lock_bh(&sipbf_lock); ++ ++ if ((dataoff + (*pskb)->len - dataoff) <= skb_headlen(*pskb)) ++ dptr = (*pskb)->data + dataoff; ++ else { ++ DEBUGP("Copy of skbuff not supported yet.\n"); ++ goto out; ++ } ++ ++ if (ip_nat_sip_hook) { ++ if (!ip_nat_sip_hook(pskb, ctinfo, ct, &dptr)) { ++ ret = NF_DROP; ++ goto out; ++ } ++ } ++ ++ if ((ctinfo) >= IP_CT_IS_REPLY) ++ goto out; ++ ++ /* After this point NAT, could have mangled skb, so ++ we need to recalculate payload lenght. */ ++ datalen = (*pskb)->len - dataoff; ++ ++ if (datalen < (sizeof("SIP/2.0 200") - 1)) ++ goto out; ++ ++ /* RTP info only in some SDP pkts */ ++ if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 && ++ memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) { ++ goto out; ++ } ++ /* Get ip and port address from SDP packet. */ ++ if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, ++ &ct_sip_hdrs[POS_CONECTION]) > 0) { ++ ++ /* We'll drop only if there are parse problems. */ ++ if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr, ++ dptr + datalen) < 0) { ++ ret = NF_DROP; ++ goto out; ++ } ++ if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen, ++ &ct_sip_hdrs[POS_MEDIA]) > 0) { ++ ++ port = simple_strtoul(dptr + matchoff, NULL, 10); ++ if (port < 1024) { ++ ret = NF_DROP; ++ goto out; ++ } ++ ret = set_expected_rtp(pskb, ct, ctinfo, ++ ipaddr, port, dptr); ++ } ++ } ++out: spin_unlock_bh(&sipbf_lock); ++ return ret; ++} ++ ++static struct ip_conntrack_helper sip[MAX_PORTS]; ++static char sip_names[MAX_PORTS][10]; ++ ++static void fini(void) ++{ ++ int i = 0; ++ for (; i < ports_c; i++) { ++ DEBUGP("unregistering helper for port %d\n", ports[i]); ++ ip_conntrack_helper_unregister(&sip[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret; ++ char *tmpname; ++ ++ if (ports_c == 0) ++ ports[ports_c++] = SIP_PORT; ++ ++ for (i = 0; i < ports_c; i++) { ++ /* Create helper structure */ ++ memset(&sip[i], 0, sizeof(struct ip_conntrack_helper)); ++ ++ sip[i].tuple.dst.protonum = IPPROTO_UDP; ++ sip[i].tuple.src.u.udp.port = htons(ports[i]); ++ sip[i].mask.src.u.udp.port = 0xFFFF; ++ sip[i].mask.dst.protonum = 0xFF; ++ sip[i].max_expected = 1; ++ sip[i].timeout = 3 * 60; /* 3 minutes */ ++ sip[i].me = THIS_MODULE; ++ sip[i].help = sip_help; ++ ++ tmpname = &sip_names[i][0]; ++ if (ports[i] == SIP_PORT) ++ sprintf(tmpname, "sip"); ++ else ++ sprintf(tmpname, "sip-%d", i); ++ sip[i].name = tmpname; ++ ++ DEBUGP("port #%d: %d\n", i, ports[i]); ++ ++ ret=ip_conntrack_helper_register(&sip[i]); ++ if (ret) { ++ printk("ERROR registering helper for port %d\n", ++ ports[i]); ++ fini(); ++ return(ret); ++ } ++ } ++ return(0); ++} ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.6.16.4/net/ipv4/netfilter/ip_nat_sip.c linux-2.6.16.4.new/net/ipv4/netfilter/ip_nat_sip.c +--- linux-2.6.16.4/net/ipv4/netfilter/ip_nat_sip.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16.4.new/net/ipv4/netfilter/ip_nat_sip.c 2006-04-12 17:31:53.000000000 +0200 +@@ -0,0 +1,249 @@ ++/* SIP extension for UDP NAT alteration. ++ * ++ * (C) 2005 by Christian Hentschel ++ * based on RR's ip_nat_ftp.c and other modules. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hentschel "); ++MODULE_DESCRIPTION("SIP NAT helper"); ++ ++#if 0 ++#define DEBUGP printk ++#else ++#define DEBUGP(format, args...) ++#endif ++ ++extern struct sip_header_nfo ct_sip_hdrs[]; ++ ++static unsigned int mangle_sip_packet(struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack *ct, ++ const char **dptr, size_t dlen, ++ char *buffer, int bufflen, ++ struct sip_header_nfo *hnfo) ++{ ++ unsigned int matchlen, matchoff; ++ ++ if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, hnfo) <= 0) ++ return 0; ++ ++ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, ++ matchoff, matchlen, buffer, bufflen)) { ++ return 0; ++ } ++ /* We need to reload this. Thanks Patrick. */ ++ *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); ++ return 1; ++} ++ ++static unsigned int ip_nat_sip(struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack *ct, ++ const char **dptr) ++{ ++ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; ++ unsigned int bufflen, dataoff; ++ uint32_t ip; ++ uint16_t port; ++ ++ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); ++ ++ if ((ctinfo) >= IP_CT_IS_REPLY) { ++ ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; ++ } else { ++ ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port; ++ } ++ bufflen = sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(ip), ntohs(port)); ++ ++ /* short packet ? */ ++ if (((*pskb)->len - dataoff) < (sizeof("SIP/2.0") - 1)) ++ return 0; ++ ++ /* Basic rules: requests and responses. */ ++ if (memcmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) == 0) { ++ ++ if ((ctinfo) < IP_CT_IS_REPLY) { ++ mangle_sip_packet(pskb, ctinfo, ct, dptr, ++ (*pskb)->len - dataoff, buffer, bufflen, ++ &ct_sip_hdrs[POS_CONTACT]); ++ return 1; ++ } ++ ++ if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, ++ buffer, bufflen, &ct_sip_hdrs[POS_VIA])) { ++ return 0; ++ } ++ ++ /* This search should ignore case, but later.. */ ++ const char *aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1, ++ (*pskb)->len - dataoff); ++ if (!aux) ++ return 0; ++ ++ if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"), ++ ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff))) { ++ return 1; ++ } ++ return mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, ++ buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]); ++ } ++ if ((ctinfo) < IP_CT_IS_REPLY) { ++ if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, ++ buffer, bufflen, &ct_sip_hdrs[POS_VIA])) { ++ return 0; ++ } ++ ++ /* Mangle Contact if exists only. - watch udp_nat_mangle()! */ ++ mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff, ++ buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]); ++ return 1; ++ } ++ /* This mangle requests headers. */ ++ return mangle_sip_packet(pskb, ctinfo, ct, dptr, ++ ct_sip_lnlen(*dptr, *dptr + (*pskb)->len - dataoff), ++ buffer, bufflen, &ct_sip_hdrs[POS_REQ_HEADER]); ++} ++ ++static int mangle_content_len(struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack *ct, ++ const char *dptr) ++{ ++ unsigned int dataoff, matchoff, matchlen; ++ char buffer[sizeof("65536")]; ++ int bufflen; ++ ++ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); ++ ++ /* Get actual SDP lenght */ ++ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, ++ &matchlen, &ct_sip_hdrs[POS_SDP_HEADER]) > 0) { ++ ++ /* since ct_sip_get_info() give us a pointer passing 'v=' ++ we need to add 2 bytes in this count. */ ++ int c_len = (*pskb)->len - dataoff - matchoff + 2; ++ ++ /* Now, update SDP lenght */ ++ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff, ++ &matchlen, &ct_sip_hdrs[POS_CONTENT]) > 0) { ++ ++ bufflen = sprintf(buffer, "%u", c_len); ++ ++ return ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, ++ matchlen, buffer, bufflen); ++ } ++ } ++ return 0; ++} ++ ++static unsigned int mangle_sdp(struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack *ct, ++ uint32_t newip, uint16_t port, ++ const char *dptr) ++{ ++ char buffer[sizeof("nnn.nnn.nnn.nnn")]; ++ unsigned int dataoff, bufflen; ++ ++ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); ++ ++ /* Mangle owner and contact info. */ ++ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); ++ if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, ++ buffer, bufflen, &ct_sip_hdrs[POS_OWNER])) { ++ return 0; ++ } ++ ++ if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, ++ buffer, bufflen, &ct_sip_hdrs[POS_CONECTION])) { ++ return 0; ++ } ++ ++ /* Mangle media port. */ ++ bufflen = sprintf(buffer, "%u", port); ++ if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff, ++ buffer, bufflen, &ct_sip_hdrs[POS_MEDIA])) { ++ return 0; ++ } ++ ++ return mangle_content_len(pskb, ctinfo, ct, dptr); ++} ++ ++/* So, this packet has hit the connection tracking matching code. ++ Mangle it, and change the expectation to match the new version. */ ++static unsigned int ip_nat_sdp(struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *exp, ++ const char *dptr) ++{ ++ struct ip_conntrack *ct = exp->master; ++ uint32_t newip; ++ uint16_t port; ++ ++ DEBUGP("ip_nat_sdp():\n"); ++ ++ /* Connection will come from reply */ ++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ ++ exp->tuple.dst.ip = newip; ++ exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; ++ exp->dir = IP_CT_DIR_REPLY; ++ ++ /* When you see the packet, we need to NAT it the same as the ++ this one. */ ++ exp->expectfn = ip_nat_follow_master; ++ ++ /* Try to get same port: if not, try to change it. */ ++ for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { ++ exp->tuple.dst.u.udp.port = htons(port); ++ if (ip_conntrack_expect_related(exp) == 0) ++ break; ++ } ++ ++ if (port == 0) ++ return NF_DROP; ++ ++ if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) { ++ ip_conntrack_unexpect_related(exp); ++ return NF_DROP; ++ } ++ return NF_ACCEPT; ++} ++ ++static void __exit fini(void) ++{ ++ ip_nat_sip_hook = NULL; ++ ip_nat_sdp_hook = NULL; ++ /* Make sure noone calls it, meanwhile. */ ++ synchronize_net(); ++} ++ ++static int __init init(void) ++{ ++ BUG_ON(ip_nat_sip_hook); ++ BUG_ON(ip_nat_sdp_hook); ++ ip_nat_sip_hook = ip_nat_sip; ++ ip_nat_sdp_hook = ip_nat_sdp; ++ return 0; ++} ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.6.16.4/net/ipv4/netfilter/Kconfig linux-2.6.16.4.new/net/ipv4/netfilter/Kconfig +--- linux-2.6.16.4/net/ipv4/netfilter/Kconfig 2006-04-12 17:29:19.000000000 +0200 ++++ linux-2.6.16.4.new/net/ipv4/netfilter/Kconfig 2006-04-12 17:32:53.000000000 +0200 +@@ -168,6 +168,19 @@ + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + ++config IP_NF_SIP ++ tristate 'SIP support' ++ depends on IP_NF_CONNTRACK ++ help ++ SIP is an application-layer control protocol that can establish, ++ modify, and terminate multimedia sessions (conferences) such as ++ Internet telephony calls. With the ip_conntrack_sip and ++ the ip_nat_sip modules you can support the protocol on a connection ++ tracking/NATing firewall. ++ ++ If you want to compile it as a module, say 'M' here and read ++ Documentation/modules.txt. If unsure, say 'N'. ++ + config IP_NF_QUEUE + tristate "IP Userspace queueing via NETLINK (OBSOLETE)" + help +@@ -545,6 +558,12 @@ + default IP_NF_NAT if IP_NF_PPTP=y + default m if IP_NF_PPTP=m + ++config IP_NF_NAT_SIP ++ tristate ++ depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n ++ default IP_NF_NAT if IP_NF_SIP=y ++ default m if IP_NF_SIP=m ++ + # mangle + specific targets + config IP_NF_MANGLE + tristate "Packet mangling" +diff -urN linux-2.6.16.4/net/ipv4/netfilter/Makefile linux-2.6.16.4.new/net/ipv4/netfilter/Makefile +--- linux-2.6.16.4/net/ipv4/netfilter/Makefile 2006-04-12 17:29:19.000000000 +0200 ++++ linux-2.6.16.4.new/net/ipv4/netfilter/Makefile 2006-04-12 17:33:39.000000000 +0200 +@@ -28,6 +28,7 @@ + obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o + obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o + obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o ++obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o + + # NAT helpers + obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o +@@ -35,6 +36,7 @@ + obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o + obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o + obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o ++obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o + + # generic IP tables + obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o +diff -urN linux-2.6.16.4/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.16.4.new/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.6.16.4/include/linux/netfilter_ipv4/ip_conntrack.h 2006-04-12 17:29:19.000000000 +0200 ++++ linux-2.6.16.4.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-04-12 17:30:38.000000000 +0200 +@@ -33,6 +33,7 @@ + #include + #include + #include ++#include + + /* per conntrack: application helper private data */ + union ip_conntrack_help { +@@ -40,6 +41,7 @@ + struct ip_ct_pptp_master ct_pptp_info; + struct ip_ct_ftp_master ct_ftp_info; + struct ip_ct_irc_master ct_irc_info; ++ struct ip_ct_sip_master ct_sip_info; + }; + + #ifdef CONFIG_IP_NF_NAT_NEEDED +diff -urN linux-2.6.16.4/include/linux/netfilter_ipv4/ip_conntrack_sip.h linux-2.6.16.4.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h +--- linux-2.6.16.4/include/linux/netfilter_ipv4/ip_conntrack_sip.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.16.4.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h 2006-04-12 17:31:12.000000000 +0200 +@@ -0,0 +1,81 @@ ++#ifndef __IP_CONNTRACK_SIP_H__ ++#define __IP_CONNTRACK_SIP_H__ ++/* SIP tracking. */ ++ ++#ifdef __KERNEL__ ++ ++#define SIP_PORT 5060 ++#define SIP_TIMEOUT 3600 ++ ++#define POS_VIA 0 ++#define POS_CONTACT 1 ++#define POS_CONTENT 2 ++#define POS_MEDIA 3 ++#define POS_OWNER 4 ++#define POS_CONECTION 5 ++#define POS_REQ_HEADER 6 ++#define POS_SDP_HEADER 7 ++ ++struct ip_ct_sip_master { ++}; ++ ++struct sip_header_nfo { ++ const char *lname; ++ size_t lnlen; ++ const char *sname; ++ size_t snlen; ++ const char *ln_str; ++ size_t ln_strlen; ++ int (*match_len)(const char *, const char *, int *); ++ ++}; ++ ++extern unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack *ct, ++ const char **dptr); ++ ++/* For NAT to hook in when on expect. */ ++extern unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *exp, ++ const char *dptr); ++ ++extern int ct_sip_get_info(const char *dptr, size_t dlen, ++ unsigned int *matchoff, ++ unsigned int *matchlen, ++ struct sip_header_nfo *hnfo); ++ ++/* get line lenght until first CR or LF seen. */ ++static __inline__ int ct_sip_lnlen(const char *line, const char *limit) ++{ ++ const char *k = line; ++ ++ while ((line <= limit) && (*line == '\r' || *line == '\n')) ++ line++; ++ ++ while (line <= limit) { ++ if (*line == '\r' || *line == '\n') ++ break; ++ line++; ++ } ++ return line - k; ++} ++ ++/* Linear string search, case sensitive. */ ++static __inline__ ++const char *ct_sip_search(const char *needle, const char *haystack, ++ size_t needle_len, size_t haystack_len) ++{ ++ const char *limit = haystack + (haystack_len - needle_len); ++ ++ while (haystack <= limit) { ++ if (memcmp(haystack, needle, needle_len) == 0) ++ return haystack; ++ haystack++; ++ } ++ return NULL; ++} ++#endif /* __KERNEL__ */ ++ ++#endif /* __IP_CONNTRACK_SIP_H__ */ diff --git a/openwrt/target/linux/netfilter.mk b/openwrt/target/linux/netfilter.mk index 26c467f8a0..0d44df2fc9 100644 --- a/openwrt/target/linux/netfilter.mk +++ b/openwrt/target/linux/netfilter.mk @@ -87,7 +87,9 @@ IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_MMS) += $(P_V4)ip_nat_mms IPT_NAT_EXTRA-$(CONFIG_IP_NF_RTSP) += $(P_V4)ip_conntrack_rtsp IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_RTSP) += $(P_V4)ip_nat_rtsp IPT_NAT_EXTRA-$(CONFIG_IP_NF_PPTP) += $(P_V4)ip_conntrack_pptp +IPT_NAT_EXTRA-$(CONFIG_IP_NF_SIP) += $(P_V4)ip_conntrack_sip IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_PPTP) += $(P_V4)ip_nat_pptp +IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_SIP) += $(P_V4)ip_nat_sip IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += $(P_V4)ip_nat_snmp_basic IPT_NAT_EXTRA-$(CONFIG_IP_NF_SIP) += $(P_V4)ip_conntrack_sip IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_SIP) += $(P_V4)ip_nat_sip diff --git a/openwrt/target/linux/x86-2.6/config b/openwrt/target/linux/x86-2.6/config index 54f63c9ad8..39fcb764fb 100644 --- a/openwrt/target/linux/x86-2.6/config +++ b/openwrt/target/linux/x86-2.6/config @@ -384,6 +384,7 @@ CONFIG_IP_NF_NETBIOS_NS=m CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_AMANDA=m CONFIG_IP_NF_PPTP=m +CONFIG_IP_NF_SIP=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_IPRANGE=m @@ -420,6 +421,7 @@ CONFIG_IP_NF_NAT_FTP=y CONFIG_IP_NF_NAT_TFTP=m CONFIG_IP_NF_NAT_AMANDA=m CONFIG_IP_NF_NAT_PPTP=m +CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_MANGLE=y CONFIG_IP_NF_TARGET_TOS=m CONFIG_IP_NF_TARGET_ECN=m