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