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 unsigned int skinnyPort = 0; /* TCP port used by the Skinny */ 402 /* protocol. */ 403 404 405 406 407 408 409 410 /* Internal utility routines (used only in alias_db.c) 411 412 Lookup table starting points: 413 StartPointIn() -- link table initial search point for 414 incoming packets 415 StartPointOut() -- link table initial search point for 416 outgoing packets 417 418 Miscellaneous: 419 SeqDiff() -- difference between two TCP sequences 420 ShowAliasStats() -- send alias statistics to a monitor file 421 */ 422 423 424 /* Local prototypes */ 425 static u_int StartPointIn(struct in_addr, u_short, int); 426 427 static u_int StartPointOut(struct in_addr, struct in_addr, 428 u_short, u_short, int); 429 430 static int SeqDiff(u_long, u_long); 431 432 static void ShowAliasStats(void); 433 434 #ifndef NO_FW_PUNCH 435 /* Firewall control */ 436 static void InitPunchFW(void); 437 static void UninitPunchFW(void); 438 static void ClearFWHole(struct alias_link *link); 439 #endif 440 441 /* Log file control */ 442 static void InitPacketAliasLog(void); 443 static void UninitPacketAliasLog(void); 444 445 static u_int 446 StartPointIn(struct in_addr alias_addr, 447 u_short alias_port, 448 int link_type) 449 { 450 u_int n; 451 452 n = alias_addr.s_addr; 453 if (link_type != LINK_PPTP) 454 n += alias_port; 455 n += link_type; 456 return(n % LINK_TABLE_IN_SIZE); 457 } 458 459 460 static u_int 461 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 462 u_short src_port, u_short dst_port, int link_type) 463 { 464 u_int n; 465 466 n = src_addr.s_addr; 467 n += dst_addr.s_addr; 468 if (link_type != LINK_PPTP) { 469 n += src_port; 470 n += dst_port; 471 } 472 n += link_type; 473 474 return(n % LINK_TABLE_OUT_SIZE); 475 } 476 477 478 static int 479 SeqDiff(u_long x, u_long y) 480 { 481 /* Return the difference between two TCP sequence numbers */ 482 483 /* 484 This function is encapsulated in case there are any unusual 485 arithmetic conditions that need to be considered. 486 */ 487 488 return (ntohl(y) - ntohl(x)); 489 } 490 491 492 static void 493 ShowAliasStats(void) 494 { 495 /* Used for debugging */ 496 497 if (monitorFile) 498 { 499 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", 500 icmpLinkCount, 501 udpLinkCount, 502 tcpLinkCount, 503 pptpLinkCount, 504 protoLinkCount, 505 fragmentIdLinkCount, 506 fragmentPtrLinkCount); 507 508 fprintf(monitorFile, " / tot=%d (sock=%d)\n", 509 icmpLinkCount + udpLinkCount 510 + tcpLinkCount 511 + pptpLinkCount 512 + protoLinkCount 513 + fragmentIdLinkCount 514 + fragmentPtrLinkCount, 515 sockCount); 516 517 fflush(monitorFile); 518 } 519 } 520 521 522 523 524 525 /* Internal routines for finding, deleting and adding links 526 527 Port Allocation: 528 GetNewPort() -- find and reserve new alias port number 529 GetSocket() -- try to allocate a socket for a given port 530 531 Link creation and deletion: 532 CleanupAliasData() - remove all link chains from lookup table 533 IncrementalCleanup() - look for stale links in a single chain 534 DeleteLink() - remove link 535 AddLink() - add link 536 ReLink() - change link 537 538 Link search: 539 FindLinkOut() - find link for outgoing packets 540 FindLinkIn() - find link for incoming packets 541 542 Port search: 543 FindNewPortGroup() - find an available group of ports 544 */ 545 546 /* Local prototypes */ 547 static int GetNewPort(struct alias_link *, int); 548 549 static u_short GetSocket(u_short, int *, int); 550 551 static void CleanupAliasData(void); 552 553 static void IncrementalCleanup(void); 554 555 static void DeleteLink(struct alias_link *); 556 557 static struct alias_link * 558 AddLink(struct in_addr, struct in_addr, struct in_addr, 559 u_short, u_short, int, int); 560 561 static struct alias_link * 562 ReLink(struct alias_link *, 563 struct in_addr, struct in_addr, struct in_addr, 564 u_short, u_short, int, int); 565 566 static struct alias_link * 567 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int); 568 569 static struct alias_link * 570 FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); 571 572 573 #define ALIAS_PORT_BASE 0x08000 574 #define ALIAS_PORT_MASK 0x07fff 575 #define ALIAS_PORT_MASK_EVEN 0x07ffe 576 #define GET_NEW_PORT_MAX_ATTEMPTS 20 577 578 #define GET_ALIAS_PORT -1 579 #define GET_ALIAS_ID GET_ALIAS_PORT 580 581 #define FIND_EVEN_ALIAS_BASE 1 582 583 /* GetNewPort() allocates port numbers. Note that if a port number 584 is already in use, that does not mean that it cannot be used by 585 another link concurrently. This is because GetNewPort() looks for 586 unused triplets: (dest addr, dest port, alias port). */ 587 588 static int 589 GetNewPort(struct alias_link *link, int alias_port_param) 590 { 591 int i; 592 int max_trials; 593 u_short port_sys; 594 u_short port_net; 595 596 /* 597 Description of alias_port_param for GetNewPort(). When 598 this parameter is zero or positive, it precisely specifies 599 the port number. GetNewPort() will return this number 600 without check that it is in use. 601 602 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly 603 selected port number. 604 */ 605 606 if (alias_port_param == GET_ALIAS_PORT) 607 { 608 /* 609 * The aliasing port is automatically selected 610 * by one of two methods below: 611 */ 612 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 613 614 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) 615 { 616 /* 617 * When the PKT_ALIAS_SAME_PORTS option is 618 * chosen, the first try will be the 619 * actual source port. If this is already 620 * in use, the remainder of the trials 621 * will be random. 622 */ 623 port_net = link->src_port; 624 port_sys = ntohs(port_net); 625 } 626 else 627 { 628 /* First trial and all subsequent are random. */ 629 port_sys = random() & ALIAS_PORT_MASK; 630 port_sys += ALIAS_PORT_BASE; 631 port_net = htons(port_sys); 632 } 633 } 634 else if (alias_port_param >= 0 && alias_port_param < 0x10000) 635 { 636 link->alias_port = (u_short) alias_port_param; 637 return(0); 638 } 639 else 640 { 641 #ifdef DEBUG 642 fprintf(stderr, "PacketAlias/GetNewPort(): "); 643 fprintf(stderr, "input parameter error\n"); 644 #endif 645 return(-1); 646 } 647 648 649 /* Port number search */ 650 for (i=0; i<max_trials; i++) 651 { 652 int go_ahead; 653 struct alias_link *search_result; 654 655 search_result = FindLinkIn(link->dst_addr, link->alias_addr, 656 link->dst_port, port_net, 657 link->link_type, 0); 658 659 if (search_result == NULL) 660 go_ahead = 1; 661 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) 662 && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 663 go_ahead = 1; 664 else 665 go_ahead = 0; 666 667 if (go_ahead) 668 { 669 if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS) 670 && (link->flags & LINK_PARTIALLY_SPECIFIED) 671 && ((link->link_type == LINK_TCP) || 672 (link->link_type == LINK_UDP))) 673 { 674 if (GetSocket(port_net, &link->sockfd, link->link_type)) 675 { 676 link->alias_port = port_net; 677 return(0); 678 } 679 } 680 else 681 { 682 link->alias_port = port_net; 683 return(0); 684 } 685 } 686 687 port_sys = random() & ALIAS_PORT_MASK; 688 port_sys += ALIAS_PORT_BASE; 689 port_net = htons(port_sys); 690 } 691 692 #ifdef DEBUG 693 fprintf(stderr, "PacketAlias/GetnewPort(): "); 694 fprintf(stderr, "could not find free port\n"); 695 #endif 696 697 return(-1); 698 } 699 700 701 static u_short 702 GetSocket(u_short port_net, int *sockfd, int link_type) 703 { 704 int err; 705 int sock; 706 struct sockaddr_in sock_addr; 707 708 if (link_type == LINK_TCP) 709 sock = socket(AF_INET, SOCK_STREAM, 0); 710 else if (link_type == LINK_UDP) 711 sock = socket(AF_INET, SOCK_DGRAM, 0); 712 else 713 { 714 #ifdef DEBUG 715 fprintf(stderr, "PacketAlias/GetSocket(): "); 716 fprintf(stderr, "incorrect link type\n"); 717 #endif 718 return(0); 719 } 720 721 if (sock < 0) 722 { 723 #ifdef DEBUG 724 fprintf(stderr, "PacketAlias/GetSocket(): "); 725 fprintf(stderr, "socket() error %d\n", *sockfd); 726 #endif 727 return(0); 728 } 729 730 sock_addr.sin_family = AF_INET; 731 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 732 sock_addr.sin_port = port_net; 733 734 err = bind(sock, 735 (struct sockaddr *) &sock_addr, 736 sizeof(sock_addr)); 737 if (err == 0) 738 { 739 sockCount++; 740 *sockfd = sock; 741 return(1); 742 } 743 else 744 { 745 close(sock); 746 return(0); 747 } 748 } 749 750 751 /* FindNewPortGroup() returns a base port number for an available 752 range of contiguous port numbers. Note that if a port number 753 is already in use, that does not mean that it cannot be used by 754 another link concurrently. This is because FindNewPortGroup() 755 looks for unused triplets: (dest addr, dest port, alias port). */ 756 757 int 758 FindNewPortGroup(struct in_addr dst_addr, 759 struct in_addr alias_addr, 760 u_short src_port, 761 u_short dst_port, 762 u_short port_count, 763 u_char proto, 764 u_char align) 765 { 766 int i, j; 767 int max_trials; 768 u_short port_sys; 769 int link_type; 770 771 /* 772 * Get link_type from protocol 773 */ 774 775 switch (proto) 776 { 777 case IPPROTO_UDP: 778 link_type = LINK_UDP; 779 break; 780 case IPPROTO_TCP: 781 link_type = LINK_TCP; 782 break; 783 default: 784 return (0); 785 break; 786 } 787 788 /* 789 * The aliasing port is automatically selected 790 * by one of two methods below: 791 */ 792 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 793 794 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) { 795 /* 796 * When the ALIAS_SAME_PORTS option is 797 * chosen, the first try will be the 798 * actual source port. If this is already 799 * in use, the remainder of the trials 800 * will be random. 801 */ 802 port_sys = ntohs(src_port); 803 804 } else { 805 806 /* First trial and all subsequent are random. */ 807 if (align == FIND_EVEN_ALIAS_BASE) 808 port_sys = random() & ALIAS_PORT_MASK_EVEN; 809 else 810 port_sys = random() & ALIAS_PORT_MASK; 811 812 port_sys += ALIAS_PORT_BASE; 813 } 814 815 /* Port number search */ 816 for (i = 0; i < max_trials; i++) { 817 818 struct alias_link *search_result; 819 820 for (j = 0; j < port_count; j++) 821 if (0 != (search_result = FindLinkIn(dst_addr, alias_addr, 822 dst_port, htons(port_sys + j), 823 link_type, 0))) 824 break; 825 826 /* Found a good range, return base */ 827 if (j == port_count) 828 return (htons(port_sys)); 829 830 /* Find a new base to try */ 831 if (align == FIND_EVEN_ALIAS_BASE) 832 port_sys = random() & ALIAS_PORT_MASK_EVEN; 833 else 834 port_sys = random() & ALIAS_PORT_MASK; 835 836 port_sys += ALIAS_PORT_BASE; 837 } 838 839 #ifdef DEBUG 840 fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 841 fprintf(stderr, "could not find free port(s)\n"); 842 #endif 843 844 return(0); 845 } 846 847 static void 848 CleanupAliasData(void) 849 { 850 struct alias_link *link; 851 int i, icount; 852 853 icount = 0; 854 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 855 { 856 link = LIST_FIRST(&linkTableOut[i]); 857 while (link != NULL) 858 { 859 struct alias_link *link_next; 860 link_next = LIST_NEXT(link, list_out); 861 icount++; 862 DeleteLink(link); 863 link = link_next; 864 } 865 } 866 867 cleanupIndex =0; 868 } 869 870 871 static void 872 IncrementalCleanup(void) 873 { 874 int icount; 875 struct alias_link *link; 876 877 icount = 0; 878 link = LIST_FIRST(&linkTableOut[cleanupIndex++]); 879 while (link != NULL) 880 { 881 int idelta; 882 struct alias_link *link_next; 883 884 link_next = LIST_NEXT(link, list_out); 885 idelta = timeStamp - link->timestamp; 886 switch (link->link_type) 887 { 888 case LINK_TCP: 889 if (idelta > link->expire_time) 890 { 891 struct tcp_dat *tcp_aux; 892 893 tcp_aux = link->data.tcp; 894 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 895 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) 896 { 897 DeleteLink(link); 898 icount++; 899 } 900 } 901 break; 902 default: 903 if (idelta > link->expire_time) 904 { 905 DeleteLink(link); 906 icount++; 907 } 908 break; 909 } 910 link = link_next; 911 } 912 913 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 914 cleanupIndex = 0; 915 } 916 917 static void 918 DeleteLink(struct alias_link *link) 919 { 920 921 /* Don't do anything if the link is marked permanent */ 922 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 923 return; 924 925 #ifndef NO_FW_PUNCH 926 /* Delete associated firewall hole, if any */ 927 ClearFWHole(link); 928 #endif 929 930 /* Free memory allocated for LSNAT server pool */ 931 if (link->server != NULL) { 932 struct server *head, *curr, *next; 933 934 head = curr = link->server; 935 do { 936 next = curr->next; 937 free(curr); 938 } while ((curr = next) != head); 939 } 940 941 /* Adjust output table pointers */ 942 LIST_REMOVE(link, list_out); 943 944 /* Adjust input table pointers */ 945 LIST_REMOVE(link, list_in); 946 947 /* Close socket, if one has been allocated */ 948 if (link->sockfd != -1) 949 { 950 sockCount--; 951 close(link->sockfd); 952 } 953 954 /* Link-type dependent cleanup */ 955 switch(link->link_type) 956 { 957 case LINK_ICMP: 958 icmpLinkCount--; 959 break; 960 case LINK_UDP: 961 udpLinkCount--; 962 break; 963 case LINK_TCP: 964 tcpLinkCount--; 965 free(link->data.tcp); 966 break; 967 case LINK_PPTP: 968 pptpLinkCount--; 969 break; 970 case LINK_FRAGMENT_ID: 971 fragmentIdLinkCount--; 972 break; 973 case LINK_FRAGMENT_PTR: 974 fragmentPtrLinkCount--; 975 if (link->data.frag_ptr != NULL) 976 free(link->data.frag_ptr); 977 break; 978 case LINK_ADDR: 979 break; 980 default: 981 protoLinkCount--; 982 break; 983 } 984 985 /* Free memory */ 986 free(link); 987 988 /* Write statistics, if logging enabled */ 989 if (packetAliasMode & PKT_ALIAS_LOG) 990 { 991 ShowAliasStats(); 992 } 993 } 994 995 996 static struct alias_link * 997 AddLink(struct in_addr src_addr, 998 struct in_addr dst_addr, 999 struct in_addr alias_addr, 1000 u_short src_port, 1001 u_short dst_port, 1002 int alias_port_param, /* if less than zero, alias */ 1003 int link_type) /* port will be automatically */ 1004 { /* chosen. If greater than */ 1005 u_int start_point; /* zero, equal to alias port */ 1006 struct alias_link *link; 1007 1008 link = malloc(sizeof(struct alias_link)); 1009 if (link != NULL) 1010 { 1011 /* Basic initialization */ 1012 link->src_addr = src_addr; 1013 link->dst_addr = dst_addr; 1014 link->alias_addr = alias_addr; 1015 link->proxy_addr.s_addr = INADDR_ANY; 1016 link->src_port = src_port; 1017 link->dst_port = dst_port; 1018 link->proxy_port = 0; 1019 link->server = NULL; 1020 link->link_type = link_type; 1021 link->sockfd = -1; 1022 link->flags = 0; 1023 link->pflags = 0; 1024 link->timestamp = timeStamp; 1025 1026 /* Expiration time */ 1027 switch (link_type) 1028 { 1029 case LINK_ICMP: 1030 link->expire_time = ICMP_EXPIRE_TIME; 1031 break; 1032 case LINK_UDP: 1033 link->expire_time = UDP_EXPIRE_TIME; 1034 break; 1035 case LINK_TCP: 1036 link->expire_time = TCP_EXPIRE_INITIAL; 1037 break; 1038 case LINK_PPTP: 1039 link->flags |= LINK_PERMANENT; /* no timeout. */ 1040 break; 1041 case LINK_FRAGMENT_ID: 1042 link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 1043 break; 1044 case LINK_FRAGMENT_PTR: 1045 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 1046 break; 1047 case LINK_ADDR: 1048 break; 1049 default: 1050 link->expire_time = PROTO_EXPIRE_TIME; 1051 break; 1052 } 1053 1054 /* Determine alias flags */ 1055 if (dst_addr.s_addr == INADDR_ANY) 1056 link->flags |= LINK_UNKNOWN_DEST_ADDR; 1057 if (dst_port == 0) 1058 link->flags |= LINK_UNKNOWN_DEST_PORT; 1059 1060 /* Determine alias port */ 1061 if (GetNewPort(link, alias_port_param) != 0) 1062 { 1063 free(link); 1064 return(NULL); 1065 } 1066 1067 /* Link-type dependent initialization */ 1068 switch(link_type) 1069 { 1070 struct tcp_dat *aux_tcp; 1071 1072 case LINK_ICMP: 1073 icmpLinkCount++; 1074 break; 1075 case LINK_UDP: 1076 udpLinkCount++; 1077 break; 1078 case LINK_TCP: 1079 aux_tcp = malloc(sizeof(struct tcp_dat)); 1080 if (aux_tcp != NULL) 1081 { 1082 int i; 1083 1084 tcpLinkCount++; 1085 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 1086 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 1087 aux_tcp->state.index = 0; 1088 aux_tcp->state.ack_modified = 0; 1089 for (i=0; i<N_LINK_TCP_DATA; i++) 1090 aux_tcp->ack[i].active = 0; 1091 aux_tcp->fwhole = -1; 1092 link->data.tcp = aux_tcp; 1093 } 1094 else 1095 { 1096 #ifdef DEBUG 1097 fprintf(stderr, "PacketAlias/AddLink: "); 1098 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 1099 #endif 1100 free(link); 1101 return (NULL); 1102 } 1103 break; 1104 case LINK_PPTP: 1105 pptpLinkCount++; 1106 break; 1107 case LINK_FRAGMENT_ID: 1108 fragmentIdLinkCount++; 1109 break; 1110 case LINK_FRAGMENT_PTR: 1111 fragmentPtrLinkCount++; 1112 break; 1113 case LINK_ADDR: 1114 break; 1115 default: 1116 protoLinkCount++; 1117 break; 1118 } 1119 1120 /* Set up pointers for output lookup table */ 1121 start_point = StartPointOut(src_addr, dst_addr, 1122 src_port, dst_port, link_type); 1123 LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out); 1124 1125 /* Set up pointers for input lookup table */ 1126 start_point = StartPointIn(alias_addr, link->alias_port, link_type); 1127 LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in); 1128 } 1129 else 1130 { 1131 #ifdef DEBUG 1132 fprintf(stderr, "PacketAlias/AddLink(): "); 1133 fprintf(stderr, "malloc() call failed.\n"); 1134 #endif 1135 } 1136 1137 if (packetAliasMode & PKT_ALIAS_LOG) 1138 { 1139 ShowAliasStats(); 1140 } 1141 1142 return(link); 1143 } 1144 1145 static struct alias_link * 1146 ReLink(struct alias_link *old_link, 1147 struct in_addr src_addr, 1148 struct in_addr dst_addr, 1149 struct in_addr alias_addr, 1150 u_short src_port, 1151 u_short dst_port, 1152 int alias_port_param, /* if less than zero, alias */ 1153 int link_type) /* port will be automatically */ 1154 { /* chosen. If greater than */ 1155 struct alias_link *new_link; /* zero, equal to alias port */ 1156 1157 new_link = AddLink(src_addr, dst_addr, alias_addr, 1158 src_port, dst_port, alias_port_param, 1159 link_type); 1160 #ifndef NO_FW_PUNCH 1161 if (new_link != NULL && 1162 old_link->link_type == LINK_TCP && 1163 old_link->data.tcp->fwhole > 0) { 1164 PunchFWHole(new_link); 1165 } 1166 #endif 1167 DeleteLink(old_link); 1168 return new_link; 1169 } 1170 1171 static struct alias_link * 1172 _FindLinkOut(struct in_addr src_addr, 1173 struct in_addr dst_addr, 1174 u_short src_port, 1175 u_short dst_port, 1176 int link_type, 1177 int replace_partial_links) 1178 { 1179 u_int i; 1180 struct alias_link *link; 1181 1182 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1183 LIST_FOREACH(link, &linkTableOut[i], list_out) 1184 { 1185 if (link->src_addr.s_addr == src_addr.s_addr 1186 && link->server == NULL 1187 && link->dst_addr.s_addr == dst_addr.s_addr 1188 && link->dst_port == dst_port 1189 && link->src_port == src_port 1190 && link->link_type == link_type) 1191 { 1192 link->timestamp = timeStamp; 1193 break; 1194 } 1195 } 1196 1197 /* Search for partially specified links. */ 1198 if (link == NULL && replace_partial_links) 1199 { 1200 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) 1201 { 1202 link = _FindLinkOut(src_addr, dst_addr, src_port, 0, 1203 link_type, 0); 1204 if (link == NULL) 1205 link = _FindLinkOut(src_addr, nullAddress, src_port, 1206 dst_port, link_type, 0); 1207 } 1208 if (link == NULL && 1209 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) 1210 { 1211 link = _FindLinkOut(src_addr, nullAddress, src_port, 0, 1212 link_type, 0); 1213 } 1214 if (link != NULL) 1215 { 1216 link = ReLink(link, 1217 src_addr, dst_addr, link->alias_addr, 1218 src_port, dst_port, link->alias_port, 1219 link_type); 1220 } 1221 } 1222 1223 return(link); 1224 } 1225 1226 static struct alias_link * 1227 FindLinkOut(struct in_addr src_addr, 1228 struct in_addr dst_addr, 1229 u_short src_port, 1230 u_short dst_port, 1231 int link_type, 1232 int replace_partial_links) 1233 { 1234 struct alias_link *link; 1235 1236 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port, 1237 link_type, replace_partial_links); 1238 1239 if (link == NULL) 1240 { 1241 /* The following allows permanent links to be 1242 specified as using the default source address 1243 (i.e. device interface address) without knowing 1244 in advance what that address is. */ 1245 if (aliasAddress.s_addr != INADDR_ANY && 1246 src_addr.s_addr == aliasAddress.s_addr) 1247 { 1248 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port, 1249 link_type, replace_partial_links); 1250 } 1251 } 1252 1253 return(link); 1254 } 1255 1256 1257 static struct alias_link * 1258 _FindLinkIn(struct in_addr dst_addr, 1259 struct in_addr alias_addr, 1260 u_short dst_port, 1261 u_short alias_port, 1262 int link_type, 1263 int replace_partial_links) 1264 { 1265 int flags_in; 1266 u_int start_point; 1267 struct alias_link *link; 1268 struct alias_link *link_fully_specified; 1269 struct alias_link *link_unknown_all; 1270 struct alias_link *link_unknown_dst_addr; 1271 struct alias_link *link_unknown_dst_port; 1272 1273 /* Initialize pointers */ 1274 link_fully_specified = NULL; 1275 link_unknown_all = NULL; 1276 link_unknown_dst_addr = NULL; 1277 link_unknown_dst_port = NULL; 1278 1279 /* If either the dest addr or port is unknown, the search 1280 loop will have to know about this. */ 1281 1282 flags_in = 0; 1283 if (dst_addr.s_addr == INADDR_ANY) 1284 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1285 if (dst_port == 0) 1286 flags_in |= LINK_UNKNOWN_DEST_PORT; 1287 1288 /* Search loop */ 1289 start_point = StartPointIn(alias_addr, alias_port, link_type); 1290 LIST_FOREACH(link, &linkTableIn[start_point], list_in) 1291 { 1292 int flags; 1293 1294 flags = flags_in | link->flags; 1295 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1296 { 1297 if (link->alias_addr.s_addr == alias_addr.s_addr 1298 && link->alias_port == alias_port 1299 && link->dst_addr.s_addr == dst_addr.s_addr 1300 && link->dst_port == dst_port 1301 && link->link_type == link_type) 1302 { 1303 link_fully_specified = link; 1304 break; 1305 } 1306 } 1307 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1308 && (flags & LINK_UNKNOWN_DEST_PORT)) 1309 { 1310 if (link->alias_addr.s_addr == alias_addr.s_addr 1311 && link->alias_port == alias_port 1312 && link->link_type == link_type) 1313 { 1314 if (link_unknown_all == NULL) 1315 link_unknown_all = link; 1316 } 1317 } 1318 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1319 { 1320 if (link->alias_addr.s_addr == alias_addr.s_addr 1321 && link->alias_port == alias_port 1322 && link->link_type == link_type 1323 && link->dst_port == dst_port) 1324 { 1325 if (link_unknown_dst_addr == NULL) 1326 link_unknown_dst_addr = link; 1327 } 1328 } 1329 else if (flags & LINK_UNKNOWN_DEST_PORT) 1330 { 1331 if (link->alias_addr.s_addr == alias_addr.s_addr 1332 && link->alias_port == alias_port 1333 && link->link_type == link_type 1334 && link->dst_addr.s_addr == dst_addr.s_addr) 1335 { 1336 if (link_unknown_dst_port == NULL) 1337 link_unknown_dst_port = link; 1338 } 1339 } 1340 } 1341 1342 1343 1344 if (link_fully_specified != NULL) 1345 { 1346 link_fully_specified->timestamp = timeStamp; 1347 link = link_fully_specified; 1348 } 1349 else if (link_unknown_dst_port != NULL) 1350 link = link_unknown_dst_port; 1351 else if (link_unknown_dst_addr != NULL) 1352 link = link_unknown_dst_addr; 1353 else if (link_unknown_all != NULL) 1354 link = link_unknown_all; 1355 else 1356 return (NULL); 1357 1358 if (replace_partial_links && 1359 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) 1360 { 1361 struct in_addr src_addr; 1362 u_short src_port; 1363 1364 if (link->server != NULL) { /* LSNAT link */ 1365 src_addr = link->server->addr; 1366 src_port = link->server->port; 1367 link->server = link->server->next; 1368 } else { 1369 src_addr = link->src_addr; 1370 src_port = link->src_port; 1371 } 1372 1373 link = ReLink(link, 1374 src_addr, dst_addr, alias_addr, 1375 src_port, dst_port, alias_port, 1376 link_type); 1377 } 1378 1379 return (link); 1380 } 1381 1382 static struct alias_link * 1383 FindLinkIn(struct in_addr dst_addr, 1384 struct in_addr alias_addr, 1385 u_short dst_port, 1386 u_short alias_port, 1387 int link_type, 1388 int replace_partial_links) 1389 { 1390 struct alias_link *link; 1391 1392 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, 1393 link_type, replace_partial_links); 1394 1395 if (link == NULL) 1396 { 1397 /* The following allows permanent links to be 1398 specified as using the default aliasing address 1399 (i.e. device interface address) without knowing 1400 in advance what that address is. */ 1401 if (aliasAddress.s_addr != INADDR_ANY && 1402 alias_addr.s_addr == aliasAddress.s_addr) 1403 { 1404 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port, 1405 link_type, replace_partial_links); 1406 } 1407 } 1408 1409 return(link); 1410 } 1411 1412 1413 1414 1415 /* External routines for finding/adding links 1416 1417 -- "external" means outside alias_db.c, but within alias*.c -- 1418 1419 FindIcmpIn(), FindIcmpOut() 1420 FindFragmentIn1(), FindFragmentIn2() 1421 AddFragmentPtrLink(), FindFragmentPtr() 1422 FindProtoIn(), FindProtoOut() 1423 FindUdpTcpIn(), FindUdpTcpOut() 1424 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 1425 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 1426 FindOriginalAddress(), FindAliasAddress() 1427 1428 (prototypes in alias_local.h) 1429 */ 1430 1431 1432 struct alias_link * 1433 FindIcmpIn(struct in_addr dst_addr, 1434 struct in_addr alias_addr, 1435 u_short id_alias, 1436 int create) 1437 { 1438 struct alias_link *link; 1439 1440 link = FindLinkIn(dst_addr, alias_addr, 1441 NO_DEST_PORT, id_alias, 1442 LINK_ICMP, 0); 1443 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1444 { 1445 struct in_addr target_addr; 1446 1447 target_addr = FindOriginalAddress(alias_addr); 1448 link = AddLink(target_addr, dst_addr, alias_addr, 1449 id_alias, NO_DEST_PORT, id_alias, 1450 LINK_ICMP); 1451 } 1452 1453 return (link); 1454 } 1455 1456 1457 struct alias_link * 1458 FindIcmpOut(struct in_addr src_addr, 1459 struct in_addr dst_addr, 1460 u_short id, 1461 int create) 1462 { 1463 struct alias_link * link; 1464 1465 link = FindLinkOut(src_addr, dst_addr, 1466 id, NO_DEST_PORT, 1467 LINK_ICMP, 0); 1468 if (link == NULL && create) 1469 { 1470 struct in_addr alias_addr; 1471 1472 alias_addr = FindAliasAddress(src_addr); 1473 link = AddLink(src_addr, dst_addr, alias_addr, 1474 id, NO_DEST_PORT, GET_ALIAS_ID, 1475 LINK_ICMP); 1476 } 1477 1478 return(link); 1479 } 1480 1481 1482 struct alias_link * 1483 FindFragmentIn1(struct in_addr dst_addr, 1484 struct in_addr alias_addr, 1485 u_short ip_id) 1486 { 1487 struct alias_link *link; 1488 1489 link = FindLinkIn(dst_addr, alias_addr, 1490 NO_DEST_PORT, ip_id, 1491 LINK_FRAGMENT_ID, 0); 1492 1493 if (link == NULL) 1494 { 1495 link = AddLink(nullAddress, dst_addr, alias_addr, 1496 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1497 LINK_FRAGMENT_ID); 1498 } 1499 1500 return(link); 1501 } 1502 1503 1504 struct alias_link * 1505 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1506 struct in_addr alias_addr, /* is not found. */ 1507 u_short ip_id) 1508 { 1509 return FindLinkIn(dst_addr, alias_addr, 1510 NO_DEST_PORT, ip_id, 1511 LINK_FRAGMENT_ID, 0); 1512 } 1513 1514 1515 struct alias_link * 1516 AddFragmentPtrLink(struct in_addr dst_addr, 1517 u_short ip_id) 1518 { 1519 return AddLink(nullAddress, dst_addr, nullAddress, 1520 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1521 LINK_FRAGMENT_PTR); 1522 } 1523 1524 1525 struct alias_link * 1526 FindFragmentPtr(struct in_addr dst_addr, 1527 u_short ip_id) 1528 { 1529 return FindLinkIn(dst_addr, nullAddress, 1530 NO_DEST_PORT, ip_id, 1531 LINK_FRAGMENT_PTR, 0); 1532 } 1533 1534 1535 struct alias_link * 1536 FindProtoIn(struct in_addr dst_addr, 1537 struct in_addr alias_addr, 1538 u_char proto) 1539 { 1540 struct alias_link *link; 1541 1542 link = FindLinkIn(dst_addr, alias_addr, 1543 NO_DEST_PORT, 0, 1544 proto, 1); 1545 1546 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1547 { 1548 struct in_addr target_addr; 1549 1550 target_addr = FindOriginalAddress(alias_addr); 1551 link = AddLink(target_addr, dst_addr, alias_addr, 1552 NO_SRC_PORT, NO_DEST_PORT, 0, 1553 proto); 1554 } 1555 1556 return (link); 1557 } 1558 1559 1560 struct alias_link * 1561 FindProtoOut(struct in_addr src_addr, 1562 struct in_addr dst_addr, 1563 u_char proto) 1564 { 1565 struct alias_link *link; 1566 1567 link = FindLinkOut(src_addr, dst_addr, 1568 NO_SRC_PORT, NO_DEST_PORT, 1569 proto, 1); 1570 1571 if (link == NULL) 1572 { 1573 struct in_addr alias_addr; 1574 1575 alias_addr = FindAliasAddress(src_addr); 1576 link = AddLink(src_addr, dst_addr, alias_addr, 1577 NO_SRC_PORT, NO_DEST_PORT, 0, 1578 proto); 1579 } 1580 1581 return (link); 1582 } 1583 1584 1585 struct alias_link * 1586 FindUdpTcpIn(struct in_addr dst_addr, 1587 struct in_addr alias_addr, 1588 u_short dst_port, 1589 u_short alias_port, 1590 u_char proto, 1591 int create) 1592 { 1593 int link_type; 1594 struct alias_link *link; 1595 1596 switch (proto) 1597 { 1598 case IPPROTO_UDP: 1599 link_type = LINK_UDP; 1600 break; 1601 case IPPROTO_TCP: 1602 link_type = LINK_TCP; 1603 break; 1604 default: 1605 return NULL; 1606 break; 1607 } 1608 1609 link = FindLinkIn(dst_addr, alias_addr, 1610 dst_port, alias_port, 1611 link_type, create); 1612 1613 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1614 { 1615 struct in_addr target_addr; 1616 1617 target_addr = FindOriginalAddress(alias_addr); 1618 link = AddLink(target_addr, dst_addr, alias_addr, 1619 alias_port, dst_port, alias_port, 1620 link_type); 1621 } 1622 1623 return(link); 1624 } 1625 1626 1627 struct alias_link * 1628 FindUdpTcpOut(struct in_addr src_addr, 1629 struct in_addr dst_addr, 1630 u_short src_port, 1631 u_short dst_port, 1632 u_char proto, 1633 int create) 1634 { 1635 int link_type; 1636 struct alias_link *link; 1637 1638 switch (proto) 1639 { 1640 case IPPROTO_UDP: 1641 link_type = LINK_UDP; 1642 break; 1643 case IPPROTO_TCP: 1644 link_type = LINK_TCP; 1645 break; 1646 default: 1647 return NULL; 1648 break; 1649 } 1650 1651 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create); 1652 1653 if (link == NULL && create) 1654 { 1655 struct in_addr alias_addr; 1656 1657 alias_addr = FindAliasAddress(src_addr); 1658 link = AddLink(src_addr, dst_addr, alias_addr, 1659 src_port, dst_port, GET_ALIAS_PORT, 1660 link_type); 1661 } 1662 1663 return(link); 1664 } 1665 1666 1667 struct alias_link * 1668 AddPptp(struct in_addr src_addr, 1669 struct in_addr dst_addr, 1670 struct in_addr alias_addr, 1671 u_int16_t src_call_id) 1672 { 1673 struct alias_link *link; 1674 1675 link = AddLink(src_addr, dst_addr, alias_addr, 1676 src_call_id, 0, GET_ALIAS_PORT, 1677 LINK_PPTP); 1678 1679 return (link); 1680 } 1681 1682 1683 struct alias_link * 1684 FindPptpOutByCallId(struct in_addr src_addr, 1685 struct in_addr dst_addr, 1686 u_int16_t src_call_id) 1687 { 1688 u_int i; 1689 struct alias_link *link; 1690 1691 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1692 LIST_FOREACH(link, &linkTableOut[i], list_out) 1693 if (link->link_type == LINK_PPTP && 1694 link->src_addr.s_addr == src_addr.s_addr && 1695 link->dst_addr.s_addr == dst_addr.s_addr && 1696 link->src_port == src_call_id) 1697 break; 1698 1699 return (link); 1700 } 1701 1702 1703 struct alias_link * 1704 FindPptpOutByPeerCallId(struct in_addr src_addr, 1705 struct in_addr dst_addr, 1706 u_int16_t dst_call_id) 1707 { 1708 u_int i; 1709 struct alias_link *link; 1710 1711 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1712 LIST_FOREACH(link, &linkTableOut[i], list_out) 1713 if (link->link_type == LINK_PPTP && 1714 link->src_addr.s_addr == src_addr.s_addr && 1715 link->dst_addr.s_addr == dst_addr.s_addr && 1716 link->dst_port == dst_call_id) 1717 break; 1718 1719 return (link); 1720 } 1721 1722 1723 struct alias_link * 1724 FindPptpInByCallId(struct in_addr dst_addr, 1725 struct in_addr alias_addr, 1726 u_int16_t dst_call_id) 1727 { 1728 u_int i; 1729 struct alias_link *link; 1730 1731 i = StartPointIn(alias_addr, 0, LINK_PPTP); 1732 LIST_FOREACH(link, &linkTableIn[i], list_in) 1733 if (link->link_type == LINK_PPTP && 1734 link->dst_addr.s_addr == dst_addr.s_addr && 1735 link->alias_addr.s_addr == alias_addr.s_addr && 1736 link->dst_port == dst_call_id) 1737 break; 1738 1739 return (link); 1740 } 1741 1742 1743 struct alias_link * 1744 FindPptpInByPeerCallId(struct in_addr dst_addr, 1745 struct in_addr alias_addr, 1746 u_int16_t alias_call_id) 1747 { 1748 struct alias_link *link; 1749 1750 link = FindLinkIn(dst_addr, alias_addr, 1751 0/* any */, alias_call_id, 1752 LINK_PPTP, 0); 1753 1754 1755 return (link); 1756 } 1757 1758 1759 struct alias_link * 1760 FindRtspOut(struct in_addr src_addr, 1761 struct in_addr dst_addr, 1762 u_short src_port, 1763 u_short alias_port, 1764 u_char proto) 1765 { 1766 int link_type; 1767 struct alias_link *link; 1768 1769 switch (proto) 1770 { 1771 case IPPROTO_UDP: 1772 link_type = LINK_UDP; 1773 break; 1774 case IPPROTO_TCP: 1775 link_type = LINK_TCP; 1776 break; 1777 default: 1778 return NULL; 1779 break; 1780 } 1781 1782 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1); 1783 1784 if (link == NULL) 1785 { 1786 struct in_addr alias_addr; 1787 1788 alias_addr = FindAliasAddress(src_addr); 1789 link = AddLink(src_addr, dst_addr, alias_addr, 1790 src_port, 0, alias_port, 1791 link_type); 1792 } 1793 1794 return(link); 1795 } 1796 1797 1798 struct in_addr 1799 FindOriginalAddress(struct in_addr alias_addr) 1800 { 1801 struct alias_link *link; 1802 1803 link = FindLinkIn(nullAddress, alias_addr, 1804 0, 0, LINK_ADDR, 0); 1805 if (link == NULL) 1806 { 1807 newDefaultLink = 1; 1808 if (targetAddress.s_addr == INADDR_ANY) 1809 return alias_addr; 1810 else if (targetAddress.s_addr == INADDR_NONE) 1811 return (aliasAddress.s_addr != INADDR_ANY) ? 1812 aliasAddress : alias_addr; 1813 else 1814 return targetAddress; 1815 } 1816 else 1817 { 1818 if (link->server != NULL) { /* LSNAT link */ 1819 struct in_addr src_addr; 1820 1821 src_addr = link->server->addr; 1822 link->server = link->server->next; 1823 return (src_addr); 1824 } else if (link->src_addr.s_addr == INADDR_ANY) 1825 return (aliasAddress.s_addr != INADDR_ANY) ? 1826 aliasAddress : alias_addr; 1827 else 1828 return link->src_addr; 1829 } 1830 } 1831 1832 1833 struct in_addr 1834 FindAliasAddress(struct in_addr original_addr) 1835 { 1836 struct alias_link *link; 1837 1838 link = FindLinkOut(original_addr, nullAddress, 1839 0, 0, LINK_ADDR, 0); 1840 if (link == NULL) 1841 { 1842 return (aliasAddress.s_addr != INADDR_ANY) ? 1843 aliasAddress : original_addr; 1844 } 1845 else 1846 { 1847 if (link->alias_addr.s_addr == INADDR_ANY) 1848 return (aliasAddress.s_addr != INADDR_ANY) ? 1849 aliasAddress : original_addr; 1850 else 1851 return link->alias_addr; 1852 } 1853 } 1854 1855 1856 /* External routines for getting or changing link data 1857 (external to alias_db.c, but internal to alias*.c) 1858 1859 SetFragmentData(), GetFragmentData() 1860 SetFragmentPtr(), GetFragmentPtr() 1861 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1862 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1863 GetOriginalPort(), GetAliasPort() 1864 SetAckModified(), GetAckModified() 1865 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1866 SetProtocolFlags(), GetProtocolFlags() 1867 SetDestCallId() 1868 */ 1869 1870 1871 void 1872 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1873 { 1874 link->data.frag_addr = src_addr; 1875 } 1876 1877 1878 void 1879 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1880 { 1881 *src_addr = link->data.frag_addr; 1882 } 1883 1884 1885 void 1886 SetFragmentPtr(struct alias_link *link, char *fptr) 1887 { 1888 link->data.frag_ptr = fptr; 1889 } 1890 1891 1892 void 1893 GetFragmentPtr(struct alias_link *link, char **fptr) 1894 { 1895 *fptr = link->data.frag_ptr; 1896 } 1897 1898 1899 void 1900 SetStateIn(struct alias_link *link, int state) 1901 { 1902 /* TCP input state */ 1903 switch (state) { 1904 case ALIAS_TCP_STATE_DISCONNECTED: 1905 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1906 link->expire_time = TCP_EXPIRE_DEAD; 1907 else 1908 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1909 break; 1910 case ALIAS_TCP_STATE_CONNECTED: 1911 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1912 link->expire_time = TCP_EXPIRE_CONNECTED; 1913 break; 1914 default: 1915 abort(); 1916 } 1917 link->data.tcp->state.in = state; 1918 } 1919 1920 1921 void 1922 SetStateOut(struct alias_link *link, int state) 1923 { 1924 /* TCP output state */ 1925 switch (state) { 1926 case ALIAS_TCP_STATE_DISCONNECTED: 1927 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1928 link->expire_time = TCP_EXPIRE_DEAD; 1929 else 1930 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1931 break; 1932 case ALIAS_TCP_STATE_CONNECTED: 1933 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1934 link->expire_time = TCP_EXPIRE_CONNECTED; 1935 break; 1936 default: 1937 abort(); 1938 } 1939 link->data.tcp->state.out = state; 1940 } 1941 1942 1943 int 1944 GetStateIn(struct alias_link *link) 1945 { 1946 /* TCP input state */ 1947 return link->data.tcp->state.in; 1948 } 1949 1950 1951 int 1952 GetStateOut(struct alias_link *link) 1953 { 1954 /* TCP output state */ 1955 return link->data.tcp->state.out; 1956 } 1957 1958 1959 struct in_addr 1960 GetOriginalAddress(struct alias_link *link) 1961 { 1962 if (link->src_addr.s_addr == INADDR_ANY) 1963 return aliasAddress; 1964 else 1965 return(link->src_addr); 1966 } 1967 1968 1969 struct in_addr 1970 GetDestAddress(struct alias_link *link) 1971 { 1972 return(link->dst_addr); 1973 } 1974 1975 1976 struct in_addr 1977 GetAliasAddress(struct alias_link *link) 1978 { 1979 if (link->alias_addr.s_addr == INADDR_ANY) 1980 return aliasAddress; 1981 else 1982 return link->alias_addr; 1983 } 1984 1985 1986 struct in_addr 1987 GetDefaultAliasAddress() 1988 { 1989 return aliasAddress; 1990 } 1991 1992 1993 void 1994 SetDefaultAliasAddress(struct in_addr alias_addr) 1995 { 1996 aliasAddress = alias_addr; 1997 } 1998 1999 2000 u_short 2001 GetOriginalPort(struct alias_link *link) 2002 { 2003 return(link->src_port); 2004 } 2005 2006 2007 u_short 2008 GetAliasPort(struct alias_link *link) 2009 { 2010 return(link->alias_port); 2011 } 2012 2013 #ifndef NO_FW_PUNCH 2014 static u_short 2015 GetDestPort(struct alias_link *link) 2016 { 2017 return(link->dst_port); 2018 } 2019 #endif 2020 2021 void 2022 SetAckModified(struct alias_link *link) 2023 { 2024 /* Indicate that ACK numbers have been modified in a TCP connection */ 2025 link->data.tcp->state.ack_modified = 1; 2026 } 2027 2028 2029 struct in_addr 2030 GetProxyAddress(struct alias_link *link) 2031 { 2032 return link->proxy_addr; 2033 } 2034 2035 2036 void 2037 SetProxyAddress(struct alias_link *link, struct in_addr addr) 2038 { 2039 link->proxy_addr = addr; 2040 } 2041 2042 2043 u_short 2044 GetProxyPort(struct alias_link *link) 2045 { 2046 return link->proxy_port; 2047 } 2048 2049 2050 void 2051 SetProxyPort(struct alias_link *link, u_short port) 2052 { 2053 link->proxy_port = port; 2054 } 2055 2056 2057 int 2058 GetAckModified(struct alias_link *link) 2059 { 2060 /* See if ACK numbers have been modified */ 2061 return link->data.tcp->state.ack_modified; 2062 } 2063 2064 2065 int 2066 GetDeltaAckIn(struct ip *pip, struct alias_link *link) 2067 { 2068 /* 2069 Find out how much the ACK number has been altered for an incoming 2070 TCP packet. To do this, a circular list of ACK numbers where the TCP 2071 packet size was altered is searched. 2072 */ 2073 2074 int i; 2075 struct tcphdr *tc; 2076 int delta, ack_diff_min; 2077 u_long ack; 2078 2079 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2080 ack = tc->th_ack; 2081 2082 delta = 0; 2083 ack_diff_min = -1; 2084 for (i=0; i<N_LINK_TCP_DATA; i++) 2085 { 2086 struct ack_data_record x; 2087 2088 x = link->data.tcp->ack[i]; 2089 if (x.active == 1) 2090 { 2091 int ack_diff; 2092 2093 ack_diff = SeqDiff(x.ack_new, ack); 2094 if (ack_diff >= 0) 2095 { 2096 if (ack_diff_min >= 0) 2097 { 2098 if (ack_diff < ack_diff_min) 2099 { 2100 delta = x.delta; 2101 ack_diff_min = ack_diff; 2102 } 2103 } 2104 else 2105 { 2106 delta = x.delta; 2107 ack_diff_min = ack_diff; 2108 } 2109 } 2110 } 2111 } 2112 return (delta); 2113 } 2114 2115 2116 int 2117 GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 2118 { 2119 /* 2120 Find out how much the sequence number has been altered for an outgoing 2121 TCP packet. To do this, a circular list of ACK numbers where the TCP 2122 packet size was altered is searched. 2123 */ 2124 2125 int i; 2126 struct tcphdr *tc; 2127 int delta, seq_diff_min; 2128 u_long seq; 2129 2130 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2131 seq = tc->th_seq; 2132 2133 delta = 0; 2134 seq_diff_min = -1; 2135 for (i=0; i<N_LINK_TCP_DATA; i++) 2136 { 2137 struct ack_data_record x; 2138 2139 x = link->data.tcp->ack[i]; 2140 if (x.active == 1) 2141 { 2142 int seq_diff; 2143 2144 seq_diff = SeqDiff(x.ack_old, seq); 2145 if (seq_diff >= 0) 2146 { 2147 if (seq_diff_min >= 0) 2148 { 2149 if (seq_diff < seq_diff_min) 2150 { 2151 delta = x.delta; 2152 seq_diff_min = seq_diff; 2153 } 2154 } 2155 else 2156 { 2157 delta = x.delta; 2158 seq_diff_min = seq_diff; 2159 } 2160 } 2161 } 2162 } 2163 return (delta); 2164 } 2165 2166 2167 void 2168 AddSeq(struct ip *pip, struct alias_link *link, int delta) 2169 { 2170 /* 2171 When a TCP packet has been altered in length, save this 2172 information in a circular list. If enough packets have 2173 been altered, then this list will begin to overwrite itself. 2174 */ 2175 2176 struct tcphdr *tc; 2177 struct ack_data_record x; 2178 int hlen, tlen, dlen; 2179 int i; 2180 2181 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2182 2183 hlen = (pip->ip_hl + tc->th_off) << 2; 2184 tlen = ntohs(pip->ip_len); 2185 dlen = tlen - hlen; 2186 2187 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 2188 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 2189 x.delta = delta; 2190 x.active = 1; 2191 2192 i = link->data.tcp->state.index; 2193 link->data.tcp->ack[i] = x; 2194 2195 i++; 2196 if (i == N_LINK_TCP_DATA) 2197 link->data.tcp->state.index = 0; 2198 else 2199 link->data.tcp->state.index = i; 2200 } 2201 2202 void 2203 SetExpire(struct alias_link *link, int expire) 2204 { 2205 if (expire == 0) 2206 { 2207 link->flags &= ~LINK_PERMANENT; 2208 DeleteLink(link); 2209 } 2210 else if (expire == -1) 2211 { 2212 link->flags |= LINK_PERMANENT; 2213 } 2214 else if (expire > 0) 2215 { 2216 link->expire_time = expire; 2217 } 2218 else 2219 { 2220 #ifdef DEBUG 2221 fprintf(stderr, "PacketAlias/SetExpire(): "); 2222 fprintf(stderr, "error in expire parameter\n"); 2223 #endif 2224 } 2225 } 2226 2227 void 2228 ClearCheckNewLink(void) 2229 { 2230 newDefaultLink = 0; 2231 } 2232 2233 void 2234 SetProtocolFlags(struct alias_link *link, int pflags) 2235 { 2236 2237 link->pflags = pflags;; 2238 } 2239 2240 int 2241 GetProtocolFlags(struct alias_link *link) 2242 { 2243 2244 return (link->pflags); 2245 } 2246 2247 void 2248 SetDestCallId(struct alias_link *link, u_int16_t cid) 2249 { 2250 2251 deleteAllLinks = 1; 2252 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr, 2253 link->src_port, cid, link->alias_port, link->link_type); 2254 deleteAllLinks = 0; 2255 } 2256 2257 2258 /* Miscellaneous Functions 2259 2260 HouseKeeping() 2261 InitPacketAliasLog() 2262 UninitPacketAliasLog() 2263 */ 2264 2265 /* 2266 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2267 is called to find and remove timed-out aliasing links. Logic exists 2268 to sweep through the entire table and linked list structure 2269 every 60 seconds. 2270 2271 (prototype in alias_local.h) 2272 */ 2273 2274 void 2275 HouseKeeping(void) 2276 { 2277 int i, n, n100; 2278 struct timeval tv; 2279 struct timezone tz; 2280 2281 /* 2282 * Save system time (seconds) in global variable timeStamp for 2283 * use by other functions. This is done so as not to unnecessarily 2284 * waste timeline by making system calls. 2285 */ 2286 gettimeofday(&tv, &tz); 2287 timeStamp = tv.tv_sec; 2288 2289 /* Compute number of spokes (output table link chains) to cover */ 2290 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 2291 n100 *= timeStamp - lastCleanupTime; 2292 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 2293 2294 n = n100/100; 2295 2296 /* Handle different cases */ 2297 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2298 { 2299 n = ALIAS_CLEANUP_MAX_SPOKES; 2300 lastCleanupTime = timeStamp; 2301 houseKeepingResidual = 0; 2302 2303 for (i=0; i<n; i++) 2304 IncrementalCleanup(); 2305 } 2306 else if (n > 0) 2307 { 2308 lastCleanupTime = timeStamp; 2309 houseKeepingResidual = n100 - 100*n; 2310 2311 for (i=0; i<n; i++) 2312 IncrementalCleanup(); 2313 } 2314 else if (n < 0) 2315 { 2316 #ifdef DEBUG 2317 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2318 fprintf(stderr, "something unexpected in time values\n"); 2319 #endif 2320 lastCleanupTime = timeStamp; 2321 houseKeepingResidual = 0; 2322 } 2323 } 2324 2325 2326 /* Init the log file and enable logging */ 2327 static void 2328 InitPacketAliasLog(void) 2329 { 2330 if ((~packetAliasMode & PKT_ALIAS_LOG) 2331 && (monitorFile = fopen("/var/log/alias.log", "w"))) 2332 { 2333 packetAliasMode |= PKT_ALIAS_LOG; 2334 fprintf(monitorFile, 2335 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2336 } 2337 } 2338 2339 2340 /* Close the log-file and disable logging. */ 2341 static void 2342 UninitPacketAliasLog(void) 2343 { 2344 if (monitorFile) { 2345 fclose(monitorFile); 2346 monitorFile = NULL; 2347 } 2348 packetAliasMode &= ~PKT_ALIAS_LOG; 2349 } 2350 2351 2352 2353 2354 2355 2356 /* Outside world interfaces 2357 2358 -- "outside world" means other than alias*.c routines -- 2359 2360 PacketAliasRedirectPort() 2361 PacketAliasAddServer() 2362 PacketAliasRedirectProto() 2363 PacketAliasRedirectAddr() 2364 PacketAliasRedirectDynamic() 2365 PacketAliasRedirectDelete() 2366 PacketAliasSetAddress() 2367 PacketAliasInit() 2368 PacketAliasUninit() 2369 PacketAliasSetMode() 2370 2371 (prototypes in alias.h) 2372 */ 2373 2374 /* Redirection from a specific public addr:port to a 2375 private addr:port */ 2376 struct alias_link * 2377 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 2378 struct in_addr dst_addr, u_short dst_port, 2379 struct in_addr alias_addr, u_short alias_port, 2380 u_char proto) 2381 { 2382 int link_type; 2383 struct alias_link *link; 2384 2385 switch(proto) 2386 { 2387 case IPPROTO_UDP: 2388 link_type = LINK_UDP; 2389 break; 2390 case IPPROTO_TCP: 2391 link_type = LINK_TCP; 2392 break; 2393 default: 2394 #ifdef DEBUG 2395 fprintf(stderr, "PacketAliasRedirectPort(): "); 2396 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2397 #endif 2398 return NULL; 2399 } 2400 2401 link = AddLink(src_addr, dst_addr, alias_addr, 2402 src_port, dst_port, alias_port, 2403 link_type); 2404 2405 if (link != NULL) 2406 { 2407 link->flags |= LINK_PERMANENT; 2408 } 2409 #ifdef DEBUG 2410 else 2411 { 2412 fprintf(stderr, "PacketAliasRedirectPort(): " 2413 "call to AddLink() failed\n"); 2414 } 2415 #endif 2416 2417 return link; 2418 } 2419 2420 /* Add server to the pool of servers */ 2421 int 2422 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) 2423 { 2424 struct server *server; 2425 2426 server = malloc(sizeof(struct server)); 2427 2428 if (server != NULL) { 2429 struct server *head; 2430 2431 server->addr = addr; 2432 server->port = port; 2433 2434 head = link->server; 2435 if (head == NULL) 2436 server->next = server; 2437 else { 2438 struct server *s; 2439 2440 for (s = head; s->next != head; s = s->next); 2441 s->next = server; 2442 server->next = head; 2443 } 2444 link->server = server; 2445 return (0); 2446 } else 2447 return (-1); 2448 } 2449 2450 /* Redirect packets of a given IP protocol from a specific 2451 public address to a private address */ 2452 struct alias_link * 2453 PacketAliasRedirectProto(struct in_addr src_addr, 2454 struct in_addr dst_addr, 2455 struct in_addr alias_addr, 2456 u_char proto) 2457 { 2458 struct alias_link *link; 2459 2460 link = AddLink(src_addr, dst_addr, alias_addr, 2461 NO_SRC_PORT, NO_DEST_PORT, 0, 2462 proto); 2463 2464 if (link != NULL) 2465 { 2466 link->flags |= LINK_PERMANENT; 2467 } 2468 #ifdef DEBUG 2469 else 2470 { 2471 fprintf(stderr, "PacketAliasRedirectProto(): " 2472 "call to AddLink() failed\n"); 2473 } 2474 #endif 2475 2476 return link; 2477 } 2478 2479 /* Static address translation */ 2480 struct alias_link * 2481 PacketAliasRedirectAddr(struct in_addr src_addr, 2482 struct in_addr alias_addr) 2483 { 2484 struct alias_link *link; 2485 2486 link = AddLink(src_addr, nullAddress, alias_addr, 2487 0, 0, 0, 2488 LINK_ADDR); 2489 2490 if (link != NULL) 2491 { 2492 link->flags |= LINK_PERMANENT; 2493 } 2494 #ifdef DEBUG 2495 else 2496 { 2497 fprintf(stderr, "PacketAliasRedirectAddr(): " 2498 "call to AddLink() failed\n"); 2499 } 2500 #endif 2501 2502 return link; 2503 } 2504 2505 2506 /* Mark the aliasing link dynamic */ 2507 int 2508 PacketAliasRedirectDynamic(struct alias_link *link) 2509 { 2510 2511 if (link->flags & LINK_PARTIALLY_SPECIFIED) 2512 return (-1); 2513 else { 2514 link->flags &= ~LINK_PERMANENT; 2515 return (0); 2516 } 2517 } 2518 2519 2520 void 2521 PacketAliasRedirectDelete(struct alias_link *link) 2522 { 2523 /* This is a dangerous function to put in the API, 2524 because an invalid pointer can crash the program. */ 2525 2526 deleteAllLinks = 1; 2527 DeleteLink(link); 2528 deleteAllLinks = 0; 2529 } 2530 2531 2532 void 2533 PacketAliasSetAddress(struct in_addr addr) 2534 { 2535 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2536 && aliasAddress.s_addr != addr.s_addr) 2537 CleanupAliasData(); 2538 2539 aliasAddress = addr; 2540 } 2541 2542 2543 void 2544 PacketAliasSetTarget(struct in_addr target_addr) 2545 { 2546 targetAddress = target_addr; 2547 } 2548 2549 2550 void 2551 PacketAliasInit(void) 2552 { 2553 int i; 2554 struct timeval tv; 2555 struct timezone tz; 2556 static int firstCall = 1; 2557 2558 if (firstCall == 1) 2559 { 2560 gettimeofday(&tv, &tz); 2561 timeStamp = tv.tv_sec; 2562 lastCleanupTime = tv.tv_sec; 2563 houseKeepingResidual = 0; 2564 2565 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2566 LIST_INIT(&linkTableOut[i]); 2567 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2568 LIST_INIT(&linkTableIn[i]); 2569 2570 atexit(PacketAliasUninit); 2571 firstCall = 0; 2572 } 2573 else 2574 { 2575 deleteAllLinks = 1; 2576 CleanupAliasData(); 2577 deleteAllLinks = 0; 2578 } 2579 2580 aliasAddress.s_addr = INADDR_ANY; 2581 targetAddress.s_addr = INADDR_ANY; 2582 2583 icmpLinkCount = 0; 2584 udpLinkCount = 0; 2585 tcpLinkCount = 0; 2586 pptpLinkCount = 0; 2587 protoLinkCount = 0; 2588 fragmentIdLinkCount = 0; 2589 fragmentPtrLinkCount = 0; 2590 sockCount = 0; 2591 2592 cleanupIndex =0; 2593 2594 packetAliasMode = PKT_ALIAS_SAME_PORTS 2595 | PKT_ALIAS_USE_SOCKETS 2596 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2597 } 2598 2599 void 2600 PacketAliasUninit(void) { 2601 deleteAllLinks = 1; 2602 CleanupAliasData(); 2603 deleteAllLinks = 0; 2604 UninitPacketAliasLog(); 2605 #ifndef NO_FW_PUNCH 2606 UninitPunchFW(); 2607 #endif 2608 } 2609 2610 2611 /* Change mode for some operations */ 2612 unsigned int 2613 PacketAliasSetMode( 2614 unsigned int flags, /* Which state to bring flags to */ 2615 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2616 probe for flag values) */ 2617 ) 2618 { 2619 /* Enable logging? */ 2620 if (flags & mask & PKT_ALIAS_LOG) 2621 { 2622 InitPacketAliasLog(); /* Do the enable */ 2623 } else 2624 /* _Disable_ logging? */ 2625 if (~flags & mask & PKT_ALIAS_LOG) { 2626 UninitPacketAliasLog(); 2627 } 2628 2629 #ifndef NO_FW_PUNCH 2630 /* Start punching holes in the firewall? */ 2631 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2632 InitPunchFW(); 2633 } else 2634 /* Stop punching holes in the firewall? */ 2635 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2636 UninitPunchFW(); 2637 } 2638 #endif 2639 2640 /* Other flags can be set/cleared without special action */ 2641 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2642 return packetAliasMode; 2643 } 2644 2645 2646 int 2647 PacketAliasCheckNewLink(void) 2648 { 2649 return newDefaultLink; 2650 } 2651 2652 2653 #ifndef NO_FW_PUNCH 2654 2655 /***************** 2656 Code to support firewall punching. This shouldn't really be in this 2657 file, but making variables global is evil too. 2658 ****************/ 2659 2660 #ifndef IPFW2 2661 #define IPFW2 1 /* use new ipfw code */ 2662 #endif 2663 2664 /* Firewall include files */ 2665 #include <net/if.h> 2666 #include <netinet/ip_fw.h> 2667 #include <string.h> 2668 #include <err.h> 2669 2670 #if IPFW2 /* support for new firewall code */ 2671 /* 2672 * helper function, updates the pointer to cmd with the length 2673 * of the current command, and also cleans up the first word of 2674 * the new command in case it has been clobbered before. 2675 */ 2676 static ipfw_insn * 2677 next_cmd(ipfw_insn *cmd) 2678 { 2679 cmd += F_LEN(cmd); 2680 bzero(cmd, sizeof(*cmd)); 2681 return cmd; 2682 } 2683 2684 /* 2685 * A function to fill simple commands of size 1. 2686 * Existing flags are preserved. 2687 */ 2688 static ipfw_insn * 2689 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int size, 2690 int flags, u_int16_t arg) 2691 { 2692 cmd->opcode = opcode; 2693 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2694 cmd->arg1 = arg; 2695 return next_cmd(cmd); 2696 } 2697 2698 static ipfw_insn * 2699 fill_ip(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2700 { 2701 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1; 2702 2703 cmd->addr.s_addr = addr; 2704 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2705 } 2706 2707 static ipfw_insn * 2708 fill_one_port(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2709 { 2710 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1; 2711 2712 cmd->ports[0] = cmd->ports[1] = port; 2713 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2714 } 2715 2716 static int 2717 fill_rule(void *buf, int bufsize, int rulenum, 2718 enum ipfw_opcodes action, int proto, 2719 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2720 { 2721 struct ip_fw *rule = (struct ip_fw *)buf; 2722 ipfw_insn *cmd = (ipfw_insn *)rule->cmd; 2723 2724 bzero(buf, bufsize); 2725 rule->rulenum = rulenum; 2726 2727 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2728 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2729 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2730 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2731 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2732 2733 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2734 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2735 2736 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2737 2738 return ((char *)cmd - (char *)buf); 2739 } 2740 #endif /* IPFW2 */ 2741 2742 static void ClearAllFWHoles(void); 2743 2744 static int fireWallBaseNum; /* The first firewall entry free for our use */ 2745 static int fireWallNumNums; /* How many entries can we use? */ 2746 static int fireWallActiveNum; /* Which entry did we last use? */ 2747 static char *fireWallField; /* bool array for entries */ 2748 2749 #define fw_setfield(field, num) \ 2750 do { \ 2751 (field)[(num) - fireWallBaseNum] = 1; \ 2752 } /*lint -save -e717 */ while(0) /*lint -restore */ 2753 #define fw_clrfield(field, num) \ 2754 do { \ 2755 (field)[(num) - fireWallBaseNum] = 0; \ 2756 } /*lint -save -e717 */ while(0) /*lint -restore */ 2757 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum]) 2758 2759 static void 2760 InitPunchFW(void) { 2761 fireWallField = malloc(fireWallNumNums); 2762 if (fireWallField) { 2763 memset(fireWallField, 0, fireWallNumNums); 2764 if (fireWallFD < 0) { 2765 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2766 } 2767 ClearAllFWHoles(); 2768 fireWallActiveNum = fireWallBaseNum; 2769 } 2770 } 2771 2772 static void 2773 UninitPunchFW(void) { 2774 ClearAllFWHoles(); 2775 if (fireWallFD >= 0) 2776 close(fireWallFD); 2777 fireWallFD = -1; 2778 if (fireWallField) 2779 free(fireWallField); 2780 fireWallField = NULL; 2781 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2782 } 2783 2784 /* Make a certain link go through the firewall */ 2785 void 2786 PunchFWHole(struct alias_link *link) { 2787 int r; /* Result code */ 2788 struct ip_fw rule; /* On-the-fly built rule */ 2789 int fwhole; /* Where to punch hole */ 2790 2791 /* Don't do anything unless we are asked to */ 2792 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2793 fireWallFD < 0 || 2794 link->link_type != LINK_TCP) 2795 return; 2796 2797 memset(&rule, 0, sizeof rule); 2798 2799 /** Build rule **/ 2800 2801 /* Find empty slot */ 2802 for (fwhole = fireWallActiveNum; 2803 fwhole < fireWallBaseNum + fireWallNumNums && 2804 fw_tstfield(fireWallField, fwhole); 2805 fwhole++) 2806 ; 2807 if (fwhole == fireWallBaseNum + fireWallNumNums) { 2808 for (fwhole = fireWallBaseNum; 2809 fwhole < fireWallActiveNum && 2810 fw_tstfield(fireWallField, fwhole); 2811 fwhole++) 2812 ; 2813 if (fwhole == fireWallActiveNum) { 2814 /* No rule point empty - we can't punch more holes. */ 2815 fireWallActiveNum = fireWallBaseNum; 2816 #ifdef DEBUG 2817 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2818 #endif 2819 return; 2820 } 2821 } 2822 /* Start next search at next position */ 2823 fireWallActiveNum = fwhole+1; 2824 2825 /* 2826 * generate two rules of the form 2827 * 2828 * add fwhole accept tcp from OAddr OPort to DAddr DPort 2829 * add fwhole accept tcp from DAddr DPort to OAddr OPort 2830 */ 2831 #if IPFW2 2832 if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) { 2833 u_int32_t rulebuf[255]; 2834 int i; 2835 2836 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2837 O_ACCEPT, IPPROTO_TCP, 2838 GetOriginalAddress(link), ntohs(GetOriginalPort(link)), 2839 GetDestAddress(link), ntohs(GetDestPort(link)) ); 2840 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2841 if (r) 2842 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2843 2844 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2845 O_ACCEPT, IPPROTO_TCP, 2846 GetDestAddress(link), ntohs(GetDestPort(link)), 2847 GetOriginalAddress(link), ntohs(GetOriginalPort(link)) ); 2848 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2849 if (r) 2850 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2851 } 2852 #else /* !IPFW2, old code to generate ipfw rule */ 2853 2854 /* Build generic part of the two rules */ 2855 rule.fw_number = fwhole; 2856 IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */ 2857 IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */ 2858 rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT; 2859 rule.fw_prot = IPPROTO_TCP; 2860 rule.fw_smsk.s_addr = INADDR_BROADCAST; 2861 rule.fw_dmsk.s_addr = INADDR_BROADCAST; 2862 2863 /* Build and apply specific part of the rules */ 2864 rule.fw_src = GetOriginalAddress(link); 2865 rule.fw_dst = GetDestAddress(link); 2866 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); 2867 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); 2868 2869 /* Skip non-bound links - XXX should not be strictly necessary, 2870 but seems to leave hole if not done. Leak of non-bound links? 2871 (Code should be left even if the problem is fixed - it is a 2872 clear optimization) */ 2873 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { 2874 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2875 #ifdef DEBUG 2876 if (r) 2877 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2878 #endif 2879 rule.fw_src = GetDestAddress(link); 2880 rule.fw_dst = GetOriginalAddress(link); 2881 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); 2882 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); 2883 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2884 #ifdef DEBUG 2885 if (r) 2886 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2887 #endif 2888 } 2889 #endif /* !IPFW2 */ 2890 /* Indicate hole applied */ 2891 link->data.tcp->fwhole = fwhole; 2892 fw_setfield(fireWallField, fwhole); 2893 } 2894 2895 /* Remove a hole in a firewall associated with a particular alias 2896 link. Calling this too often is harmless. */ 2897 static void 2898 ClearFWHole(struct alias_link *link) { 2899 if (link->link_type == LINK_TCP) { 2900 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ 2901 struct ip_fw rule; 2902 2903 if (fwhole < 0) 2904 return; 2905 2906 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2907 #if IPFW2 2908 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, 2909 &fwhole, sizeof fwhole)) 2910 ; 2911 #else /* !IPFW2 */ 2912 rule.fw_number = fwhole; 2913 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, 2914 &rule, sizeof rule)) 2915 ; 2916 #endif /* !IPFW2 */ 2917 fw_clrfield(fireWallField, fwhole); 2918 link->data.tcp->fwhole = -1; 2919 } 2920 } 2921 2922 /* Clear out the entire range dedicated to firewall holes. */ 2923 static void 2924 ClearAllFWHoles(void) { 2925 struct ip_fw rule; /* On-the-fly built rule */ 2926 int i; 2927 2928 if (fireWallFD < 0) 2929 return; 2930 2931 memset(&rule, 0, sizeof rule); 2932 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { 2933 #if IPFW2 2934 int r = i; 2935 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)) 2936 ; 2937 #else /* !IPFW2 */ 2938 rule.fw_number = i; 2939 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2940 ; 2941 #endif /* !IPFW2 */ 2942 } 2943 memset(fireWallField, 0, fireWallNumNums); 2944 } 2945 #endif 2946 2947 void 2948 PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2949 #ifndef NO_FW_PUNCH 2950 fireWallBaseNum = base; 2951 fireWallNumNums = num; 2952 #endif 2953 } 2954 2955 void 2956 PacketAliasSetSkinnyPort(unsigned int port) { 2957 skinnyPort = port; 2958 } 2959