linux/net/netfilter/nf_nat_sip.c
<<
>>
Prefs
   1/* SIP extension for NAT alteration.
   2 *
   3 * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
   4 * based on RR's ip_nat_ftp.c and other modules.
   5 * (C) 2007 United Security Providers
   6 * (C) 2007, 2008, 2011, 2012 Patrick McHardy <kaber@trash.net>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/skbuff.h>
  15#include <linux/inet.h>
  16#include <linux/udp.h>
  17#include <linux/tcp.h>
  18
  19#include <net/netfilter/nf_nat.h>
  20#include <net/netfilter/nf_nat_helper.h>
  21#include <net/netfilter/nf_conntrack_helper.h>
  22#include <net/netfilter/nf_conntrack_expect.h>
  23#include <net/netfilter/nf_conntrack_seqadj.h>
  24#include <linux/netfilter/nf_conntrack_sip.h>
  25
  26#define NAT_HELPER_NAME "sip"
  27
  28MODULE_LICENSE("GPL");
  29MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
  30MODULE_DESCRIPTION("SIP NAT helper");
  31MODULE_ALIAS_NF_NAT_HELPER(NAT_HELPER_NAME);
  32
  33static struct nf_conntrack_nat_helper nat_helper_sip =
  34        NF_CT_NAT_HELPER_INIT(NAT_HELPER_NAME);
  35
  36static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff,
  37                                  unsigned int dataoff,
  38                                  const char **dptr, unsigned int *datalen,
  39                                  unsigned int matchoff, unsigned int matchlen,
  40                                  const char *buffer, unsigned int buflen)
  41{
  42        enum ip_conntrack_info ctinfo;
  43        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
  44        struct tcphdr *th;
  45        unsigned int baseoff;
  46
  47        if (nf_ct_protonum(ct) == IPPROTO_TCP) {
  48                th = (struct tcphdr *)(skb->data + protoff);
  49                baseoff = protoff + th->doff * 4;
  50                matchoff += dataoff - baseoff;
  51
  52                if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
  53                                                protoff, matchoff, matchlen,
  54                                                buffer, buflen, false))
  55                        return 0;
  56        } else {
  57                baseoff = protoff + sizeof(struct udphdr);
  58                matchoff += dataoff - baseoff;
  59
  60                if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
  61                                              protoff, matchoff, matchlen,
  62                                              buffer, buflen))
  63                        return 0;
  64        }
  65
  66        /* Reload data pointer and adjust datalen value */
  67        *dptr = skb->data + dataoff;
  68        *datalen += buflen - matchlen;
  69        return 1;
  70}
  71
  72static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer,
  73                            const union nf_inet_addr *addr, bool delim)
  74{
  75        if (nf_ct_l3num(ct) == NFPROTO_IPV4)
  76                return sprintf(buffer, "%pI4", &addr->ip);
  77        else {
  78                if (delim)
  79                        return sprintf(buffer, "[%pI6c]", &addr->ip6);
  80                else
  81                        return sprintf(buffer, "%pI6c", &addr->ip6);
  82        }
  83}
  84
  85static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer,
  86                                 const union nf_inet_addr *addr, u16 port)
  87{
  88        if (nf_ct_l3num(ct) == NFPROTO_IPV4)
  89                return sprintf(buffer, "%pI4:%u", &addr->ip, port);
  90        else
  91                return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port);
  92}
  93
  94static int map_addr(struct sk_buff *skb, unsigned int protoff,
  95                    unsigned int dataoff,
  96                    const char **dptr, unsigned int *datalen,
  97                    unsigned int matchoff, unsigned int matchlen,
  98                    union nf_inet_addr *addr, __be16 port)
  99{
 100        enum ip_conntrack_info ctinfo;
 101        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 102        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 103        struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
 104        char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
 105        unsigned int buflen;
 106        union nf_inet_addr newaddr;
 107        __be16 newport;
 108
 109        if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, addr) &&
 110            ct->tuplehash[dir].tuple.src.u.udp.port == port) {
 111                newaddr = ct->tuplehash[!dir].tuple.dst.u3;
 112                newport = ct->tuplehash[!dir].tuple.dst.u.udp.port;
 113        } else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) &&
 114                   ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
 115                newaddr = ct->tuplehash[!dir].tuple.src.u3;
 116                newport = ct_sip_info->forced_dport ? :
 117                          ct->tuplehash[!dir].tuple.src.u.udp.port;
 118        } else
 119                return 1;
 120
 121        if (nf_inet_addr_cmp(&newaddr, addr) && newport == port)
 122                return 1;
 123
 124        buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport));
 125        return mangle_packet(skb, protoff, dataoff, dptr, datalen,
 126                             matchoff, matchlen, buffer, buflen);
 127}
 128
 129static int map_sip_addr(struct sk_buff *skb, unsigned int protoff,
 130                        unsigned int dataoff,
 131                        const char **dptr, unsigned int *datalen,
 132                        enum sip_header_types type)
 133{
 134        enum ip_conntrack_info ctinfo;
 135        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 136        unsigned int matchlen, matchoff;
 137        union nf_inet_addr addr;
 138        __be16 port;
 139
 140        if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
 141                                    &matchoff, &matchlen, &addr, &port) <= 0)
 142                return 1;
 143        return map_addr(skb, protoff, dataoff, dptr, datalen,
 144                        matchoff, matchlen, &addr, port);
 145}
 146
 147static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
 148                               unsigned int dataoff,
 149                               const char **dptr, unsigned int *datalen)
 150{
 151        enum ip_conntrack_info ctinfo;
 152        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 153        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 154        struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
 155        unsigned int coff, matchoff, matchlen;
 156        enum sip_header_types hdr;
 157        union nf_inet_addr addr;
 158        __be16 port;
 159        int request, in_header;
 160
 161        /* Basic rules: requests and responses. */
 162        if (strncasecmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
 163                if (ct_sip_parse_request(ct, *dptr, *datalen,
 164                                         &matchoff, &matchlen,
 165                                         &addr, &port) > 0 &&
 166                    !map_addr(skb, protoff, dataoff, dptr, datalen,
 167                              matchoff, matchlen, &addr, port)) {
 168                        nf_ct_helper_log(skb, ct, "cannot mangle SIP message");
 169                        return NF_DROP;
 170                }
 171                request = 1;
 172        } else
 173                request = 0;
 174
 175        if (nf_ct_protonum(ct) == IPPROTO_TCP)
 176                hdr = SIP_HDR_VIA_TCP;
 177        else
 178                hdr = SIP_HDR_VIA_UDP;
 179
 180        /* Translate topmost Via header and parameters */
 181        if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
 182                                    hdr, NULL, &matchoff, &matchlen,
 183                                    &addr, &port) > 0) {
 184                unsigned int olen, matchend, poff, plen, buflen, n;
 185                char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
 186
 187                /* We're only interested in headers related to this
 188                 * connection */
 189                if (request) {
 190                        if (!nf_inet_addr_cmp(&addr,
 191                                        &ct->tuplehash[dir].tuple.src.u3) ||
 192                            port != ct->tuplehash[dir].tuple.src.u.udp.port)
 193                                goto next;
 194                } else {
 195                        if (!nf_inet_addr_cmp(&addr,
 196                                        &ct->tuplehash[dir].tuple.dst.u3) ||
 197                            port != ct->tuplehash[dir].tuple.dst.u.udp.port)
 198                                goto next;
 199                }
 200
 201                olen = *datalen;
 202                if (!map_addr(skb, protoff, dataoff, dptr, datalen,
 203                              matchoff, matchlen, &addr, port)) {
 204                        nf_ct_helper_log(skb, ct, "cannot mangle Via header");
 205                        return NF_DROP;
 206                }
 207
 208                matchend = matchoff + matchlen + *datalen - olen;
 209
 210                /* The maddr= parameter (RFC 2361) specifies where to send
 211                 * the reply. */
 212                if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
 213                                               "maddr=", &poff, &plen,
 214                                               &addr, true) > 0 &&
 215                    nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) &&
 216                    !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) {
 217                        buflen = sip_sprintf_addr(ct, buffer,
 218                                        &ct->tuplehash[!dir].tuple.dst.u3,
 219                                        true);
 220                        if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
 221                                           poff, plen, buffer, buflen)) {
 222                                nf_ct_helper_log(skb, ct, "cannot mangle maddr");
 223                                return NF_DROP;
 224                        }
 225                }
 226
 227                /* The received= parameter (RFC 2361) contains the address
 228                 * from which the server received the request. */
 229                if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
 230                                               "received=", &poff, &plen,
 231                                               &addr, false) > 0 &&
 232                    nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) &&
 233                    !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) {
 234                        buflen = sip_sprintf_addr(ct, buffer,
 235                                        &ct->tuplehash[!dir].tuple.src.u3,
 236                                        false);
 237                        if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
 238                                           poff, plen, buffer, buflen)) {
 239                                nf_ct_helper_log(skb, ct, "cannot mangle received");
 240                                return NF_DROP;
 241                        }
 242                }
 243
 244                /* The rport= parameter (RFC 3581) contains the port number
 245                 * from which the server received the request. */
 246                if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
 247                                                 "rport=", &poff, &plen,
 248                                                 &n) > 0 &&
 249                    htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
 250                    htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
 251                        __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
 252                        buflen = sprintf(buffer, "%u", ntohs(p));
 253                        if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
 254                                           poff, plen, buffer, buflen)) {
 255                                nf_ct_helper_log(skb, ct, "cannot mangle rport");
 256                                return NF_DROP;
 257                        }
 258                }
 259        }
 260
 261next:
 262        /* Translate Contact headers */
 263        coff = 0;
 264        in_header = 0;
 265        while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen,
 266                                       SIP_HDR_CONTACT, &in_header,
 267                                       &matchoff, &matchlen,
 268                                       &addr, &port) > 0) {
 269                if (!map_addr(skb, protoff, dataoff, dptr, datalen,
 270                              matchoff, matchlen,
 271                              &addr, port)) {
 272                        nf_ct_helper_log(skb, ct, "cannot mangle contact");
 273                        return NF_DROP;
 274                }
 275        }
 276
 277        if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) ||
 278            !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) {
 279                nf_ct_helper_log(skb, ct, "cannot mangle SIP from/to");
 280                return NF_DROP;
 281        }
 282
 283        /* Mangle destination port for Cisco phones, then fix up checksums */
 284        if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) {
 285                struct udphdr *uh;
 286
 287                if (!skb_make_writable(skb, skb->len)) {
 288                        nf_ct_helper_log(skb, ct, "cannot mangle packet");
 289                        return NF_DROP;
 290                }
 291
 292                uh = (void *)skb->data + protoff;
 293                uh->dest = ct_sip_info->forced_dport;
 294
 295                if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff,
 296                                              0, 0, NULL, 0)) {
 297                        nf_ct_helper_log(skb, ct, "cannot mangle packet");
 298                        return NF_DROP;
 299                }
 300        }
 301
 302        return NF_ACCEPT;
 303}
 304
 305static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff,
 306                                  s16 off)
 307{
 308        enum ip_conntrack_info ctinfo;
 309        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 310        const struct tcphdr *th;
 311
 312        if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0)
 313                return;
 314
 315        th = (struct tcphdr *)(skb->data + protoff);
 316        nf_ct_seqadj_set(ct, ctinfo, th->seq, off);
 317}
 318
 319/* Handles expected signalling connections and media streams */
 320static void nf_nat_sip_expected(struct nf_conn *ct,
 321                                struct nf_conntrack_expect *exp)
 322{
 323        struct nf_nat_range2 range;
 324
 325        /* This must be a fresh one. */
 326        BUG_ON(ct->status & IPS_NAT_DONE_MASK);
 327
 328        /* For DST manip, map port here to where it's expected. */
 329        range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
 330        range.min_proto = range.max_proto = exp->saved_proto;
 331        range.min_addr = range.max_addr = exp->saved_addr;
 332        nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
 333
 334        /* Change src to where master sends to, but only if the connection
 335         * actually came from the same source. */
 336        if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
 337                             &ct->master->tuplehash[exp->dir].tuple.src.u3)) {
 338                range.flags = NF_NAT_RANGE_MAP_IPS;
 339                range.min_addr = range.max_addr
 340                        = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
 341                nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
 342        }
 343}
 344
 345static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
 346                                      unsigned int dataoff,
 347                                      const char **dptr, unsigned int *datalen,
 348                                      struct nf_conntrack_expect *exp,
 349                                      unsigned int matchoff,
 350                                      unsigned int matchlen)
 351{
 352        enum ip_conntrack_info ctinfo;
 353        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 354        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 355        struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
 356        union nf_inet_addr newaddr;
 357        u_int16_t port;
 358        __be16 srcport;
 359        char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
 360        unsigned int buflen;
 361
 362        /* Connection will come from reply */
 363        if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
 364                             &ct->tuplehash[!dir].tuple.dst.u3))
 365                newaddr = exp->tuple.dst.u3;
 366        else
 367                newaddr = ct->tuplehash[!dir].tuple.dst.u3;
 368
 369        /* If the signalling port matches the connection's source port in the
 370         * original direction, try to use the destination port in the opposite
 371         * direction. */
 372        srcport = ct_sip_info->forced_dport ? :
 373                  ct->tuplehash[dir].tuple.src.u.udp.port;
 374        if (exp->tuple.dst.u.udp.port == srcport)
 375                port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
 376        else
 377                port = ntohs(exp->tuple.dst.u.udp.port);
 378
 379        exp->saved_addr = exp->tuple.dst.u3;
 380        exp->tuple.dst.u3 = newaddr;
 381        exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
 382        exp->dir = !dir;
 383        exp->expectfn = nf_nat_sip_expected;
 384
 385        for (; port != 0; port++) {
 386                int ret;
 387
 388                exp->tuple.dst.u.udp.port = htons(port);
 389                ret = nf_ct_expect_related(exp);
 390                if (ret == 0)
 391                        break;
 392                else if (ret != -EBUSY) {
 393                        port = 0;
 394                        break;
 395                }
 396        }
 397
 398        if (port == 0) {
 399                nf_ct_helper_log(skb, ct, "all ports in use for SIP");
 400                return NF_DROP;
 401        }
 402
 403        if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) ||
 404            exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
 405                buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port);
 406                if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
 407                                   matchoff, matchlen, buffer, buflen)) {
 408                        nf_ct_helper_log(skb, ct, "cannot mangle packet");
 409                        goto err;
 410                }
 411        }
 412        return NF_ACCEPT;
 413
 414err:
 415        nf_ct_unexpect_related(exp);
 416        return NF_DROP;
 417}
 418
 419static int mangle_content_len(struct sk_buff *skb, unsigned int protoff,
 420                              unsigned int dataoff,
 421                              const char **dptr, unsigned int *datalen)
 422{
 423        enum ip_conntrack_info ctinfo;
 424        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 425        unsigned int matchoff, matchlen;
 426        char buffer[sizeof("65536")];
 427        int buflen, c_len;
 428
 429        /* Get actual SDP length */
 430        if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
 431                                  SDP_HDR_VERSION, SDP_HDR_UNSPEC,
 432                                  &matchoff, &matchlen) <= 0)
 433                return 0;
 434        c_len = *datalen - matchoff + strlen("v=");
 435
 436        /* Now, update SDP length */
 437        if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH,
 438                              &matchoff, &matchlen) <= 0)
 439                return 0;
 440
 441        buflen = sprintf(buffer, "%u", c_len);
 442        return mangle_packet(skb, protoff, dataoff, dptr, datalen,
 443                             matchoff, matchlen, buffer, buflen);
 444}
 445
 446static int mangle_sdp_packet(struct sk_buff *skb, unsigned int protoff,
 447                             unsigned int dataoff,
 448                             const char **dptr, unsigned int *datalen,
 449                             unsigned int sdpoff,
 450                             enum sdp_header_types type,
 451                             enum sdp_header_types term,
 452                             char *buffer, int buflen)
 453{
 454        enum ip_conntrack_info ctinfo;
 455        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 456        unsigned int matchlen, matchoff;
 457
 458        if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
 459                                  &matchoff, &matchlen) <= 0)
 460                return -ENOENT;
 461        return mangle_packet(skb, protoff, dataoff, dptr, datalen,
 462                             matchoff, matchlen, buffer, buflen) ? 0 : -EINVAL;
 463}
 464
 465static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,
 466                                    unsigned int dataoff,
 467                                    const char **dptr, unsigned int *datalen,
 468                                    unsigned int sdpoff,
 469                                    enum sdp_header_types type,
 470                                    enum sdp_header_types term,
 471                                    const union nf_inet_addr *addr)
 472{
 473        enum ip_conntrack_info ctinfo;
 474        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 475        char buffer[INET6_ADDRSTRLEN];
 476        unsigned int buflen;
 477
 478        buflen = sip_sprintf_addr(ct, buffer, addr, false);
 479        if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen,
 480                              sdpoff, type, term, buffer, buflen))
 481                return 0;
 482
 483        return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
 484}
 485
 486static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff,
 487                                    unsigned int dataoff,
 488                                    const char **dptr, unsigned int *datalen,
 489                                    unsigned int matchoff,
 490                                    unsigned int matchlen,
 491                                    u_int16_t port)
 492{
 493        char buffer[sizeof("nnnnn")];
 494        unsigned int buflen;
 495
 496        buflen = sprintf(buffer, "%u", port);
 497        if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
 498                           matchoff, matchlen, buffer, buflen))
 499                return 0;
 500
 501        return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
 502}
 503
 504static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff,
 505                                       unsigned int dataoff,
 506                                       const char **dptr, unsigned int *datalen,
 507                                       unsigned int sdpoff,
 508                                       const union nf_inet_addr *addr)
 509{
 510        enum ip_conntrack_info ctinfo;
 511        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 512        char buffer[INET6_ADDRSTRLEN];
 513        unsigned int buflen;
 514
 515        /* Mangle session description owner and contact addresses */
 516        buflen = sip_sprintf_addr(ct, buffer, addr, false);
 517        if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
 518                              SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen))
 519                return 0;
 520
 521        switch (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
 522                                  SDP_HDR_CONNECTION, SDP_HDR_MEDIA,
 523                                  buffer, buflen)) {
 524        case 0:
 525        /*
 526         * RFC 2327:
 527         *
 528         * Session description
 529         *
 530         * c=* (connection information - not required if included in all media)
 531         */
 532        case -ENOENT:
 533                break;
 534        default:
 535                return 0;
 536        }
 537
 538        return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
 539}
 540
 541/* So, this packet has hit the connection tracking matching code.
 542   Mangle it, and change the expectation to match the new version. */
 543static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
 544                                     unsigned int dataoff,
 545                                     const char **dptr, unsigned int *datalen,
 546                                     struct nf_conntrack_expect *rtp_exp,
 547                                     struct nf_conntrack_expect *rtcp_exp,
 548                                     unsigned int mediaoff,
 549                                     unsigned int medialen,
 550                                     union nf_inet_addr *rtp_addr)
 551{
 552        enum ip_conntrack_info ctinfo;
 553        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 554        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 555        u_int16_t port;
 556
 557        /* Connection will come from reply */
 558        if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
 559                             &ct->tuplehash[!dir].tuple.dst.u3))
 560                *rtp_addr = rtp_exp->tuple.dst.u3;
 561        else
 562                *rtp_addr = ct->tuplehash[!dir].tuple.dst.u3;
 563
 564        rtp_exp->saved_addr = rtp_exp->tuple.dst.u3;
 565        rtp_exp->tuple.dst.u3 = *rtp_addr;
 566        rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
 567        rtp_exp->dir = !dir;
 568        rtp_exp->expectfn = nf_nat_sip_expected;
 569
 570        rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3;
 571        rtcp_exp->tuple.dst.u3 = *rtp_addr;
 572        rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
 573        rtcp_exp->dir = !dir;
 574        rtcp_exp->expectfn = nf_nat_sip_expected;
 575
 576        /* Try to get same pair of ports: if not, try to change them. */
 577        for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
 578             port != 0; port += 2) {
 579                int ret;
 580
 581                rtp_exp->tuple.dst.u.udp.port = htons(port);
 582                ret = nf_ct_expect_related(rtp_exp);
 583                if (ret == -EBUSY)
 584                        continue;
 585                else if (ret < 0) {
 586                        port = 0;
 587                        break;
 588                }
 589                rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
 590                ret = nf_ct_expect_related(rtcp_exp);
 591                if (ret == 0)
 592                        break;
 593                else if (ret == -EBUSY) {
 594                        nf_ct_unexpect_related(rtp_exp);
 595                        continue;
 596                } else if (ret < 0) {
 597                        nf_ct_unexpect_related(rtp_exp);
 598                        port = 0;
 599                        break;
 600                }
 601        }
 602
 603        if (port == 0) {
 604                nf_ct_helper_log(skb, ct, "all ports in use for SDP media");
 605                goto err1;
 606        }
 607
 608        /* Update media port. */
 609        if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
 610            !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen,
 611                             mediaoff, medialen, port)) {
 612                nf_ct_helper_log(skb, ct, "cannot mangle SDP message");
 613                goto err2;
 614        }
 615
 616        return NF_ACCEPT;
 617
 618err2:
 619        nf_ct_unexpect_related(rtp_exp);
 620        nf_ct_unexpect_related(rtcp_exp);
 621err1:
 622        return NF_DROP;
 623}
 624
 625static struct nf_ct_helper_expectfn sip_nat = {
 626        .name           = "sip",
 627        .expectfn       = nf_nat_sip_expected,
 628};
 629
 630static void __exit nf_nat_sip_fini(void)
 631{
 632        nf_nat_helper_unregister(&nat_helper_sip);
 633        RCU_INIT_POINTER(nf_nat_sip_hooks, NULL);
 634        nf_ct_helper_expectfn_unregister(&sip_nat);
 635        synchronize_rcu();
 636}
 637
 638static const struct nf_nat_sip_hooks sip_hooks = {
 639        .msg            = nf_nat_sip,
 640        .seq_adjust     = nf_nat_sip_seq_adjust,
 641        .expect         = nf_nat_sip_expect,
 642        .sdp_addr       = nf_nat_sdp_addr,
 643        .sdp_port       = nf_nat_sdp_port,
 644        .sdp_session    = nf_nat_sdp_session,
 645        .sdp_media      = nf_nat_sdp_media,
 646};
 647
 648static int __init nf_nat_sip_init(void)
 649{
 650        BUG_ON(nf_nat_sip_hooks != NULL);
 651        nf_nat_helper_register(&nat_helper_sip);
 652        RCU_INIT_POINTER(nf_nat_sip_hooks, &sip_hooks);
 653        nf_ct_helper_expectfn_register(&sip_nat);
 654        return 0;
 655}
 656
 657module_init(nf_nat_sip_init);
 658module_exit(nf_nat_sip_fini);
 659