root/net/netfilter/nf_nat_sip.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mangle_packet
  2. sip_sprintf_addr
  3. sip_sprintf_addr_port
  4. map_addr
  5. map_sip_addr
  6. nf_nat_sip
  7. nf_nat_sip_seq_adjust
  8. nf_nat_sip_expected
  9. nf_nat_sip_expect
  10. mangle_content_len
  11. mangle_sdp_packet
  12. nf_nat_sdp_addr
  13. nf_nat_sdp_port
  14. nf_nat_sdp_session
  15. nf_nat_sdp_media
  16. nf_nat_sip_fini
  17. nf_nat_sip_init

   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 
  26 MODULE_LICENSE("GPL");
  27 MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
  28 MODULE_DESCRIPTION("SIP NAT helper");
  29 MODULE_ALIAS_NF_NAT_HELPER(NAT_HELPER_NAME);
  30 
  31 static struct nf_conntrack_nat_helper nat_helper_sip =
  32         NF_CT_NAT_HELPER_INIT(NAT_HELPER_NAME);
  33 
  34 static 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 
  70 static 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 
  83 static 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 
  92 static 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 
 127 static 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 
 145 static 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 
 259 next:
 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 
 303 static 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 */
 318 static 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 
 373 static 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 
 442 err:
 443         nf_ct_unexpect_related(exp);
 444         return NF_DROP;
 445 }
 446 
 447 static 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 
 474 static 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 
 493 static 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 
 514 static 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 
 532 static 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. */
 571 static 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 
 648 err2:
 649         nf_ct_unexpect_related(rtp_exp);
 650         nf_ct_unexpect_related(rtcp_exp);
 651 err1:
 652         return NF_DROP;
 653 }
 654 
 655 static struct nf_ct_helper_expectfn sip_nat = {
 656         .name           = "sip",
 657         .expectfn       = nf_nat_sip_expected,
 658 };
 659 
 660 static 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 
 668 static 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 
 678 static 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 
 687 module_init(nf_nat_sip_init);
 688 module_exit(nf_nat_sip_fini);

/* [<][>][^][v][top][bottom][index][help] */