netfilter: add protocol independent NAT core
[deliverable/linux.git] / net / ipv4 / netfilter / nf_nat_sip.c
index ea4a23813d26e66bf3c5e1513dbdb247b53a06dd..47a47186a7911fb716209883bf891b0e3251402d 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <linux/netfilter/nf_conntrack_sip.h>
@@ -30,7 +29,8 @@ MODULE_DESCRIPTION("SIP NAT helper");
 MODULE_ALIAS("ip_nat_sip");
 
 
-static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff,
+static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff,
+                                 unsigned int dataoff,
                                  const char **dptr, unsigned int *datalen,
                                  unsigned int matchoff, unsigned int matchlen,
                                  const char *buffer, unsigned int buflen)
@@ -46,7 +46,7 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff,
                matchoff += dataoff - baseoff;
 
                if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
-                                               matchoff, matchlen,
+                                               protoff, matchoff, matchlen,
                                                buffer, buflen, false))
                        return 0;
        } else {
@@ -54,7 +54,7 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff,
                matchoff += dataoff - baseoff;
 
                if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
-                                             matchoff, matchlen,
+                                             protoff, matchoff, matchlen,
                                              buffer, buflen))
                        return 0;
        }
@@ -65,7 +65,8 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff,
        return 1;
 }
 
-static int map_addr(struct sk_buff *skb, unsigned int dataoff,
+static int map_addr(struct sk_buff *skb, unsigned int protoff,
+                   unsigned int dataoff,
                    const char **dptr, unsigned int *datalen,
                    unsigned int matchoff, unsigned int matchlen,
                    union nf_inet_addr *addr, __be16 port)
@@ -94,11 +95,12 @@ static int map_addr(struct sk_buff *skb, unsigned int dataoff,
 
        buflen = sprintf(buffer, "%pI4:%u", &newaddr, ntohs(newport));
 
-       return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
-                            buffer, buflen);
+       return mangle_packet(skb, protoff, dataoff, dptr, datalen,
+                            matchoff, matchlen, buffer, buflen);
 }
 
-static int map_sip_addr(struct sk_buff *skb, unsigned int dataoff,
+static int map_sip_addr(struct sk_buff *skb, unsigned int protoff,
+                       unsigned int dataoff,
                        const char **dptr, unsigned int *datalen,
                        enum sip_header_types type)
 {
@@ -111,11 +113,12 @@ static int map_sip_addr(struct sk_buff *skb, unsigned int dataoff,
        if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
                                    &matchoff, &matchlen, &addr, &port) <= 0)
                return 1;
-       return map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
-                       &addr, port);
+       return map_addr(skb, protoff, dataoff, dptr, datalen,
+                       matchoff, matchlen, &addr, port);
 }
 
-static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
+static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int protoff,
+                              unsigned int dataoff,
                               const char **dptr, unsigned int *datalen)
 {
        enum ip_conntrack_info ctinfo;
@@ -132,8 +135,8 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
                if (ct_sip_parse_request(ct, *dptr, *datalen,
                                         &matchoff, &matchlen,
                                         &addr, &port) > 0 &&
-                   !map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
-                             &addr, port))
+                   !map_addr(skb, protoff, dataoff, dptr, datalen,
+                             matchoff, matchlen, &addr, port))
                        return NF_DROP;
                request = 1;
        } else
@@ -148,7 +151,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
        if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
                                    hdr, NULL, &matchoff, &matchlen,
                                    &addr, &port) > 0) {
-               unsigned int matchend, poff, plen, buflen, n;
+               unsigned int olen, matchend, poff, plen, buflen, n;
                char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
 
                /* We're only interested in headers related to this
@@ -163,22 +166,23 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
                                goto next;
                }
 
-               if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
-                             &addr, port))
+               olen = *datalen;
+               if (!map_addr(skb, protoff, dataoff, dptr, datalen,
+                             matchoff, matchlen, &addr, port))
                        return NF_DROP;
 
-               matchend = matchoff + matchlen;
+               matchend = matchoff + matchlen + *datalen - olen;
 
                /* The maddr= parameter (RFC 2361) specifies where to send
                 * the reply. */
                if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
                                               "maddr=", &poff, &plen,
-                                              &addr) > 0 &&
+                                              &addr, true) > 0 &&
                    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
                    addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
                        buflen = sprintf(buffer, "%pI4",
                                        &ct->tuplehash[!dir].tuple.dst.u3.ip);
