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 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/ip.h> 16#include <net/ip.h> 17#include <linux/udp.h> 18#include <linux/tcp.h> 19 20#include <net/netfilter/nf_nat.h> 21#include <net/netfilter/nf_nat_helper.h> 22#include <net/netfilter/nf_nat_rule.h> 23#include <net/netfilter/nf_conntrack_helper.h> 24#include <net/netfilter/nf_conntrack_expect.h> 25#include <linux/netfilter/nf_conntrack_sip.h> 26 27MODULE_LICENSE("GPL"); 28MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); 29MODULE_DESCRIPTION("SIP NAT helper"); 30MODULE_ALIAS("ip_nat_sip"); 31 32 33static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff, 34 const char **dptr, unsigned int *datalen, 35 unsigned int matchoff, unsigned int matchlen, 36 const char *buffer, unsigned int buflen) 37{ 38 enum ip_conntrack_info ctinfo; 39 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 40 struct tcphdr *th; 41 unsigned int baseoff; 42 43 if (nf_ct_protonum(ct) == IPPROTO_TCP) { 44 th = (struct tcphdr *)(skb->data + ip_hdrlen(skb)); 45 baseoff = ip_hdrlen(skb) + th->doff * 4; 46 matchoff += dataoff - baseoff; 47 48 if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo, 49 matchoff, matchlen, 50 buffer, buflen, false)) 51 return 0; 52 } else { 53 baseoff = ip_hdrlen(skb) + sizeof(struct udphdr); 54 matchoff += dataoff - baseoff; 55 56 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, 57 matchoff, matchlen, 58 buffer, buflen)) 59 return 0; 60 } 61 62 /* Reload data pointer and adjust datalen value */ 63 *dptr = skb->data + dataoff; 64 *datalen += buflen - matchlen; 65 return 1; 66} 67 68static int map_addr(struct sk_buff *skb, unsigned int dataoff, 69 const char **dptr, unsigned int *datalen, 70 unsigned int matchoff, unsigned int matchlen, 71 union nf_inet_addr *addr, __be16 port) 72{ 73 enum ip_conntrack_info ctinfo; 74 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 75 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 76 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; 77 unsigned int buflen; 78 __be32 newaddr; 79 __be16 newport; 80 81 if (ct->tuplehash[dir].tuple.src.u3.ip == addr->ip && 82 ct->tuplehash[dir].tuple.src.u.udp.port == port) { 83 newaddr = ct->tuplehash[!dir].tuple.dst.u3.ip; 84 newport = ct->tuplehash[!dir].tuple.dst.u.udp.port; 85 } else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip && 86 ct->tuplehash[dir].tuple.dst.u.udp.port == port) { 87 newaddr = ct->tuplehash[!dir].tuple.src.u3.ip; 88 newport = ct->tuplehash[!dir].tuple.src.u.udp.port; 89 } else 90 return 1; 91 92 if (newaddr == addr->ip && newport == port) 93 return 1; 94 95 buflen = sprintf(buffer, "%pI4:%u", &newaddr, ntohs(newport)); 96 97 return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen, 98 buffer, buflen); 99} 100 101static int map_sip_addr(struct sk_buff *skb, unsigned int dataoff, 102 const char **dptr, unsigned int *datalen, 103 enum sip_header_types type) 104{ 105 enum ip_conntrack_info ctinfo; 106 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 107 unsigned int matchlen, matchoff; 108 union nf_inet_addr addr; 109 __be16 port; 110 111 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL, 112 &matchoff, &matchlen, &addr, &port) <= 0) 113 return 1; 114 return map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, 115 &addr, port); 116} 117 118static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, 119 const char **dptr, unsigned int *datalen) 120{ 121 enum ip_conntrack_info ctinfo; 122 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 123 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 124 unsigned int coff, matchoff, matchlen; 125 enum sip_header_types hdr; 126 union nf_inet_addr addr; 127 __be16 port; 128 int request, in_header; 129 130 /* Basic rules: requests and responses. */ 131 if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { 132 if (ct_sip_parse_request(ct, *dptr, *datalen, 133 &matchoff, &matchlen, 134 &addr, &port) > 0 && 135 !map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, 136 &addr, port)) 137 return NF_DROP; 138 request = 1; 139 } else 140 request = 0; 141 142 if (nf_ct_protonum(ct) == IPPROTO_TCP) 143 hdr = SIP_HDR_VIA_TCP; 144 else 145 hdr = SIP_HDR_VIA_UDP; 146 147 /* Translate topmost Via header and parameters */ 148 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, 149 hdr, NULL, &matchoff, &matchlen, 150 &addr, &port) > 0) { 151 unsigned int matchend, poff, plen, buflen, n; 152 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; 153 154 /* We're only interested in headers related to this 155 * connection */ 156 if (request) { 157 if (addr.ip != ct->tuplehash[dir].tuple.src.u3.ip || 158 port != ct->tuplehash[dir].tuple.src.u.udp.port) 159 goto next; 160 } else { 161 if (addr.ip != ct->tuplehash[dir].tuple.dst.u3.ip || 162 port != ct->tuplehash[dir].tuple.dst.u.udp.port) 163 goto next; 164 } 165 166 if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, 167 &addr, port)) 168 return NF_DROP; 169 170 matchend = matchoff + matchlen; 171 172 /* The maddr= parameter (RFC 2361) specifies where to send 173 * the reply. */ 174 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, 175 "maddr=", &poff, &plen, 176 &addr) > 0 && 177 addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && 178 addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { 179 buflen = sprintf(buffer, "%pI4", 180 &ct->tuplehash[!dir].tuple.dst.u3.ip); 181 if (!mangle_packet(skb, dataoff, dptr, datalen, 182 poff, plen, buffer, buflen)) 183 return NF_DROP; 184 } 185 186 /* The received= parameter (RFC 2361) contains the address 187 * from which the server received the request. */ 188 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, 189 "received=", &poff, &plen, 190 &addr) > 0 && 191 addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && 192 addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { 193 buflen = sprintf(buffer, "%pI4", 194 &ct->tuplehash[!dir].tuple.src.u3.ip); 195 if (!mangle_packet(skb, dataoff, dptr, datalen, 196 poff, plen, buffer, buflen)) 197 return NF_DROP; 198 } 199 200 /* The rport= parameter (RFC 3581) contains the port number 201 * from which the server received the request. */ 202 if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, 203 "rport=", &poff, &plen, 204 &n) > 0 && 205 htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && 206 htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { 207 __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; 208 buflen = sprintf(buffer, "%u", ntohs(p)); 209 if (!mangle_packet(skb, dataoff, dptr, datalen, 210 poff, plen, buffer, buflen)) 211 return NF_DROP; 212 } 213 } 214 215next: 216 /* Translate Contact headers */ 217 coff = 0; 218 in_header = 0; 219 while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen, 220 SIP_HDR_CONTACT, &in_header, 221 &matchoff, &matchlen, 222 &addr, &port) > 0) { 223 if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen, 224 &addr, port)) 225 return NF_DROP; 226 } 227 228 if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) || 229 !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO)) 230 return NF_DROP; 231 232 return NF_ACCEPT; 233} 234 235static void ip_nat_sip_seq_adjust(struct sk_buff *skb, s16 off) 236{ 237 enum ip_conntrack_info ctinfo; 238 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 239 const struct tcphdr *th; 240 241 if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0) 242 return; 243 244 th = (struct tcphdr *)(skb->data + ip_hdrlen(skb)); 245 nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); 246} 247 248/* Handles expected signalling connections and media streams */ 249static void ip_nat_sip_expected(struct nf_conn *ct, 250 struct nf_conntrack_expect *exp) 251{ 252 struct nf_nat_range range; 253 254 /* This must be a fresh one. */ 255 BUG_ON(ct->status & IPS_NAT_DONE_MASK); 256 257 /* For DST manip, map port here to where it's expected. */ 258 range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); 259 range.min = range.max = exp->saved_proto; 260 range.min_ip = range.max_ip = exp->saved_ip; 261 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); 262 263 /* Change src to where master sends to, but only if the connection 264 * actually came from the same source. */ 265 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 266 ct->master->tuplehash[exp->dir].tuple.src.u3.ip) { 267 range.flags = IP_NAT_RANGE_MAP_IPS; 268 range.min_ip = range.max_ip 269 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; 270 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); 271 } 272} 273 274static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff, 275 const char **dptr, unsigned int *datalen, 276 struct nf_conntrack_expect *exp, 277 unsigned int matchoff, 278 unsigned int matchlen) 279{ 280 enum ip_conntrack_info ctinfo; 281 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 282 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 283 __be32 newip; 284 u_int16_t port; 285 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; 286 unsigned buflen; 287 288 /* Connection will come from reply */ 289 if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip) 290 newip = exp->tuple.dst.u3.ip; 291 else 292 newip = ct->tuplehash[!dir].tuple.dst.u3.ip; 293 294 /* If the signalling port matches the connection's source port in the 295 * original direction, try to use the destination port in the opposite 296 * direction. */ 297 if (exp->tuple.dst.u.udp.port == 298 ct->tuplehash[dir].tuple.src.u.udp.port) 299 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); 300 else 301 port = ntohs(exp->tuple.dst.u.udp.port); 302 303 exp->saved_ip = exp->tuple.dst.u3.ip; 304 exp->tuple.dst.u3.ip = newip; 305 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; 306 exp->dir = !dir; 307 exp->expectfn = ip_nat_sip_expected; 308 309 for (; port != 0; port++) { 310 exp->tuple.dst.u.udp.port = htons(port); 311 if (nf_ct_expect_related(exp) == 0) 312 break; 313 } 314 315 if (port == 0) 316 return NF_DROP; 317 318 if (exp->tuple.dst.u3.ip != exp->saved_ip || 319 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { 320 buflen = sprintf(buffer, "%pI4:%u", &newip, port); 321 if (!mangle_packet(skb, dataoff, dptr, datalen, 322 matchoff, matchlen, buffer, buflen)) 323 goto err; 324 } 325 return NF_ACCEPT; 326 327err: 328 nf_ct_unexpect_related(exp); 329 return NF_DROP; 330} 331 332static int mangle_content_len(struct sk_buff *skb, unsigned int dataoff, 333 const char **dptr, unsigned int *datalen) 334{ 335 enum ip_conntrack_info ctinfo; 336 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 337 unsigned int matchoff, matchlen; 338 char buffer[sizeof("65536")]; 339 int buflen, c_len; 340 341 /* Get actual SDP length */ 342 if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, 343 SDP_HDR_VERSION, SDP_HDR_UNSPEC, 344 &matchoff, &matchlen) <= 0) 345 return 0; 346 c_len = *datalen - matchoff + strlen("v="); 347 348 /* Now, update SDP length */ 349 if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH, 350 &matchoff, &matchlen) <= 0) 351 return 0; 352 353 buflen = sprintf(buffer, "%u", c_len); 354 return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen, 355 buffer, buflen); 356} 357 358static int mangle_sdp_packet(struct sk_buff *skb, unsigned int dataoff, 359 const char **dptr, unsigned int *datalen, 360 unsigned int sdpoff, 361 enum sdp_header_types type, 362 enum sdp_header_types term, 363 char *buffer, int buflen) 364{ 365 enum ip_conntrack_info ctinfo; 366 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 367 unsigned int matchlen, matchoff; 368 369 if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term, 370 &matchoff, &matchlen) <= 0) 371 return -ENOENT; 372 return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen, 373 buffer, buflen) ? 0 : -EINVAL; 374} 375 376static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, unsigned int dataoff, 377 const char **dptr, unsigned int *datalen, 378 unsigned int sdpoff, 379 enum sdp_header_types type, 380 enum sdp_header_types term, 381 const union nf_inet_addr *addr) 382{ 383 char buffer[sizeof("nnn.nnn.nnn.nnn")]; 384 unsigned int buflen; 385 386 buflen = sprintf(buffer, "%pI4", &addr->ip); 387 if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, type, term, 388 buffer, buflen)) 389 return 0; 390 391 return mangle_content_len(skb, dataoff, dptr, datalen); 392} 393 394static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int dataoff, 395 const char **dptr, unsigned int *datalen, 396 unsigned int matchoff, 397 unsigned int matchlen, 398 u_int16_t port) 399{ 400 char buffer[sizeof("nnnnn")]; 401 unsigned int buflen; 402 403 buflen = sprintf(buffer, "%u", port); 404 if (!mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen, 405 buffer, buflen)) 406 return 0; 407 408 return mangle_content_len(skb, dataoff, dptr, datalen); 409} 410 411static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int dataoff, 412 const char **dptr, unsigned int *datalen, 413 unsigned int sdpoff, 414 const union nf_inet_addr *addr) 415{ 416 char buffer[sizeof("nnn.nnn.nnn.nnn")]; 417 unsigned int buflen; 418 419 /* Mangle session description owner and contact addresses */ 420 buflen = sprintf(buffer, "%pI4", &addr->ip); 421 if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, 422 SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA, 423 buffer, buflen)) 424 return 0; 425 426 switch (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, 427 SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA, 428 buffer, buflen)) { 429 case 0: 430 /* 431 * RFC 2327: 432 * 433 * Session description 434 * 435 * c=* (connection information - not required if included in all media) 436 */ 437 case -ENOENT: 438 break; 439 default: 440 return 0; 441 } 442 443 return mangle_content_len(skb, dataoff, dptr, datalen); 444} 445 446/* So, this packet has hit the connection tracking matching code. 447 Mangle it, and change the expectation to match the new version. */ 448static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff, 449 const char **dptr, unsigned int *datalen, 450 struct nf_conntrack_expect *rtp_exp, 451 struct nf_conntrack_expect *rtcp_exp, 452 unsigned int mediaoff, 453 unsigned int medialen, 454 union nf_inet_addr *rtp_addr) 455{ 456 enum ip_conntrack_info ctinfo; 457 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 458 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 459 u_int16_t port; 460 461 /* Connection will come from reply */ 462 if (ct->tuplehash[dir].tuple.src.u3.ip == 463 ct->tuplehash[!dir].tuple.dst.u3.ip) 464 rtp_addr->ip = rtp_exp->tuple.dst.u3.ip; 465 else 466 rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip; 467 468 rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; 469 rtp_exp->tuple.dst.u3.ip = rtp_addr->ip; 470 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; 471 rtp_exp->dir = !dir; 472 rtp_exp->expectfn = ip_nat_sip_expected; 473 474 rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; 475 rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip; 476 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; 477 rtcp_exp->dir = !dir; 478 rtcp_exp->expectfn = ip_nat_sip_expected; 479 480 /* Try to get same pair of ports: if not, try to change them. */ 481 for (port = ntohs(rtp_exp->tuple.dst.u.udp.port); 482 port != 0; port += 2) { 483 rtp_exp->tuple.dst.u.udp.port = htons(port); 484 if (nf_ct_expect_related(rtp_exp) != 0) 485 continue; 486 rtcp_exp->tuple.dst.u.udp.port = htons(port + 1); 487 if (nf_ct_expect_related(rtcp_exp) == 0) 488 break; 489 nf_ct_unexpect_related(rtp_exp); 490 } 491 492 if (port == 0) 493 goto err1; 494 495 /* Update media port. */ 496 if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port && 497 !ip_nat_sdp_port(skb, dataoff, dptr, datalen, 498 mediaoff, medialen, port)) 499 goto err2; 500 501 return NF_ACCEPT; 502 503err2: 504 nf_ct_unexpect_related(rtp_exp); 505 nf_ct_unexpect_related(rtcp_exp); 506err1: 507 return NF_DROP; 508} 509 510static void __exit nf_nat_sip_fini(void) 511{ 512 rcu_assign_pointer(nf_nat_sip_hook, NULL); 513 rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, NULL); 514 rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); 515 rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); 516 rcu_assign_pointer(nf_nat_sdp_port_hook, NULL); 517 rcu_assign_pointer(nf_nat_sdp_session_hook, NULL); 518 rcu_assign_pointer(nf_nat_sdp_media_hook, NULL); 519 synchronize_rcu(); 520} 521 522static int __init nf_nat_sip_init(void) 523{ 524 BUG_ON(nf_nat_sip_hook != NULL); 525 BUG_ON(nf_nat_sip_seq_adjust_hook != NULL); 526 BUG_ON(nf_nat_sip_expect_hook != NULL); 527 BUG_ON(nf_nat_sdp_addr_hook != NULL); 528 BUG_ON(nf_nat_sdp_port_hook != NULL); 529 BUG_ON(nf_nat_sdp_session_hook != NULL); 530 BUG_ON(nf_nat_sdp_media_hook != NULL); 531 rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); 532 rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, ip_nat_sip_seq_adjust); 533 rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); 534 rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); 535 rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port); 536 rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session); 537 rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media); 538 return 0; 539} 540 541module_init(nf_nat_sip_init); 542module_exit(nf_nat_sip_fini); 543