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