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