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