1/*- 2 * Copyright (c) 2001 Charles Mott <cm@linktel.net> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/11/sys/netinet/libalias/alias.c 360971 2020-05-12 16:49:04Z emaste $"); 29 30/* 31 Alias.c provides supervisory control for the functions of the 32 packet aliasing software. It consists of routines to monitor 33 TCP connection state, protocol-specific aliasing routines, 34 fragment handling and the following outside world functional 35 interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn, 36 PacketAliasIn and PacketAliasOut. 37 38 The other C program files are briefly described. The data 39 structure framework which holds information needed to translate 40 packets is encapsulated in alias_db.c. Data is accessed by 41 function calls, so other segments of the program need not know 42 about the underlying data structures. Alias_ftp.c contains 43 special code for modifying the ftp PORT command used to establish 44 data connections, while alias_irc.c does the same for IRC 45 DCC. Alias_util.c contains a few utility routines. 46 47 Version 1.0 August, 1996 (cjm) 48 49 Version 1.1 August 20, 1996 (cjm) 50 PPP host accepts incoming connections for ports 0 to 1023. 51 (Gary Roberts pointed out the need to handle incoming 52 connections.) 53 54 Version 1.2 September 7, 1996 (cjm) 55 Fragment handling error in alias_db.c corrected. 56 (Tom Torrance helped fix this problem.) 57 58 Version 1.4 September 16, 1996 (cjm) 59 - A more generalized method for handling incoming 60 connections, without the 0-1023 restriction, is 61 implemented in alias_db.c 62 - Improved ICMP support in alias.c. Traceroute 63 packet streams can now be correctly aliased. 64 - TCP connection closing logic simplified in 65 alias.c and now allows for additional 1 minute 66 "grace period" after FIN or RST is observed. 67 68 Version 1.5 September 17, 1996 (cjm) 69 Corrected error in handling incoming UDP packets with 0 checksum. 70 (Tom Torrance helped fix this problem.) 71 72 Version 1.6 September 18, 1996 (cjm) 73 Simplified ICMP aliasing scheme. Should now support 74 traceroute from Win95 as well as FreeBSD. 75 76 Version 1.7 January 9, 1997 (cjm) 77 - Out-of-order fragment handling. 78 - IP checksum error fixed for ftp transfers 79 from aliasing host. 80 - Integer return codes added to all 81 aliasing/de-aliasing functions. 82 - Some obsolete comments cleaned up. 83 - Differential checksum computations for 84 IP header (TCP, UDP and ICMP were already 85 differential). 86 87 Version 2.1 May 1997 (cjm) 88 - Added support for outgoing ICMP error 89 messages. 90 - Added two functions PacketAliasIn2() 91 and PacketAliasOut2() for dynamic address 92 control (e.g. round-robin allocation of 93 incoming packets). 94 95 Version 2.2 July 1997 (cjm) 96 - Rationalized API function names to begin 97 with "PacketAlias..." 98 - Eliminated PacketAliasIn2() and 99 PacketAliasOut2() as poorly conceived. 100 101 Version 2.3 Dec 1998 (dillon) 102 - Major bounds checking additions, see FreeBSD/CVS 103 104 Version 3.1 May, 2000 (salander) 105 - Added hooks to handle PPTP. 106 107 Version 3.2 July, 2000 (salander and satoh) 108 - Added PacketUnaliasOut routine. 109 - Added hooks to handle RTSP/RTP. 110 111 See HISTORY file for additional revisions. 112*/ 113 114#ifdef _KERNEL 115#include <sys/param.h> 116#include <sys/systm.h> 117#include <sys/mbuf.h> 118#include <sys/sysctl.h> 119#else 120#include <sys/types.h> 121#include <stdlib.h> 122#include <stdio.h> 123#include <ctype.h> 124#include <dlfcn.h> 125#include <errno.h> 126#include <string.h> 127#endif 128 129#include <netinet/in_systm.h> 130#include <netinet/in.h> 131#include <netinet/ip.h> 132#include <netinet/ip_icmp.h> 133#include <netinet/tcp.h> 134#include <netinet/udp.h> 135 136#ifdef _KERNEL 137#include <netinet/libalias/alias.h> 138#include <netinet/libalias/alias_local.h> 139#include <netinet/libalias/alias_mod.h> 140#else 141#include <err.h> 142#include "alias.h" 143#include "alias_local.h" 144#include "alias_mod.h" 145#endif 146 147/* 148 * Define libalias SYSCTL Node 149 */ 150#ifdef SYSCTL_NODE 151 152SYSCTL_DECL(_net_inet); 153SYSCTL_DECL(_net_inet_ip); 154SYSCTL_NODE(_net_inet_ip, OID_AUTO, alias, CTLFLAG_RW, NULL, "Libalias sysctl API"); 155 156#endif 157 158static __inline int 159twowords(void *p) 160{ 161 uint8_t *c = p; 162 163#if BYTE_ORDER == LITTLE_ENDIAN 164 uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0]; 165 uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2]; 166#else 167 uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1]; 168 uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3]; 169#endif 170 return (s1 + s2); 171} 172 173/* TCP Handling Routines 174 175 TcpMonitorIn() -- These routines monitor TCP connections, and 176 TcpMonitorOut() delete a link when a connection is closed. 177 178These routines look for SYN, FIN and RST flags to determine when TCP 179connections open and close. When a TCP connection closes, the data 180structure containing packet aliasing information is deleted after 181a timeout period. 182*/ 183 184/* Local prototypes */ 185static void TcpMonitorIn(u_char, struct alias_link *); 186 187static void TcpMonitorOut(u_char, struct alias_link *); 188 189 190static void 191TcpMonitorIn(u_char th_flags, struct alias_link *lnk) 192{ 193 194 switch (GetStateIn(lnk)) { 195 case ALIAS_TCP_STATE_NOT_CONNECTED: 196 if (th_flags & TH_RST) 197 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED); 198 else if (th_flags & TH_SYN) 199 SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED); 200 break; 201 case ALIAS_TCP_STATE_CONNECTED: 202 if (th_flags & (TH_FIN | TH_RST)) 203 SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED); 204 break; 205 } 206} 207 208static void 209TcpMonitorOut(u_char th_flags, struct alias_link *lnk) 210{ 211 212 switch (GetStateOut(lnk)) { 213 case ALIAS_TCP_STATE_NOT_CONNECTED: 214 if (th_flags & TH_RST) 215 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED); 216 else if (th_flags & TH_SYN) 217 SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED); 218 break; 219 case ALIAS_TCP_STATE_CONNECTED: 220 if (th_flags & (TH_FIN | TH_RST)) 221 SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED); 222 break; 223 } 224} 225 226 227 228 229 230/* Protocol Specific Packet Aliasing Routines 231 232 IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2() 233 IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2() 234 ProtoAliasIn(), ProtoAliasOut() 235 UdpAliasIn(), UdpAliasOut() 236 TcpAliasIn(), TcpAliasOut() 237 238These routines handle protocol specific details of packet aliasing. 239One may observe a certain amount of repetitive arithmetic in these 240functions, the purpose of which is to compute a revised checksum 241without actually summing over the entire data packet, which could be 242unnecessarily time consuming. 243 244The purpose of the packet aliasing routines is to replace the source 245address of the outgoing packet and then correctly put it back for 246any incoming packets. For TCP and UDP, ports are also re-mapped. 247 248For ICMP echo/timestamp requests and replies, the following scheme 249is used: the ID number is replaced by an alias for the outgoing 250packet. 251 252ICMP error messages are handled by looking at the IP fragment 253in the data section of the message. 254 255For TCP and UDP protocols, a port number is chosen for an outgoing 256packet, and then incoming packets are identified by IP address and 257port numbers. For TCP packets, there is additional logic in the event 258that sequence and ACK numbers have been altered (as in the case for 259FTP data port commands). 260 261The port numbers used by the packet aliasing module are not true 262ports in the Unix sense. No sockets are actually bound to ports. 263They are more correctly thought of as placeholders. 264 265All packets go through the aliasing mechanism, whether they come from 266the gateway machine or other machines on a local area network. 267*/ 268 269 270/* Local prototypes */ 271static int IcmpAliasIn1(struct libalias *, struct ip *); 272static int IcmpAliasIn2(struct libalias *, struct ip *); 273static int IcmpAliasIn(struct libalias *, struct ip *); 274 275static int IcmpAliasOut1(struct libalias *, struct ip *, int create); 276static int IcmpAliasOut2(struct libalias *, struct ip *); 277static int IcmpAliasOut(struct libalias *, struct ip *, int create); 278 279static int ProtoAliasIn(struct libalias *la, struct in_addr ip_src, 280 struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum); 281static int ProtoAliasOut(struct libalias *la, struct in_addr *ip_src, 282 struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, 283 int create); 284 285static int UdpAliasIn(struct libalias *, struct ip *); 286static int UdpAliasOut(struct libalias *, struct ip *, int, int create); 287 288static int TcpAliasIn(struct libalias *, struct ip *); 289static int TcpAliasOut(struct libalias *, struct ip *, int, int create); 290 291 292static int 293IcmpAliasIn1(struct libalias *la, struct ip *pip) 294{ 295 296 LIBALIAS_LOCK_ASSERT(la); 297/* 298 De-alias incoming echo and timestamp replies. 299 Alias incoming echo and timestamp requests. 300*/ 301 struct alias_link *lnk; 302 struct icmp *ic; 303 304 ic = (struct icmp *)ip_next(pip); 305 306/* Get source address from ICMP data field and restore original data */ 307 lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1); 308 if (lnk != NULL) { 309 u_short original_id; 310 int accumulate; 311 312 original_id = GetOriginalPort(lnk); 313 314/* Adjust ICMP checksum */ 315 accumulate = ic->icmp_id; 316 accumulate -= original_id; 317 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 318 319/* Put original sequence number back in */ 320 ic->icmp_id = original_id; 321 322/* Put original address back into IP header */ 323 { 324 struct in_addr original_address; 325 326 original_address = GetOriginalAddress(lnk); 327 DifferentialChecksum(&pip->ip_sum, 328 &original_address, &pip->ip_dst, 2); 329 pip->ip_dst = original_address; 330 } 331 332 return (PKT_ALIAS_OK); 333 } 334 return (PKT_ALIAS_IGNORED); 335} 336 337static int 338IcmpAliasIn2(struct libalias *la, struct ip *pip) 339{ 340 341 LIBALIAS_LOCK_ASSERT(la); 342/* 343 Alias incoming ICMP error messages containing 344 IP header and first 64 bits of datagram. 345*/ 346 struct ip *ip; 347 struct icmp *ic, *ic2; 348 struct udphdr *ud; 349 struct tcphdr *tc; 350 struct alias_link *lnk; 351 352 ic = (struct icmp *)ip_next(pip); 353 ip = &ic->icmp_ip; 354 355 ud = (struct udphdr *)ip_next(ip); 356 tc = (struct tcphdr *)ip_next(ip); 357 ic2 = (struct icmp *)ip_next(ip); 358 359 if (ip->ip_p == IPPROTO_UDP) 360 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src, 361 ud->uh_dport, ud->uh_sport, 362 IPPROTO_UDP, 0); 363 else if (ip->ip_p == IPPROTO_TCP) 364 lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src, 365 tc->th_dport, tc->th_sport, 366 IPPROTO_TCP, 0); 367 else if (ip->ip_p == IPPROTO_ICMP) { 368 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) 369 lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0); 370 else 371 lnk = NULL; 372 } else 373 lnk = NULL; 374 375 if (lnk != NULL) { 376 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) { 377 int accumulate, accumulate2; 378 struct in_addr original_address; 379 u_short original_port; 380 381 original_address = GetOriginalAddress(lnk); 382 original_port = GetOriginalPort(lnk); 383 384/* Adjust ICMP checksum */ 385 accumulate = twowords(&ip->ip_src); 386 accumulate -= twowords(&original_address); 387 accumulate += ud->uh_sport; 388 accumulate -= original_port; 389 accumulate2 = accumulate; 390 accumulate2 += ip->ip_sum; 391 ADJUST_CHECKSUM(accumulate, ip->ip_sum); 392 accumulate2 -= ip->ip_sum; 393 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum); 394 395/* Un-alias address in IP header */ 396 DifferentialChecksum(&pip->ip_sum, 397 &original_address, &pip->ip_dst, 2); 398 pip->ip_dst = original_address; 399 400/* Un-alias address and port number of original IP packet 401fragment contained in ICMP data section */ 402 ip->ip_src = original_address; 403 ud->uh_sport = original_port; 404 } else if (ip->ip_p == IPPROTO_ICMP) { 405 int accumulate, accumulate2; 406 struct in_addr original_address; 407 u_short original_id; 408 409 original_address = GetOriginalAddress(lnk); 410 original_id = GetOriginalPort(lnk); 411 412/* Adjust ICMP checksum */ 413 accumulate = twowords(&ip->ip_src); 414 accumulate -= twowords(&original_address); 415 accumulate += ic2->icmp_id; 416 accumulate -= original_id; 417 accumulate2 = accumulate; 418 accumulate2 += ip->ip_sum; 419 ADJUST_CHECKSUM(accumulate, ip->ip_sum); 420 accumulate2 -= ip->ip_sum; 421 ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum); 422 423/* Un-alias address in IP header */ 424 DifferentialChecksum(&pip->ip_sum, 425 &original_address, &pip->ip_dst, 2); 426 pip->ip_dst = original_address; 427 428/* Un-alias address of original IP packet and sequence number of 429 embedded ICMP datagram */ 430 ip->ip_src = original_address; 431 ic2->icmp_id = original_id; 432 } 433 return (PKT_ALIAS_OK); 434 } 435 return (PKT_ALIAS_IGNORED); 436} 437 438 439static int 440IcmpAliasIn(struct libalias *la, struct ip *pip) 441{ 442 struct icmp *ic; 443 int dlen, iresult; 444 445 LIBALIAS_LOCK_ASSERT(la); 446 447 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 448 if (dlen < ICMP_MINLEN) 449 return (PKT_ALIAS_IGNORED); 450 451/* Return if proxy-only mode is enabled */ 452 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) 453 return (PKT_ALIAS_OK); 454 455 ic = (struct icmp *)ip_next(pip); 456 457 iresult = PKT_ALIAS_IGNORED; 458 switch (ic->icmp_type) { 459 case ICMP_ECHOREPLY: 460 case ICMP_TSTAMPREPLY: 461 if (ic->icmp_code == 0) { 462 iresult = IcmpAliasIn1(la, pip); 463 } 464 break; 465 case ICMP_UNREACH: 466 case ICMP_SOURCEQUENCH: 467 case ICMP_TIMXCEED: 468 case ICMP_PARAMPROB: 469 if (dlen < ICMP_ADVLENMIN || 470 dlen < ICMP_ADVLEN(ic)) 471 return (PKT_ALIAS_IGNORED); 472 iresult = IcmpAliasIn2(la, pip); 473 break; 474 case ICMP_ECHO: 475 case ICMP_TSTAMP: 476 iresult = IcmpAliasIn1(la, pip); 477 break; 478 } 479 return (iresult); 480} 481 482 483static int 484IcmpAliasOut1(struct libalias *la, struct ip *pip, int create) 485{ 486/* 487 Alias outgoing echo and timestamp requests. 488 De-alias outgoing echo and timestamp replies. 489*/ 490 struct alias_link *lnk; 491 struct icmp *ic; 492 493 LIBALIAS_LOCK_ASSERT(la); 494 ic = (struct icmp *)ip_next(pip); 495 496/* Save overwritten data for when echo packet returns */ 497 lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create); 498 if (lnk != NULL) { 499 u_short alias_id; 500 int accumulate; 501 502 alias_id = GetAliasPort(lnk); 503 504/* Since data field is being modified, adjust ICMP checksum */ 505 accumulate = ic->icmp_id; 506 accumulate -= alias_id; 507 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 508 509/* Alias sequence number */ 510 ic->icmp_id = alias_id; 511 512/* Change source address */ 513 { 514 struct in_addr alias_address; 515 516 alias_address = GetAliasAddress(lnk); 517 DifferentialChecksum(&pip->ip_sum, 518 &alias_address, &pip->ip_src, 2); 519 pip->ip_src = alias_address; 520 } 521 522 return (PKT_ALIAS_OK); 523 } 524 return (PKT_ALIAS_IGNORED); 525} 526 527 528static int 529IcmpAliasOut2(struct libalias *la, struct ip *pip) 530{ 531/* 532 Alias outgoing ICMP error messages containing 533 IP header and first 64 bits of datagram. 534*/ 535 struct ip *ip; 536 struct icmp *ic, *ic2; 537 struct udphdr *ud; 538 struct tcphdr *tc; 539 struct alias_link *lnk; 540 541 LIBALIAS_LOCK_ASSERT(la); 542 ic = (struct icmp *)ip_next(pip); 543 ip = &ic->icmp_ip; 544 545 ud = (struct udphdr *)ip_next(ip); 546 tc = (struct tcphdr *)ip_next(ip); 547 ic2 = (struct icmp *)ip_next(ip); 548 549 if (ip->ip_p == IPPROTO_UDP) 550 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src, 551 ud->uh_dport, ud->uh_sport, 552 IPPROTO_UDP, 0); 553 else if (ip->ip_p == IPPROTO_TCP) 554 lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src, 555 tc->th_dport, tc->th_sport, 556 IPPROTO_TCP, 0); 557 else if (ip->ip_p == IPPROTO_ICMP) { 558 if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP) 559 lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0); 560 else 561 lnk = NULL; 562 } else 563 lnk = NULL; 564 565 if (lnk != NULL) { 566 if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) { 567 int accumulate; 568 struct in_addr alias_address; 569 u_short alias_port; 570 571 alias_address = GetAliasAddress(lnk); 572 alias_port = GetAliasPort(lnk); 573 574/* Adjust ICMP checksum */ 575 accumulate = twowords(&ip->ip_dst); 576 accumulate -= twowords(&alias_address); 577 accumulate += ud->uh_dport; 578 accumulate -= alias_port; 579 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 580 581/* 582 * Alias address in IP header if it comes from the host 583 * the original TCP/UDP packet was destined for. 584 */ 585 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) { 586 DifferentialChecksum(&pip->ip_sum, 587 &alias_address, &pip->ip_src, 2); 588 pip->ip_src = alias_address; 589 } 590/* Alias address and port number of original IP packet 591fragment contained in ICMP data section */ 592 ip->ip_dst = alias_address; 593 ud->uh_dport = alias_port; 594 } else if (ip->ip_p == IPPROTO_ICMP) { 595 int accumulate; 596 struct in_addr alias_address; 597 u_short alias_id; 598 599 alias_address = GetAliasAddress(lnk); 600 alias_id = GetAliasPort(lnk); 601 602/* Adjust ICMP checksum */ 603 accumulate = twowords(&ip->ip_dst); 604 accumulate -= twowords(&alias_address); 605 accumulate += ic2->icmp_id; 606 accumulate -= alias_id; 607 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 608 609/* 610 * Alias address in IP header if it comes from the host 611 * the original ICMP message was destined for. 612 */ 613 if (pip->ip_src.s_addr == ip->ip_dst.s_addr) { 614 DifferentialChecksum(&pip->ip_sum, 615 &alias_address, &pip->ip_src, 2); 616 pip->ip_src = alias_address; 617 } 618/* Alias address of original IP packet and sequence number of 619 embedded ICMP datagram */ 620 ip->ip_dst = alias_address; 621 ic2->icmp_id = alias_id; 622 } 623 return (PKT_ALIAS_OK); 624 } 625 return (PKT_ALIAS_IGNORED); 626} 627 628 629static int 630IcmpAliasOut(struct libalias *la, struct ip *pip, int create) 631{ 632 int iresult; 633 struct icmp *ic; 634 635 LIBALIAS_LOCK_ASSERT(la); 636 (void)create; 637 638/* Return if proxy-only mode is enabled */ 639 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) 640 return (PKT_ALIAS_OK); 641 642 ic = (struct icmp *)ip_next(pip); 643 644 iresult = PKT_ALIAS_IGNORED; 645 switch (ic->icmp_type) { 646 case ICMP_ECHO: 647 case ICMP_TSTAMP: 648 if (ic->icmp_code == 0) { 649 iresult = IcmpAliasOut1(la, pip, create); 650 } 651 break; 652 case ICMP_UNREACH: 653 case ICMP_SOURCEQUENCH: 654 case ICMP_TIMXCEED: 655 case ICMP_PARAMPROB: 656 iresult = IcmpAliasOut2(la, pip); 657 break; 658 case ICMP_ECHOREPLY: 659 case ICMP_TSTAMPREPLY: 660 iresult = IcmpAliasOut1(la, pip, create); 661 } 662 return (iresult); 663} 664 665static int 666ProtoAliasIn(struct libalias *la, struct in_addr ip_src, 667 struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum) 668{ 669/* 670 Handle incoming IP packets. The 671 only thing which is done in this case is to alias 672 the dest IP address of the packet to our inside 673 machine. 674*/ 675 struct alias_link *lnk; 676 677 LIBALIAS_LOCK_ASSERT(la); 678/* Return if proxy-only mode is enabled */ 679 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) 680 return (PKT_ALIAS_OK); 681 682 lnk = FindProtoIn(la, ip_src, *ip_dst, ip_p); 683 if (lnk != NULL) { 684 struct in_addr original_address; 685 686 original_address = GetOriginalAddress(lnk); 687 688/* Restore original IP address */ 689 DifferentialChecksum(ip_sum, 690 &original_address, ip_dst, 2); 691 *ip_dst = original_address; 692 693 return (PKT_ALIAS_OK); 694 } 695 return (PKT_ALIAS_IGNORED); 696} 697 698static int 699ProtoAliasOut(struct libalias *la, struct in_addr *ip_src, 700 struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create) 701{ 702/* 703 Handle outgoing IP packets. The 704 only thing which is done in this case is to alias 705 the source IP address of the packet. 706*/ 707 struct alias_link *lnk; 708 709 LIBALIAS_LOCK_ASSERT(la); 710 711/* Return if proxy-only mode is enabled */ 712 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) 713 return (PKT_ALIAS_OK); 714 715 if (!create) 716 return (PKT_ALIAS_IGNORED); 717 718 lnk = FindProtoOut(la, *ip_src, ip_dst, ip_p); 719 if (lnk != NULL) { 720 struct in_addr alias_address; 721 722 alias_address = GetAliasAddress(lnk); 723 724/* Change source address */ 725 DifferentialChecksum(ip_sum, 726 &alias_address, ip_src, 2); 727 *ip_src = alias_address; 728 729 return (PKT_ALIAS_OK); 730 } 731 return (PKT_ALIAS_IGNORED); 732} 733 734 735static int 736UdpAliasIn(struct libalias *la, struct ip *pip) 737{ 738 struct udphdr *ud; 739 struct alias_link *lnk; 740 int dlen; 741 742 LIBALIAS_LOCK_ASSERT(la); 743 744 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 745 if (dlen < sizeof(struct udphdr)) 746 return (PKT_ALIAS_IGNORED); 747 748 ud = (struct udphdr *)ip_next(pip); 749 if (dlen < ntohs(ud->uh_ulen)) 750 return (PKT_ALIAS_IGNORED); 751 752 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst, 753 ud->uh_sport, ud->uh_dport, 754 IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)); 755 if (lnk != NULL) { 756 struct in_addr alias_address; 757 struct in_addr original_address; 758 struct in_addr proxy_address; 759 u_short alias_port; 760 u_short proxy_port; 761 int accumulate; 762 int error; 763 struct alias_data ad = { 764 .lnk = lnk, 765 .oaddr = &original_address, 766 .aaddr = &alias_address, 767 .aport = &alias_port, 768 .sport = &ud->uh_sport, 769 .dport = &ud->uh_dport, 770 .maxpktsize = 0 771 }; 772 773 alias_address = GetAliasAddress(lnk); 774 original_address = GetOriginalAddress(lnk); 775 proxy_address = GetProxyAddress(lnk); 776 alias_port = ud->uh_dport; 777 ud->uh_dport = GetOriginalPort(lnk); 778 proxy_port = GetProxyPort(lnk); 779 780 /* Walk out chain. */ 781 error = find_handler(IN, UDP, la, pip, &ad); 782 /* If we cannot figure out the packet, ignore it. */ 783 if (error < 0) 784 return (PKT_ALIAS_IGNORED); 785 786/* If UDP checksum is not zero, then adjust since destination port */ 787/* is being unaliased and destination address is being altered. */ 788 if (ud->uh_sum != 0) { 789 accumulate = alias_port; 790 accumulate -= ud->uh_dport; 791 accumulate += twowords(&alias_address); 792 accumulate -= twowords(&original_address); 793 794/* If this is a proxy packet, modify checksum because of source change.*/ 795 if (proxy_port != 0) { 796 accumulate += ud->uh_sport; 797 accumulate -= proxy_port; 798 } 799 800 if (proxy_address.s_addr != 0) { 801 accumulate += twowords(&pip->ip_src); 802 accumulate -= twowords(&proxy_address); 803 } 804 805 ADJUST_CHECKSUM(accumulate, ud->uh_sum); 806 } 807/* XXX: Could the two if's below be concatenated to one ? */ 808/* Restore source port and/or address in case of proxying*/ 809 810 if (proxy_port != 0) 811 ud->uh_sport = proxy_port; 812 813 if (proxy_address.s_addr != 0) { 814 DifferentialChecksum(&pip->ip_sum, 815 &proxy_address, &pip->ip_src, 2); 816 pip->ip_src = proxy_address; 817 } 818 819/* Restore original IP address */ 820 DifferentialChecksum(&pip->ip_sum, 821 &original_address, &pip->ip_dst, 2); 822 pip->ip_dst = original_address; 823 824 return (PKT_ALIAS_OK); 825 } 826 return (PKT_ALIAS_IGNORED); 827} 828 829static int 830UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) 831{ 832 struct udphdr *ud; 833 struct alias_link *lnk; 834 struct in_addr dest_address; 835 struct in_addr proxy_server_address; 836 u_short dest_port; 837 u_short proxy_server_port; 838 int proxy_type; 839 int dlen, error; 840 841 LIBALIAS_LOCK_ASSERT(la); 842 843/* Return if proxy-only mode is enabled and not proxyrule found.*/ 844 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 845 if (dlen < sizeof(struct udphdr)) 846 return (PKT_ALIAS_IGNORED); 847 848 ud = (struct udphdr *)ip_next(pip); 849 if (dlen < ntohs(ud->uh_ulen)) 850 return (PKT_ALIAS_IGNORED); 851 852 proxy_type = ProxyCheck(la, &proxy_server_address, 853 &proxy_server_port, pip->ip_src, pip->ip_dst, 854 ud->uh_dport, pip->ip_p); 855 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) 856 return (PKT_ALIAS_OK); 857 858/* If this is a transparent proxy, save original destination, 859 * then alter the destination and adjust checksums */ 860 dest_port = ud->uh_dport; 861 dest_address = pip->ip_dst; 862 863 if (proxy_type != 0) { 864 int accumulate; 865 866 accumulate = twowords(&pip->ip_dst); 867 accumulate -= twowords(&proxy_server_address); 868 869 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 870 871 if (ud->uh_sum != 0) { 872 accumulate = twowords(&pip->ip_dst); 873 accumulate -= twowords(&proxy_server_address); 874 accumulate += ud->uh_dport; 875 accumulate -= proxy_server_port; 876 ADJUST_CHECKSUM(accumulate, ud->uh_sum); 877 } 878 pip->ip_dst = proxy_server_address; 879 ud->uh_dport = proxy_server_port; 880 } 881 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst, 882 ud->uh_sport, ud->uh_dport, 883 IPPROTO_UDP, create); 884 if (lnk != NULL) { 885 u_short alias_port; 886 struct in_addr alias_address; 887 struct alias_data ad = { 888 .lnk = lnk, 889 .oaddr = NULL, 890 .aaddr = &alias_address, 891 .aport = &alias_port, 892 .sport = &ud->uh_sport, 893 .dport = &ud->uh_dport, 894 .maxpktsize = 0 895 }; 896 897/* Save original destination address, if this is a proxy packet. 898 * Also modify packet to include destination encoding. This may 899 * change the size of IP header. */ 900 if (proxy_type != 0) { 901 SetProxyPort(lnk, dest_port); 902 SetProxyAddress(lnk, dest_address); 903 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type); 904 ud = (struct udphdr *)ip_next(pip); 905 } 906 907 alias_address = GetAliasAddress(lnk); 908 alias_port = GetAliasPort(lnk); 909 910 /* Walk out chain. */ 911 error = find_handler(OUT, UDP, la, pip, &ad); 912 913/* If UDP checksum is not zero, adjust since source port is */ 914/* being aliased and source address is being altered */ 915 if (ud->uh_sum != 0) { 916 int accumulate; 917 918 accumulate = ud->uh_sport; 919 accumulate -= alias_port; 920 accumulate += twowords(&pip->ip_src); 921 accumulate -= twowords(&alias_address); 922 ADJUST_CHECKSUM(accumulate, ud->uh_sum); 923 } 924/* Put alias port in UDP header */ 925 ud->uh_sport = alias_port; 926 927/* Change source address */ 928 DifferentialChecksum(&pip->ip_sum, 929 &alias_address, &pip->ip_src, 2); 930 pip->ip_src = alias_address; 931 932 return (PKT_ALIAS_OK); 933 } 934 return (PKT_ALIAS_IGNORED); 935} 936 937 938 939static int 940TcpAliasIn(struct libalias *la, struct ip *pip) 941{ 942 struct tcphdr *tc; 943 struct alias_link *lnk; 944 int dlen; 945 946 LIBALIAS_LOCK_ASSERT(la); 947 948 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 949 if (dlen < sizeof(struct tcphdr)) 950 return (PKT_ALIAS_IGNORED); 951 tc = (struct tcphdr *)ip_next(pip); 952 953 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst, 954 tc->th_sport, tc->th_dport, 955 IPPROTO_TCP, 956 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)); 957 if (lnk != NULL) { 958 struct in_addr alias_address; 959 struct in_addr original_address; 960 struct in_addr proxy_address; 961 u_short alias_port; 962 u_short proxy_port; 963 int accumulate, error; 964 965 /* 966 * The init of MANY vars is a bit below, but aliashandlepptpin 967 * seems to need the destination port that came within the 968 * packet and not the original one looks below [*]. 969 */ 970 971 struct alias_data ad = { 972 .lnk = lnk, 973 .oaddr = NULL, 974 .aaddr = NULL, 975 .aport = NULL, 976 .sport = &tc->th_sport, 977 .dport = &tc->th_dport, 978 .maxpktsize = 0 979 }; 980 981 /* Walk out chain. */ 982 error = find_handler(IN, TCP, la, pip, &ad); 983 984 alias_address = GetAliasAddress(lnk); 985 original_address = GetOriginalAddress(lnk); 986 proxy_address = GetProxyAddress(lnk); 987 alias_port = tc->th_dport; 988 tc->th_dport = GetOriginalPort(lnk); 989 proxy_port = GetProxyPort(lnk); 990 991 /* 992 * Look above, if anyone is going to add find_handler AFTER 993 * this aliashandlepptpin/point, please redo alias_data too. 994 * Uncommenting the piece here below should be enough. 995 */ 996#if 0 997 struct alias_data ad = { 998 .lnk = lnk, 999 .oaddr = &original_address, 1000 .aaddr = &alias_address, 1001 .aport = &alias_port, 1002 .sport = &ud->uh_sport, 1003 .dport = &ud->uh_dport, 1004 .maxpktsize = 0 1005 }; 1006 1007 /* Walk out chain. */ 1008 error = find_handler(la, pip, &ad); 1009 if (error == EHDNOF) 1010 printf("Protocol handler not found\n"); 1011#endif 1012 1013/* Adjust TCP checksum since destination port is being unaliased */ 1014/* and destination port is being altered. */ 1015 accumulate = alias_port; 1016 accumulate -= tc->th_dport; 1017 accumulate += twowords(&alias_address); 1018 accumulate -= twowords(&original_address); 1019 1020/* If this is a proxy, then modify the TCP source port and 1021 checksum accumulation */ 1022 if (proxy_port != 0) { 1023 accumulate += tc->th_sport; 1024 tc->th_sport = proxy_port; 1025 accumulate -= tc->th_sport; 1026 accumulate += twowords(&pip->ip_src); 1027 accumulate -= twowords(&proxy_address); 1028 } 1029/* See if ACK number needs to be modified */ 1030 if (GetAckModified(lnk) == 1) { 1031 int delta; 1032 1033 tc = (struct tcphdr *)ip_next(pip); 1034 delta = GetDeltaAckIn(tc->th_ack, lnk); 1035 if (delta != 0) { 1036 accumulate += twowords(&tc->th_ack); 1037 tc->th_ack = htonl(ntohl(tc->th_ack) - delta); 1038 accumulate -= twowords(&tc->th_ack); 1039 } 1040 } 1041 ADJUST_CHECKSUM(accumulate, tc->th_sum); 1042 1043/* Restore original IP address */ 1044 accumulate = twowords(&pip->ip_dst); 1045 pip->ip_dst = original_address; 1046 accumulate -= twowords(&pip->ip_dst); 1047 1048/* If this is a transparent proxy packet, then modify the source 1049 address */ 1050 if (proxy_address.s_addr != 0) { 1051 accumulate += twowords(&pip->ip_src); 1052 pip->ip_src = proxy_address; 1053 accumulate -= twowords(&pip->ip_src); 1054 } 1055 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 1056 1057/* Monitor TCP connection state */ 1058 tc = (struct tcphdr *)ip_next(pip); 1059 TcpMonitorIn(tc->th_flags, lnk); 1060 1061 return (PKT_ALIAS_OK); 1062 } 1063 return (PKT_ALIAS_IGNORED); 1064} 1065 1066static int 1067TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) 1068{ 1069 int dlen, proxy_type, error; 1070 u_short dest_port; 1071 u_short proxy_server_port; 1072 struct in_addr dest_address; 1073 struct in_addr proxy_server_address; 1074 struct tcphdr *tc; 1075 struct alias_link *lnk; 1076 1077 LIBALIAS_LOCK_ASSERT(la); 1078 1079 dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 1080 if (dlen < sizeof(struct tcphdr)) 1081 return (PKT_ALIAS_IGNORED); 1082 tc = (struct tcphdr *)ip_next(pip); 1083 1084 if (create) 1085 proxy_type = ProxyCheck(la, &proxy_server_address, 1086 &proxy_server_port, pip->ip_src, pip->ip_dst, 1087 tc->th_dport, pip->ip_p); 1088 else 1089 proxy_type = 0; 1090 1091 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) 1092 return (PKT_ALIAS_OK); 1093 1094/* If this is a transparent proxy, save original destination, 1095 then alter the destination and adjust checksums */ 1096 dest_port = tc->th_dport; 1097 dest_address = pip->ip_dst; 1098 if (proxy_type != 0) { 1099 int accumulate; 1100 1101 accumulate = tc->th_dport; 1102 tc->th_dport = proxy_server_port; 1103 accumulate -= tc->th_dport; 1104 accumulate += twowords(&pip->ip_dst); 1105 accumulate -= twowords(&proxy_server_address); 1106 ADJUST_CHECKSUM(accumulate, tc->th_sum); 1107 1108 accumulate = twowords(&pip->ip_dst); 1109 pip->ip_dst = proxy_server_address; 1110 accumulate -= twowords(&pip->ip_dst); 1111 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 1112 } 1113 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst, 1114 tc->th_sport, tc->th_dport, 1115 IPPROTO_TCP, create); 1116 if (lnk == NULL) 1117 return (PKT_ALIAS_IGNORED); 1118 if (lnk != NULL) { 1119 u_short alias_port; 1120 struct in_addr alias_address; 1121 int accumulate; 1122 struct alias_data ad = { 1123 .lnk = lnk, 1124 .oaddr = NULL, 1125 .aaddr = &alias_address, 1126 .aport = &alias_port, 1127 .sport = &tc->th_sport, 1128 .dport = &tc->th_dport, 1129 .maxpktsize = maxpacketsize 1130 }; 1131 1132/* Save original destination address, if this is a proxy packet. 1133 Also modify packet to include destination encoding. This may 1134 change the size of IP header. */ 1135 if (proxy_type != 0) { 1136 SetProxyPort(lnk, dest_port); 1137 SetProxyAddress(lnk, dest_address); 1138 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type); 1139 tc = (struct tcphdr *)ip_next(pip); 1140 } 1141/* Get alias address and port */ 1142 alias_port = GetAliasPort(lnk); 1143 alias_address = GetAliasAddress(lnk); 1144 1145/* Monitor TCP connection state */ 1146 tc = (struct tcphdr *)ip_next(pip); 1147 TcpMonitorOut(tc->th_flags, lnk); 1148 1149 /* Walk out chain. */ 1150 error = find_handler(OUT, TCP, la, pip, &ad); 1151 1152/* Adjust TCP checksum since source port is being aliased */ 1153/* and source address is being altered */ 1154 accumulate = tc->th_sport; 1155 tc->th_sport = alias_port; 1156 accumulate -= tc->th_sport; 1157 accumulate += twowords(&pip->ip_src); 1158 accumulate -= twowords(&alias_address); 1159 1160/* Modify sequence number if necessary */ 1161 if (GetAckModified(lnk) == 1) { 1162 int delta; 1163 1164 tc = (struct tcphdr *)ip_next(pip); 1165 delta = GetDeltaSeqOut(tc->th_seq, lnk); 1166 if (delta != 0) { 1167 accumulate += twowords(&tc->th_seq); 1168 tc->th_seq = htonl(ntohl(tc->th_seq) + delta); 1169 accumulate -= twowords(&tc->th_seq); 1170 } 1171 } 1172 ADJUST_CHECKSUM(accumulate, tc->th_sum); 1173 1174/* Change source address */ 1175 accumulate = twowords(&pip->ip_src); 1176 pip->ip_src = alias_address; 1177 accumulate -= twowords(&pip->ip_src); 1178 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 1179 1180 return (PKT_ALIAS_OK); 1181 } 1182 return (PKT_ALIAS_IGNORED); 1183} 1184 1185 1186 1187 1188/* Fragment Handling 1189 1190 FragmentIn() 1191 FragmentOut() 1192 1193The packet aliasing module has a limited ability for handling IP 1194fragments. If the ICMP, TCP or UDP header is in the first fragment 1195received, then the ID number of the IP packet is saved, and other 1196fragments are identified according to their ID number and IP address 1197they were sent from. Pointers to unresolved fragments can also be 1198saved and recalled when a header fragment is seen. 1199*/ 1200 1201/* Local prototypes */ 1202static int FragmentIn(struct libalias *la, struct in_addr ip_src, 1203 struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum); 1204static int FragmentOut(struct libalias *, struct in_addr *ip_src, 1205 u_short *ip_sum); 1206 1207static int 1208FragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst, 1209 u_short ip_id, u_short *ip_sum) 1210{ 1211 struct alias_link *lnk; 1212 1213 LIBALIAS_LOCK_ASSERT(la); 1214 lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id); 1215 if (lnk != NULL) { 1216 struct in_addr original_address; 1217 1218 GetFragmentAddr(lnk, &original_address); 1219 DifferentialChecksum(ip_sum, 1220 &original_address, ip_dst, 2); 1221 *ip_dst = original_address; 1222 1223 return (PKT_ALIAS_OK); 1224 } 1225 return (PKT_ALIAS_UNRESOLVED_FRAGMENT); 1226} 1227 1228static int 1229FragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum) 1230{ 1231 struct in_addr alias_address; 1232 1233 LIBALIAS_LOCK_ASSERT(la); 1234 alias_address = FindAliasAddress(la, *ip_src); 1235 DifferentialChecksum(ip_sum, 1236 &alias_address, ip_src, 2); 1237 *ip_src = alias_address; 1238 1239 return (PKT_ALIAS_OK); 1240} 1241 1242 1243 1244 1245 1246 1247/* Outside World Access 1248 1249 PacketAliasSaveFragment() 1250 PacketAliasGetFragment() 1251 PacketAliasFragmentIn() 1252 PacketAliasIn() 1253 PacketAliasOut() 1254 PacketUnaliasOut() 1255 1256(prototypes in alias.h) 1257*/ 1258 1259int 1260LibAliasSaveFragment(struct libalias *la, char *ptr) 1261{ 1262 int iresult; 1263 struct alias_link *lnk; 1264 struct ip *pip; 1265 1266 LIBALIAS_LOCK(la); 1267 pip = (struct ip *)ptr; 1268 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id); 1269 iresult = PKT_ALIAS_ERROR; 1270 if (lnk != NULL) { 1271 SetFragmentPtr(lnk, ptr); 1272 iresult = PKT_ALIAS_OK; 1273 } 1274 LIBALIAS_UNLOCK(la); 1275 return (iresult); 1276} 1277 1278char * 1279LibAliasGetFragment(struct libalias *la, char *ptr) 1280{ 1281 struct alias_link *lnk; 1282 char *fptr; 1283 struct ip *pip; 1284 1285 LIBALIAS_LOCK(la); 1286 pip = (struct ip *)ptr; 1287 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id); 1288 if (lnk != NULL) { 1289 GetFragmentPtr(lnk, &fptr); 1290 SetFragmentPtr(lnk, NULL); 1291 SetExpire(lnk, 0); /* Deletes link */ 1292 } else 1293 fptr = NULL; 1294 1295 LIBALIAS_UNLOCK(la); 1296 return (fptr); 1297} 1298 1299void 1300LibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly 1301 * de-aliased header 1302 * fragment */ 1303 char *ptr_fragment /* Points to fragment which must be 1304 * de-aliased */ 1305) 1306{ 1307 struct ip *pip; 1308 struct ip *fpip; 1309 1310 LIBALIAS_LOCK(la); 1311 (void)la; 1312 pip = (struct ip *)ptr; 1313 fpip = (struct ip *)ptr_fragment; 1314 1315 DifferentialChecksum(&fpip->ip_sum, 1316 &pip->ip_dst, &fpip->ip_dst, 2); 1317 fpip->ip_dst = pip->ip_dst; 1318 LIBALIAS_UNLOCK(la); 1319} 1320 1321/* Local prototypes */ 1322static int 1323LibAliasOutLocked(struct libalias *la, char *ptr, 1324 int maxpacketsize, int create); 1325static int 1326LibAliasInLocked(struct libalias *la, char *ptr, 1327 int maxpacketsize); 1328 1329int 1330LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize) 1331{ 1332 int res; 1333 1334 LIBALIAS_LOCK(la); 1335 res = LibAliasInLocked(la, ptr, maxpacketsize); 1336 LIBALIAS_UNLOCK(la); 1337 return (res); 1338} 1339 1340static int 1341LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize) 1342{ 1343 struct in_addr alias_addr; 1344 struct ip *pip; 1345 int iresult; 1346 1347 if (la->packetAliasMode & PKT_ALIAS_REVERSE) { 1348 la->packetAliasMode &= ~PKT_ALIAS_REVERSE; 1349 iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1); 1350 la->packetAliasMode |= PKT_ALIAS_REVERSE; 1351 goto getout; 1352 } 1353 HouseKeeping(la); 1354 ClearCheckNewLink(la); 1355 pip = (struct ip *)ptr; 1356 alias_addr = pip->ip_dst; 1357 1358 /* Defense against mangled packets */ 1359 if (ntohs(pip->ip_len) > maxpacketsize 1360 || (pip->ip_hl << 2) > maxpacketsize) { 1361 iresult = PKT_ALIAS_IGNORED; 1362 goto getout; 1363 } 1364 1365 iresult = PKT_ALIAS_IGNORED; 1366 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 1367 switch (pip->ip_p) { 1368 case IPPROTO_ICMP: 1369 iresult = IcmpAliasIn(la, pip); 1370 break; 1371 case IPPROTO_UDP: 1372 iresult = UdpAliasIn(la, pip); 1373 break; 1374 case IPPROTO_TCP: 1375 iresult = TcpAliasIn(la, pip); 1376 break; 1377#ifdef _KERNEL 1378 case IPPROTO_SCTP: 1379 iresult = SctpAlias(la, pip, SN_TO_LOCAL); 1380 break; 1381#endif 1382 case IPPROTO_GRE: { 1383 int error; 1384 struct alias_data ad = { 1385 .lnk = NULL, 1386 .oaddr = NULL, 1387 .aaddr = NULL, 1388 .aport = NULL, 1389 .sport = NULL, 1390 .dport = NULL, 1391 .maxpktsize = 0 1392 }; 1393 1394 /* Walk out chain. */ 1395 error = find_handler(IN, IP, la, pip, &ad); 1396 if (error == 0) 1397 iresult = PKT_ALIAS_OK; 1398 else 1399 iresult = ProtoAliasIn(la, pip->ip_src, 1400 &pip->ip_dst, pip->ip_p, &pip->ip_sum); 1401 } 1402 break; 1403 default: 1404 iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst, 1405 pip->ip_p, &pip->ip_sum); 1406 break; 1407 } 1408 1409 if (ntohs(pip->ip_off) & IP_MF) { 1410 struct alias_link *lnk; 1411 1412 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id); 1413 if (lnk != NULL) { 1414 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT; 1415 SetFragmentAddr(lnk, pip->ip_dst); 1416 } else { 1417 iresult = PKT_ALIAS_ERROR; 1418 } 1419 } 1420 } else { 1421 iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id, 1422 &pip->ip_sum); 1423 } 1424 1425getout: 1426 return (iresult); 1427} 1428 1429 1430 1431/* Unregistered address ranges */ 1432 1433/* 10.0.0.0 -> 10.255.255.255 */ 1434#define UNREG_ADDR_A_LOWER 0x0a000000 1435#define UNREG_ADDR_A_UPPER 0x0affffff 1436 1437/* 172.16.0.0 -> 172.31.255.255 */ 1438#define UNREG_ADDR_B_LOWER 0xac100000 1439#define UNREG_ADDR_B_UPPER 0xac1fffff 1440 1441/* 192.168.0.0 -> 192.168.255.255 */ 1442#define UNREG_ADDR_C_LOWER 0xc0a80000 1443#define UNREG_ADDR_C_UPPER 0xc0a8ffff 1444 1445/* 100.64.0.0 -> 100.127.255.255 (RFC 6598 - Carrier Grade NAT) */ 1446#define UNREG_ADDR_CGN_LOWER 0x64400000 1447#define UNREG_ADDR_CGN_UPPER 0x647fffff 1448 1449int 1450LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize) 1451{ 1452 int res; 1453 1454 LIBALIAS_LOCK(la); 1455 res = LibAliasOutLocked(la, ptr, maxpacketsize, 1); 1456 LIBALIAS_UNLOCK(la); 1457 return (res); 1458} 1459 1460int 1461LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create) 1462{ 1463 int res; 1464 1465 LIBALIAS_LOCK(la); 1466 res = LibAliasOutLocked(la, ptr, maxpacketsize, create); 1467 LIBALIAS_UNLOCK(la); 1468 return (res); 1469} 1470 1471static int 1472LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */ 1473 int maxpacketsize, /* How much the packet data may grow (FTP 1474 * and IRC inline changes) */ 1475 int create /* Create new entries ? */ 1476) 1477{ 1478 int iresult; 1479 struct in_addr addr_save; 1480 struct ip *pip; 1481 1482 if (la->packetAliasMode & PKT_ALIAS_REVERSE) { 1483 la->packetAliasMode &= ~PKT_ALIAS_REVERSE; 1484 iresult = LibAliasInLocked(la, ptr, maxpacketsize); 1485 la->packetAliasMode |= PKT_ALIAS_REVERSE; 1486 goto getout; 1487 } 1488 HouseKeeping(la); 1489 ClearCheckNewLink(la); 1490 pip = (struct ip *)ptr; 1491 1492 /* Defense against mangled packets */ 1493 if (ntohs(pip->ip_len) > maxpacketsize 1494 || (pip->ip_hl << 2) > maxpacketsize) { 1495 iresult = PKT_ALIAS_IGNORED; 1496 goto getout; 1497 } 1498 1499 addr_save = GetDefaultAliasAddress(la); 1500 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY || 1501 la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) { 1502 u_long addr; 1503 int iclass; 1504 1505 iclass = 0; 1506 addr = ntohl(pip->ip_src.s_addr); 1507 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER) 1508 iclass = 3; 1509 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER) 1510 iclass = 2; 1511 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER) 1512 iclass = 1; 1513 else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER && 1514 la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) 1515 iclass = 4; 1516 1517 if (iclass == 0) { 1518 SetDefaultAliasAddress(la, pip->ip_src); 1519 } 1520 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) { 1521 SetDefaultAliasAddress(la, pip->ip_src); 1522 } 1523 iresult = PKT_ALIAS_IGNORED; 1524 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 1525 switch (pip->ip_p) { 1526 case IPPROTO_ICMP: 1527 iresult = IcmpAliasOut(la, pip, create); 1528 break; 1529 case IPPROTO_UDP: 1530 iresult = UdpAliasOut(la, pip, maxpacketsize, create); 1531 break; 1532 case IPPROTO_TCP: 1533 iresult = TcpAliasOut(la, pip, maxpacketsize, create); 1534 break; 1535#ifdef _KERNEL 1536 case IPPROTO_SCTP: 1537 iresult = SctpAlias(la, pip, SN_TO_GLOBAL); 1538 break; 1539#endif 1540 case IPPROTO_GRE: { 1541 int error; 1542 struct alias_data ad = { 1543 .lnk = NULL, 1544 .oaddr = NULL, 1545 .aaddr = NULL, 1546 .aport = NULL, 1547 .sport = NULL, 1548 .dport = NULL, 1549 .maxpktsize = 0 1550 }; 1551 /* Walk out chain. */ 1552 error = find_handler(OUT, IP, la, pip, &ad); 1553 if (error == 0) 1554 iresult = PKT_ALIAS_OK; 1555 else 1556 iresult = ProtoAliasOut(la, &pip->ip_src, 1557 pip->ip_dst, pip->ip_p, &pip->ip_sum, create); 1558 } 1559 break; 1560 default: 1561 iresult = ProtoAliasOut(la, &pip->ip_src, 1562 pip->ip_dst, pip->ip_p, &pip->ip_sum, create); 1563 break; 1564 } 1565 } else { 1566 iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum); 1567 } 1568 1569 SetDefaultAliasAddress(la, addr_save); 1570getout: 1571 return (iresult); 1572} 1573 1574int 1575LibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */ 1576 int maxpacketsize /* for error checking */ 1577) 1578{ 1579 struct ip *pip; 1580 struct icmp *ic; 1581 struct udphdr *ud; 1582 struct tcphdr *tc; 1583 struct alias_link *lnk; 1584 int iresult = PKT_ALIAS_IGNORED; 1585 1586 LIBALIAS_LOCK(la); 1587 pip = (struct ip *)ptr; 1588 1589 /* Defense against mangled packets */ 1590 if (ntohs(pip->ip_len) > maxpacketsize 1591 || (pip->ip_hl << 2) > maxpacketsize) 1592 goto getout; 1593 1594 ud = (struct udphdr *)ip_next(pip); 1595 tc = (struct tcphdr *)ip_next(pip); 1596 ic = (struct icmp *)ip_next(pip); 1597 1598 /* Find a link */ 1599 if (pip->ip_p == IPPROTO_UDP) 1600 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src, 1601 ud->uh_dport, ud->uh_sport, 1602 IPPROTO_UDP, 0); 1603 else if (pip->ip_p == IPPROTO_TCP) 1604 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src, 1605 tc->th_dport, tc->th_sport, 1606 IPPROTO_TCP, 0); 1607 else if (pip->ip_p == IPPROTO_ICMP) 1608 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0); 1609 else 1610 lnk = NULL; 1611 1612 /* Change it from an aliased packet to an unaliased packet */ 1613 if (lnk != NULL) { 1614 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) { 1615 int accumulate; 1616 struct in_addr original_address; 1617 u_short original_port; 1618 1619 original_address = GetOriginalAddress(lnk); 1620 original_port = GetOriginalPort(lnk); 1621 1622 /* Adjust TCP/UDP checksum */ 1623 accumulate = twowords(&pip->ip_src); 1624 accumulate -= twowords(&original_address); 1625 1626 if (pip->ip_p == IPPROTO_UDP) { 1627 accumulate += ud->uh_sport; 1628 accumulate -= original_port; 1629 ADJUST_CHECKSUM(accumulate, ud->uh_sum); 1630 } else { 1631 accumulate += tc->th_sport; 1632 accumulate -= original_port; 1633 ADJUST_CHECKSUM(accumulate, tc->th_sum); 1634 } 1635 1636 /* Adjust IP checksum */ 1637 DifferentialChecksum(&pip->ip_sum, 1638 &original_address, &pip->ip_src, 2); 1639 1640 /* Un-alias source address and port number */ 1641 pip->ip_src = original_address; 1642 if (pip->ip_p == IPPROTO_UDP) 1643 ud->uh_sport = original_port; 1644 else 1645 tc->th_sport = original_port; 1646 1647 iresult = PKT_ALIAS_OK; 1648 1649 } else if (pip->ip_p == IPPROTO_ICMP) { 1650 1651 int accumulate; 1652 struct in_addr original_address; 1653 u_short original_id; 1654 1655 original_address = GetOriginalAddress(lnk); 1656 original_id = GetOriginalPort(lnk); 1657 1658 /* Adjust ICMP checksum */ 1659 accumulate = twowords(&pip->ip_src); 1660 accumulate -= twowords(&original_address); 1661 accumulate += ic->icmp_id; 1662 accumulate -= original_id; 1663 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 1664 1665 /* Adjust IP checksum */ 1666 DifferentialChecksum(&pip->ip_sum, 1667 &original_address, &pip->ip_src, 2); 1668 1669 /* Un-alias source address and port number */ 1670 pip->ip_src = original_address; 1671 ic->icmp_id = original_id; 1672 1673 iresult = PKT_ALIAS_OK; 1674 } 1675 } 1676getout: 1677 LIBALIAS_UNLOCK(la); 1678 return (iresult); 1679 1680} 1681 1682#ifndef _KERNEL 1683 1684int 1685LibAliasRefreshModules(void) 1686{ 1687 char buf[256], conf[] = "/etc/libalias.conf"; 1688 FILE *fd; 1689 int i, len; 1690 1691 fd = fopen(conf, "r"); 1692 if (fd == NULL) 1693 err(1, "fopen(%s)", conf); 1694 1695 LibAliasUnLoadAllModule(); 1696 1697 for (;;) { 1698 fgets(buf, 256, fd); 1699 if (feof(fd)) 1700 break; 1701 len = strlen(buf); 1702 if (len > 1) { 1703 for (i = 0; i < len; i++) 1704 if (!isspace(buf[i])) 1705 break; 1706 if (buf[i] == '#') 1707 continue; 1708 buf[len - 1] = '\0'; 1709 LibAliasLoadModule(buf); 1710 } 1711 } 1712 fclose(fd); 1713 return (0); 1714} 1715 1716int 1717LibAliasLoadModule(char *path) 1718{ 1719 struct dll *t; 1720 void *handle; 1721 struct proto_handler *m; 1722 const char *error; 1723 moduledata_t *p; 1724 1725 handle = dlopen (path, RTLD_LAZY); 1726 if (!handle) { 1727 fprintf(stderr, "%s\n", dlerror()); 1728 return (EINVAL); 1729 } 1730 1731 p = dlsym(handle, "alias_mod"); 1732 if ((error = dlerror()) != NULL) { 1733 fprintf(stderr, "%s\n", dlerror()); 1734 return (EINVAL); 1735 } 1736 1737 t = malloc(sizeof(struct dll)); 1738 if (t == NULL) 1739 return (ENOMEM); 1740 strncpy(t->name, p->name, DLL_LEN); 1741 t->handle = handle; 1742 if (attach_dll(t) == EEXIST) { 1743 free(t); 1744 fprintf(stderr, "dll conflict\n"); 1745 return (EEXIST); 1746 } 1747 1748 m = dlsym(t->handle, "handlers"); 1749 if ((error = dlerror()) != NULL) { 1750 fprintf(stderr, "%s\n", error); 1751 return (EINVAL); 1752 } 1753 1754 LibAliasAttachHandlers(m); 1755 return (0); 1756} 1757 1758int 1759LibAliasUnLoadAllModule(void) 1760{ 1761 struct dll *t; 1762 struct proto_handler *p; 1763 1764 /* Unload all modules then reload everything. */ 1765 while ((p = first_handler()) != NULL) { 1766 LibAliasDetachHandlers(p); 1767 } 1768 while ((t = walk_dll_chain()) != NULL) { 1769 dlclose(t->handle); 1770 free(t); 1771 } 1772 return (1); 1773} 1774 1775#endif 1776 1777#ifdef _KERNEL 1778/* 1779 * m_megapullup() - this function is a big hack. 1780 * Thankfully, it's only used in ng_nat and ipfw+nat. 1781 * 1782 * It allocates an mbuf with cluster and copies the specified part of the chain 1783 * into cluster, so that it is all contiguous and can be accessed via a plain 1784 * (char *) pointer. This is required, because libalias doesn't know how to 1785 * handle mbuf chains. 1786 * 1787 * On success, m_megapullup returns an mbuf (possibly with cluster) containing 1788 * the input packet, on failure NULL. The input packet is always consumed. 1789 */ 1790struct mbuf * 1791m_megapullup(struct mbuf *m, int len) 1792{ 1793 struct mbuf *mcl; 1794 1795 if (len > m->m_pkthdr.len) 1796 goto bad; 1797 1798 if (m->m_next == NULL && M_WRITABLE(m)) 1799 return (m); 1800 1801 if (len <= MJUMPAGESIZE) 1802 mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR); 1803 else if (len <= MJUM9BYTES) 1804 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); 1805 else if (len <= MJUM16BYTES) 1806 mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES); 1807 else 1808 goto bad; 1809 if (mcl == NULL) 1810 goto bad; 1811 m_align(mcl, len); 1812 m_move_pkthdr(mcl, m); 1813 m_copydata(m, 0, len, mtod(mcl, caddr_t)); 1814 mcl->m_len = mcl->m_pkthdr.len = len; 1815 m_freem(m); 1816 1817 return (mcl); 1818bad: 1819 m_freem(m); 1820 return (NULL); 1821} 1822#endif 1823