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