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