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