-                       if (!mangle_packet(skb, dataoff, dptr, datalen,
+                       if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
                                           poff, plen, buffer, buflen))
                                return NF_DROP;
                }
@@ -187,12 +191,12 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
                 * from which the server received the request. */
                if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
                                               "received=", &poff, &plen,
-                                              &addr) > 0 &&
+                                              &addr, false) > 0 &&
                    addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
                    addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
                        buflen = sprintf(buffer, "%pI4",
                                        &ct->tuplehash[!dir].tuple.src.u3.ip);
-                       if (!mangle_packet(skb, dataoff, dptr, datalen,
+                       if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
                                           poff, plen, buffer, buflen))
                                return NF_DROP;
                }
@@ -206,7 +210,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
                    htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
                        __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
                        buflen = sprintf(buffer, "%u", ntohs(p));
-                       if (!mangle_packet(skb, dataoff, dptr, datalen,
+                       if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
                                           poff, plen, buffer, buflen))
                                return NF_DROP;
                }
@@ -220,13 +224,14 @@ next:
                                       SIP_HDR_CONTACT, &in_header,
                                       &matchoff, &matchlen,
                                       &addr, &port) > 0) {
-               if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
+               if (!map_addr(skb, protoff, dataoff, dptr, datalen,
+                             matchoff, matchlen,
                              &addr, port))
                        return NF_DROP;
        }
 
-       if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) ||
-           !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO))
+       if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) ||
+           !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO))
                return NF_DROP;
 
        return NF_ACCEPT;
