1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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__FBSDID("$FreeBSD$"); 31 32/* 33 Alias_db.c encapsulates all data structures used for storing 34 packet aliasing data. Other parts of the aliasing software 35 access data through functions provided in this file. 36 37 Data storage is based on the notion of a "link", which is 38 established for ICMP echo/reply packets, UDP datagrams and 39 TCP stream connections. A link stores the original source 40 and destination addresses. For UDP and TCP, it also stores 41 source and destination port numbers, as well as an alias 42 port number. Links are also used to store information about 43 fragments. 44 45 There is a facility for sweeping through and deleting old 46 links as new packets are sent through. A simple timeout is 47 used for ICMP and UDP links. TCP links are left alone unless 48 there is an incomplete connection, in which case the link 49 can be deleted after a certain amount of time. 50 51 Initial version: August, 1996 (cjm) 52 53 Version 1.4: September 16, 1996 (cjm) 54 Facility for handling incoming links added. 55 56 Version 1.6: September 18, 1996 (cjm) 57 ICMP data handling simplified. 58 59 Version 1.7: January 9, 1997 (cjm) 60 Fragment handling simplified. 61 Saves pointers for unresolved fragments. 62 Permits links for unspecified remote ports 63 or unspecified remote addresses. 64 Fixed bug which did not properly zero port 65 table entries after a link was deleted. 66 Cleaned up some obsolete comments. 67 68 Version 1.8: January 14, 1997 (cjm) 69 Fixed data type error in StartPoint(). 70 (This error did not exist prior to v1.7 71 and was discovered and fixed by Ari Suutari) 72 73 Version 1.9: February 1, 1997 74 Optionally, connections initiated from packet aliasing host 75 machine will will not have their port number aliased unless it 76 conflicts with an aliasing port already being used. (cjm) 77 78 All options earlier being #ifdef'ed are now available through 79 a new interface, SetPacketAliasMode(). This allows run time 80 control (which is now available in PPP+pktAlias through the 81 'alias' keyword). (ee) 82 83 Added ability to create an alias port without 84 either destination address or port specified. 85 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) 86 87 Removed K&R style function headers 88 and general cleanup. (ee) 89 90 Added packetAliasMode to replace compiler #defines's (ee) 91 92 Allocates sockets for partially specified 93 ports if ALIAS_USE_SOCKETS defined. (cjm) 94 95 Version 2.0: March, 1997 96 SetAliasAddress() will now clean up alias links 97 if the aliasing address is changed. (cjm) 98 99 PacketAliasPermanentLink() function added to support permanent 100 links. (J. Fortes suggested the need for this.) 101 Examples: 102 103 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port 104 105 (192.168.0.2, port 21) <-> alias port 3604, known dest addr 106 unknown dest port 107 108 These permanent links allow for incoming connections to 109 machines on the local network. They can be given with a 110 user-chosen amount of specificity, with increasing specificity 111 meaning more security. (cjm) 112 113 Quite a bit of rework to the basic engine. The portTable[] 114 array, which kept track of which ports were in use was replaced 115 by a table/linked list structure. (cjm) 116 117 SetExpire() function added. (cjm) 118 119 DeleteLink() no longer frees memory association with a pointer 120 to a fragment (this bug was first recognized by E. Eklund in 121 v1.9). 122 123 Version 2.1: May, 1997 (cjm) 124 Packet aliasing engine reworked so that it can handle 125 multiple external addresses rather than just a single 126 host address. 127 128 PacketAliasRedirectPort() and PacketAliasRedirectAddr() 129 added to the API. The first function is a more generalized 130 version of PacketAliasPermanentLink(). The second function 131 implements static network address translation. 132 133 Version 3.2: July, 2000 (salander and satoh) 134 Added FindNewPortGroup to get contiguous range of port values. 135 136 Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing 137 link but not actually add one. 138 139 Added FindRtspOut, which is closely derived from FindUdpTcpOut, 140 except that the alias port (from FindNewPortGroup) is provided 141 as input. 142 143 See HISTORY file for additional revisions. 144*/ 145 146#ifdef _KERNEL 147#include <machine/stdarg.h> 148#include <sys/param.h> 149#include <sys/kernel.h> 150#include <sys/systm.h> 151#include <sys/lock.h> 152#include <sys/module.h> 153#include <sys/rwlock.h> 154#include <sys/syslog.h> 155#else 156#include <stdarg.h> 157#include <stdlib.h> 158#include <stdio.h> 159#include <sys/errno.h> 160#include <sys/time.h> 161#include <unistd.h> 162#endif 163 164#include <sys/socket.h> 165#include <netinet/tcp.h> 166 167#ifdef _KERNEL 168#include <netinet/libalias/alias.h> 169#include <netinet/libalias/alias_local.h> 170#include <netinet/libalias/alias_mod.h> 171#include <net/if.h> 172#else 173#include "alias.h" 174#include "alias_local.h" 175#include "alias_mod.h" 176#endif 177 178static LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead); 179 180/* 181 Constants (note: constants are also defined 182 near relevant functions or structs) 183*/ 184 185/* Parameters used for cleanup of expired links */ 186/* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */ 187#define ALIAS_CLEANUP_INTERVAL_SECS 64 188#define ALIAS_CLEANUP_MAX_SPOKES (LINK_TABLE_OUT_SIZE/5) 189 190/* Timeouts (in seconds) for different link types */ 191#define ICMP_EXPIRE_TIME 60 192#define UDP_EXPIRE_TIME 60 193#define PROTO_EXPIRE_TIME 60 194#define FRAGMENT_ID_EXPIRE_TIME 10 195#define FRAGMENT_PTR_EXPIRE_TIME 30 196 197/* TCP link expire time for different cases */ 198/* When the link has been used and closed - minimal grace time to 199 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 200#ifndef TCP_EXPIRE_DEAD 201#define TCP_EXPIRE_DEAD 10 202#endif 203 204/* When the link has been used and closed on one side - the other side 205 is allowed to still send data */ 206#ifndef TCP_EXPIRE_SINGLEDEAD 207#define TCP_EXPIRE_SINGLEDEAD 90 208#endif 209 210/* When the link isn't yet up */ 211#ifndef TCP_EXPIRE_INITIAL 212#define TCP_EXPIRE_INITIAL 300 213#endif 214 215/* When the link is up */ 216#ifndef TCP_EXPIRE_CONNECTED 217#define TCP_EXPIRE_CONNECTED 86400 218#endif 219 220/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 221 These constants can be anything except zero, which indicates an 222 unknown port number. */ 223 224#define NO_DEST_PORT 1 225#define NO_SRC_PORT 1 226 227/* Matches any/unknown address in FindLinkIn/Out() and AddLink(). */ 228static struct in_addr const ANY_ADDR = { INADDR_ANY }; 229 230/* Data Structures 231 232 The fundamental data structure used in this program is 233 "struct alias_link". Whenever a TCP connection is made, 234 a UDP datagram is sent out, or an ICMP echo request is made, 235 a link record is made (if it has not already been created). 236 The link record is identified by the source address/port 237 and the destination address/port. In the case of an ICMP 238 echo request, the source port is treated as being equivalent 239 with the 16-bit ID number of the ICMP packet. 240 241 The link record also can store some auxiliary data. For 242 TCP connections that have had sequence and acknowledgment 243 modifications, data space is available to track these changes. 244 A state field is used to keep track in changes to the TCP 245 connection state. ID numbers of fragments can also be 246 stored in the auxiliary space. Pointers to unresolved 247 fragments can also be stored. 248 249 The link records support two independent chainings. Lookup 250 tables for input and out tables hold the initial pointers 251 the link chains. On input, the lookup table indexes on alias 252 port and link type. On output, the lookup table indexes on 253 source address, destination address, source port, destination 254 port and link type. 255*/ 256 257/* used to save changes to ACK/sequence numbers */ 258struct ack_data_record { 259 u_long ack_old; 260 u_long ack_new; 261 int delta; 262 int active; 263}; 264 265/* Information about TCP connection */ 266struct tcp_state { 267 int in; /* State for outside -> inside */ 268 int out; /* State for inside -> outside */ 269 int index; /* Index to ACK data array */ 270 /* Indicates whether ACK and sequence numbers been modified */ 271 int ack_modified; 272}; 273 274/* Number of distinct ACK number changes 275 * saved for a modified TCP stream */ 276#define N_LINK_TCP_DATA 3 277struct tcp_dat { 278 struct tcp_state state; 279 struct ack_data_record ack[N_LINK_TCP_DATA]; 280 /* Which firewall record is used for this hole? */ 281 int fwhole; 282}; 283 284/* LSNAT server pool (circular list) */ 285struct server { 286 struct in_addr addr; 287 u_short port; 288 struct server *next; 289}; 290 291/* Main data structure */ 292struct alias_link { 293 struct libalias *la; 294 /* Address and port information */ 295 struct in_addr src_addr; 296 struct in_addr dst_addr; 297 struct in_addr alias_addr; 298 struct in_addr proxy_addr; 299 u_short src_port; 300 u_short dst_port; 301 u_short alias_port; 302 u_short proxy_port; 303 struct server *server; 304 /* Type of link: TCP, UDP, ICMP, proto, frag */ 305 int link_type; 306/* values for link_type */ 307#define LINK_ICMP IPPROTO_ICMP 308#define LINK_UDP IPPROTO_UDP 309#define LINK_TCP IPPROTO_TCP 310#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 311#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 312#define LINK_ADDR (IPPROTO_MAX + 3) 313#define LINK_PPTP (IPPROTO_MAX + 4) 314 315 int flags; /* indicates special characteristics */ 316 int pflags; /* protocol-specific flags */ 317/* flag bits */ 318#define LINK_UNKNOWN_DEST_PORT 0x01 319#define LINK_UNKNOWN_DEST_ADDR 0x02 320#define LINK_PERMANENT 0x04 321#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 322#define LINK_UNFIREWALLED 0x08 323 324 int timestamp; /* Time link was last accessed */ 325 int expire_time; /* Expire time for link */ 326#ifndef NO_USE_SOCKETS 327 int sockfd; /* socket descriptor */ 328#endif 329 /* Linked list of pointers for input and output lookup tables */ 330 LIST_ENTRY (alias_link) list_out; 331 LIST_ENTRY (alias_link) list_in; 332 /* Auxiliary data */ 333 union { 334 char *frag_ptr; 335 struct in_addr frag_addr; 336 struct tcp_dat *tcp; 337 } data; 338}; 339 340/* Clean up procedure. */ 341static void finishoff(void); 342 343/* Kernel module definition. */ 344#ifdef _KERNEL 345MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing"); 346 347MODULE_VERSION(libalias, 1); 348 349static int 350alias_mod_handler(module_t mod, int type, void *data) 351{ 352 switch (type) { 353 case MOD_QUIESCE: 354 case MOD_UNLOAD: 355 finishoff(); 356 case MOD_LOAD: 357 return (0); 358 default: 359 return (EINVAL); 360 } 361} 362 363static moduledata_t alias_mod = { 364 "alias", alias_mod_handler, NULL 365}; 366 367DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND); 368#endif 369 370/* Internal utility routines (used only in alias_db.c) 371 372Lookup table starting points: 373 StartPointIn() -- link table initial search point for 374 incoming packets 375 StartPointOut() -- link table initial search point for 376 outgoing packets 377 378Miscellaneous: 379 SeqDiff() -- difference between two TCP sequences 380 ShowAliasStats() -- send alias statistics to a monitor file 381*/ 382 383/* Local prototypes */ 384static u_int StartPointIn(struct in_addr, u_short, int); 385 386static u_int 387StartPointOut(struct in_addr, struct in_addr, 388 u_short, u_short, int); 389 390static int SeqDiff(u_long, u_long); 391 392#ifndef NO_FW_PUNCH 393/* Firewall control */ 394static void InitPunchFW(struct libalias *); 395static void UninitPunchFW(struct libalias *); 396static void ClearFWHole(struct alias_link *); 397 398#endif 399 400/* Log file control */ 401static void ShowAliasStats(struct libalias *); 402static int InitPacketAliasLog(struct libalias *); 403static void UninitPacketAliasLog(struct libalias *); 404 405void SctpShowAliasStats(struct libalias *la); 406 407static u_int 408StartPointIn(struct in_addr alias_addr, 409 u_short alias_port, 410 int link_type) 411{ 412 u_int n; 413 414 n = alias_addr.s_addr; 415 if (link_type != LINK_PPTP) 416 n += alias_port; 417 n += link_type; 418 return (n % LINK_TABLE_IN_SIZE); 419} 420 421static u_int 422StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 423 u_short src_port, u_short dst_port, int link_type) 424{ 425 u_int n; 426 427 n = src_addr.s_addr; 428 n += dst_addr.s_addr; 429 if (link_type != LINK_PPTP) { 430 n += src_port; 431 n += dst_port; 432 } 433 n += link_type; 434 435 return (n % LINK_TABLE_OUT_SIZE); 436} 437 438static int 439SeqDiff(u_long x, u_long y) 440{ 441/* Return the difference between two TCP sequence numbers 442 * This function is encapsulated in case there are any unusual 443 * arithmetic conditions that need to be considered. 444 */ 445 return (ntohl(y) - ntohl(x)); 446} 447 448#ifdef _KERNEL 449static void 450AliasLog(char *str, const char *format, ...) 451{ 452 va_list ap; 453 454 va_start(ap, format); 455 vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap); 456 va_end(ap); 457} 458#else 459static void 460AliasLog(FILE *stream, const char *format, ...) 461{ 462 va_list ap; 463 464 va_start(ap, format); 465 vfprintf(stream, format, ap); 466 va_end(ap); 467 fflush(stream); 468} 469#endif 470 471static void 472ShowAliasStats(struct libalias *la) 473{ 474 LIBALIAS_LOCK_ASSERT(la); 475 /* Used for debugging */ 476 if (la->logDesc) { 477 int tot = la->icmpLinkCount + la->udpLinkCount + 478 (la->sctpLinkCount>>1) + /* sctp counts half associations */ 479 la->tcpLinkCount + la->pptpLinkCount + 480 la->protoLinkCount + la->fragmentIdLinkCount + 481 la->fragmentPtrLinkCount; 482 483 AliasLog(la->logDesc, 484 "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u", 485 la->icmpLinkCount, 486 la->udpLinkCount, 487 la->tcpLinkCount, 488 la->sctpLinkCount>>1, /* sctp counts half associations */ 489 la->pptpLinkCount, 490 la->protoLinkCount, 491 la->fragmentIdLinkCount, 492 la->fragmentPtrLinkCount, 493 tot); 494#ifndef _KERNEL 495 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount); 496#endif 497 } 498} 499 500void SctpShowAliasStats(struct libalias *la) 501{ 502 ShowAliasStats(la); 503} 504 505/* Internal routines for finding, deleting and adding links 506 507Port Allocation: 508 GetNewPort() -- find and reserve new alias port number 509 GetSocket() -- try to allocate a socket for a given port 510 511Link creation and deletion: 512 CleanupAliasData() - remove all link chains from lookup table 513 IncrementalCleanup() - look for stale links in a single chain 514 DeleteLink() - remove link 515 AddLink() - add link 516 ReLink() - change link 517 518Link search: 519 FindLinkOut() - find link for outgoing packets 520 FindLinkIn() - find link for incoming packets 521 522Port search: 523 FindNewPortGroup() - find an available group of ports 524*/ 525 526/* Local prototypes */ 527static int GetNewPort(struct libalias *, struct alias_link *, int); 528#ifndef NO_USE_SOCKETS 529static u_short GetSocket(struct libalias *, u_short, int *, int); 530#endif 531static void CleanupAliasData(struct libalias *); 532static void IncrementalCleanup(struct libalias *); 533static void DeleteLink(struct alias_link *); 534 535static struct alias_link * 536ReLink(struct alias_link *, 537 struct in_addr, struct in_addr, struct in_addr, 538 u_short, u_short, int, int); 539 540static struct alias_link * 541FindLinkOut(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 542 543static struct alias_link * 544FindLinkIn(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int); 545 546#define ALIAS_PORT_BASE 0x08000 547#define ALIAS_PORT_MASK 0x07fff 548#define ALIAS_PORT_MASK_EVEN 0x07ffe 549#define GET_NEW_PORT_MAX_ATTEMPTS 20 550 551#define FIND_EVEN_ALIAS_BASE 1 552 553/* GetNewPort() allocates port numbers. Note that if a port number 554 is already in use, that does not mean that it cannot be used by 555 another link concurrently. This is because GetNewPort() looks for 556 unused triplets: (dest addr, dest port, alias port). */ 557 558static int 559GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param) 560{ 561 int i; 562 int max_trials; 563 u_short port_sys; 564 u_short port_net; 565 566 LIBALIAS_LOCK_ASSERT(la); 567 /* 568 * Description of alias_port_param for GetNewPort(). When 569 * this parameter is zero or positive, it precisely specifies 570 * the port number. GetNewPort() will return this number 571 * without check that it is in use. 572 573 * When this parameter is GET_ALIAS_PORT, it indicates to get 574 * a randomly selected port number. 575 */ 576 if (alias_port_param == GET_ALIAS_PORT) { 577 /* 578 * The aliasing port is automatically selected by one of 579 * two methods below: 580 */ 581 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 582 583 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 584 /* 585 * When the PKT_ALIAS_SAME_PORTS option is chosen, 586 * the first try will be the actual source port. If 587 * this is already in use, the remainder of the 588 * trials will be random. 589 */ 590 port_net = lnk->src_port; 591 port_sys = ntohs(port_net); 592 } else if (la->aliasPortLower) { 593 /* First trial is a random port in the aliasing range. */ 594 port_sys = la->aliasPortLower + 595 (arc4random() % la->aliasPortLength); 596 port_net = htons(port_sys); 597 } else { 598 /* First trial and all subsequent are random. */ 599 port_sys = arc4random() & ALIAS_PORT_MASK; 600 port_sys += ALIAS_PORT_BASE; 601 port_net = htons(port_sys); 602 } 603 } else if (alias_port_param >= 0 && alias_port_param < 0x10000) { 604 lnk->alias_port = (u_short) alias_port_param; 605 return (0); 606 } else { 607#ifdef LIBALIAS_DEBUG 608 fprintf(stderr, "PacketAlias/GetNewPort(): "); 609 fprintf(stderr, "input parameter error\n"); 610#endif 611 return (-1); 612 } 613 614 /* Port number search */ 615 for (i = 0; i < max_trials; i++) { 616 int go_ahead; 617 struct alias_link *search_result; 618 619 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr, 620 lnk->dst_port, port_net, 621 lnk->link_type, 0); 622 623 if (search_result == NULL) 624 go_ahead = 1; 625 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED) 626 && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 627 go_ahead = 1; 628 else 629 go_ahead = 0; 630 631 if (go_ahead) { 632#ifndef NO_USE_SOCKETS 633 if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS) 634 && (lnk->flags & LINK_PARTIALLY_SPECIFIED) 635 && ((lnk->link_type == LINK_TCP) || 636 (lnk->link_type == LINK_UDP))) { 637 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) { 638 lnk->alias_port = port_net; 639 return (0); 640 } 641 } else { 642#endif 643 lnk->alias_port = port_net; 644 return (0); 645#ifndef NO_USE_SOCKETS 646 } 647#endif 648 } 649 if (la->aliasPortLower) { 650 port_sys = la->aliasPortLower + 651 (arc4random() % la->aliasPortLength); 652 port_net = htons(port_sys); 653 } else { 654 port_sys = arc4random() & ALIAS_PORT_MASK; 655 port_sys += ALIAS_PORT_BASE; 656 port_net = htons(port_sys); 657 } 658 } 659 660#ifdef LIBALIAS_DEBUG 661 fprintf(stderr, "PacketAlias/GetnewPort(): "); 662 fprintf(stderr, "could not find free port\n"); 663#endif 664 665 return (-1); 666} 667 668#ifndef NO_USE_SOCKETS 669static u_short 670GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type) 671{ 672 int err; 673 int sock; 674 struct sockaddr_in sock_addr; 675 676 LIBALIAS_LOCK_ASSERT(la); 677 if (link_type == LINK_TCP) 678 sock = socket(AF_INET, SOCK_STREAM, 0); 679 else if (link_type == LINK_UDP) 680 sock = socket(AF_INET, SOCK_DGRAM, 0); 681 else { 682#ifdef LIBALIAS_DEBUG 683 fprintf(stderr, "PacketAlias/GetSocket(): "); 684 fprintf(stderr, "incorrect link type\n"); 685#endif 686 return (0); 687 } 688 689 if (sock < 0) { 690#ifdef LIBALIAS_DEBUG 691 fprintf(stderr, "PacketAlias/GetSocket(): "); 692 fprintf(stderr, "socket() error %d\n", *sockfd); 693#endif 694 return (0); 695 } 696 sock_addr.sin_family = AF_INET; 697 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 698 sock_addr.sin_port = port_net; 699 700 err = bind(sock, 701 (struct sockaddr *)&sock_addr, 702 sizeof(sock_addr)); 703 if (err == 0) { 704 la->sockCount++; 705 *sockfd = sock; 706 return (1); 707 } else { 708 close(sock); 709 return (0); 710 } 711} 712#endif 713 714/* FindNewPortGroup() returns a base port number for an available 715 range of contiguous port numbers. Note that if a port number 716 is already in use, that does not mean that it cannot be used by 717 another link concurrently. This is because FindNewPortGroup() 718 looks for unused triplets: (dest addr, dest port, alias port). */ 719 720int 721FindNewPortGroup(struct libalias *la, 722 struct in_addr dst_addr, 723 struct in_addr alias_addr, 724 u_short src_port, 725 u_short dst_port, 726 u_short port_count, 727 u_char proto, 728 u_char align) 729{ 730 int i, j; 731 int max_trials; 732 u_short port_sys; 733 int link_type; 734 735 LIBALIAS_LOCK_ASSERT(la); 736 /* 737 * Get link_type from protocol 738 */ 739 740 switch (proto) { 741 case IPPROTO_UDP: 742 link_type = LINK_UDP; 743 break; 744 case IPPROTO_TCP: 745 link_type = LINK_TCP; 746 break; 747 default: 748 return (0); 749 break; 750 } 751 752 /* 753 * The aliasing port is automatically selected by one of two 754 * methods below: 755 */ 756 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 757 758 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) { 759 /* 760 * When the ALIAS_SAME_PORTS option is chosen, the first 761 * try will be the actual source port. If this is already 762 * in use, the remainder of the trials will be random. 763 */ 764 port_sys = ntohs(src_port); 765 766 } else { 767 /* First trial and all subsequent are random. */ 768 if (align == FIND_EVEN_ALIAS_BASE) 769 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN; 770 else 771 port_sys = arc4random() & ALIAS_PORT_MASK; 772 773 port_sys += ALIAS_PORT_BASE; 774 } 775 776 /* Port number search */ 777 for (i = 0; i < max_trials; i++) { 778 struct alias_link *search_result; 779 780 for (j = 0; j < port_count; j++) 781 if ((search_result = FindLinkIn(la, dst_addr, 782 alias_addr, dst_port, htons(port_sys + j), 783 link_type, 0)) != NULL) 784 break; 785 786 /* Found a good range, return base */ 787 if (j == port_count) 788 return (htons(port_sys)); 789 790 /* Find a new base to try */ 791 if (align == FIND_EVEN_ALIAS_BASE) 792 port_sys = arc4random() & ALIAS_PORT_MASK_EVEN; 793 else 794 port_sys = arc4random() & ALIAS_PORT_MASK; 795 796 port_sys += ALIAS_PORT_BASE; 797 } 798 799#ifdef LIBALIAS_DEBUG 800 fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 801 fprintf(stderr, "could not find free port(s)\n"); 802#endif 803 804 return (0); 805} 806 807static void 808CleanupAliasData(struct libalias *la) 809{ 810 struct alias_link *lnk; 811 int i; 812 813 LIBALIAS_LOCK_ASSERT(la); 814 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { 815 lnk = LIST_FIRST(&la->linkTableOut[i]); 816 while (lnk != NULL) { 817 struct alias_link *link_next = LIST_NEXT(lnk, list_out); 818 DeleteLink(lnk); 819 lnk = link_next; 820 } 821 } 822 823 la->cleanupIndex = 0; 824} 825 826static void 827IncrementalCleanup(struct libalias *la) 828{ 829 struct alias_link *lnk, *lnk_tmp; 830 831 LIBALIAS_LOCK_ASSERT(la); 832 LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++], 833 list_out, lnk_tmp) { 834 if (la->timeStamp - lnk->timestamp > lnk->expire_time) 835 DeleteLink(lnk); 836 } 837 838 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE) 839 la->cleanupIndex = 0; 840} 841 842static void 843DeleteLink(struct alias_link *lnk) 844{ 845 struct libalias *la = lnk->la; 846 847 LIBALIAS_LOCK_ASSERT(la); 848 /* Don't do anything if the link is marked permanent */ 849 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT) 850 return; 851 852#ifndef NO_FW_PUNCH 853 /* Delete associated firewall hole, if any */ 854 ClearFWHole(lnk); 855#endif 856 857 /* Free memory allocated for LSNAT server pool */ 858 if (lnk->server != NULL) { 859 struct server *head, *curr, *next; 860 861 head = curr = lnk->server; 862 do { 863 next = curr->next; 864 free(curr); 865 } while ((curr = next) != head); 866 } 867 /* Adjust output table pointers */ 868 LIST_REMOVE(lnk, list_out); 869 870 /* Adjust input table pointers */ 871 LIST_REMOVE(lnk, list_in); 872#ifndef NO_USE_SOCKETS 873 /* Close socket, if one has been allocated */ 874 if (lnk->sockfd != -1) { 875 la->sockCount--; 876 close(lnk->sockfd); 877 } 878#endif 879 /* Link-type dependent cleanup */ 880 switch (lnk->link_type) { 881 case LINK_ICMP: 882 la->icmpLinkCount--; 883 break; 884 case LINK_UDP: 885 la->udpLinkCount--; 886 break; 887 case LINK_TCP: 888 la->tcpLinkCount--; 889 free(lnk->data.tcp); 890 break; 891 case LINK_PPTP: 892 la->pptpLinkCount--; 893 break; 894 case LINK_FRAGMENT_ID: 895 la->fragmentIdLinkCount--; 896 break; 897 case LINK_FRAGMENT_PTR: 898 la->fragmentPtrLinkCount--; 899 if (lnk->data.frag_ptr != NULL) 900 free(lnk->data.frag_ptr); 901 break; 902 case LINK_ADDR: 903 break; 904 default: 905 la->protoLinkCount--; 906 break; 907 } 908 909 /* Free memory */ 910 free(lnk); 911 912 /* Write statistics, if logging enabled */ 913 if (la->packetAliasMode & PKT_ALIAS_LOG) { 914 ShowAliasStats(la); 915 } 916} 917 918struct alias_link * 919AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr, 920 struct in_addr alias_addr, u_short src_port, u_short dst_port, 921 int alias_port_param, int link_type) 922{ 923 u_int start_point; 924 struct alias_link *lnk; 925 926 LIBALIAS_LOCK_ASSERT(la); 927 lnk = malloc(sizeof(struct alias_link)); 928 if (lnk != NULL) { 929 /* Basic initialization */ 930 lnk->la = la; 931 lnk->src_addr = src_addr; 932 lnk->dst_addr = dst_addr; 933 lnk->alias_addr = alias_addr; 934 lnk->proxy_addr.s_addr = INADDR_ANY; 935 lnk->src_port = src_port; 936 lnk->dst_port = dst_port; 937 lnk->proxy_port = 0; 938 lnk->server = NULL; 939 lnk->link_type = link_type; 940#ifndef NO_USE_SOCKETS 941 lnk->sockfd = -1; 942#endif 943 lnk->flags = 0; 944 lnk->pflags = 0; 945 lnk->timestamp = la->timeStamp; 946 947 /* Expiration time */ 948 switch (link_type) { 949 case LINK_ICMP: 950 lnk->expire_time = ICMP_EXPIRE_TIME; 951 break; 952 case LINK_UDP: 953 lnk->expire_time = UDP_EXPIRE_TIME; 954 break; 955 case LINK_TCP: 956 lnk->expire_time = TCP_EXPIRE_INITIAL; 957 break; 958 case LINK_PPTP: 959 lnk->flags |= LINK_PERMANENT; /* no timeout. */ 960 break; 961 case LINK_FRAGMENT_ID: 962 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME; 963 break; 964 case LINK_FRAGMENT_PTR: 965 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 966 break; 967 case LINK_ADDR: 968 break; 969 default: 970 lnk->expire_time = PROTO_EXPIRE_TIME; 971 break; 972 } 973 974 /* Determine alias flags */ 975 if (dst_addr.s_addr == INADDR_ANY) 976 lnk->flags |= LINK_UNKNOWN_DEST_ADDR; 977 if (dst_port == 0) 978 lnk->flags |= LINK_UNKNOWN_DEST_PORT; 979 980 /* Determine alias port */ 981 if (GetNewPort(la, lnk, alias_port_param) != 0) { 982 free(lnk); 983 return (NULL); 984 } 985 /* Link-type dependent initialization */ 986 switch (link_type) { 987 struct tcp_dat *aux_tcp; 988 989 case LINK_ICMP: 990 la->icmpLinkCount++; 991 break; 992 case LINK_UDP: 993 la->udpLinkCount++; 994 break; 995 case LINK_TCP: 996 aux_tcp = malloc(sizeof(struct tcp_dat)); 997 if (aux_tcp != NULL) { 998 int i; 999 1000 la->tcpLinkCount++; 1001 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 1002 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 1003 aux_tcp->state.index = 0; 1004 aux_tcp->state.ack_modified = 0; 1005 for (i = 0; i < N_LINK_TCP_DATA; i++) 1006 aux_tcp->ack[i].active = 0; 1007 aux_tcp->fwhole = -1; 1008 lnk->data.tcp = aux_tcp; 1009 } else { 1010#ifdef LIBALIAS_DEBUG 1011 fprintf(stderr, "PacketAlias/AddLink: "); 1012 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 1013#endif 1014 free(lnk); 1015 return (NULL); 1016 } 1017 break; 1018 case LINK_PPTP: 1019 la->pptpLinkCount++; 1020 break; 1021 case LINK_FRAGMENT_ID: 1022 la->fragmentIdLinkCount++; 1023 break; 1024 case LINK_FRAGMENT_PTR: 1025 la->fragmentPtrLinkCount++; 1026 break; 1027 case LINK_ADDR: 1028 break; 1029 default: 1030 la->protoLinkCount++; 1031 break; 1032 } 1033 1034 /* Set up pointers for output lookup table */ 1035 start_point = StartPointOut(src_addr, dst_addr, 1036 src_port, dst_port, link_type); 1037 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out); 1038 1039 /* Set up pointers for input lookup table */ 1040 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type); 1041 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in); 1042 } else { 1043#ifdef LIBALIAS_DEBUG 1044 fprintf(stderr, "PacketAlias/AddLink(): "); 1045 fprintf(stderr, "malloc() call failed.\n"); 1046#endif 1047 } 1048 if (la->packetAliasMode & PKT_ALIAS_LOG) { 1049 ShowAliasStats(la); 1050 } 1051 return (lnk); 1052} 1053 1054/* 1055 * If alias_port_param is less than zero, alias port will be automatically 1056 * chosen. If greater than zero, equal to alias port 1057 */ 1058static struct alias_link * 1059ReLink(struct alias_link *old_lnk, 1060 struct in_addr src_addr, 1061 struct in_addr dst_addr, 1062 struct in_addr alias_addr, 1063 u_short src_port, 1064 u_short dst_port, 1065 int alias_port_param, 1066 int link_type) 1067{ 1068 struct alias_link *new_lnk; 1069 struct libalias *la = old_lnk->la; 1070 1071 LIBALIAS_LOCK_ASSERT(la); 1072 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1073 src_port, dst_port, alias_port_param, 1074 link_type); 1075#ifndef NO_FW_PUNCH 1076 if (new_lnk != NULL && 1077 old_lnk->link_type == LINK_TCP && 1078 old_lnk->data.tcp->fwhole > 0) { 1079 PunchFWHole(new_lnk); 1080 } 1081#endif 1082 DeleteLink(old_lnk); 1083 return (new_lnk); 1084} 1085 1086static struct alias_link * 1087_FindLinkOut(struct libalias *la, struct in_addr src_addr, 1088 struct in_addr dst_addr, 1089 u_short src_port, 1090 u_short dst_port, 1091 int link_type, 1092 int replace_partial_links) 1093{ 1094 u_int i; 1095 struct alias_link *lnk; 1096 1097 LIBALIAS_LOCK_ASSERT(la); 1098 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1099 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) { 1100 if (lnk->dst_addr.s_addr == dst_addr.s_addr && 1101 lnk->src_addr.s_addr == src_addr.s_addr && 1102 lnk->src_port == src_port && 1103 lnk->dst_port == dst_port && 1104 lnk->link_type == link_type && 1105 lnk->server == NULL) { 1106 lnk->timestamp = la->timeStamp; 1107 break; 1108 } 1109 } 1110 1111 /* Search for partially specified links. */ 1112 if (lnk == NULL && replace_partial_links) { 1113 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { 1114 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, 1115 link_type, 0); 1116 if (lnk == NULL) 1117 lnk = _FindLinkOut(la, src_addr, ANY_ADDR, src_port, 1118 dst_port, link_type, 0); 1119 } 1120 if (lnk == NULL && 1121 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { 1122 lnk = _FindLinkOut(la, src_addr, ANY_ADDR, src_port, 0, 1123 link_type, 0); 1124 } 1125 if (lnk != NULL) { 1126 lnk = ReLink(lnk, 1127 src_addr, dst_addr, lnk->alias_addr, 1128 src_port, dst_port, lnk->alias_port, 1129 link_type); 1130 } 1131 } 1132 return (lnk); 1133} 1134 1135static struct alias_link * 1136FindLinkOut(struct libalias *la, struct in_addr src_addr, 1137 struct in_addr dst_addr, 1138 u_short src_port, 1139 u_short dst_port, 1140 int link_type, 1141 int replace_partial_links) 1142{ 1143 struct alias_link *lnk; 1144 1145 LIBALIAS_LOCK_ASSERT(la); 1146 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, 1147 link_type, replace_partial_links); 1148 1149 if (lnk == NULL) { 1150 /* 1151 * The following allows permanent links to be specified as 1152 * using the default source address (i.e. device interface 1153 * address) without knowing in advance what that address 1154 * is. 1155 */ 1156 if (la->aliasAddress.s_addr != INADDR_ANY && 1157 src_addr.s_addr == la->aliasAddress.s_addr) { 1158 lnk = _FindLinkOut(la, ANY_ADDR, dst_addr, src_port, dst_port, 1159 link_type, replace_partial_links); 1160 } 1161 } 1162 return (lnk); 1163} 1164 1165static struct alias_link * 1166_FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1167 struct in_addr alias_addr, 1168 u_short dst_port, 1169 u_short alias_port, 1170 int link_type, 1171 int replace_partial_links) 1172{ 1173 int flags_in; 1174 u_int start_point; 1175 struct alias_link *lnk; 1176 struct alias_link *lnk_fully_specified; 1177 struct alias_link *lnk_unknown_all; 1178 struct alias_link *lnk_unknown_dst_addr; 1179 struct alias_link *lnk_unknown_dst_port; 1180 1181 LIBALIAS_LOCK_ASSERT(la); 1182 /* Initialize pointers */ 1183 lnk_fully_specified = NULL; 1184 lnk_unknown_all = NULL; 1185 lnk_unknown_dst_addr = NULL; 1186 lnk_unknown_dst_port = NULL; 1187 1188 /* If either the dest addr or port is unknown, the search 1189 * loop will have to know about this. */ 1190 flags_in = 0; 1191 if (dst_addr.s_addr == INADDR_ANY) 1192 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1193 if (dst_port == 0) 1194 flags_in |= LINK_UNKNOWN_DEST_PORT; 1195 1196 /* Search loop */ 1197 start_point = StartPointIn(alias_addr, alias_port, link_type); 1198 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) { 1199 int flags; 1200 1201 flags = flags_in | lnk->flags; 1202 if (!(flags & LINK_PARTIALLY_SPECIFIED)) { 1203 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1204 && lnk->alias_port == alias_port 1205 && lnk->dst_addr.s_addr == dst_addr.s_addr 1206 && lnk->dst_port == dst_port 1207 && lnk->link_type == link_type) { 1208 lnk_fully_specified = lnk; 1209 break; 1210 } 1211 } else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1212 && (flags & LINK_UNKNOWN_DEST_PORT)) { 1213 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1214 && lnk->alias_port == alias_port 1215 && lnk->link_type == link_type) { 1216 if (lnk_unknown_all == NULL) 1217 lnk_unknown_all = lnk; 1218 } 1219 } else if (flags & LINK_UNKNOWN_DEST_ADDR) { 1220 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1221 && lnk->alias_port == alias_port 1222 && lnk->link_type == link_type 1223 && lnk->dst_port == dst_port) { 1224 if (lnk_unknown_dst_addr == NULL) 1225 lnk_unknown_dst_addr = lnk; 1226 } 1227 } else if (flags & LINK_UNKNOWN_DEST_PORT) { 1228 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1229 && lnk->alias_port == alias_port 1230 && lnk->link_type == link_type 1231 && lnk->dst_addr.s_addr == dst_addr.s_addr) { 1232 if (lnk_unknown_dst_port == NULL) 1233 lnk_unknown_dst_port = lnk; 1234 } 1235 } 1236 } 1237 1238 if (lnk_fully_specified != NULL) { 1239 lnk_fully_specified->timestamp = la->timeStamp; 1240 lnk = lnk_fully_specified; 1241 } else if (lnk_unknown_dst_port != NULL) 1242 lnk = lnk_unknown_dst_port; 1243 else if (lnk_unknown_dst_addr != NULL) 1244 lnk = lnk_unknown_dst_addr; 1245 else if (lnk_unknown_all != NULL) 1246 lnk = lnk_unknown_all; 1247 else 1248 return (NULL); 1249 1250 if (replace_partial_links && 1251 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) { 1252 struct in_addr src_addr; 1253 u_short src_port; 1254 1255 if (lnk->server != NULL) { /* LSNAT link */ 1256 src_addr = lnk->server->addr; 1257 src_port = lnk->server->port; 1258 lnk->server = lnk->server->next; 1259 } else { 1260 src_addr = lnk->src_addr; 1261 src_port = lnk->src_port; 1262 } 1263 1264 if (link_type == LINK_SCTP) { 1265 lnk->src_addr = src_addr; 1266 lnk->src_port = src_port; 1267 return (lnk); 1268 } 1269 lnk = ReLink(lnk, 1270 src_addr, dst_addr, alias_addr, 1271 src_port, dst_port, alias_port, 1272 link_type); 1273 } 1274 return (lnk); 1275} 1276 1277static struct alias_link * 1278FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1279 struct in_addr alias_addr, 1280 u_short dst_port, 1281 u_short alias_port, 1282 int link_type, 1283 int replace_partial_links) 1284{ 1285 struct alias_link *lnk; 1286 1287 LIBALIAS_LOCK_ASSERT(la); 1288 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, 1289 link_type, replace_partial_links); 1290 1291 if (lnk == NULL) { 1292 /* 1293 * The following allows permanent links to be specified as 1294 * using the default aliasing address (i.e. device 1295 * interface address) without knowing in advance what that 1296 * address is. 1297 */ 1298 if (la->aliasAddress.s_addr != INADDR_ANY && 1299 alias_addr.s_addr == la->aliasAddress.s_addr) { 1300 lnk = _FindLinkIn(la, dst_addr, ANY_ADDR, dst_port, alias_port, 1301 link_type, replace_partial_links); 1302 } 1303 } 1304 return (lnk); 1305} 1306 1307/* External routines for finding/adding links 1308 1309-- "external" means outside alias_db.c, but within alias*.c -- 1310 1311 FindIcmpIn(), FindIcmpOut() 1312 FindFragmentIn1(), FindFragmentIn2() 1313 AddFragmentPtrLink(), FindFragmentPtr() 1314 FindProtoIn(), FindProtoOut() 1315 FindUdpTcpIn(), FindUdpTcpOut() 1316 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 1317 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 1318 FindOriginalAddress(), FindAliasAddress() 1319 1320(prototypes in alias_local.h) 1321*/ 1322 1323struct alias_link * 1324FindIcmpIn(struct libalias *la, struct in_addr dst_addr, 1325 struct in_addr alias_addr, 1326 u_short id_alias, 1327 int create) 1328{ 1329 struct alias_link *lnk; 1330 1331 LIBALIAS_LOCK_ASSERT(la); 1332 lnk = FindLinkIn(la, dst_addr, alias_addr, 1333 NO_DEST_PORT, id_alias, 1334 LINK_ICMP, 0); 1335 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1336 struct in_addr target_addr; 1337 1338 target_addr = FindOriginalAddress(la, alias_addr); 1339 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1340 id_alias, NO_DEST_PORT, id_alias, 1341 LINK_ICMP); 1342 } 1343 return (lnk); 1344} 1345 1346struct alias_link * 1347FindIcmpOut(struct libalias *la, struct in_addr src_addr, 1348 struct in_addr dst_addr, 1349 u_short id, 1350 int create) 1351{ 1352 struct alias_link *lnk; 1353 1354 LIBALIAS_LOCK_ASSERT(la); 1355 lnk = FindLinkOut(la, src_addr, dst_addr, 1356 id, NO_DEST_PORT, 1357 LINK_ICMP, 0); 1358 if (lnk == NULL && create) { 1359 struct in_addr alias_addr; 1360 1361 alias_addr = FindAliasAddress(la, src_addr); 1362 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1363 id, NO_DEST_PORT, GET_ALIAS_ID, 1364 LINK_ICMP); 1365 } 1366 return (lnk); 1367} 1368 1369struct alias_link * 1370FindFragmentIn1(struct libalias *la, struct in_addr dst_addr, 1371 struct in_addr alias_addr, 1372 u_short ip_id) 1373{ 1374 struct alias_link *lnk; 1375 1376 LIBALIAS_LOCK_ASSERT(la); 1377 lnk = FindLinkIn(la, dst_addr, alias_addr, 1378 NO_DEST_PORT, ip_id, 1379 LINK_FRAGMENT_ID, 0); 1380 1381 if (lnk == NULL) { 1382 lnk = AddLink(la, ANY_ADDR, dst_addr, alias_addr, 1383 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1384 LINK_FRAGMENT_ID); 1385 } 1386 return (lnk); 1387} 1388 1389/* Doesn't add a link if one is not found. */ 1390struct alias_link * 1391FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, 1392 struct in_addr alias_addr, u_short ip_id) 1393{ 1394 LIBALIAS_LOCK_ASSERT(la); 1395 return FindLinkIn(la, dst_addr, alias_addr, 1396 NO_DEST_PORT, ip_id, 1397 LINK_FRAGMENT_ID, 0); 1398} 1399 1400struct alias_link * 1401AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr, 1402 u_short ip_id) 1403{ 1404 LIBALIAS_LOCK_ASSERT(la); 1405 return AddLink(la, ANY_ADDR, dst_addr, ANY_ADDR, 1406 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1407 LINK_FRAGMENT_PTR); 1408} 1409 1410struct alias_link * 1411FindFragmentPtr(struct libalias *la, struct in_addr dst_addr, 1412 u_short ip_id) 1413{ 1414 LIBALIAS_LOCK_ASSERT(la); 1415 return FindLinkIn(la, dst_addr, ANY_ADDR, 1416 NO_DEST_PORT, ip_id, 1417 LINK_FRAGMENT_PTR, 0); 1418} 1419 1420struct alias_link * 1421FindProtoIn(struct libalias *la, struct in_addr dst_addr, 1422 struct in_addr alias_addr, 1423 u_char proto) 1424{ 1425 struct alias_link *lnk; 1426 1427 LIBALIAS_LOCK_ASSERT(la); 1428 lnk = FindLinkIn(la, dst_addr, alias_addr, 1429 NO_DEST_PORT, 0, 1430 proto, 1); 1431 1432 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1433 struct in_addr target_addr; 1434 1435 target_addr = FindOriginalAddress(la, alias_addr); 1436 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1437 NO_SRC_PORT, NO_DEST_PORT, 0, 1438 proto); 1439 } 1440 return (lnk); 1441} 1442 1443struct alias_link * 1444FindProtoOut(struct libalias *la, struct in_addr src_addr, 1445 struct in_addr dst_addr, 1446 u_char proto) 1447{ 1448 struct alias_link *lnk; 1449 1450 LIBALIAS_LOCK_ASSERT(la); 1451 lnk = FindLinkOut(la, src_addr, dst_addr, 1452 NO_SRC_PORT, NO_DEST_PORT, 1453 proto, 1); 1454 1455 if (lnk == NULL) { 1456 struct in_addr alias_addr; 1457 1458 alias_addr = FindAliasAddress(la, src_addr); 1459 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1460 NO_SRC_PORT, NO_DEST_PORT, 0, 1461 proto); 1462 } 1463 return (lnk); 1464} 1465 1466struct alias_link * 1467FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr, 1468 struct in_addr alias_addr, 1469 u_short dst_port, 1470 u_short alias_port, 1471 u_char proto, 1472 int create) 1473{ 1474 int link_type; 1475 struct alias_link *lnk; 1476 1477 LIBALIAS_LOCK_ASSERT(la); 1478 switch (proto) { 1479 case IPPROTO_UDP: 1480 link_type = LINK_UDP; 1481 break; 1482 case IPPROTO_TCP: 1483 link_type = LINK_TCP; 1484 break; 1485 default: 1486 return (NULL); 1487 break; 1488 } 1489 1490 lnk = FindLinkIn(la, dst_addr, alias_addr, 1491 dst_port, alias_port, 1492 link_type, create); 1493 1494 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1495 struct in_addr target_addr; 1496 1497 target_addr = FindOriginalAddress(la, alias_addr); 1498 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1499 alias_port, dst_port, alias_port, 1500 link_type); 1501 } 1502 return (lnk); 1503} 1504 1505struct alias_link * 1506FindUdpTcpOut(struct libalias *la, struct in_addr src_addr, 1507 struct in_addr dst_addr, 1508 u_short src_port, 1509 u_short dst_port, 1510 u_char proto, 1511 int create) 1512{ 1513 int link_type; 1514 struct alias_link *lnk; 1515 1516 LIBALIAS_LOCK_ASSERT(la); 1517 switch (proto) { 1518 case IPPROTO_UDP: 1519 link_type = LINK_UDP; 1520 break; 1521 case IPPROTO_TCP: 1522 link_type = LINK_TCP; 1523 break; 1524 default: 1525 return (NULL); 1526 break; 1527 } 1528 1529 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); 1530 1531 if (lnk == NULL && create) { 1532 struct in_addr alias_addr; 1533 1534 alias_addr = FindAliasAddress(la, src_addr); 1535 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1536 src_port, dst_port, GET_ALIAS_PORT, 1537 link_type); 1538 } 1539 return (lnk); 1540} 1541 1542struct alias_link * 1543AddPptp(struct libalias *la, struct in_addr src_addr, 1544 struct in_addr dst_addr, 1545 struct in_addr alias_addr, 1546 u_int16_t src_call_id) 1547{ 1548 struct alias_link *lnk; 1549 1550 LIBALIAS_LOCK_ASSERT(la); 1551 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1552 src_call_id, 0, GET_ALIAS_PORT, 1553 LINK_PPTP); 1554 1555 return (lnk); 1556} 1557 1558struct alias_link * 1559FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, 1560 struct in_addr dst_addr, 1561 u_int16_t src_call_id) 1562{ 1563 u_int i; 1564 struct alias_link *lnk; 1565 1566 LIBALIAS_LOCK_ASSERT(la); 1567 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1568 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1569 if (lnk->link_type == LINK_PPTP && 1570 lnk->src_addr.s_addr == src_addr.s_addr && 1571 lnk->dst_addr.s_addr == dst_addr.s_addr && 1572 lnk->src_port == src_call_id) 1573 break; 1574 1575 return (lnk); 1576} 1577 1578struct alias_link * 1579FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, 1580 struct in_addr dst_addr, 1581 u_int16_t dst_call_id) 1582{ 1583 u_int i; 1584 struct alias_link *lnk; 1585 1586 LIBALIAS_LOCK_ASSERT(la); 1587 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1588 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1589 if (lnk->link_type == LINK_PPTP && 1590 lnk->src_addr.s_addr == src_addr.s_addr && 1591 lnk->dst_addr.s_addr == dst_addr.s_addr && 1592 lnk->dst_port == dst_call_id) 1593 break; 1594 1595 return (lnk); 1596} 1597 1598struct alias_link * 1599FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, 1600 struct in_addr alias_addr, 1601 u_int16_t dst_call_id) 1602{ 1603 u_int i; 1604 struct alias_link *lnk; 1605 1606 LIBALIAS_LOCK_ASSERT(la); 1607 i = StartPointIn(alias_addr, 0, LINK_PPTP); 1608 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in) 1609 if (lnk->link_type == LINK_PPTP && 1610 lnk->dst_addr.s_addr == dst_addr.s_addr && 1611 lnk->alias_addr.s_addr == alias_addr.s_addr && 1612 lnk->dst_port == dst_call_id) 1613 break; 1614 1615 return (lnk); 1616} 1617 1618struct alias_link * 1619FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, 1620 struct in_addr alias_addr, 1621 u_int16_t alias_call_id) 1622{ 1623 struct alias_link *lnk; 1624 1625 LIBALIAS_LOCK_ASSERT(la); 1626 lnk = FindLinkIn(la, dst_addr, alias_addr, 1627 0 /* any */ , alias_call_id, 1628 LINK_PPTP, 0); 1629 1630 return (lnk); 1631} 1632 1633struct alias_link * 1634FindRtspOut(struct libalias *la, struct in_addr src_addr, 1635 struct in_addr dst_addr, 1636 u_short src_port, 1637 u_short alias_port, 1638 u_char proto) 1639{ 1640 int link_type; 1641 struct alias_link *lnk; 1642 1643 LIBALIAS_LOCK_ASSERT(la); 1644 switch (proto) { 1645 case IPPROTO_UDP: 1646 link_type = LINK_UDP; 1647 break; 1648 case IPPROTO_TCP: 1649 link_type = LINK_TCP; 1650 break; 1651 default: 1652 return (NULL); 1653 break; 1654 } 1655 1656 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); 1657 1658 if (lnk == NULL) { 1659 struct in_addr alias_addr; 1660 1661 alias_addr = FindAliasAddress(la, src_addr); 1662 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1663 src_port, 0, alias_port, 1664 link_type); 1665 } 1666 return (lnk); 1667} 1668 1669struct in_addr 1670FindOriginalAddress(struct libalias *la, struct in_addr alias_addr) 1671{ 1672 struct alias_link *lnk; 1673 1674 LIBALIAS_LOCK_ASSERT(la); 1675 lnk = FindLinkIn(la, ANY_ADDR, alias_addr, 1676 0, 0, LINK_ADDR, 0); 1677 if (lnk == NULL) { 1678 if (la->targetAddress.s_addr == INADDR_ANY) 1679 return (alias_addr); 1680 else if (la->targetAddress.s_addr == INADDR_NONE) 1681 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1682 la->aliasAddress : alias_addr; 1683 else 1684 return (la->targetAddress); 1685 } else { 1686 if (lnk->server != NULL) { /* LSNAT link */ 1687 struct in_addr src_addr; 1688 1689 src_addr = lnk->server->addr; 1690 lnk->server = lnk->server->next; 1691 return (src_addr); 1692 } else if (lnk->src_addr.s_addr == INADDR_ANY) 1693 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1694 la->aliasAddress : alias_addr; 1695 else 1696 return (lnk->src_addr); 1697 } 1698} 1699 1700struct in_addr 1701FindAliasAddress(struct libalias *la, struct in_addr original_addr) 1702{ 1703 struct alias_link *lnk; 1704 1705 LIBALIAS_LOCK_ASSERT(la); 1706 lnk = FindLinkOut(la, original_addr, ANY_ADDR, 1707 0, 0, LINK_ADDR, 0); 1708 if (lnk == NULL) { 1709 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1710 la->aliasAddress : original_addr; 1711 } else { 1712 if (lnk->alias_addr.s_addr == INADDR_ANY) 1713 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1714 la->aliasAddress : original_addr; 1715 else 1716 return (lnk->alias_addr); 1717 } 1718} 1719 1720/* External routines for getting or changing link data 1721 (external to alias_db.c, but internal to alias*.c) 1722 1723 SetFragmentData(), GetFragmentData() 1724 SetFragmentPtr(), GetFragmentPtr() 1725 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1726 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1727 GetOriginalPort(), GetAliasPort() 1728 SetAckModified(), GetAckModified() 1729 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1730 SetProtocolFlags(), GetProtocolFlags() 1731 SetDestCallId() 1732*/ 1733 1734void 1735SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr) 1736{ 1737 lnk->data.frag_addr = src_addr; 1738} 1739 1740void 1741GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr) 1742{ 1743 *src_addr = lnk->data.frag_addr; 1744} 1745 1746void 1747SetFragmentPtr(struct alias_link *lnk, void *fptr) 1748{ 1749 lnk->data.frag_ptr = fptr; 1750} 1751 1752void 1753GetFragmentPtr(struct alias_link *lnk, void **fptr) 1754{ 1755 *fptr = lnk->data.frag_ptr; 1756} 1757 1758void 1759SetStateIn(struct alias_link *lnk, int state) 1760{ 1761 /* TCP input state */ 1762 switch (state) { 1763 case ALIAS_TCP_STATE_DISCONNECTED: 1764 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1765 lnk->expire_time = TCP_EXPIRE_DEAD; 1766 else 1767 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1768 break; 1769 case ALIAS_TCP_STATE_CONNECTED: 1770 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1771 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1772 break; 1773 default: 1774#ifdef _KERNEL 1775 panic("libalias:SetStateIn() unknown state"); 1776#else 1777 abort(); 1778#endif 1779 } 1780 lnk->data.tcp->state.in = state; 1781} 1782 1783void 1784SetStateOut(struct alias_link *lnk, int state) 1785{ 1786 /* TCP output state */ 1787 switch (state) { 1788 case ALIAS_TCP_STATE_DISCONNECTED: 1789 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1790 lnk->expire_time = TCP_EXPIRE_DEAD; 1791 else 1792 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1793 break; 1794 case ALIAS_TCP_STATE_CONNECTED: 1795 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1796 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1797 break; 1798 default: 1799#ifdef _KERNEL 1800 panic("libalias:SetStateOut() unknown state"); 1801#else 1802 abort(); 1803#endif 1804 } 1805 lnk->data.tcp->state.out = state; 1806} 1807 1808int 1809GetStateIn(struct alias_link *lnk) 1810{ 1811 /* TCP input state */ 1812 return (lnk->data.tcp->state.in); 1813} 1814 1815int 1816GetStateOut(struct alias_link *lnk) 1817{ 1818 /* TCP output state */ 1819 return (lnk->data.tcp->state.out); 1820} 1821 1822struct in_addr 1823GetOriginalAddress(struct alias_link *lnk) 1824{ 1825 if (lnk->src_addr.s_addr == INADDR_ANY) 1826 return (lnk->la->aliasAddress); 1827 else 1828 return (lnk->src_addr); 1829} 1830 1831struct in_addr 1832GetDestAddress(struct alias_link *lnk) 1833{ 1834 return (lnk->dst_addr); 1835} 1836 1837struct in_addr 1838GetAliasAddress(struct alias_link *lnk) 1839{ 1840 if (lnk->alias_addr.s_addr == INADDR_ANY) 1841 return (lnk->la->aliasAddress); 1842 else 1843 return (lnk->alias_addr); 1844} 1845 1846struct in_addr 1847GetDefaultAliasAddress(struct libalias *la) 1848{ 1849 LIBALIAS_LOCK_ASSERT(la); 1850 return (la->aliasAddress); 1851} 1852 1853void 1854SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) 1855{ 1856 LIBALIAS_LOCK_ASSERT(la); 1857 la->aliasAddress = alias_addr; 1858} 1859 1860u_short 1861GetOriginalPort(struct alias_link *lnk) 1862{ 1863 return (lnk->src_port); 1864} 1865 1866u_short 1867GetAliasPort(struct alias_link *lnk) 1868{ 1869 return (lnk->alias_port); 1870} 1871 1872#ifndef NO_FW_PUNCH 1873static u_short 1874GetDestPort(struct alias_link *lnk) 1875{ 1876 return (lnk->dst_port); 1877} 1878 1879#endif 1880 1881/* Indicate that ACK numbers have been modified in a TCP connection */ 1882void 1883SetAckModified(struct alias_link *lnk) 1884{ 1885 lnk->data.tcp->state.ack_modified = 1; 1886} 1887 1888struct in_addr 1889GetProxyAddress(struct alias_link *lnk) 1890{ 1891 return (lnk->proxy_addr); 1892} 1893 1894void 1895SetProxyAddress(struct alias_link *lnk, struct in_addr addr) 1896{ 1897 lnk->proxy_addr = addr; 1898} 1899 1900u_short 1901GetProxyPort(struct alias_link *lnk) 1902{ 1903 return (lnk->proxy_port); 1904} 1905 1906void 1907SetProxyPort(struct alias_link *lnk, u_short port) 1908{ 1909 lnk->proxy_port = port; 1910} 1911 1912/* See if ACK numbers have been modified */ 1913int 1914GetAckModified(struct alias_link *lnk) 1915{ 1916 return (lnk->data.tcp->state.ack_modified); 1917} 1918 1919/* 1920 * Find out how much the ACK number has been altered for an 1921 * incoming TCP packet. To do this, a circular list of ACK 1922 * numbers where the TCP packet size was altered is searched. 1923 */ 1924// XXX ip free 1925int 1926GetDeltaAckIn(u_long ack, struct alias_link *lnk) 1927{ 1928 int i, j; 1929 int delta, ack_diff_min; 1930 1931 delta = 0; 1932 ack_diff_min = -1; 1933 i = lnk->data.tcp->state.index; 1934 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1935 struct ack_data_record x; 1936 1937 if (i == 0) 1938 i = N_LINK_TCP_DATA; 1939 i--; 1940 x = lnk->data.tcp->ack[i]; 1941 if (x.active == 1) { 1942 int ack_diff; 1943 1944 ack_diff = SeqDiff(x.ack_new, ack); 1945 if (ack_diff >= 0) { 1946 if (ack_diff_min >= 0) { 1947 if (ack_diff < ack_diff_min) { 1948 delta = x.delta; 1949 ack_diff_min = ack_diff; 1950 } 1951 } else { 1952 delta = x.delta; 1953 ack_diff_min = ack_diff; 1954 } 1955 } 1956 } 1957 } 1958 return (delta); 1959} 1960 1961/* 1962 * Find out how much the sequence number has been altered for an 1963 * outgoing TCP packet. To do this, a circular list of ACK numbers 1964 * where the TCP packet size was altered is searched. 1965 */ 1966// XXX ip free 1967int 1968GetDeltaSeqOut(u_long seq, struct alias_link *lnk) 1969{ 1970 int i, j; 1971 int delta, seq_diff_min; 1972 1973 delta = 0; 1974 seq_diff_min = -1; 1975 i = lnk->data.tcp->state.index; 1976 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1977 struct ack_data_record x; 1978 1979 if (i == 0) 1980 i = N_LINK_TCP_DATA; 1981 i--; 1982 x = lnk->data.tcp->ack[i]; 1983 if (x.active == 1) { 1984 int seq_diff; 1985 1986 seq_diff = SeqDiff(x.ack_old, seq); 1987 if (seq_diff >= 0) { 1988 if (seq_diff_min >= 0) { 1989 if (seq_diff < seq_diff_min) { 1990 delta = x.delta; 1991 seq_diff_min = seq_diff; 1992 } 1993 } else { 1994 delta = x.delta; 1995 seq_diff_min = seq_diff; 1996 } 1997 } 1998 } 1999 } 2000 return (delta); 2001} 2002 2003/* 2004 * When a TCP packet has been altered in length, save this 2005 * information in a circular list. If enough packets have been 2006 * altered, then this list will begin to overwrite itself. 2007 */ 2008// XXX ip free 2009void 2010AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len, 2011 u_long th_seq, u_int th_off) 2012{ 2013 struct ack_data_record x; 2014 int hlen, tlen, dlen; 2015 int i; 2016 2017 hlen = (ip_hl + th_off) << 2; 2018 tlen = ntohs(ip_len); 2019 dlen = tlen - hlen; 2020 2021 x.ack_old = htonl(ntohl(th_seq) + dlen); 2022 x.ack_new = htonl(ntohl(th_seq) + dlen + delta); 2023 x.delta = delta; 2024 x.active = 1; 2025 2026 i = lnk->data.tcp->state.index; 2027 lnk->data.tcp->ack[i] = x; 2028 2029 i++; 2030 if (i == N_LINK_TCP_DATA) 2031 lnk->data.tcp->state.index = 0; 2032 else 2033 lnk->data.tcp->state.index = i; 2034} 2035 2036void 2037SetExpire(struct alias_link *lnk, int expire) 2038{ 2039 if (expire == 0) { 2040 lnk->flags &= ~LINK_PERMANENT; 2041 DeleteLink(lnk); 2042 } else if (expire == -1) { 2043 lnk->flags |= LINK_PERMANENT; 2044 } else if (expire > 0) { 2045 lnk->expire_time = expire; 2046 } else { 2047#ifdef LIBALIAS_DEBUG 2048 fprintf(stderr, "PacketAlias/SetExpire(): "); 2049 fprintf(stderr, "error in expire parameter\n"); 2050#endif 2051 } 2052} 2053 2054void 2055SetProtocolFlags(struct alias_link *lnk, int pflags) 2056{ 2057 lnk->pflags = pflags; 2058} 2059 2060int 2061GetProtocolFlags(struct alias_link *lnk) 2062{ 2063 return (lnk->pflags); 2064} 2065 2066void 2067SetDestCallId(struct alias_link *lnk, u_int16_t cid) 2068{ 2069 struct libalias *la = lnk->la; 2070 2071 LIBALIAS_LOCK_ASSERT(la); 2072 la->deleteAllLinks = 1; 2073 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, 2074 lnk->src_port, cid, lnk->alias_port, lnk->link_type); 2075 la->deleteAllLinks = 0; 2076} 2077 2078/* Miscellaneous Functions 2079 2080 HouseKeeping() 2081 InitPacketAliasLog() 2082 UninitPacketAliasLog() 2083*/ 2084 2085/* 2086 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2087 is called to find and remove timed-out aliasing links. Logic exists 2088 to sweep through the entire table and linked list structure 2089 every 60 seconds. 2090 2091 (prototype in alias_local.h) 2092*/ 2093 2094void 2095HouseKeeping(struct libalias *la) 2096{ 2097 int i, n; 2098#ifndef _KERNEL 2099 struct timeval tv; 2100#endif 2101 2102 LIBALIAS_LOCK_ASSERT(la); 2103 /* 2104 * Save system time (seconds) in global variable timeStamp for use 2105 * by other functions. This is done so as not to unnecessarily 2106 * waste timeline by making system calls. 2107 */ 2108#ifdef _KERNEL 2109 la->timeStamp = time_uptime; 2110#else 2111 gettimeofday(&tv, NULL); 2112 la->timeStamp = tv.tv_sec; 2113#endif 2114 2115 /* Compute number of spokes (output table link chains) to cover */ 2116 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime); 2117 n /= ALIAS_CLEANUP_INTERVAL_SECS; 2118 2119 /* Handle different cases */ 2120 if (n > 0) { 2121 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2122 n = ALIAS_CLEANUP_MAX_SPOKES; 2123 la->lastCleanupTime = la->timeStamp; 2124 for (i = 0; i < n; i++) 2125 IncrementalCleanup(la); 2126 } else if (n < 0) { 2127#ifdef LIBALIAS_DEBUG 2128 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2129 fprintf(stderr, "something unexpected in time values\n"); 2130#endif 2131 la->lastCleanupTime = la->timeStamp; 2132 } 2133} 2134 2135/* Init the log file and enable logging */ 2136static int 2137InitPacketAliasLog(struct libalias *la) 2138{ 2139 LIBALIAS_LOCK_ASSERT(la); 2140 if (~la->packetAliasMode & PKT_ALIAS_LOG) { 2141#ifdef _KERNEL 2142 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE))) 2143 ; 2144#else 2145 if ((la->logDesc = fopen("/var/log/alias.log", "w"))) 2146 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2147#endif 2148 else 2149 return (ENOMEM); /* log initialization failed */ 2150 la->packetAliasMode |= PKT_ALIAS_LOG; 2151 } 2152 2153 return (1); 2154} 2155 2156/* Close the log-file and disable logging. */ 2157static void 2158UninitPacketAliasLog(struct libalias *la) 2159{ 2160 LIBALIAS_LOCK_ASSERT(la); 2161 if (la->logDesc) { 2162#ifdef _KERNEL 2163 free(la->logDesc); 2164#else 2165 fclose(la->logDesc); 2166#endif 2167 la->logDesc = NULL; 2168 } 2169 la->packetAliasMode &= ~PKT_ALIAS_LOG; 2170} 2171 2172/* Outside world interfaces 2173 2174-- "outside world" means other than alias*.c routines -- 2175 2176 PacketAliasRedirectPort() 2177 PacketAliasAddServer() 2178 PacketAliasRedirectProto() 2179 PacketAliasRedirectAddr() 2180 PacketAliasRedirectDynamic() 2181 PacketAliasRedirectDelete() 2182 PacketAliasSetAddress() 2183 PacketAliasInit() 2184 PacketAliasUninit() 2185 PacketAliasSetMode() 2186 2187(prototypes in alias.h) 2188*/ 2189 2190/* Redirection from a specific public addr:port to a 2191 private addr:port */ 2192struct alias_link * 2193LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2194 struct in_addr dst_addr, u_short dst_port, 2195 struct in_addr alias_addr, u_short alias_port, 2196 u_char proto) 2197{ 2198 int link_type; 2199 struct alias_link *lnk; 2200 2201 LIBALIAS_LOCK(la); 2202 switch (proto) { 2203 case IPPROTO_UDP: 2204 link_type = LINK_UDP; 2205 break; 2206 case IPPROTO_TCP: 2207 link_type = LINK_TCP; 2208 break; 2209 case IPPROTO_SCTP: 2210 link_type = LINK_SCTP; 2211 break; 2212 default: 2213#ifdef LIBALIAS_DEBUG 2214 fprintf(stderr, "PacketAliasRedirectPort(): "); 2215 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n"); 2216#endif 2217 lnk = NULL; 2218 goto getout; 2219 } 2220 2221 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2222 src_port, dst_port, alias_port, 2223 link_type); 2224 2225 if (lnk != NULL) { 2226 lnk->flags |= LINK_PERMANENT; 2227 } 2228#ifdef LIBALIAS_DEBUG 2229 else { 2230 fprintf(stderr, "PacketAliasRedirectPort(): " 2231 "call to AddLink() failed\n"); 2232 } 2233#endif 2234 2235getout: 2236 LIBALIAS_UNLOCK(la); 2237 return (lnk); 2238} 2239 2240/* Add server to the pool of servers */ 2241int 2242LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 2243{ 2244 struct server *server; 2245 int res; 2246 2247 LIBALIAS_LOCK(la); 2248 (void)la; 2249 2250 server = malloc(sizeof(struct server)); 2251 2252 if (server != NULL) { 2253 struct server *head; 2254 2255 server->addr = addr; 2256 server->port = port; 2257 2258 head = lnk->server; 2259 if (head == NULL) 2260 server->next = server; 2261 else { 2262 struct server *s; 2263 2264 for (s = head; s->next != head; s = s->next) 2265 ; 2266 s->next = server; 2267 server->next = head; 2268 } 2269 lnk->server = server; 2270 res = 0; 2271 } else 2272 res = -1; 2273 2274 LIBALIAS_UNLOCK(la); 2275 return (res); 2276} 2277 2278/* Redirect packets of a given IP protocol from a specific 2279 public address to a private address */ 2280struct alias_link * 2281LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2282 struct in_addr dst_addr, 2283 struct in_addr alias_addr, 2284 u_char proto) 2285{ 2286 struct alias_link *lnk; 2287 2288 LIBALIAS_LOCK(la); 2289 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2290 NO_SRC_PORT, NO_DEST_PORT, 0, 2291 proto); 2292 2293 if (lnk != NULL) { 2294 lnk->flags |= LINK_PERMANENT; 2295 } 2296#ifdef LIBALIAS_DEBUG 2297 else { 2298 fprintf(stderr, "PacketAliasRedirectProto(): " 2299 "call to AddLink() failed\n"); 2300 } 2301#endif 2302 2303 LIBALIAS_UNLOCK(la); 2304 return (lnk); 2305} 2306 2307/* Static address translation */ 2308struct alias_link * 2309LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2310 struct in_addr alias_addr) 2311{ 2312 struct alias_link *lnk; 2313 2314 LIBALIAS_LOCK(la); 2315 lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr, 2316 0, 0, 0, 2317 LINK_ADDR); 2318 2319 if (lnk != NULL) { 2320 lnk->flags |= LINK_PERMANENT; 2321 } 2322#ifdef LIBALIAS_DEBUG 2323 else { 2324 fprintf(stderr, "PacketAliasRedirectAddr(): " 2325 "call to AddLink() failed\n"); 2326 } 2327#endif 2328 2329 LIBALIAS_UNLOCK(la); 2330 return (lnk); 2331} 2332 2333/* Mark the aliasing link dynamic */ 2334int 2335LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2336{ 2337 int res; 2338 2339 LIBALIAS_LOCK(la); 2340 (void)la; 2341 2342 if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2343 res = -1; 2344 else { 2345 lnk->flags &= ~LINK_PERMANENT; 2346 res = 0; 2347 } 2348 LIBALIAS_UNLOCK(la); 2349 return (res); 2350} 2351 2352/* This is a dangerous function to put in the API, 2353 because an invalid pointer can crash the program. */ 2354void 2355LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 2356{ 2357 LIBALIAS_LOCK(la); 2358 la->deleteAllLinks = 1; 2359 DeleteLink(lnk); 2360 la->deleteAllLinks = 0; 2361 LIBALIAS_UNLOCK(la); 2362} 2363 2364void 2365LibAliasSetAddress(struct libalias *la, struct in_addr addr) 2366{ 2367 LIBALIAS_LOCK(la); 2368 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2369 && la->aliasAddress.s_addr != addr.s_addr) 2370 CleanupAliasData(la); 2371 2372 la->aliasAddress = addr; 2373 LIBALIAS_UNLOCK(la); 2374} 2375 2376void 2377LibAliasSetAliasPortRange(struct libalias *la, u_short port_low, 2378 u_short port_high) 2379{ 2380 LIBALIAS_LOCK(la); 2381 la->aliasPortLower = port_low; 2382 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */ 2383 la->aliasPortLength = port_high - port_low + 1; 2384 LIBALIAS_UNLOCK(la); 2385} 2386 2387void 2388LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 2389{ 2390 LIBALIAS_LOCK(la); 2391 la->targetAddress = target_addr; 2392 LIBALIAS_UNLOCK(la); 2393} 2394 2395static void 2396finishoff(void) 2397{ 2398 while (!LIST_EMPTY(&instancehead)) 2399 LibAliasUninit(LIST_FIRST(&instancehead)); 2400} 2401 2402struct libalias * 2403LibAliasInit(struct libalias *la) 2404{ 2405 int i; 2406#ifndef _KERNEL 2407 struct timeval tv; 2408#endif 2409 2410 if (la == NULL) { 2411#ifdef _KERNEL 2412#undef malloc /* XXX: ugly */ 2413 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO); 2414#else 2415 la = calloc(sizeof *la, 1); 2416 if (la == NULL) 2417 return (la); 2418#endif 2419 2420#ifndef _KERNEL 2421 /* kernel cleans up on module unload */ 2422 if (LIST_EMPTY(&instancehead)) 2423 atexit(finishoff); 2424#endif 2425 LIST_INSERT_HEAD(&instancehead, la, instancelist); 2426 2427#ifdef _KERNEL 2428 la->timeStamp = time_uptime; 2429 la->lastCleanupTime = time_uptime; 2430#else 2431 gettimeofday(&tv, NULL); 2432 la->timeStamp = tv.tv_sec; 2433 la->lastCleanupTime = tv.tv_sec; 2434#endif 2435 2436 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2437 LIST_INIT(&la->linkTableOut[i]); 2438 for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2439 LIST_INIT(&la->linkTableIn[i]); 2440#ifdef _KERNEL 2441 AliasSctpInit(la); 2442#endif 2443 LIBALIAS_LOCK_INIT(la); 2444 LIBALIAS_LOCK(la); 2445 } else { 2446 LIBALIAS_LOCK(la); 2447 la->deleteAllLinks = 1; 2448 CleanupAliasData(la); 2449 la->deleteAllLinks = 0; 2450#ifdef _KERNEL 2451 AliasSctpTerm(la); 2452 AliasSctpInit(la); 2453#endif 2454 } 2455 2456 la->aliasAddress.s_addr = INADDR_ANY; 2457 la->targetAddress.s_addr = INADDR_ANY; 2458 2459 la->icmpLinkCount = 0; 2460 la->udpLinkCount = 0; 2461 la->tcpLinkCount = 0; 2462 la->sctpLinkCount = 0; 2463 la->pptpLinkCount = 0; 2464 la->protoLinkCount = 0; 2465 la->fragmentIdLinkCount = 0; 2466 la->fragmentPtrLinkCount = 0; 2467 la->sockCount = 0; 2468 2469 la->cleanupIndex = 0; 2470 2471 la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2472#ifndef NO_USE_SOCKETS 2473 | PKT_ALIAS_USE_SOCKETS 2474#endif 2475 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2476#ifndef NO_FW_PUNCH 2477 la->fireWallFD = -1; 2478#endif 2479#ifndef _KERNEL 2480 LibAliasRefreshModules(); 2481#endif 2482 LIBALIAS_UNLOCK(la); 2483 return (la); 2484} 2485 2486void 2487LibAliasUninit(struct libalias *la) 2488{ 2489 LIBALIAS_LOCK(la); 2490#ifdef _KERNEL 2491 AliasSctpTerm(la); 2492#endif 2493 la->deleteAllLinks = 1; 2494 CleanupAliasData(la); 2495 la->deleteAllLinks = 0; 2496 UninitPacketAliasLog(la); 2497#ifndef NO_FW_PUNCH 2498 UninitPunchFW(la); 2499#endif 2500 LIST_REMOVE(la, instancelist); 2501 LIBALIAS_UNLOCK(la); 2502 LIBALIAS_LOCK_DESTROY(la); 2503 free(la); 2504} 2505 2506/* Change mode for some operations */ 2507unsigned int 2508LibAliasSetMode( 2509 struct libalias *la, 2510 unsigned int flags, /* Which state to bring flags to */ 2511 unsigned int mask /* Mask of which flags to affect (use 0 to 2512 * do a probe for flag values) */ 2513) 2514{ 2515 int res = -1; 2516 2517 LIBALIAS_LOCK(la); 2518 if (flags & mask & PKT_ALIAS_LOG) { 2519 /* Enable logging */ 2520 if (InitPacketAliasLog(la) == ENOMEM) 2521 goto getout; 2522 } else if (~flags & mask & PKT_ALIAS_LOG) 2523 /* _Disable_ logging */ 2524 UninitPacketAliasLog(la); 2525 2526#ifndef NO_FW_PUNCH 2527 if (flags & mask & PKT_ALIAS_PUNCH_FW) 2528 /* Start punching holes in the firewall? */ 2529 InitPunchFW(la); 2530 else if (~flags & mask & PKT_ALIAS_PUNCH_FW) 2531 /* Stop punching holes in the firewall? */ 2532 UninitPunchFW(la); 2533#endif 2534 2535 /* Other flags can be set/cleared without special action */ 2536 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2537 res = la->packetAliasMode; 2538getout: 2539 LIBALIAS_UNLOCK(la); 2540 return (res); 2541} 2542 2543/* never used and never worked, to be removed in FreeBSD 14 */ 2544int 2545LibAliasCheckNewLink(struct libalias *la) 2546{ 2547 (void)la; 2548 return (0); 2549} 2550 2551#ifndef NO_FW_PUNCH 2552 2553/***************** 2554 Code to support firewall punching. This shouldn't really be in this 2555 file, but making variables global is evil too. 2556 ****************/ 2557 2558/* Firewall include files */ 2559#include <net/if.h> 2560#include <netinet/ip_fw.h> 2561#include <string.h> 2562#include <err.h> 2563 2564/* 2565 * helper function, updates the pointer to cmd with the length 2566 * of the current command, and also cleans up the first word of 2567 * the new command in case it has been clobbered before. 2568 */ 2569static ipfw_insn * 2570next_cmd(ipfw_insn * cmd) 2571{ 2572 cmd += F_LEN(cmd); 2573 bzero(cmd, sizeof(*cmd)); 2574 return (cmd); 2575} 2576 2577/* 2578 * A function to fill simple commands of size 1. 2579 * Existing flags are preserved. 2580 */ 2581static ipfw_insn * 2582fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2583 int flags, u_int16_t arg) 2584{ 2585 cmd->opcode = opcode; 2586 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2587 cmd->arg1 = arg; 2588 return next_cmd(cmd); 2589} 2590 2591static ipfw_insn * 2592fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2593{ 2594 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1; 2595 2596 cmd->addr.s_addr = addr; 2597 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2598} 2599 2600static ipfw_insn * 2601fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2602{ 2603 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1; 2604 2605 cmd->ports[0] = cmd->ports[1] = port; 2606 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2607} 2608 2609static int 2610fill_rule(void *buf, int bufsize, int rulenum, 2611 enum ipfw_opcodes action, int proto, 2612 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2613{ 2614 struct ip_fw *rule = (struct ip_fw *)buf; 2615 ipfw_insn *cmd = (ipfw_insn *)rule->cmd; 2616 2617 bzero(buf, bufsize); 2618 rule->rulenum = rulenum; 2619 2620 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2621 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2622 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2623 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2624 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2625 2626 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2627 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2628 2629 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2630 2631 return ((char *)cmd - (char *)buf); 2632} 2633 2634static void ClearAllFWHoles(struct libalias *la); 2635 2636#define fw_setfield(la, field, num) \ 2637do { \ 2638 (field)[(num) - la->fireWallBaseNum] = 1; \ 2639} /*lint -save -e717 */ while(0)/* lint -restore */ 2640 2641#define fw_clrfield(la, field, num) \ 2642do { \ 2643 (field)[(num) - la->fireWallBaseNum] = 0; \ 2644} /*lint -save -e717 */ while(0)/* lint -restore */ 2645 2646#define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2647 2648static void 2649InitPunchFW(struct libalias *la) 2650{ 2651 la->fireWallField = malloc(la->fireWallNumNums); 2652 if (la->fireWallField) { 2653 memset(la->fireWallField, 0, la->fireWallNumNums); 2654 if (la->fireWallFD < 0) { 2655 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2656 } 2657 ClearAllFWHoles(la); 2658 la->fireWallActiveNum = la->fireWallBaseNum; 2659 } 2660} 2661 2662static void 2663UninitPunchFW(struct libalias *la) 2664{ 2665 ClearAllFWHoles(la); 2666 if (la->fireWallFD >= 0) 2667 close(la->fireWallFD); 2668 la->fireWallFD = -1; 2669 if (la->fireWallField) 2670 free(la->fireWallField); 2671 la->fireWallField = NULL; 2672 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2673} 2674 2675/* Make a certain link go through the firewall */ 2676void 2677PunchFWHole(struct alias_link *lnk) 2678{ 2679 struct libalias *la; 2680 int r; /* Result code */ 2681 struct ip_fw rule; /* On-the-fly built rule */ 2682 int fwhole; /* Where to punch hole */ 2683 2684 la = lnk->la; 2685 2686 /* Don't do anything unless we are asked to */ 2687 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2688 la->fireWallFD < 0 || 2689 lnk->link_type != LINK_TCP) 2690 return; 2691 2692 memset(&rule, 0, sizeof rule); 2693 2694 /** Build rule **/ 2695 2696 /* Find empty slot */ 2697 for (fwhole = la->fireWallActiveNum; 2698 fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2699 fw_tstfield(la, la->fireWallField, fwhole); 2700 fwhole++); 2701 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2702 for (fwhole = la->fireWallBaseNum; 2703 fwhole < la->fireWallActiveNum && 2704 fw_tstfield(la, la->fireWallField, fwhole); 2705 fwhole++); 2706 if (fwhole == la->fireWallActiveNum) { 2707 /* No rule point empty - we can't punch more holes. */ 2708 la->fireWallActiveNum = la->fireWallBaseNum; 2709#ifdef LIBALIAS_DEBUG 2710 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2711#endif 2712 return; 2713 } 2714 } 2715 /* Start next search at next position */ 2716 la->fireWallActiveNum = fwhole + 1; 2717 2718 /* 2719 * generate two rules of the form 2720 * 2721 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2722 * accept tcp from DAddr DPort to OAddr OPort 2723 */ 2724 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2725 u_int32_t rulebuf[255]; 2726 int i; 2727 2728 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2729 O_ACCEPT, IPPROTO_TCP, 2730 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2731 GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2732 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2733 if (r) 2734 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2735 2736 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2737 O_ACCEPT, IPPROTO_TCP, 2738 GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2739 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2740 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2741 if (r) 2742 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2743 } 2744 2745 /* Indicate hole applied */ 2746 lnk->data.tcp->fwhole = fwhole; 2747 fw_setfield(la, la->fireWallField, fwhole); 2748} 2749 2750/* Remove a hole in a firewall associated with a particular alias 2751 lnk. Calling this too often is harmless. */ 2752static void 2753ClearFWHole(struct alias_link *lnk) 2754{ 2755 struct libalias *la; 2756 2757 la = lnk->la; 2758 if (lnk->link_type == LINK_TCP) { 2759 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall hole? */ 2760 struct ip_fw rule; 2761 2762 if (fwhole < 0) 2763 return; 2764 2765 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2766 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2767 &fwhole, sizeof fwhole)); 2768 fw_clrfield(la, la->fireWallField, fwhole); 2769 lnk->data.tcp->fwhole = -1; 2770 } 2771} 2772 2773/* Clear out the entire range dedicated to firewall holes. */ 2774static void 2775ClearAllFWHoles(struct libalias *la) 2776{ 2777 struct ip_fw rule; /* On-the-fly built rule */ 2778 int i; 2779 2780 if (la->fireWallFD < 0) 2781 return; 2782 2783 memset(&rule, 0, sizeof rule); 2784 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2785 int r = i; 2786 2787 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2788 } 2789 /* XXX: third arg correct here ? /phk */ 2790 memset(la->fireWallField, 0, la->fireWallNumNums); 2791} 2792 2793#endif /* !NO_FW_PUNCH */ 2794 2795void 2796LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2797{ 2798 LIBALIAS_LOCK(la); 2799#ifndef NO_FW_PUNCH 2800 la->fireWallBaseNum = base; 2801 la->fireWallNumNums = num; 2802#endif 2803 LIBALIAS_UNLOCK(la); 2804} 2805 2806void 2807LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2808{ 2809 LIBALIAS_LOCK(la); 2810 la->skinnyPort = port; 2811 LIBALIAS_UNLOCK(la); 2812} 2813 2814/* 2815 * Find the address to redirect incoming packets 2816 */ 2817struct in_addr 2818FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm) 2819{ 2820 struct alias_link *lnk; 2821 struct in_addr redir; 2822 2823 LIBALIAS_LOCK_ASSERT(la); 2824 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2825 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1); 2826 if (lnk != NULL) { 2827 /* port redirect */ 2828 return (lnk->src_addr); 2829 } else { 2830 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst); 2831 if (redir.s_addr == la->aliasAddress.s_addr || 2832 redir.s_addr == la->targetAddress.s_addr) { 2833 /* No address found */ 2834 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2835 NO_DEST_PORT, 0, LINK_SCTP, 1); 2836 if (lnk != NULL) 2837 /* redirect proto */ 2838 return (lnk->src_addr); 2839 } 2840 return (redir); /* address redirect */ 2841 } 2842} 2843