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