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