Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[cascardo/linux.git] / net / ipv4 / netfilter / nf_nat_sip.c
index b12cd7c..fac97cf 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
+#include <net/ip.h>
 #include <linux/udp.h>
 
 #include <net/netfilter/nf_nat.h>
@@ -92,7 +93,7 @@ static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo,
        if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
                                      matchoff, matchlen, addr, addrlen))
                return 0;
-       *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+       *dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr);
        return 1;
 
 }
@@ -106,7 +107,7 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb,
        struct addr_map map;
        int dataoff, datalen;
 
-       dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+       dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
        datalen = (*pskb)->len - dataoff;
        if (datalen < sizeof("SIP/2.0") - 1)
                return NF_DROP;
@@ -155,7 +156,7 @@ static unsigned int mangle_sip_packet(struct sk_buff **pskb,
                return 0;
 
        /* We need to reload this. Thanks Patrick. */
-       *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+       *dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr);
        return 1;
 }
 
@@ -168,7 +169,7 @@ static int mangle_content_len(struct sk_buff **pskb,
        char buffer[sizeof("65536")];
        int bufflen;
 
-       dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+       dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
 
        /* Get actual SDP lenght */
        if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff,
@@ -200,7 +201,7 @@ static unsigned int mangle_sdp(struct sk_buff **pskb,
        char buffer[sizeof("nnn.nnn.nnn.nnn")];
        unsigned int dataoff, bufflen;
 
-       dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+       dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
 
        /* Mangle owner and contact info. */
        bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
@@ -221,6 +222,29 @@ static unsigned int mangle_sdp(struct sk_buff **pskb,
        return mangle_content_len(pskb, ctinfo, ct, dptr);
 }
 
+static void ip_nat_sdp_expect(struct nf_conn *ct,
+                             struct nf_conntrack_expect *exp)
+{
+       struct nf_nat_range range;
+
+       /* This must be a fresh one. */
+       BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+
+       /* Change src to where master sends to */
+       range.flags = IP_NAT_RANGE_MAP_IPS;
+       range.min_ip = range.max_ip
+               = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+       /* hook doesn't matter, but it has to do source manip */
+       nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
+
+       /* For DST manip, map port here to where it's expected. */
+       range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+       range.min = range.max = exp->saved_proto;
+       range.min_ip = range.max_ip = exp->saved_ip;
+       /* hook doesn't matter, but it has to do destination manip */
+       nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
+}
+
 /* 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,
@@ -238,13 +262,14 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb,
        /* Connection will come from reply */
        newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
 
+       exp->saved_ip = exp->tuple.dst.u3.ip;
        exp->tuple.dst.u3.ip = newip;
        exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
        exp->dir = !dir;
 
        /* When you see the packet, we need to NAT it the same as the
           this one. */
-       exp->expectfn = nf_nat_follow_master;
+       exp->expectfn = ip_nat_sdp_expect;
 
        /* Try to get same port: if not, try to change it. */
        for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {