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