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