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