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 != INADDR_ANY && 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 != INADDR_ANY && 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.s_addr != INADDR_ANY) ? 1809 aliasAddress : alias_addr; 1810 else 1811 return targetAddress; 1812 } 1813 else 1814 { 1815 if (link->server != NULL) { /* LSNAT link */ 1816 struct in_addr src_addr; 1817 1818 src_addr = link->server->addr; 1819 link->server = link->server->next; 1820 return (src_addr); 1821 } else if (link->src_addr.s_addr == INADDR_ANY) 1822 return (aliasAddress.s_addr != INADDR_ANY) ? 1823 aliasAddress : alias_addr; 1824 else 1825 return link->src_addr; 1826 } 1827 } 1828 1829 1830 struct in_addr 1831 FindAliasAddress(struct in_addr original_addr) 1832 { 1833 struct alias_link *link; 1834 1835 link = FindLinkOut(original_addr, nullAddress, 1836 0, 0, LINK_ADDR, 0); 1837 if (link == NULL) 1838 { 1839 return (aliasAddress.s_addr != INADDR_ANY) ? 1840 aliasAddress : original_addr; 1841 } 1842 else 1843 { 1844 if (link->alias_addr.s_addr == INADDR_ANY) 1845 return (aliasAddress.s_addr != INADDR_ANY) ? 1846 aliasAddress : original_addr; 1847 else 1848 return link->alias_addr; 1849 } 1850 } 1851 1852 1853 /* External routines for getting or changing link data 1854 (external to alias_db.c, but internal to alias*.c) 1855 1856 SetFragmentData(), GetFragmentData() 1857 SetFragmentPtr(), GetFragmentPtr() 1858 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1859 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1860 GetOriginalPort(), GetAliasPort() 1861 SetAckModified(), GetAckModified() 1862 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1863 SetProtocolFlags(), GetProtocolFlags() 1864 SetDestCallId() 1865 */ 1866 1867 1868 void 1869 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1870 { 1871 link->data.frag_addr = src_addr; 1872 } 1873 1874 1875 void 1876 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1877 { 1878 *src_addr = link->data.frag_addr; 1879 } 1880 1881 1882 void 1883 SetFragmentPtr(struct alias_link *link, char *fptr) 1884 { 1885 link->data.frag_ptr = fptr; 1886 } 1887 1888 1889 void 1890 GetFragmentPtr(struct alias_link *link, char **fptr) 1891 { 1892 *fptr = link->data.frag_ptr; 1893 } 1894 1895 1896 void 1897 SetStateIn(struct alias_link *link, int state) 1898 { 1899 /* TCP input state */ 1900 switch (state) { 1901 case ALIAS_TCP_STATE_DISCONNECTED: 1902 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1903 link->expire_time = TCP_EXPIRE_DEAD; 1904 else 1905 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1906 break; 1907 case ALIAS_TCP_STATE_CONNECTED: 1908 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1909 link->expire_time = TCP_EXPIRE_CONNECTED; 1910 break; 1911 default: 1912 abort(); 1913 } 1914 link->data.tcp->state.in = state; 1915 } 1916 1917 1918 void 1919 SetStateOut(struct alias_link *link, int state) 1920 { 1921 /* TCP output state */ 1922 switch (state) { 1923 case ALIAS_TCP_STATE_DISCONNECTED: 1924 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1925 link->expire_time = TCP_EXPIRE_DEAD; 1926 else 1927 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1928 break; 1929 case ALIAS_TCP_STATE_CONNECTED: 1930 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1931 link->expire_time = TCP_EXPIRE_CONNECTED; 1932 break; 1933 default: 1934 abort(); 1935 } 1936 link->data.tcp->state.out = state; 1937 } 1938 1939 1940 int 1941 GetStateIn(struct alias_link *link) 1942 { 1943 /* TCP input state */ 1944 return link->data.tcp->state.in; 1945 } 1946 1947 1948 int 1949 GetStateOut(struct alias_link *link) 1950 { 1951 /* TCP output state */ 1952 return link->data.tcp->state.out; 1953 } 1954 1955 1956 struct in_addr 1957 GetOriginalAddress(struct alias_link *link) 1958 { 1959 if (link->src_addr.s_addr == INADDR_ANY) 1960 return aliasAddress; 1961 else 1962 return(link->src_addr); 1963 } 1964 1965 1966 struct in_addr 1967 GetDestAddress(struct alias_link *link) 1968 { 1969 return(link->dst_addr); 1970 } 1971 1972 1973 struct in_addr 1974 GetAliasAddress(struct alias_link *link) 1975 { 1976 if (link->alias_addr.s_addr == INADDR_ANY) 1977 return aliasAddress; 1978 else 1979 return link->alias_addr; 1980 } 1981 1982 1983 struct in_addr 1984 GetDefaultAliasAddress() 1985 { 1986 return aliasAddress; 1987 } 1988 1989 1990 void 1991 SetDefaultAliasAddress(struct in_addr alias_addr) 1992 { 1993 aliasAddress = alias_addr; 1994 } 1995 1996 1997 u_short 1998 GetOriginalPort(struct alias_link *link) 1999 { 2000 return(link->src_port); 2001 } 2002 2003 2004 u_short 2005 GetAliasPort(struct alias_link *link) 2006 { 2007 return(link->alias_port); 2008 } 2009 2010 #ifndef NO_FW_PUNCH 2011 static u_short 2012 GetDestPort(struct alias_link *link) 2013 { 2014 return(link->dst_port); 2015 } 2016 #endif 2017 2018 void 2019 SetAckModified(struct alias_link *link) 2020 { 2021 /* Indicate that ACK numbers have been modified in a TCP connection */ 2022 link->data.tcp->state.ack_modified = 1; 2023 } 2024 2025 2026 struct in_addr 2027 GetProxyAddress(struct alias_link *link) 2028 { 2029 return link->proxy_addr; 2030 } 2031 2032 2033 void 2034 SetProxyAddress(struct alias_link *link, struct in_addr addr) 2035 { 2036 link->proxy_addr = addr; 2037 } 2038 2039 2040 u_short 2041 GetProxyPort(struct alias_link *link) 2042 { 2043 return link->proxy_port; 2044 } 2045 2046 2047 void 2048 SetProxyPort(struct alias_link *link, u_short port) 2049 { 2050 link->proxy_port = port; 2051 } 2052 2053 2054 int 2055 GetAckModified(struct alias_link *link) 2056 { 2057 /* See if ACK numbers have been modified */ 2058 return link->data.tcp->state.ack_modified; 2059 } 2060 2061 2062 int 2063 GetDeltaAckIn(struct ip *pip, struct alias_link *link) 2064 { 2065 /* 2066 Find out how much the ACK number has been altered for an incoming 2067 TCP packet. To do this, a circular list of ACK numbers where the TCP 2068 packet size was altered is searched. 2069 */ 2070 2071 int i; 2072 struct tcphdr *tc; 2073 int delta, ack_diff_min; 2074 u_long ack; 2075 2076 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2077 ack = tc->th_ack; 2078 2079 delta = 0; 2080 ack_diff_min = -1; 2081 for (i=0; i<N_LINK_TCP_DATA; i++) 2082 { 2083 struct ack_data_record x; 2084 2085 x = link->data.tcp->ack[i]; 2086 if (x.active == 1) 2087 { 2088 int ack_diff; 2089 2090 ack_diff = SeqDiff(x.ack_new, ack); 2091 if (ack_diff >= 0) 2092 { 2093 if (ack_diff_min >= 0) 2094 { 2095 if (ack_diff < ack_diff_min) 2096 { 2097 delta = x.delta; 2098 ack_diff_min = ack_diff; 2099 } 2100 } 2101 else 2102 { 2103 delta = x.delta; 2104 ack_diff_min = ack_diff; 2105 } 2106 } 2107 } 2108 } 2109 return (delta); 2110 } 2111 2112 2113 int 2114 GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 2115 { 2116 /* 2117 Find out how much the sequence number has been altered for an outgoing 2118 TCP packet. To do this, a circular list of ACK numbers where the TCP 2119 packet size was altered is searched. 2120 */ 2121 2122 int i; 2123 struct tcphdr *tc; 2124 int delta, seq_diff_min; 2125 u_long seq; 2126 2127 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2128 seq = tc->th_seq; 2129 2130 delta = 0; 2131 seq_diff_min = -1; 2132 for (i=0; i<N_LINK_TCP_DATA; i++) 2133 { 2134 struct ack_data_record x; 2135 2136 x = link->data.tcp->ack[i]; 2137 if (x.active == 1) 2138 { 2139 int seq_diff; 2140 2141 seq_diff = SeqDiff(x.ack_old, seq); 2142 if (seq_diff >= 0) 2143 { 2144 if (seq_diff_min >= 0) 2145 { 2146 if (seq_diff < seq_diff_min) 2147 { 2148 delta = x.delta; 2149 seq_diff_min = seq_diff; 2150 } 2151 } 2152 else 2153 { 2154 delta = x.delta; 2155 seq_diff_min = seq_diff; 2156 } 2157 } 2158 } 2159 } 2160 return (delta); 2161 } 2162 2163 2164 void 2165 AddSeq(struct ip *pip, struct alias_link *link, int delta) 2166 { 2167 /* 2168 When a TCP packet has been altered in length, save this 2169 information in a circular list. If enough packets have 2170 been altered, then this list will begin to overwrite itself. 2171 */ 2172 2173 struct tcphdr *tc; 2174 struct ack_data_record x; 2175 int hlen, tlen, dlen; 2176 int i; 2177 2178 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2179 2180 hlen = (pip->ip_hl + tc->th_off) << 2; 2181 tlen = ntohs(pip->ip_len); 2182 dlen = tlen - hlen; 2183 2184 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 2185 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 2186 x.delta = delta; 2187 x.active = 1; 2188 2189 i = link->data.tcp->state.index; 2190 link->data.tcp->ack[i] = x; 2191 2192 i++; 2193 if (i == N_LINK_TCP_DATA) 2194 link->data.tcp->state.index = 0; 2195 else 2196 link->data.tcp->state.index = i; 2197 } 2198 2199 void 2200 SetExpire(struct alias_link *link, int expire) 2201 { 2202 if (expire == 0) 2203 { 2204 link->flags &= ~LINK_PERMANENT; 2205 DeleteLink(link); 2206 } 2207 else if (expire == -1) 2208 { 2209 link->flags |= LINK_PERMANENT; 2210 } 2211 else if (expire > 0) 2212 { 2213 link->expire_time = expire; 2214 } 2215 else 2216 { 2217 #ifdef DEBUG 2218 fprintf(stderr, "PacketAlias/SetExpire(): "); 2219 fprintf(stderr, "error in expire parameter\n"); 2220 #endif 2221 } 2222 } 2223 2224 void 2225 ClearCheckNewLink(void) 2226 { 2227 newDefaultLink = 0; 2228 } 2229 2230 void 2231 SetProtocolFlags(struct alias_link *link, int pflags) 2232 { 2233 2234 link->pflags = pflags;; 2235 } 2236 2237 int 2238 GetProtocolFlags(struct alias_link *link) 2239 { 2240 2241 return (link->pflags); 2242 } 2243 2244 void 2245 SetDestCallId(struct alias_link *link, u_int16_t cid) 2246 { 2247 2248 deleteAllLinks = 1; 2249 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr, 2250 link->src_port, cid, link->alias_port, link->link_type); 2251 deleteAllLinks = 0; 2252 } 2253 2254 2255 /* Miscellaneous Functions 2256 2257 HouseKeeping() 2258 InitPacketAliasLog() 2259 UninitPacketAliasLog() 2260 */ 2261 2262 /* 2263 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2264 is called to find and remove timed-out aliasing links. Logic exists 2265 to sweep through the entire table and linked list structure 2266 every 60 seconds. 2267 2268 (prototype in alias_local.h) 2269 */ 2270 2271 void 2272 HouseKeeping(void) 2273 { 2274 int i, n, n100; 2275 struct timeval tv; 2276 struct timezone tz; 2277 2278 /* 2279 * Save system time (seconds) in global variable timeStamp for 2280 * use by other functions. This is done so as not to unnecessarily 2281 * waste timeline by making system calls. 2282 */ 2283 gettimeofday(&tv, &tz); 2284 timeStamp = tv.tv_sec; 2285 2286 /* Compute number of spokes (output table link chains) to cover */ 2287 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 2288 n100 *= timeStamp - lastCleanupTime; 2289 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 2290 2291 n = n100/100; 2292 2293 /* Handle different cases */ 2294 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2295 { 2296 n = ALIAS_CLEANUP_MAX_SPOKES; 2297 lastCleanupTime = timeStamp; 2298 houseKeepingResidual = 0; 2299 2300 for (i=0; i<n; i++) 2301 IncrementalCleanup(); 2302 } 2303 else if (n > 0) 2304 { 2305 lastCleanupTime = timeStamp; 2306 houseKeepingResidual = n100 - 100*n; 2307 2308 for (i=0; i<n; i++) 2309 IncrementalCleanup(); 2310 } 2311 else if (n < 0) 2312 { 2313 #ifdef DEBUG 2314 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2315 fprintf(stderr, "something unexpected in time values\n"); 2316 #endif 2317 lastCleanupTime = timeStamp; 2318 houseKeepingResidual = 0; 2319 } 2320 } 2321 2322 2323 /* Init the log file and enable logging */ 2324 static void 2325 InitPacketAliasLog(void) 2326 { 2327 if ((~packetAliasMode & PKT_ALIAS_LOG) 2328 && (monitorFile = fopen("/var/log/alias.log", "w"))) 2329 { 2330 packetAliasMode |= PKT_ALIAS_LOG; 2331 fprintf(monitorFile, 2332 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2333 } 2334 } 2335 2336 2337 /* Close the log-file and disable logging. */ 2338 static void 2339 UninitPacketAliasLog(void) 2340 { 2341 if (monitorFile) { 2342 fclose(monitorFile); 2343 monitorFile = NULL; 2344 } 2345 packetAliasMode &= ~PKT_ALIAS_LOG; 2346 } 2347 2348 2349 2350 2351 2352 2353 /* Outside world interfaces 2354 2355 -- "outside world" means other than alias*.c routines -- 2356 2357 PacketAliasRedirectPort() 2358 PacketAliasAddServer() 2359 PacketAliasRedirectProto() 2360 PacketAliasRedirectAddr() 2361 PacketAliasRedirectDynamic() 2362 PacketAliasRedirectDelete() 2363 PacketAliasSetAddress() 2364 PacketAliasInit() 2365 PacketAliasUninit() 2366 PacketAliasSetMode() 2367 2368 (prototypes in alias.h) 2369 */ 2370 2371 /* Redirection from a specific public addr:port to a 2372 private addr:port */ 2373 struct alias_link * 2374 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 2375 struct in_addr dst_addr, u_short dst_port, 2376 struct in_addr alias_addr, u_short alias_port, 2377 u_char proto) 2378 { 2379 int link_type; 2380 struct alias_link *link; 2381 2382 switch(proto) 2383 { 2384 case IPPROTO_UDP: 2385 link_type = LINK_UDP; 2386 break; 2387 case IPPROTO_TCP: 2388 link_type = LINK_TCP; 2389 break; 2390 default: 2391 #ifdef DEBUG 2392 fprintf(stderr, "PacketAliasRedirectPort(): "); 2393 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2394 #endif 2395 return NULL; 2396 } 2397 2398 link = AddLink(src_addr, dst_addr, alias_addr, 2399 src_port, dst_port, alias_port, 2400 link_type); 2401 2402 if (link != NULL) 2403 { 2404 link->flags |= LINK_PERMANENT; 2405 } 2406 #ifdef DEBUG 2407 else 2408 { 2409 fprintf(stderr, "PacketAliasRedirectPort(): " 2410 "call to AddLink() failed\n"); 2411 } 2412 #endif 2413 2414 return link; 2415 } 2416 2417 /* Add server to the pool of servers */ 2418 int 2419 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) 2420 { 2421 struct server *server; 2422 2423 server = malloc(sizeof(struct server)); 2424 2425 if (server != NULL) { 2426 struct server *head; 2427 2428 server->addr = addr; 2429 server->port = port; 2430 2431 head = link->server; 2432 if (head == NULL) 2433 server->next = server; 2434 else { 2435 struct server *s; 2436 2437 for (s = head; s->next != head; s = s->next); 2438 s->next = server; 2439 server->next = head; 2440 } 2441 link->server = server; 2442 return (0); 2443 } else 2444 return (-1); 2445 } 2446 2447 /* Redirect packets of a given IP protocol from a specific 2448 public address to a private address */ 2449 struct alias_link * 2450 PacketAliasRedirectProto(struct in_addr src_addr, 2451 struct in_addr dst_addr, 2452 struct in_addr alias_addr, 2453 u_char proto) 2454 { 2455 struct alias_link *link; 2456 2457 link = AddLink(src_addr, dst_addr, alias_addr, 2458 NO_SRC_PORT, NO_DEST_PORT, 0, 2459 proto); 2460 2461 if (link != NULL) 2462 { 2463 link->flags |= LINK_PERMANENT; 2464 } 2465 #ifdef DEBUG 2466 else 2467 { 2468 fprintf(stderr, "PacketAliasRedirectProto(): " 2469 "call to AddLink() failed\n"); 2470 } 2471 #endif 2472 2473 return link; 2474 } 2475 2476 /* Static address translation */ 2477 struct alias_link * 2478 PacketAliasRedirectAddr(struct in_addr src_addr, 2479 struct in_addr alias_addr) 2480 { 2481 struct alias_link *link; 2482 2483 link = AddLink(src_addr, nullAddress, alias_addr, 2484 0, 0, 0, 2485 LINK_ADDR); 2486 2487 if (link != NULL) 2488 { 2489 link->flags |= LINK_PERMANENT; 2490 } 2491 #ifdef DEBUG 2492 else 2493 { 2494 fprintf(stderr, "PacketAliasRedirectAddr(): " 2495 "call to AddLink() failed\n"); 2496 } 2497 #endif 2498 2499 return link; 2500 } 2501 2502 2503 /* Mark the aliasing link dynamic */ 2504 int 2505 PacketAliasRedirectDynamic(struct alias_link *link) 2506 { 2507 2508 if (link->flags & LINK_PARTIALLY_SPECIFIED) 2509 return (-1); 2510 else { 2511 link->flags &= ~LINK_PERMANENT; 2512 return (0); 2513 } 2514 } 2515 2516 2517 void 2518 PacketAliasRedirectDelete(struct alias_link *link) 2519 { 2520 /* This is a dangerous function to put in the API, 2521 because an invalid pointer can crash the program. */ 2522 2523 deleteAllLinks = 1; 2524 DeleteLink(link); 2525 deleteAllLinks = 0; 2526 } 2527 2528 2529 void 2530 PacketAliasSetAddress(struct in_addr addr) 2531 { 2532 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2533 && aliasAddress.s_addr != addr.s_addr) 2534 CleanupAliasData(); 2535 2536 aliasAddress = addr; 2537 } 2538 2539 2540 void 2541 PacketAliasSetTarget(struct in_addr target_addr) 2542 { 2543 targetAddress = target_addr; 2544 } 2545 2546 2547 void 2548 PacketAliasInit(void) 2549 { 2550 int i; 2551 struct timeval tv; 2552 struct timezone tz; 2553 static int firstCall = 1; 2554 2555 if (firstCall == 1) 2556 { 2557 gettimeofday(&tv, &tz); 2558 timeStamp = tv.tv_sec; 2559 lastCleanupTime = tv.tv_sec; 2560 houseKeepingResidual = 0; 2561 2562 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2563 LIST_INIT(&linkTableOut[i]); 2564 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2565 LIST_INIT(&linkTableIn[i]); 2566 2567 atexit(PacketAliasUninit); 2568 firstCall = 0; 2569 } 2570 else 2571 { 2572 deleteAllLinks = 1; 2573 CleanupAliasData(); 2574 deleteAllLinks = 0; 2575 } 2576 2577 aliasAddress.s_addr = INADDR_ANY; 2578 targetAddress.s_addr = INADDR_ANY; 2579 2580 icmpLinkCount = 0; 2581 udpLinkCount = 0; 2582 tcpLinkCount = 0; 2583 pptpLinkCount = 0; 2584 protoLinkCount = 0; 2585 fragmentIdLinkCount = 0; 2586 fragmentPtrLinkCount = 0; 2587 sockCount = 0; 2588 2589 cleanupIndex =0; 2590 2591 packetAliasMode = PKT_ALIAS_SAME_PORTS 2592 | PKT_ALIAS_USE_SOCKETS 2593 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2594 } 2595 2596 void 2597 PacketAliasUninit(void) { 2598 deleteAllLinks = 1; 2599 CleanupAliasData(); 2600 deleteAllLinks = 0; 2601 UninitPacketAliasLog(); 2602 #ifndef NO_FW_PUNCH 2603 UninitPunchFW(); 2604 #endif 2605 } 2606 2607 2608 /* Change mode for some operations */ 2609 unsigned int 2610 PacketAliasSetMode( 2611 unsigned int flags, /* Which state to bring flags to */ 2612 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2613 probe for flag values) */ 2614 ) 2615 { 2616 /* Enable logging? */ 2617 if (flags & mask & PKT_ALIAS_LOG) 2618 { 2619 InitPacketAliasLog(); /* Do the enable */ 2620 } else 2621 /* _Disable_ logging? */ 2622 if (~flags & mask & PKT_ALIAS_LOG) { 2623 UninitPacketAliasLog(); 2624 } 2625 2626 #ifndef NO_FW_PUNCH 2627 /* Start punching holes in the firewall? */ 2628 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2629 InitPunchFW(); 2630 } else 2631 /* Stop punching holes in the firewall? */ 2632 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2633 UninitPunchFW(); 2634 } 2635 #endif 2636 2637 /* Other flags can be set/cleared without special action */ 2638 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2639 return packetAliasMode; 2640 } 2641 2642 2643 int 2644 PacketAliasCheckNewLink(void) 2645 { 2646 return newDefaultLink; 2647 } 2648 2649 2650 #ifndef NO_FW_PUNCH 2651 2652 /***************** 2653 Code to support firewall punching. This shouldn't really be in this 2654 file, but making variables global is evil too. 2655 ****************/ 2656 2657 #ifndef IPFW2 2658 #define IPFW2 1 /* use new ipfw code */ 2659 #endif 2660 2661 /* Firewall include files */ 2662 #include <net/if.h> 2663 #include <netinet/ip_fw.h> 2664 #include <string.h> 2665 #include <err.h> 2666 2667 #if IPFW2 /* support for new firewall code */ 2668 /* 2669 * helper function, updates the pointer to cmd with the length 2670 * of the current command, and also cleans up the first word of 2671 * the new command in case it has been clobbered before. 2672 */ 2673 static ipfw_insn * 2674 next_cmd(ipfw_insn *cmd) 2675 { 2676 cmd += F_LEN(cmd); 2677 bzero(cmd, sizeof(*cmd)); 2678 return cmd; 2679 } 2680 2681 /* 2682 * A function to fill simple commands of size 1. 2683 * Existing flags are preserved. 2684 */ 2685 static ipfw_insn * 2686 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int size, 2687 int flags, u_int16_t arg) 2688 { 2689 cmd->opcode = opcode; 2690 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2691 cmd->arg1 = arg; 2692 return next_cmd(cmd); 2693 } 2694 2695 static ipfw_insn * 2696 fill_ip(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2697 { 2698 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1; 2699 2700 cmd->addr.s_addr = addr; 2701 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2702 } 2703 2704 static ipfw_insn * 2705 fill_one_port(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2706 { 2707 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1; 2708 2709 cmd->ports[0] = cmd->ports[1] = port; 2710 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2711 } 2712 2713 static int 2714 fill_rule(void *buf, int bufsize, int rulenum, 2715 enum ipfw_opcodes action, int proto, 2716 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2717 { 2718 struct ip_fw *rule = (struct ip_fw *)buf; 2719 ipfw_insn *cmd = (ipfw_insn *)rule->cmd; 2720 2721 bzero(buf, bufsize); 2722 rule->rulenum = rulenum; 2723 2724 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2725 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2726 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2727 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2728 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2729 2730 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2731 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2732 2733 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2734 2735 return ((char *)cmd - (char *)buf); 2736 } 2737 #endif /* IPFW2 */ 2738 2739 static void ClearAllFWHoles(void); 2740 2741 static int fireWallBaseNum; /* The first firewall entry free for our use */ 2742 static int fireWallNumNums; /* How many entries can we use? */ 2743 static int fireWallActiveNum; /* Which entry did we last use? */ 2744 static char *fireWallField; /* bool array for entries */ 2745 2746 #define fw_setfield(field, num) \ 2747 do { \ 2748 (field)[(num) - fireWallBaseNum] = 1; \ 2749 } /*lint -save -e717 */ while(0) /*lint -restore */ 2750 #define fw_clrfield(field, num) \ 2751 do { \ 2752 (field)[(num) - fireWallBaseNum] = 0; \ 2753 } /*lint -save -e717 */ while(0) /*lint -restore */ 2754 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum]) 2755 2756 static void 2757 InitPunchFW(void) { 2758 fireWallField = malloc(fireWallNumNums); 2759 if (fireWallField) { 2760 memset(fireWallField, 0, fireWallNumNums); 2761 if (fireWallFD < 0) { 2762 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2763 } 2764 ClearAllFWHoles(); 2765 fireWallActiveNum = fireWallBaseNum; 2766 } 2767 } 2768 2769 static void 2770 UninitPunchFW(void) { 2771 ClearAllFWHoles(); 2772 if (fireWallFD >= 0) 2773 close(fireWallFD); 2774 fireWallFD = -1; 2775 if (fireWallField) 2776 free(fireWallField); 2777 fireWallField = NULL; 2778 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2779 } 2780 2781 /* Make a certain link go through the firewall */ 2782 void 2783 PunchFWHole(struct alias_link *link) { 2784 int r; /* Result code */ 2785 struct ip_fw rule; /* On-the-fly built rule */ 2786 int fwhole; /* Where to punch hole */ 2787 2788 /* Don't do anything unless we are asked to */ 2789 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2790 fireWallFD < 0 || 2791 link->link_type != LINK_TCP) 2792 return; 2793 2794 memset(&rule, 0, sizeof rule); 2795 2796 /** Build rule **/ 2797 2798 /* Find empty slot */ 2799 for (fwhole = fireWallActiveNum; 2800 fwhole < fireWallBaseNum + fireWallNumNums && 2801 fw_tstfield(fireWallField, fwhole); 2802 fwhole++) 2803 ; 2804 if (fwhole == fireWallBaseNum + fireWallNumNums) { 2805 for (fwhole = fireWallBaseNum; 2806 fwhole < fireWallActiveNum && 2807 fw_tstfield(fireWallField, fwhole); 2808 fwhole++) 2809 ; 2810 if (fwhole == fireWallActiveNum) { 2811 /* No rule point empty - we can't punch more holes. */ 2812 fireWallActiveNum = fireWallBaseNum; 2813 #ifdef DEBUG 2814 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2815 #endif 2816 return; 2817 } 2818 } 2819 /* Start next search at next position */ 2820 fireWallActiveNum = fwhole+1; 2821 2822 /* 2823 * generate two rules of the form 2824 * 2825 * add fwhole accept tcp from OAddr OPort to DAddr DPort 2826 * add fwhole accept tcp from DAddr DPort to OAddr OPort 2827 */ 2828 #if IPFW2 2829 if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) { 2830 u_int32_t rulebuf[255]; 2831 int i; 2832 2833 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2834 O_ACCEPT, IPPROTO_TCP, 2835 GetOriginalAddress(link), ntohs(GetOriginalPort(link)), 2836 GetDestAddress(link), ntohs(GetDestPort(link)) ); 2837 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2838 if (r) 2839 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2840 2841 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2842 O_ACCEPT, IPPROTO_TCP, 2843 GetDestAddress(link), ntohs(GetDestPort(link)), 2844 GetOriginalAddress(link), ntohs(GetOriginalPort(link)) ); 2845 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2846 if (r) 2847 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2848 } 2849 #else /* !IPFW2, old code to generate ipfw rule */ 2850 2851 /* Build generic part of the two rules */ 2852 rule.fw_number = fwhole; 2853 IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */ 2854 IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */ 2855 rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT; 2856 rule.fw_prot = IPPROTO_TCP; 2857 rule.fw_smsk.s_addr = INADDR_BROADCAST; 2858 rule.fw_dmsk.s_addr = INADDR_BROADCAST; 2859 2860 /* Build and apply specific part of the rules */ 2861 rule.fw_src = GetOriginalAddress(link); 2862 rule.fw_dst = GetDestAddress(link); 2863 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); 2864 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); 2865 2866 /* Skip non-bound links - XXX should not be strictly necessary, 2867 but seems to leave hole if not done. Leak of non-bound links? 2868 (Code should be left even if the problem is fixed - it is a 2869 clear optimization) */ 2870 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { 2871 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2872 #ifdef DEBUG 2873 if (r) 2874 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2875 #endif 2876 rule.fw_src = GetDestAddress(link); 2877 rule.fw_dst = GetOriginalAddress(link); 2878 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); 2879 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); 2880 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2881 #ifdef DEBUG 2882 if (r) 2883 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2884 #endif 2885 } 2886 #endif /* !IPFW2 */ 2887 /* Indicate hole applied */ 2888 link->data.tcp->fwhole = fwhole; 2889 fw_setfield(fireWallField, fwhole); 2890 } 2891 2892 /* Remove a hole in a firewall associated with a particular alias 2893 link. Calling this too often is harmless. */ 2894 static void 2895 ClearFWHole(struct alias_link *link) { 2896 if (link->link_type == LINK_TCP) { 2897 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ 2898 struct ip_fw rule; 2899 2900 if (fwhole < 0) 2901 return; 2902 2903 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2904 #if IPFW2 2905 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, 2906 &fwhole, sizeof fwhole)) 2907 ; 2908 #else /* !IPFW2 */ 2909 rule.fw_number = fwhole; 2910 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, 2911 &rule, sizeof rule)) 2912 ; 2913 #endif /* !IPFW2 */ 2914 fw_clrfield(fireWallField, fwhole); 2915 link->data.tcp->fwhole = -1; 2916 } 2917 } 2918 2919 /* Clear out the entire range dedicated to firewall holes. */ 2920 static void 2921 ClearAllFWHoles(void) { 2922 struct ip_fw rule; /* On-the-fly built rule */ 2923 int i; 2924 2925 if (fireWallFD < 0) 2926 return; 2927 2928 memset(&rule, 0, sizeof rule); 2929 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { 2930 #if IPFW2 2931 int r = i; 2932 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)) 2933 ; 2934 #else /* !IPFW2 */ 2935 rule.fw_number = i; 2936 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2937 ; 2938 #endif /* !IPFW2 */ 2939 } 2940 memset(fireWallField, 0, fireWallNumNums); 2941 } 2942 #endif 2943 2944 void 2945 PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2946 #ifndef NO_FW_PUNCH 2947 fireWallBaseNum = base; 2948 fireWallNumNums = num; 2949 #endif 2950 } 2951