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