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