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