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, 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 721 ud = (struct udphdr *)ip_next(pip); 722 723 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst, 724 ud->uh_sport, ud->uh_dport, 725 IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)); 726 if (lnk != NULL) { 727 struct in_addr alias_address; 728 struct in_addr original_address; 729 struct in_addr proxy_address; 730 u_short alias_port; 731 u_short proxy_port; 732 int accumulate; 733 int r = 0, error; 734 struct alias_data ad = { 735 .lnk = lnk, 736 .oaddr = &original_address, 737 .aaddr = &alias_address, 738 .aport = &alias_port, 739 .sport = &ud->uh_sport, 740 .dport = &ud->uh_dport, 741 .maxpktsize = 0 742 }; 743 744 alias_address = GetAliasAddress(lnk); 745 original_address = GetOriginalAddress(lnk); 746 proxy_address = GetProxyAddress(lnk); 747 alias_port = ud->uh_dport; 748 ud->uh_dport = GetOriginalPort(lnk); 749 proxy_port = GetProxyPort(lnk); 750 751 /* Walk out chain. */ 752 error = find_handler(IN, UDP, la, pip, &ad); 753 754 /* If UDP checksum is not zero, then adjust since destination port */ 755 /* is being unaliased and destination address is being altered. */ 756 if (ud->uh_sum != 0) { 757 accumulate = alias_port; 758 accumulate -= ud->uh_dport; 759 accumulate += twowords(&alias_address); 760 accumulate -= twowords(&original_address); 761 762 /* If this is a proxy packet, modify checksum because of source change.*/ 763 if (proxy_port != 0) { 764 accumulate += ud->uh_sport; 765 accumulate -= proxy_port; 766 } 767 768 if (proxy_address.s_addr != 0) { 769 accumulate += twowords(&pip->ip_src); 770 accumulate -= twowords(&proxy_address); 771 } 772 773 ADJUST_CHECKSUM(accumulate, ud->uh_sum); 774 } 775 /* XXX: Could the two if's below be concatenated to one ? */ 776 /* Restore source port and/or address in case of proxying*/ 777 778 if (proxy_port != 0) 779 ud->uh_sport = proxy_port; 780 781 if (proxy_address.s_addr != 0) { 782 DifferentialChecksum(&pip->ip_sum, 783 &proxy_address, &pip->ip_src, 2); 784 pip->ip_src = proxy_address; 785 } 786 787 /* Restore original IP address */ 788 DifferentialChecksum(&pip->ip_sum, 789 &original_address, &pip->ip_dst, 2); 790 pip->ip_dst = original_address; 791 792 /* 793 * If we cannot figure out the packet, ignore it. 794 */ 795 if (r < 0) 796 return (PKT_ALIAS_IGNORED); 797 else 798 return (PKT_ALIAS_OK); 799 } 800 return (PKT_ALIAS_IGNORED); 801 } 802 803 static int 804 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) 805 { 806 struct udphdr *ud; 807 struct alias_link *lnk; 808 struct in_addr dest_address; 809 struct in_addr proxy_server_address; 810 u_short dest_port; 811 u_short proxy_server_port; 812 int proxy_type; 813 int error; 814 815 LIBALIAS_LOCK_ASSERT(la); 816 817 /* Return if proxy-only mode is enabled and not proxyrule found.*/ 818 ud = (struct udphdr *)ip_next(pip); 819 proxy_type = ProxyCheck(la, &proxy_server_address, 820 &proxy_server_port, pip->ip_src, pip->ip_dst, 821 ud->uh_dport, pip->ip_p); 822 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) 823 return (PKT_ALIAS_OK); 824 825 /* If this is a transparent proxy, save original destination, 826 * then alter the destination and adjust checksums */ 827 dest_port = ud->uh_dport; 828 dest_address = pip->ip_dst; 829 830 if (proxy_type != 0) { 831 int accumulate; 832 833 accumulate = twowords(&pip->ip_dst); 834 accumulate -= twowords(&proxy_server_address); 835 836 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 837 838 if (ud->uh_sum != 0) { 839 accumulate = twowords(&pip->ip_dst); 840 accumulate -= twowords(&proxy_server_address); 841 accumulate += ud->uh_dport; 842 accumulate -= proxy_server_port; 843 ADJUST_CHECKSUM(accumulate, ud->uh_sum); 844 } 845 pip->ip_dst = proxy_server_address; 846 ud->uh_dport = proxy_server_port; 847 } 848 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst, 849 ud->uh_sport, ud->uh_dport, 850 IPPROTO_UDP, create); 851 if (lnk != NULL) { 852 u_short alias_port; 853 struct in_addr alias_address; 854 struct alias_data ad = { 855 .lnk = lnk, 856 .oaddr = NULL, 857 .aaddr = &alias_address, 858 .aport = &alias_port, 859 .sport = &ud->uh_sport, 860 .dport = &ud->uh_dport, 861 .maxpktsize = 0 862 }; 863 864 /* Save original destination address, if this is a proxy packet. 865 * Also modify packet to include destination encoding. This may 866 * change the size of IP header. */ 867 if (proxy_type != 0) { 868 SetProxyPort(lnk, dest_port); 869 SetProxyAddress(lnk, dest_address); 870 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type); 871 ud = (struct udphdr *)ip_next(pip); 872 } 873 874 alias_address = GetAliasAddress(lnk); 875 alias_port = GetAliasPort(lnk); 876 877 /* Walk out chain. */ 878 error = find_handler(OUT, UDP, la, pip, &ad); 879 880 /* If UDP checksum is not zero, adjust since source port is */ 881 /* being aliased and source address is being altered */ 882 if (ud->uh_sum != 0) { 883 int accumulate; 884 885 accumulate = ud->uh_sport; 886 accumulate -= alias_port; 887 accumulate += twowords(&pip->ip_src); 888 accumulate -= twowords(&alias_address); 889 ADJUST_CHECKSUM(accumulate, ud->uh_sum); 890 } 891 /* Put alias port in UDP header */ 892 ud->uh_sport = alias_port; 893 894 /* Change source address */ 895 DifferentialChecksum(&pip->ip_sum, 896 &alias_address, &pip->ip_src, 2); 897 pip->ip_src = alias_address; 898 899 return (PKT_ALIAS_OK); 900 } 901 return (PKT_ALIAS_IGNORED); 902 } 903 904 905 906 static int 907 TcpAliasIn(struct libalias *la, struct ip *pip) 908 { 909 struct tcphdr *tc; 910 struct alias_link *lnk; 911 912 LIBALIAS_LOCK_ASSERT(la); 913 tc = (struct tcphdr *)ip_next(pip); 914 915 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst, 916 tc->th_sport, tc->th_dport, 917 IPPROTO_TCP, 918 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)); 919 if (lnk != NULL) { 920 struct in_addr alias_address; 921 struct in_addr original_address; 922 struct in_addr proxy_address; 923 u_short alias_port; 924 u_short proxy_port; 925 int accumulate, error; 926 927 /* 928 * The init of MANY vars is a bit below, but aliashandlepptpin 929 * seems to need the destination port that came within the 930 * packet and not the original one looks below [*]. 931 */ 932 933 struct alias_data ad = { 934 .lnk = lnk, 935 .oaddr = NULL, 936 .aaddr = NULL, 937 .aport = NULL, 938 .sport = &tc->th_sport, 939 .dport = &tc->th_dport, 940 .maxpktsize = 0 941 }; 942 943 /* Walk out chain. */ 944 error = find_handler(IN, TCP, la, pip, &ad); 945 946 alias_address = GetAliasAddress(lnk); 947 original_address = GetOriginalAddress(lnk); 948 proxy_address = GetProxyAddress(lnk); 949 alias_port = tc->th_dport; 950 tc->th_dport = GetOriginalPort(lnk); 951 proxy_port = GetProxyPort(lnk); 952 953 /* 954 * Look above, if anyone is going to add find_handler AFTER 955 * this aliashandlepptpin/point, please redo alias_data too. 956 * Uncommenting the piece here below should be enough. 957 */ 958 #if 0 959 struct alias_data ad = { 960 .lnk = lnk, 961 .oaddr = &original_address, 962 .aaddr = &alias_address, 963 .aport = &alias_port, 964 .sport = &ud->uh_sport, 965 .dport = &ud->uh_dport, 966 .maxpktsize = 0 967 }; 968 969 /* Walk out chain. */ 970 error = find_handler(la, pip, &ad); 971 if (error == EHDNOF) 972 printf("Protocol handler not found\n"); 973 #endif 974 975 /* Adjust TCP checksum since destination port is being unaliased */ 976 /* and destination port is being altered. */ 977 accumulate = alias_port; 978 accumulate -= tc->th_dport; 979 accumulate += twowords(&alias_address); 980 accumulate -= twowords(&original_address); 981 982 /* If this is a proxy, then modify the TCP source port and 983 checksum accumulation */ 984 if (proxy_port != 0) { 985 accumulate += tc->th_sport; 986 tc->th_sport = proxy_port; 987 accumulate -= tc->th_sport; 988 accumulate += twowords(&pip->ip_src); 989 accumulate -= twowords(&proxy_address); 990 } 991 /* See if ACK number needs to be modified */ 992 if (GetAckModified(lnk) == 1) { 993 int delta; 994 995 tc = (struct tcphdr *)ip_next(pip); 996 delta = GetDeltaAckIn(tc->th_ack, lnk); 997 if (delta != 0) { 998 accumulate += twowords(&tc->th_ack); 999 tc->th_ack = htonl(ntohl(tc->th_ack) - delta); 1000 accumulate -= twowords(&tc->th_ack); 1001 } 1002 } 1003 ADJUST_CHECKSUM(accumulate, tc->th_sum); 1004 1005 /* Restore original IP address */ 1006 accumulate = twowords(&pip->ip_dst); 1007 pip->ip_dst = original_address; 1008 accumulate -= twowords(&pip->ip_dst); 1009 1010 /* If this is a transparent proxy packet, then modify the source 1011 address */ 1012 if (proxy_address.s_addr != 0) { 1013 accumulate += twowords(&pip->ip_src); 1014 pip->ip_src = proxy_address; 1015 accumulate -= twowords(&pip->ip_src); 1016 } 1017 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 1018 1019 /* Monitor TCP connection state */ 1020 tc = (struct tcphdr *)ip_next(pip); 1021 TcpMonitorIn(tc->th_flags, lnk); 1022 1023 return (PKT_ALIAS_OK); 1024 } 1025 return (PKT_ALIAS_IGNORED); 1026 } 1027 1028 static int 1029 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create) 1030 { 1031 int proxy_type, error; 1032 u_short dest_port; 1033 u_short proxy_server_port; 1034 struct in_addr dest_address; 1035 struct in_addr proxy_server_address; 1036 struct tcphdr *tc; 1037 struct alias_link *lnk; 1038 1039 LIBALIAS_LOCK_ASSERT(la); 1040 tc = (struct tcphdr *)ip_next(pip); 1041 1042 if (create) 1043 proxy_type = ProxyCheck(la, &proxy_server_address, 1044 &proxy_server_port, pip->ip_src, pip->ip_dst, 1045 tc->th_dport, pip->ip_p); 1046 else 1047 proxy_type = 0; 1048 1049 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)) 1050 return (PKT_ALIAS_OK); 1051 1052 /* If this is a transparent proxy, save original destination, 1053 then alter the destination and adjust checksums */ 1054 dest_port = tc->th_dport; 1055 dest_address = pip->ip_dst; 1056 if (proxy_type != 0) { 1057 int accumulate; 1058 1059 accumulate = tc->th_dport; 1060 tc->th_dport = proxy_server_port; 1061 accumulate -= tc->th_dport; 1062 accumulate += twowords(&pip->ip_dst); 1063 accumulate -= twowords(&proxy_server_address); 1064 ADJUST_CHECKSUM(accumulate, tc->th_sum); 1065 1066 accumulate = twowords(&pip->ip_dst); 1067 pip->ip_dst = proxy_server_address; 1068 accumulate -= twowords(&pip->ip_dst); 1069 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 1070 } 1071 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst, 1072 tc->th_sport, tc->th_dport, 1073 IPPROTO_TCP, create); 1074 if (lnk == NULL) 1075 return (PKT_ALIAS_IGNORED); 1076 if (lnk != NULL) { 1077 u_short alias_port; 1078 struct in_addr alias_address; 1079 int accumulate; 1080 struct alias_data ad = { 1081 .lnk = lnk, 1082 .oaddr = NULL, 1083 .aaddr = &alias_address, 1084 .aport = &alias_port, 1085 .sport = &tc->th_sport, 1086 .dport = &tc->th_dport, 1087 .maxpktsize = maxpacketsize 1088 }; 1089 1090 /* Save original destination address, if this is a proxy packet. 1091 Also modify packet to include destination encoding. This may 1092 change the size of IP header. */ 1093 if (proxy_type != 0) { 1094 SetProxyPort(lnk, dest_port); 1095 SetProxyAddress(lnk, dest_address); 1096 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type); 1097 tc = (struct tcphdr *)ip_next(pip); 1098 } 1099 /* Get alias address and port */ 1100 alias_port = GetAliasPort(lnk); 1101 alias_address = GetAliasAddress(lnk); 1102 1103 /* Monitor TCP connection state */ 1104 tc = (struct tcphdr *)ip_next(pip); 1105 TcpMonitorOut(tc->th_flags, lnk); 1106 1107 /* Walk out chain. */ 1108 error = find_handler(OUT, TCP, la, pip, &ad); 1109 1110 /* Adjust TCP checksum since source port is being aliased */ 1111 /* and source address is being altered */ 1112 accumulate = tc->th_sport; 1113 tc->th_sport = alias_port; 1114 accumulate -= tc->th_sport; 1115 accumulate += twowords(&pip->ip_src); 1116 accumulate -= twowords(&alias_address); 1117 1118 /* Modify sequence number if necessary */ 1119 if (GetAckModified(lnk) == 1) { 1120 int delta; 1121 1122 tc = (struct tcphdr *)ip_next(pip); 1123 delta = GetDeltaSeqOut(tc->th_seq, lnk); 1124 if (delta != 0) { 1125 accumulate += twowords(&tc->th_seq); 1126 tc->th_seq = htonl(ntohl(tc->th_seq) + delta); 1127 accumulate -= twowords(&tc->th_seq); 1128 } 1129 } 1130 ADJUST_CHECKSUM(accumulate, tc->th_sum); 1131 1132 /* Change source address */ 1133 accumulate = twowords(&pip->ip_src); 1134 pip->ip_src = alias_address; 1135 accumulate -= twowords(&pip->ip_src); 1136 ADJUST_CHECKSUM(accumulate, pip->ip_sum); 1137 1138 return (PKT_ALIAS_OK); 1139 } 1140 return (PKT_ALIAS_IGNORED); 1141 } 1142 1143 1144 1145 1146 /* Fragment Handling 1147 1148 FragmentIn() 1149 FragmentOut() 1150 1151 The packet aliasing module has a limited ability for handling IP 1152 fragments. If the ICMP, TCP or UDP header is in the first fragment 1153 received, then the ID number of the IP packet is saved, and other 1154 fragments are identified according to their ID number and IP address 1155 they were sent from. Pointers to unresolved fragments can also be 1156 saved and recalled when a header fragment is seen. 1157 */ 1158 1159 /* Local prototypes */ 1160 static int FragmentIn(struct libalias *la, struct in_addr ip_src, 1161 struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum); 1162 static int FragmentOut(struct libalias *, struct in_addr *ip_src, 1163 u_short *ip_sum); 1164 1165 static int 1166 FragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst, 1167 u_short ip_id, u_short *ip_sum) 1168 { 1169 struct alias_link *lnk; 1170 1171 LIBALIAS_LOCK_ASSERT(la); 1172 lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id); 1173 if (lnk != NULL) { 1174 struct in_addr original_address; 1175 1176 GetFragmentAddr(lnk, &original_address); 1177 DifferentialChecksum(ip_sum, 1178 &original_address, ip_dst, 2); 1179 *ip_dst = original_address; 1180 1181 return (PKT_ALIAS_OK); 1182 } 1183 return (PKT_ALIAS_UNRESOLVED_FRAGMENT); 1184 } 1185 1186 static int 1187 FragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum) 1188 { 1189 struct in_addr alias_address; 1190 1191 LIBALIAS_LOCK_ASSERT(la); 1192 alias_address = FindAliasAddress(la, *ip_src); 1193 DifferentialChecksum(ip_sum, 1194 &alias_address, ip_src, 2); 1195 *ip_src = alias_address; 1196 1197 return (PKT_ALIAS_OK); 1198 } 1199 1200 1201 1202 1203 1204 1205 /* Outside World Access 1206 1207 PacketAliasSaveFragment() 1208 PacketAliasGetFragment() 1209 PacketAliasFragmentIn() 1210 PacketAliasIn() 1211 PacketAliasOut() 1212 PacketUnaliasOut() 1213 1214 (prototypes in alias.h) 1215 */ 1216 1217 // XXX ip free 1218 int 1219 LibAliasSaveFragment(struct libalias *la, char *ptr) 1220 { 1221 int iresult; 1222 struct alias_link *lnk; 1223 struct ip *pip; 1224 1225 LIBALIAS_LOCK(la); 1226 pip = (struct ip *)ptr; 1227 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id); 1228 iresult = PKT_ALIAS_ERROR; 1229 if (lnk != NULL) { 1230 SetFragmentPtr(lnk, ptr); 1231 iresult = PKT_ALIAS_OK; 1232 } 1233 LIBALIAS_UNLOCK(la); 1234 return (iresult); 1235 } 1236 1237 // XXX ip free 1238 char * 1239 LibAliasGetFragment(struct libalias *la, char *ptr) 1240 { 1241 struct alias_link *lnk; 1242 char *fptr; 1243 struct ip *pip; 1244 1245 LIBALIAS_LOCK(la); 1246 pip = (struct ip *)ptr; 1247 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id); 1248 if (lnk != NULL) { 1249 GetFragmentPtr(lnk, &fptr); 1250 SetFragmentPtr(lnk, NULL); 1251 SetExpire(lnk, 0); /* Deletes link */ 1252 } else 1253 fptr = NULL; 1254 1255 LIBALIAS_UNLOCK(la); 1256 return (fptr); 1257 } 1258 1259 // XXX ip free 1260 void 1261 LibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly 1262 * de-aliased header 1263 * fragment */ 1264 char *ptr_fragment /* Points to fragment which must be 1265 * de-aliased */ 1266 ) 1267 { 1268 struct ip *pip; 1269 struct ip *fpip; 1270 1271 LIBALIAS_LOCK(la); 1272 (void)la; 1273 pip = (struct ip *)ptr; 1274 fpip = (struct ip *)ptr_fragment; 1275 1276 DifferentialChecksum(&fpip->ip_sum, 1277 &pip->ip_dst, &fpip->ip_dst, 2); 1278 fpip->ip_dst = pip->ip_dst; 1279 LIBALIAS_UNLOCK(la); 1280 } 1281 1282 /* Local prototypes */ 1283 static int 1284 LibAliasOutLocked(struct libalias *la, char *ptr, 1285 int maxpacketsize, int create); 1286 static int 1287 LibAliasInLocked(struct libalias *la, char *ptr, 1288 int maxpacketsize); 1289 1290 int 1291 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize) 1292 { 1293 int res; 1294 1295 LIBALIAS_LOCK(la); 1296 res = LibAliasInLocked(la, ptr, maxpacketsize); 1297 LIBALIAS_UNLOCK(la); 1298 return (res); 1299 } 1300 1301 static int 1302 LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize) 1303 { 1304 struct in_addr alias_addr; 1305 struct ip *pip; 1306 int iresult; 1307 1308 if (la->packetAliasMode & PKT_ALIAS_REVERSE) { 1309 la->packetAliasMode &= ~PKT_ALIAS_REVERSE; 1310 iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1); 1311 la->packetAliasMode |= PKT_ALIAS_REVERSE; 1312 goto getout; 1313 } 1314 HouseKeeping(la); 1315 ClearCheckNewLink(la); 1316 pip = (struct ip *)ptr; 1317 alias_addr = pip->ip_dst; 1318 1319 /* Defense against mangled packets */ 1320 if (ntohs(pip->ip_len) > maxpacketsize 1321 || (pip->ip_hl << 2) > maxpacketsize) { 1322 iresult = PKT_ALIAS_IGNORED; 1323 goto getout; 1324 } 1325 1326 iresult = PKT_ALIAS_IGNORED; 1327 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 1328 switch (pip->ip_p) { 1329 case IPPROTO_ICMP: 1330 iresult = IcmpAliasIn(la, pip); 1331 break; 1332 case IPPROTO_UDP: 1333 iresult = UdpAliasIn(la, pip); 1334 break; 1335 case IPPROTO_TCP: 1336 iresult = TcpAliasIn(la, pip); 1337 break; 1338 case IPPROTO_GRE: { 1339 int error; 1340 struct alias_data ad = { 1341 .lnk = NULL, 1342 .oaddr = NULL, 1343 .aaddr = NULL, 1344 .aport = NULL, 1345 .sport = NULL, 1346 .dport = NULL, 1347 .maxpktsize = 0 1348 }; 1349 1350 /* Walk out chain. */ 1351 error = find_handler(IN, IP, la, pip, &ad); 1352 if (error == 0) 1353 iresult = PKT_ALIAS_OK; 1354 else 1355 iresult = ProtoAliasIn(la, pip->ip_src, 1356 &pip->ip_dst, pip->ip_p, &pip->ip_sum); 1357 } 1358 break; 1359 default: 1360 iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst, 1361 pip->ip_p, &pip->ip_sum); 1362 break; 1363 } 1364 1365 if (ntohs(pip->ip_off) & IP_MF) { 1366 struct alias_link *lnk; 1367 1368 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id); 1369 if (lnk != NULL) { 1370 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT; 1371 SetFragmentAddr(lnk, pip->ip_dst); 1372 } else { 1373 iresult = PKT_ALIAS_ERROR; 1374 } 1375 } 1376 } else { 1377 iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id, 1378 &pip->ip_sum); 1379 } 1380 1381 getout: 1382 return (iresult); 1383 } 1384 1385 1386 1387 /* Unregistered address ranges */ 1388 1389 /* 10.0.0.0 -> 10.255.255.255 */ 1390 #define UNREG_ADDR_A_LOWER 0x0a000000 1391 #define UNREG_ADDR_A_UPPER 0x0affffff 1392 1393 /* 172.16.0.0 -> 172.31.255.255 */ 1394 #define UNREG_ADDR_B_LOWER 0xac100000 1395 #define UNREG_ADDR_B_UPPER 0xac1fffff 1396 1397 /* 192.168.0.0 -> 192.168.255.255 */ 1398 #define UNREG_ADDR_C_LOWER 0xc0a80000 1399 #define UNREG_ADDR_C_UPPER 0xc0a8ffff 1400 1401 int 1402 LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize) 1403 { 1404 int res; 1405 1406 LIBALIAS_LOCK(la); 1407 res = LibAliasOutLocked(la, ptr, maxpacketsize, 1); 1408 LIBALIAS_UNLOCK(la); 1409 return (res); 1410 } 1411 1412 int 1413 LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create) 1414 { 1415 int res; 1416 1417 LIBALIAS_LOCK(la); 1418 res = LibAliasOutLocked(la, ptr, maxpacketsize, create); 1419 LIBALIAS_UNLOCK(la); 1420 return (res); 1421 } 1422 1423 static int 1424 LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */ 1425 int maxpacketsize, /* How much the packet data may grow (FTP 1426 * and IRC inline changes) */ 1427 int create /* Create new entries ? */ 1428 ) 1429 { 1430 int iresult; 1431 struct in_addr addr_save; 1432 struct ip *pip; 1433 1434 if (la->packetAliasMode & PKT_ALIAS_REVERSE) { 1435 la->packetAliasMode &= ~PKT_ALIAS_REVERSE; 1436 iresult = LibAliasInLocked(la, ptr, maxpacketsize); 1437 la->packetAliasMode |= PKT_ALIAS_REVERSE; 1438 goto getout; 1439 } 1440 HouseKeeping(la); 1441 ClearCheckNewLink(la); 1442 pip = (struct ip *)ptr; 1443 1444 /* Defense against mangled packets */ 1445 if (ntohs(pip->ip_len) > maxpacketsize 1446 || (pip->ip_hl << 2) > maxpacketsize) { 1447 iresult = PKT_ALIAS_IGNORED; 1448 goto getout; 1449 } 1450 1451 addr_save = GetDefaultAliasAddress(la); 1452 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) { 1453 u_long addr; 1454 int iclass; 1455 1456 iclass = 0; 1457 addr = ntohl(pip->ip_src.s_addr); 1458 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER) 1459 iclass = 3; 1460 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER) 1461 iclass = 2; 1462 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER) 1463 iclass = 1; 1464 1465 if (iclass == 0) { 1466 SetDefaultAliasAddress(la, pip->ip_src); 1467 } 1468 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) { 1469 SetDefaultAliasAddress(la, pip->ip_src); 1470 } 1471 iresult = PKT_ALIAS_IGNORED; 1472 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 1473 switch (pip->ip_p) { 1474 case IPPROTO_ICMP: 1475 iresult = IcmpAliasOut(la, pip, create); 1476 break; 1477 case IPPROTO_UDP: 1478 iresult = UdpAliasOut(la, pip, maxpacketsize, create); 1479 break; 1480 case IPPROTO_TCP: 1481 iresult = TcpAliasOut(la, pip, maxpacketsize, create); 1482 break; 1483 case IPPROTO_GRE: { 1484 int error; 1485 struct alias_data ad = { 1486 .lnk = NULL, 1487 .oaddr = NULL, 1488 .aaddr = NULL, 1489 .aport = NULL, 1490 .sport = NULL, 1491 .dport = NULL, 1492 .maxpktsize = 0 1493 }; 1494 /* Walk out chain. */ 1495 error = find_handler(OUT, IP, la, pip, &ad); 1496 if (error == 0) 1497 iresult = PKT_ALIAS_OK; 1498 else 1499 iresult = ProtoAliasOut(la, &pip->ip_src, 1500 pip->ip_dst, pip->ip_p, &pip->ip_sum, create); 1501 } 1502 break; 1503 default: 1504 iresult = ProtoAliasOut(la, &pip->ip_src, 1505 pip->ip_dst, pip->ip_p, &pip->ip_sum, create); 1506 break; 1507 } 1508 } else { 1509 iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum); 1510 } 1511 1512 SetDefaultAliasAddress(la, addr_save); 1513 getout: 1514 return (iresult); 1515 } 1516 1517 int 1518 LibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */ 1519 int maxpacketsize /* for error checking */ 1520 ) 1521 { 1522 struct ip *pip; 1523 struct icmp *ic; 1524 struct udphdr *ud; 1525 struct tcphdr *tc; 1526 struct alias_link *lnk; 1527 int iresult = PKT_ALIAS_IGNORED; 1528 1529 LIBALIAS_LOCK(la); 1530 pip = (struct ip *)ptr; 1531 1532 /* Defense against mangled packets */ 1533 if (ntohs(pip->ip_len) > maxpacketsize 1534 || (pip->ip_hl << 2) > maxpacketsize) 1535 goto getout; 1536 1537 ud = (struct udphdr *)ip_next(pip); 1538 tc = (struct tcphdr *)ip_next(pip); 1539 ic = (struct icmp *)ip_next(pip); 1540 1541 /* Find a link */ 1542 if (pip->ip_p == IPPROTO_UDP) 1543 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src, 1544 ud->uh_dport, ud->uh_sport, 1545 IPPROTO_UDP, 0); 1546 else if (pip->ip_p == IPPROTO_TCP) 1547 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src, 1548 tc->th_dport, tc->th_sport, 1549 IPPROTO_TCP, 0); 1550 else if (pip->ip_p == IPPROTO_ICMP) 1551 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0); 1552 else 1553 lnk = NULL; 1554 1555 /* Change it from an aliased packet to an unaliased packet */ 1556 if (lnk != NULL) { 1557 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) { 1558 int accumulate; 1559 struct in_addr original_address; 1560 u_short original_port; 1561 1562 original_address = GetOriginalAddress(lnk); 1563 original_port = GetOriginalPort(lnk); 1564 1565 /* Adjust TCP/UDP checksum */ 1566 accumulate = twowords(&pip->ip_src); 1567 accumulate -= twowords(&original_address); 1568 1569 if (pip->ip_p == IPPROTO_UDP) { 1570 accumulate += ud->uh_sport; 1571 accumulate -= original_port; 1572 ADJUST_CHECKSUM(accumulate, ud->uh_sum); 1573 } else { 1574 accumulate += tc->th_sport; 1575 accumulate -= original_port; 1576 ADJUST_CHECKSUM(accumulate, tc->th_sum); 1577 } 1578 1579 /* Adjust IP checksum */ 1580 DifferentialChecksum(&pip->ip_sum, 1581 &original_address, &pip->ip_src, 2); 1582 1583 /* Un-alias source address and port number */ 1584 pip->ip_src = original_address; 1585 if (pip->ip_p == IPPROTO_UDP) 1586 ud->uh_sport = original_port; 1587 else 1588 tc->th_sport = original_port; 1589 1590 iresult = PKT_ALIAS_OK; 1591 1592 } else if (pip->ip_p == IPPROTO_ICMP) { 1593 1594 int accumulate; 1595 struct in_addr original_address; 1596 u_short original_id; 1597 1598 original_address = GetOriginalAddress(lnk); 1599 original_id = GetOriginalPort(lnk); 1600 1601 /* Adjust ICMP checksum */ 1602 accumulate = twowords(&pip->ip_src); 1603 accumulate -= twowords(&original_address); 1604 accumulate += ic->icmp_id; 1605 accumulate -= original_id; 1606 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum); 1607 1608 /* Adjust IP checksum */ 1609 DifferentialChecksum(&pip->ip_sum, 1610 &original_address, &pip->ip_src, 2); 1611 1612 /* Un-alias source address and port number */ 1613 pip->ip_src = original_address; 1614 ic->icmp_id = original_id; 1615 1616 iresult = PKT_ALIAS_OK; 1617 } 1618 } 1619 getout: 1620 LIBALIAS_UNLOCK(la); 1621 return (iresult); 1622 1623 } 1624 1625 #ifndef _KERNEL 1626 1627 int 1628 LibAliasRefreshModules(void) 1629 { 1630 char buf[256], conf[] = "/etc/libalias.conf"; 1631 FILE *fd; 1632 int i, len; 1633 1634 fd = fopen(conf, "r"); 1635 if (fd == NULL) 1636 err(1, "fopen(%s)", conf); 1637 1638 LibAliasUnLoadAllModule(); 1639 1640 for (;;) { 1641 fgets(buf, 256, fd); 1642 if (feof(fd)) 1643 break; 1644 len = strlen(buf); 1645 if (len > 1) { 1646 for (i = 0; i < len; i++) 1647 if (!isspace(buf[i])) 1648 break; 1649 if (buf[i] == '#') 1650 continue; 1651 buf[len - 1] = '\0'; 1652 printf("Loading %s\n", buf); 1653 LibAliasLoadModule(buf); 1654 } 1655 } 1656 return (0); 1657 } 1658 1659 int 1660 LibAliasLoadModule(char *path) 1661 { 1662 struct dll *t; 1663 void *handle; 1664 struct proto_handler *m; 1665 const char *error; 1666 moduledata_t *p; 1667 1668 handle = dlopen (path, RTLD_LAZY); 1669 if (!handle) { 1670 fprintf(stderr, "%s\n", dlerror()); 1671 return (EINVAL); 1672 } 1673 1674 p = dlsym(handle, "alias_mod"); 1675 if ((error = dlerror()) != NULL) { 1676 fprintf(stderr, "%s\n", dlerror()); 1677 return (EINVAL); 1678 } 1679 1680 t = malloc(sizeof(struct dll)); 1681 if (t == NULL) 1682 return (ENOMEM); 1683 strncpy(t->name, p->name, DLL_LEN); 1684 t->handle = handle; 1685 if (attach_dll(t) == EEXIST) { 1686 free(t); 1687 fprintf(stderr, "dll conflict\n"); 1688 return (EEXIST); 1689 } 1690 1691 m = dlsym(t->handle, "handlers"); 1692 if ((error = dlerror()) != NULL) { 1693 fprintf(stderr, "%s\n", error); 1694 return (EINVAL); 1695 } 1696 1697 LibAliasAttachHandlers(m); 1698 return (0); 1699 } 1700 1701 int 1702 LibAliasUnLoadAllModule(void) 1703 { 1704 struct dll *t; 1705 struct proto_handler *p; 1706 1707 /* Unload all modules then reload everything. */ 1708 while ((p = first_handler()) != NULL) { 1709 detach_handler(p); 1710 } 1711 while ((t = walk_dll_chain()) != NULL) { 1712 dlclose(t->handle); 1713 free(t); 1714 } 1715 return (1); 1716 } 1717 1718 #endif 1719 1720 #ifdef _KERNEL 1721 /* 1722 * m_megapullup() - this function is a big hack. 1723 * Thankfully, it's only used in ng_nat and ipfw+nat. 1724 * 1725 * It allocates an mbuf with cluster and copies the specified part of the chain 1726 * into cluster, so that it is all contiguous and can be accessed via a plain 1727 * (char *) pointer. This is required, because libalias doesn't know how to 1728 * handle mbuf chains. 1729 * 1730 * On success, m_megapullup returns an mbuf (possibly with cluster) containing 1731 * the input packet, on failure NULL. The input packet is always consumed. 1732 */ 1733 struct mbuf * 1734 m_megapullup(struct mbuf *m, int len) { 1735 struct mbuf *mcl; 1736 1737 if (len > m->m_pkthdr.len) 1738 goto bad; 1739 1740 /* Do not reallocate packet if it is sequentional, 1741 * writable and has some extra space for expansion. 1742 * XXX: Constant 100bytes is completely empirical. */ 1743 #define RESERVE 100 1744 if (m->m_next == NULL && M_WRITABLE(m) && M_TRAILINGSPACE(m) >= RESERVE) 1745 return (m); 1746 1747 if (len <= MCLBYTES - RESERVE) { 1748 mcl = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1749 } else if (len < MJUM16BYTES) { 1750 int size; 1751 if (len <= MJUMPAGESIZE - RESERVE) { 1752 size = MJUMPAGESIZE; 1753 } else if (len <= MJUM9BYTES - RESERVE) { 1754 size = MJUM9BYTES; 1755 } else { 1756 size = MJUM16BYTES; 1757 }; 1758 mcl = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size); 1759 } else { 1760 goto bad; 1761 } 1762 if (mcl == NULL) 1763 goto bad; 1764 1765 m_move_pkthdr(mcl, m); 1766 m_copydata(m, 0, len, mtod(mcl, caddr_t)); 1767 mcl->m_len = mcl->m_pkthdr.len = len; 1768 m_freem(m); 1769 1770 return (mcl); 1771 bad: 1772 m_freem(m); 1773 return (NULL); 1774 } 1775 #endif 1776