@@ -249,15 +254,15 @@ static void ip_nat_sip_seq_adjust(struct sk_buff *skb, s16 off)
 static void ip_nat_sip_expected(struct nf_conn *ct,
                                struct nf_conntrack_expect *exp)
 {
-       struct nf_nat_ipv4_range range;
+       struct nf_nat_range range;
 
        /* This must be a fresh one. */
        BUG_ON(ct->status & IPS_NAT_DONE_MASK);
 
        /* For DST manip, map port here to where it's expected. */
        range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
-       range.min = range.max = exp->saved_proto;
-       range.min_ip = range.max_ip = exp->saved_ip;
+       range.min_proto = range.max_proto = exp->saved_proto;
+       range.min_addr = range.max_addr = exp->saved_addr;
        nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
 
        /* Change src to where master sends to, but only if the connection
@@ -265,13 +270,14 @@ static void ip_nat_sip_expected(struct nf_conn *ct,
        if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
            ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
                range.flags = NF_NAT_RANGE_MAP_IPS;
-               range.min_ip = range.max_ip
-                       = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+               range.min_addr = range.max_addr
+                       = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
                nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
        }
 }
 
-static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
+static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
+                                     unsigned int dataoff,
                                      const char **dptr, unsigned int *datalen,
                                      struct nf_conntrack_expect *exp,
                                      unsigned int matchoff,
@@ -300,7 +306,7 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
        else
                port = ntohs(exp->tuple.dst.u.udp.port);
 
-       exp->saved_ip = exp->tuple.dst.u3.ip;
+       exp->saved_addr = exp->tuple.dst.u3;
        exp->tuple.dst.u3.ip = newip;
        exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
        exp->dir = !dir;
@@ -322,10 +328,10 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
        if (port == 0)
                return NF_DROP;
 
-       if (exp->tuple.dst.u3.ip != exp->saved_ip ||
+       if (exp->tuple.dst.u3.ip != exp->saved_addr.ip ||
            exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
                buflen = sprintf(buffer, "%pI4:%u", &newip, port);
-               if (!mangle_packet(skb, dataoff, dptr, datalen,
+               if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
                                   matchoff, matchlen, buffer, buflen))
                        goto err;
        }
@@ -336,7 +342,8 @@ err:
        return NF_DROP;
 }
 
-static int mangle_content_len(struct sk_buff *skb, unsigned int dataoff,
+static int mangle_content_len(struct sk_buff *skb, unsigned int protoff,
+                             unsigned int dataoff,
                              const char **dptr, unsigned int *datalen)
 {
        enum ip_conntrack_info ctinfo;
@@ -358,11 +365,12 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int dataoff,
                return 0;
 
        buflen = sprintf(buffer, "%u", c_len);
-       return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
-                            buffer, buflen);
+       return mangle_packet(skb, protoff, dataoff, dptr, datalen,
+                            matchoff, matchlen, buffer, buflen);
 }
 
-static int mangle_sdp_packet(struct sk_buff *skb, unsigned int dataoff,
+static int mangle_sdp_packet(struct sk_buff *skb, unsigned int protoff,
+                            unsigned int dataoff,
                             const char **dptr, unsigned int *datalen,
                             unsigned int sdpoff,
                             enum sdp_header_types type,
@@ -376,11 +384,12 @@ static int mangle_sdp_packet(struct sk_buff *skb, unsigned int dataoff,
        if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
                                  &matchoff, &matchlen) <= 0)
                return -ENOENT;
-       return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
-                            buffer, buflen) ? 0 : -EINVAL;
+       return mangle_packet(skb, protoff, dataoff, dptr, datalen,
+                            matchoff, matchlen, buffer, buflen) ? 0 : -EINVAL;
 }
 
-static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, unsigned int dataoff,
+static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,
+                                   unsigned int dataoff,
                                    const char **dptr, unsigned int *datalen,
                                    unsigned int sdpoff,
                                    enum sdp_header_types type,
@@ -391,14 +400,15 @@ static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, unsigned int dataoff,
        unsigned int buflen;
 
        buflen = sprintf(buffer, "%pI4", &addr->ip);
-       if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, type, term,
-                             buffer, buflen))
+       if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen,
+                             sdpoff, type, term, buffer, buflen))
                return 0;
 
-       return mangle_content_len(skb, dataoff, dptr, datalen);
+       return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
 }
 
-static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int dataoff,
+static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int protoff,
+                                   unsigned int dataoff,
                                    const char **dptr, unsigned int *datalen,
                                    unsigned int matchoff,
                                    unsigned int matchlen,
@@ -408,14 +418,15 @@ static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int dataoff,
        unsigned int buflen;
 
        buflen = sprintf(buffer, "%u", port);
-       if (!mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
-                          buffer, buflen))
+       if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
+                          matchoff, matchlen, buffer, buflen))
                return 0;
 
-       return mangle_content_len(skb, dataoff, dptr, datalen);
+       return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
 }
 
-static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int dataoff,
+static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int protoff,
+                                      unsigned int dataoff,
                                       const char **dptr, unsigned int *datalen,
                                       unsigned int sdpoff,
                                       const union nf_inet_addr *addr)
@@ -425,12 +436,12 @@ static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int dataoff
 
        /* Mangle session description owner and contact addresses */
        buflen = sprintf(buffer, "%pI4", &addr->ip);
-       if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
+       if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
                               SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA,
                               buffer, buflen))
                return 0;
 
-       switch (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
+       switch (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
                                  SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA,
                                  buffer, buflen)) {
        case 0:
@@ -447,12 +458,13 @@ static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int dataoff
                return 0;
        }
 
-       return mangle_content_len(skb, dataoff, dptr, datalen);
+       return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
 }
 
 /* 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_media(struct sk_buff *skb, unsigned int dataoff,
+static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
+                                    unsigned int dataoff,
                                     const char **dptr, unsigned int *datalen,
                                     struct nf_conntrack_expect *rtp_exp,
                                     struct nf_conntrack_expect *rtcp_exp,
@@ -472,13 +484,13 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
        else
                rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
 
-       rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
+       rtp_exp->saved_addr = rtp_exp->tuple.dst.u3;
        rtp_exp->tuple.dst.u3.ip = rtp_addr->ip;
        rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
        rtp_exp->dir = !dir;
        rtp_exp->expectfn = ip_nat_sip_expected;
 
-       rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
+       rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3;
        rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip;
        rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
        rtcp_exp->dir = !dir;
@@ -513,7 +525,7 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
 
        /* Update media port. */
        if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
-           !ip_nat_sdp_port(skb, dataoff, dptr, datalen,
+           !ip_nat_sdp_port(skb, protoff, dataoff, dptr, datalen,
                             mediaoff, medialen, port))
                goto err2;
 
This page took 0.0496 seconds and 5 git commands to generate.