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