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