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, icount; 848 849 icount = 0; 850 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 851 { 852 link = LIST_FIRST(&linkTableOut[i]); 853 while (link != NULL) 854 { 855 struct alias_link *link_next; 856 link_next = LIST_NEXT(link, list_out); 857 icount++; 858 DeleteLink(link); 859 link = link_next; 860 } 861 } 862 863 cleanupIndex =0; 864 } 865 866 867 static void 868 IncrementalCleanup(void) 869 { 870 int icount; 871 struct alias_link *link; 872 873 icount = 0; 874 link = LIST_FIRST(&linkTableOut[cleanupIndex++]); 875 while (link != NULL) 876 { 877 int idelta; 878 struct alias_link *link_next; 879 880 link_next = LIST_NEXT(link, list_out); 881 idelta = timeStamp - link->timestamp; 882 switch (link->link_type) 883 { 884 case LINK_TCP: 885 if (idelta > link->expire_time) 886 { 887 struct tcp_dat *tcp_aux; 888 889 tcp_aux = link->data.tcp; 890 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 891 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) 892 { 893 DeleteLink(link); 894 icount++; 895 } 896 } 897 break; 898 default: 899 if (idelta > link->expire_time) 900 { 901 DeleteLink(link); 902 icount++; 903 } 904 break; 905 } 906 link = link_next; 907 } 908 909 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 910 cleanupIndex = 0; 911 } 912 913 static void 914 DeleteLink(struct alias_link *link) 915 { 916 917 /* Don't do anything if the link is marked permanent */ 918 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 919 return; 920 921 #ifndef NO_FW_PUNCH 922 /* Delete associated firewall hole, if any */ 923 ClearFWHole(link); 924 #endif 925 926 /* Free memory allocated for LSNAT server pool */ 927 if (link->server != NULL) { 928 struct server *head, *curr, *next; 929 930 head = curr = link->server; 931 do { 932 next = curr->next; 933 free(curr); 934 } while ((curr = next) != head); 935 } 936 937 /* Adjust output table pointers */ 938 LIST_REMOVE(link, list_out); 939 940 /* Adjust input table pointers */ 941 LIST_REMOVE(link, list_in); 942 943 /* Close socket, if one has been allocated */ 944 if (link->sockfd != -1) 945 { 946 sockCount--; 947 close(link->sockfd); 948 } 949 950 /* Link-type dependent cleanup */ 951 switch(link->link_type) 952 { 953 case LINK_ICMP: 954 icmpLinkCount--; 955 break; 956 case LINK_UDP: 957 udpLinkCount--; 958 break; 959 case LINK_TCP: 960 tcpLinkCount--; 961 free(link->data.tcp); 962 break; 963 case LINK_PPTP: 964 pptpLinkCount--; 965 break; 966 case LINK_FRAGMENT_ID: 967 fragmentIdLinkCount--; 968 break; 969 case LINK_FRAGMENT_PTR: 970 fragmentPtrLinkCount--; 971 if (link->data.frag_ptr != NULL) 972 free(link->data.frag_ptr); 973 break; 974 case LINK_ADDR: 975 break; 976 default: 977 protoLinkCount--; 978 break; 979 } 980 981 /* Free memory */ 982 free(link); 983 984 /* Write statistics, if logging enabled */ 985 if (packetAliasMode & PKT_ALIAS_LOG) 986 { 987 ShowAliasStats(); 988 } 989 } 990 991 992 static struct alias_link * 993 AddLink(struct in_addr src_addr, 994 struct in_addr dst_addr, 995 struct in_addr alias_addr, 996 u_short src_port, 997 u_short dst_port, 998 int alias_port_param, /* if less than zero, alias */ 999 int link_type) /* port will be automatically */ 1000 { /* chosen. If greater than */ 1001 u_int start_point; /* zero, equal to alias port */ 1002 struct alias_link *link; 1003 1004 link = malloc(sizeof(struct alias_link)); 1005 if (link != NULL) 1006 { 1007 /* Basic initialization */ 1008 link->src_addr = src_addr; 1009 link->dst_addr = dst_addr; 1010 link->alias_addr = alias_addr; 1011 link->proxy_addr.s_addr = INADDR_ANY; 1012 link->src_port = src_port; 1013 link->dst_port = dst_port; 1014 link->proxy_port = 0; 1015 link->server = NULL; 1016 link->link_type = link_type; 1017 link->sockfd = -1; 1018 link->flags = 0; 1019 link->timestamp = timeStamp; 1020 1021 /* Expiration time */ 1022 switch (link_type) 1023 { 1024 case LINK_ICMP: 1025 link->expire_time = ICMP_EXPIRE_TIME; 1026 break; 1027 case LINK_UDP: 1028 link->expire_time = UDP_EXPIRE_TIME; 1029 break; 1030 case LINK_TCP: 1031 link->expire_time = TCP_EXPIRE_INITIAL; 1032 break; 1033 case LINK_PPTP: 1034 link->flags |= LINK_PERMANENT; /* no timeout. */ 1035 break; 1036 case LINK_FRAGMENT_ID: 1037 link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 1038 break; 1039 case LINK_FRAGMENT_PTR: 1040 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 1041 break; 1042 case LINK_ADDR: 1043 break; 1044 default: 1045 link->expire_time = PROTO_EXPIRE_TIME; 1046 break; 1047 } 1048 1049 /* Determine alias flags */ 1050 if (dst_addr.s_addr == INADDR_ANY) 1051 link->flags |= LINK_UNKNOWN_DEST_ADDR; 1052 if (dst_port == 0) 1053 link->flags |= LINK_UNKNOWN_DEST_PORT; 1054 1055 /* Determine alias port */ 1056 if (GetNewPort(link, alias_port_param) != 0) 1057 { 1058 free(link); 1059 return(NULL); 1060 } 1061 1062 /* Link-type dependent initialization */ 1063 switch(link_type) 1064 { 1065 struct tcp_dat *aux_tcp; 1066 1067 case LINK_ICMP: 1068 icmpLinkCount++; 1069 break; 1070 case LINK_UDP: 1071 udpLinkCount++; 1072 break; 1073 case LINK_TCP: 1074 aux_tcp = malloc(sizeof(struct tcp_dat)); 1075 if (aux_tcp != NULL) 1076 { 1077 int i; 1078 1079 tcpLinkCount++; 1080 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 1081 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 1082 aux_tcp->state.index = 0; 1083 aux_tcp->state.ack_modified = 0; 1084 for (i=0; i<N_LINK_TCP_DATA; i++) 1085 aux_tcp->ack[i].active = 0; 1086 aux_tcp->fwhole = -1; 1087 link->data.tcp = aux_tcp; 1088 } 1089 else 1090 { 1091 #ifdef DEBUG 1092 fprintf(stderr, "PacketAlias/AddLink: "); 1093 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 1094 #endif 1095 free(link); 1096 return (NULL); 1097 } 1098 break; 1099 case LINK_PPTP: 1100 pptpLinkCount++; 1101 break; 1102 case LINK_FRAGMENT_ID: 1103 fragmentIdLinkCount++; 1104 break; 1105 case LINK_FRAGMENT_PTR: 1106 fragmentPtrLinkCount++; 1107 break; 1108 case LINK_ADDR: 1109 break; 1110 default: 1111 protoLinkCount++; 1112 break; 1113 } 1114 1115 /* Set up pointers for output lookup table */ 1116 start_point = StartPointOut(src_addr, dst_addr, 1117 src_port, dst_port, link_type); 1118 LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out); 1119 1120 /* Set up pointers for input lookup table */ 1121 start_point = StartPointIn(alias_addr, link->alias_port, link_type); 1122 LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in); 1123 } 1124 else 1125 { 1126 #ifdef DEBUG 1127 fprintf(stderr, "PacketAlias/AddLink(): "); 1128 fprintf(stderr, "malloc() call failed.\n"); 1129 #endif 1130 } 1131 1132 if (packetAliasMode & PKT_ALIAS_LOG) 1133 { 1134 ShowAliasStats(); 1135 } 1136 1137 return(link); 1138 } 1139 1140 static struct alias_link * 1141 ReLink(struct alias_link *old_link, 1142 struct in_addr src_addr, 1143 struct in_addr dst_addr, 1144 struct in_addr alias_addr, 1145 u_short src_port, 1146 u_short dst_port, 1147 int alias_port_param, /* if less than zero, alias */ 1148 int link_type) /* port will be automatically */ 1149 { /* chosen. If greater than */ 1150 struct alias_link *new_link; /* zero, equal to alias port */ 1151 1152 new_link = AddLink(src_addr, dst_addr, alias_addr, 1153 src_port, dst_port, alias_port_param, 1154 link_type); 1155 #ifndef NO_FW_PUNCH 1156 if (new_link != NULL && 1157 old_link->link_type == LINK_TCP && 1158 old_link->data.tcp->fwhole > 0) { 1159 PunchFWHole(new_link); 1160 } 1161 #endif 1162 DeleteLink(old_link); 1163 return new_link; 1164 } 1165 1166 static struct alias_link * 1167 _FindLinkOut(struct in_addr src_addr, 1168 struct in_addr dst_addr, 1169 u_short src_port, 1170 u_short dst_port, 1171 int link_type, 1172 int replace_partial_links) 1173 { 1174 u_int i; 1175 struct alias_link *link; 1176 1177 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1178 LIST_FOREACH(link, &linkTableOut[i], list_out) 1179 { 1180 if (link->src_addr.s_addr == src_addr.s_addr 1181 && link->server == NULL 1182 && link->dst_addr.s_addr == dst_addr.s_addr 1183 && link->dst_port == dst_port 1184 && link->src_port == src_port 1185 && link->link_type == link_type) 1186 { 1187 link->timestamp = timeStamp; 1188 break; 1189 } 1190 } 1191 1192 /* Search for partially specified links. */ 1193 if (link == NULL && replace_partial_links) 1194 { 1195 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) 1196 { 1197 link = _FindLinkOut(src_addr, dst_addr, src_port, 0, 1198 link_type, 0); 1199 if (link == NULL) 1200 link = _FindLinkOut(src_addr, nullAddress, src_port, 1201 dst_port, link_type, 0); 1202 } 1203 if (link == NULL && 1204 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) 1205 { 1206 link = _FindLinkOut(src_addr, nullAddress, src_port, 0, 1207 link_type, 0); 1208 } 1209 if (link != NULL) 1210 { 1211 link = ReLink(link, 1212 src_addr, dst_addr, link->alias_addr, 1213 src_port, dst_port, link->alias_port, 1214 link_type); 1215 } 1216 } 1217 1218 return(link); 1219 } 1220 1221 static struct alias_link * 1222 FindLinkOut(struct in_addr src_addr, 1223 struct in_addr dst_addr, 1224 u_short src_port, 1225 u_short dst_port, 1226 int link_type, 1227 int replace_partial_links) 1228 { 1229 struct alias_link *link; 1230 1231 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port, 1232 link_type, replace_partial_links); 1233 1234 if (link == NULL) 1235 { 1236 /* The following allows permanent links to be 1237 specified as using the default source address 1238 (i.e. device interface address) without knowing 1239 in advance what that address is. */ 1240 if (aliasAddress.s_addr != 0 && 1241 src_addr.s_addr == aliasAddress.s_addr) 1242 { 1243 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port, 1244 link_type, replace_partial_links); 1245 } 1246 } 1247 1248 return(link); 1249 } 1250 1251 1252 static struct alias_link * 1253 _FindLinkIn(struct in_addr dst_addr, 1254 struct in_addr alias_addr, 1255 u_short dst_port, 1256 u_short alias_port, 1257 int link_type, 1258 int replace_partial_links) 1259 { 1260 int flags_in; 1261 u_int start_point; 1262 struct alias_link *link; 1263 struct alias_link *link_fully_specified; 1264 struct alias_link *link_unknown_all; 1265 struct alias_link *link_unknown_dst_addr; 1266 struct alias_link *link_unknown_dst_port; 1267 1268 /* Initialize pointers */ 1269 link_fully_specified = NULL; 1270 link_unknown_all = NULL; 1271 link_unknown_dst_addr = NULL; 1272 link_unknown_dst_port = NULL; 1273 1274 /* If either the dest addr or port is unknown, the search 1275 loop will have to know about this. */ 1276 1277 flags_in = 0; 1278 if (dst_addr.s_addr == INADDR_ANY) 1279 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1280 if (dst_port == 0) 1281 flags_in |= LINK_UNKNOWN_DEST_PORT; 1282 1283 /* Search loop */ 1284 start_point = StartPointIn(alias_addr, alias_port, link_type); 1285 LIST_FOREACH(link, &linkTableIn[start_point], list_in) 1286 { 1287 int flags; 1288 1289 flags = flags_in | link->flags; 1290 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1291 { 1292 if (link->alias_addr.s_addr == alias_addr.s_addr 1293 && link->alias_port == alias_port 1294 && link->dst_addr.s_addr == dst_addr.s_addr 1295 && link->dst_port == dst_port 1296 && link->link_type == link_type) 1297 { 1298 link_fully_specified = link; 1299 break; 1300 } 1301 } 1302 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1303 && (flags & LINK_UNKNOWN_DEST_PORT)) 1304 { 1305 if (link->alias_addr.s_addr == alias_addr.s_addr 1306 && link->alias_port == alias_port 1307 && link->link_type == link_type) 1308 { 1309 if (link_unknown_all == NULL) 1310 link_unknown_all = link; 1311 } 1312 } 1313 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1314 { 1315 if (link->alias_addr.s_addr == alias_addr.s_addr 1316 && link->alias_port == alias_port 1317 && link->link_type == link_type 1318 && link->dst_port == dst_port) 1319 { 1320 if (link_unknown_dst_addr == NULL) 1321 link_unknown_dst_addr = link; 1322 } 1323 } 1324 else if (flags & LINK_UNKNOWN_DEST_PORT) 1325 { 1326 if (link->alias_addr.s_addr == alias_addr.s_addr 1327 && link->alias_port == alias_port 1328 && link->link_type == link_type 1329 && link->dst_addr.s_addr == dst_addr.s_addr) 1330 { 1331 if (link_unknown_dst_port == NULL) 1332 link_unknown_dst_port = link; 1333 } 1334 } 1335 } 1336 1337 1338 1339 if (link_fully_specified != NULL) 1340 { 1341 link_fully_specified->timestamp = timeStamp; 1342 link = link_fully_specified; 1343 } 1344 else if (link_unknown_dst_port != NULL) 1345 link = link_unknown_dst_port; 1346 else if (link_unknown_dst_addr != NULL) 1347 link = link_unknown_dst_addr; 1348 else if (link_unknown_all != NULL) 1349 link = link_unknown_all; 1350 else 1351 return (NULL); 1352 1353 if (replace_partial_links && 1354 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) 1355 { 1356 struct in_addr src_addr; 1357 u_short src_port; 1358 1359 if (link->server != NULL) { /* LSNAT link */ 1360 src_addr = link->server->addr; 1361 src_port = link->server->port; 1362 link->server = link->server->next; 1363 } else { 1364 src_addr = link->src_addr; 1365 src_port = link->src_port; 1366 } 1367 1368 link = ReLink(link, 1369 src_addr, dst_addr, alias_addr, 1370 src_port, dst_port, alias_port, 1371 link_type); 1372 } 1373 1374 return (link); 1375 } 1376 1377 static struct alias_link * 1378 FindLinkIn(struct in_addr dst_addr, 1379 struct in_addr alias_addr, 1380 u_short dst_port, 1381 u_short alias_port, 1382 int link_type, 1383 int replace_partial_links) 1384 { 1385 struct alias_link *link; 1386 1387 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, 1388 link_type, replace_partial_links); 1389 1390 if (link == NULL) 1391 { 1392 /* The following allows permanent links to be 1393 specified as using the default aliasing address 1394 (i.e. device interface address) without knowing 1395 in advance what that address is. */ 1396 if (aliasAddress.s_addr != 0 && 1397 alias_addr.s_addr == aliasAddress.s_addr) 1398 { 1399 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port, 1400 link_type, replace_partial_links); 1401 } 1402 } 1403 1404 return(link); 1405 } 1406 1407 1408 1409 1410 /* External routines for finding/adding links 1411 1412 -- "external" means outside alias_db.c, but within alias*.c -- 1413 1414 FindIcmpIn(), FindIcmpOut() 1415 FindFragmentIn1(), FindFragmentIn2() 1416 AddFragmentPtrLink(), FindFragmentPtr() 1417 FindProtoIn(), FindProtoOut() 1418 FindUdpTcpIn(), FindUdpTcpOut() 1419 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 1420 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 1421 FindOriginalAddress(), FindAliasAddress() 1422 1423 (prototypes in alias_local.h) 1424 */ 1425 1426 1427 struct alias_link * 1428 FindIcmpIn(struct in_addr dst_addr, 1429 struct in_addr alias_addr, 1430 u_short id_alias, 1431 int create) 1432 { 1433 struct alias_link *link; 1434 1435 link = FindLinkIn(dst_addr, alias_addr, 1436 NO_DEST_PORT, id_alias, 1437 LINK_ICMP, 0); 1438 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1439 { 1440 struct in_addr target_addr; 1441 1442 target_addr = FindOriginalAddress(alias_addr); 1443 link = AddLink(target_addr, dst_addr, alias_addr, 1444 id_alias, NO_DEST_PORT, id_alias, 1445 LINK_ICMP); 1446 } 1447 1448 return (link); 1449 } 1450 1451 1452 struct alias_link * 1453 FindIcmpOut(struct in_addr src_addr, 1454 struct in_addr dst_addr, 1455 u_short id, 1456 int create) 1457 { 1458 struct alias_link * link; 1459 1460 link = FindLinkOut(src_addr, dst_addr, 1461 id, NO_DEST_PORT, 1462 LINK_ICMP, 0); 1463 if (link == NULL && create) 1464 { 1465 struct in_addr alias_addr; 1466 1467 alias_addr = FindAliasAddress(src_addr); 1468 link = AddLink(src_addr, dst_addr, alias_addr, 1469 id, NO_DEST_PORT, GET_ALIAS_ID, 1470 LINK_ICMP); 1471 } 1472 1473 return(link); 1474 } 1475 1476 1477 struct alias_link * 1478 FindFragmentIn1(struct in_addr dst_addr, 1479 struct in_addr alias_addr, 1480 u_short ip_id) 1481 { 1482 struct alias_link *link; 1483 1484 link = FindLinkIn(dst_addr, alias_addr, 1485 NO_DEST_PORT, ip_id, 1486 LINK_FRAGMENT_ID, 0); 1487 1488 if (link == NULL) 1489 { 1490 link = AddLink(nullAddress, dst_addr, alias_addr, 1491 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1492 LINK_FRAGMENT_ID); 1493 } 1494 1495 return(link); 1496 } 1497 1498 1499 struct alias_link * 1500 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1501 struct in_addr alias_addr, /* is not found. */ 1502 u_short ip_id) 1503 { 1504 return FindLinkIn(dst_addr, alias_addr, 1505 NO_DEST_PORT, ip_id, 1506 LINK_FRAGMENT_ID, 0); 1507 } 1508 1509 1510 struct alias_link * 1511 AddFragmentPtrLink(struct in_addr dst_addr, 1512 u_short ip_id) 1513 { 1514 return AddLink(nullAddress, dst_addr, nullAddress, 1515 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1516 LINK_FRAGMENT_PTR); 1517 } 1518 1519 1520 struct alias_link * 1521 FindFragmentPtr(struct in_addr dst_addr, 1522 u_short ip_id) 1523 { 1524 return FindLinkIn(dst_addr, nullAddress, 1525 NO_DEST_PORT, ip_id, 1526 LINK_FRAGMENT_PTR, 0); 1527 } 1528 1529 1530 struct alias_link * 1531 FindProtoIn(struct in_addr dst_addr, 1532 struct in_addr alias_addr, 1533 u_char proto) 1534 { 1535 struct alias_link *link; 1536 1537 link = FindLinkIn(dst_addr, alias_addr, 1538 NO_DEST_PORT, 0, 1539 proto, 1); 1540 1541 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1542 { 1543 struct in_addr target_addr; 1544 1545 target_addr = FindOriginalAddress(alias_addr); 1546 link = AddLink(target_addr, dst_addr, alias_addr, 1547 NO_SRC_PORT, NO_DEST_PORT, 0, 1548 proto); 1549 } 1550 1551 return (link); 1552 } 1553 1554 1555 struct alias_link * 1556 FindProtoOut(struct in_addr src_addr, 1557 struct in_addr dst_addr, 1558 u_char proto) 1559 { 1560 struct alias_link *link; 1561 1562 link = FindLinkOut(src_addr, dst_addr, 1563 NO_SRC_PORT, NO_DEST_PORT, 1564 proto, 1); 1565 1566 if (link == NULL) 1567 { 1568 struct in_addr alias_addr; 1569 1570 alias_addr = FindAliasAddress(src_addr); 1571 link = AddLink(src_addr, dst_addr, alias_addr, 1572 NO_SRC_PORT, NO_DEST_PORT, 0, 1573 proto); 1574 } 1575 1576 return (link); 1577 } 1578 1579 1580 struct alias_link * 1581 FindUdpTcpIn(struct in_addr dst_addr, 1582 struct in_addr alias_addr, 1583 u_short dst_port, 1584 u_short alias_port, 1585 u_char proto, 1586 int create) 1587 { 1588 int link_type; 1589 struct alias_link *link; 1590 1591 switch (proto) 1592 { 1593 case IPPROTO_UDP: 1594 link_type = LINK_UDP; 1595 break; 1596 case IPPROTO_TCP: 1597 link_type = LINK_TCP; 1598 break; 1599 default: 1600 return NULL; 1601 break; 1602 } 1603 1604 link = FindLinkIn(dst_addr, alias_addr, 1605 dst_port, alias_port, 1606 link_type, create); 1607 1608 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1609 { 1610 struct in_addr target_addr; 1611 1612 target_addr = FindOriginalAddress(alias_addr); 1613 link = AddLink(target_addr, dst_addr, alias_addr, 1614 alias_port, dst_port, alias_port, 1615 link_type); 1616 } 1617 1618 return(link); 1619 } 1620 1621 1622 struct alias_link * 1623 FindUdpTcpOut(struct in_addr src_addr, 1624 struct in_addr dst_addr, 1625 u_short src_port, 1626 u_short dst_port, 1627 u_char proto, 1628 int create) 1629 { 1630 int link_type; 1631 struct alias_link *link; 1632 1633 switch (proto) 1634 { 1635 case IPPROTO_UDP: 1636 link_type = LINK_UDP; 1637 break; 1638 case IPPROTO_TCP: 1639 link_type = LINK_TCP; 1640 break; 1641 default: 1642 return NULL; 1643 break; 1644 } 1645 1646 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create); 1647 1648 if (link == NULL && create) 1649 { 1650 struct in_addr alias_addr; 1651 1652 alias_addr = FindAliasAddress(src_addr); 1653 link = AddLink(src_addr, dst_addr, alias_addr, 1654 src_port, dst_port, GET_ALIAS_PORT, 1655 link_type); 1656 } 1657 1658 return(link); 1659 } 1660 1661 1662 struct alias_link * 1663 AddPptp(struct in_addr src_addr, 1664 struct in_addr dst_addr, 1665 struct in_addr alias_addr, 1666 u_int16_t src_call_id) 1667 { 1668 struct alias_link *link; 1669 1670 link = AddLink(src_addr, dst_addr, alias_addr, 1671 src_call_id, 0, GET_ALIAS_PORT, 1672 LINK_PPTP); 1673 1674 return (link); 1675 } 1676 1677 1678 struct alias_link * 1679 FindPptpOutByCallId(struct in_addr src_addr, 1680 struct in_addr dst_addr, 1681 u_int16_t src_call_id) 1682 { 1683 u_int i; 1684 struct alias_link *link; 1685 1686 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1687 LIST_FOREACH(link, &linkTableOut[i], list_out) 1688 if (link->link_type == LINK_PPTP && 1689 link->src_addr.s_addr == src_addr.s_addr && 1690 link->dst_addr.s_addr == dst_addr.s_addr && 1691 link->src_port == src_call_id) 1692 break; 1693 1694 return (link); 1695 } 1696 1697 1698 struct alias_link * 1699 FindPptpOutByPeerCallId(struct in_addr src_addr, 1700 struct in_addr dst_addr, 1701 u_int16_t dst_call_id) 1702 { 1703 u_int i; 1704 struct alias_link *link; 1705 1706 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1707 LIST_FOREACH(link, &linkTableOut[i], list_out) 1708 if (link->link_type == LINK_PPTP && 1709 link->src_addr.s_addr == src_addr.s_addr && 1710 link->dst_addr.s_addr == dst_addr.s_addr && 1711 link->dst_port == dst_call_id) 1712 break; 1713 1714 return (link); 1715 } 1716 1717 1718 struct alias_link * 1719 FindPptpInByCallId(struct in_addr dst_addr, 1720 struct in_addr alias_addr, 1721 u_int16_t dst_call_id) 1722 { 1723 u_int i; 1724 struct alias_link *link; 1725 1726 i = StartPointIn(alias_addr, 0, LINK_PPTP); 1727 LIST_FOREACH(link, &linkTableIn[i], list_in) 1728 if (link->link_type == LINK_PPTP && 1729 link->dst_addr.s_addr == dst_addr.s_addr && 1730 link->alias_addr.s_addr == alias_addr.s_addr && 1731 link->dst_port == dst_call_id) 1732 break; 1733 1734 return (link); 1735 } 1736 1737 1738 struct alias_link * 1739 FindPptpInByPeerCallId(struct in_addr dst_addr, 1740 struct in_addr alias_addr, 1741 u_int16_t alias_call_id) 1742 { 1743 struct alias_link *link; 1744 1745 link = FindLinkIn(dst_addr, alias_addr, 1746 0/* any */, alias_call_id, 1747 LINK_PPTP, 0); 1748 1749 1750 return (link); 1751 } 1752 1753 1754 struct alias_link * 1755 FindRtspOut(struct in_addr src_addr, 1756 struct in_addr dst_addr, 1757 u_short src_port, 1758 u_short alias_port, 1759 u_char proto) 1760 { 1761 int link_type; 1762 struct alias_link *link; 1763 1764 switch (proto) 1765 { 1766 case IPPROTO_UDP: 1767 link_type = LINK_UDP; 1768 break; 1769 case IPPROTO_TCP: 1770 link_type = LINK_TCP; 1771 break; 1772 default: 1773 return NULL; 1774 break; 1775 } 1776 1777 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1); 1778 1779 if (link == NULL) 1780 { 1781 struct in_addr alias_addr; 1782 1783 alias_addr = FindAliasAddress(src_addr); 1784 link = AddLink(src_addr, dst_addr, alias_addr, 1785 src_port, 0, alias_port, 1786 link_type); 1787 } 1788 1789 return(link); 1790 } 1791 1792 1793 struct in_addr 1794 FindOriginalAddress(struct in_addr alias_addr) 1795 { 1796 struct alias_link *link; 1797 1798 link = FindLinkIn(nullAddress, alias_addr, 1799 0, 0, LINK_ADDR, 0); 1800 if (link == NULL) 1801 { 1802 newDefaultLink = 1; 1803 if (targetAddress.s_addr == INADDR_ANY) 1804 return alias_addr; 1805 else if (targetAddress.s_addr == INADDR_NONE) 1806 return aliasAddress; 1807 else 1808 return targetAddress; 1809 } 1810 else 1811 { 1812 if (link->server != NULL) { /* LSNAT link */ 1813 struct in_addr src_addr; 1814 1815 src_addr = link->server->addr; 1816 link->server = link->server->next; 1817 return (src_addr); 1818 } else if (link->src_addr.s_addr == INADDR_ANY) 1819 return aliasAddress; 1820 else 1821 return link->src_addr; 1822 } 1823 } 1824 1825 1826 struct in_addr 1827 FindAliasAddress(struct in_addr original_addr) 1828 { 1829 struct alias_link *link; 1830 1831 link = FindLinkOut(original_addr, nullAddress, 1832 0, 0, LINK_ADDR, 0); 1833 if (link == NULL) 1834 { 1835 return aliasAddress; 1836 } 1837 else 1838 { 1839 if (link->alias_addr.s_addr == INADDR_ANY) 1840 return aliasAddress; 1841 else 1842 return link->alias_addr; 1843 } 1844 } 1845 1846 1847 /* External routines for getting or changing link data 1848 (external to alias_db.c, but internal to alias*.c) 1849 1850 SetFragmentData(), GetFragmentData() 1851 SetFragmentPtr(), GetFragmentPtr() 1852 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1853 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1854 GetOriginalPort(), GetAliasPort() 1855 SetAckModified(), GetAckModified() 1856 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1857 SetLastLineCrlfTermed(), GetLastLineCrlfTermed() 1858 SetDestCallId() 1859 */ 1860 1861 1862 void 1863 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1864 { 1865 link->data.frag_addr = src_addr; 1866 } 1867 1868 1869 void 1870 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1871 { 1872 *src_addr = link->data.frag_addr; 1873 } 1874 1875 1876 void 1877 SetFragmentPtr(struct alias_link *link, char *fptr) 1878 { 1879 link->data.frag_ptr = fptr; 1880 } 1881 1882 1883 void 1884 GetFragmentPtr(struct alias_link *link, char **fptr) 1885 { 1886 *fptr = link->data.frag_ptr; 1887 } 1888 1889 1890 void 1891 SetStateIn(struct alias_link *link, int state) 1892 { 1893 /* TCP input state */ 1894 switch (state) { 1895 case ALIAS_TCP_STATE_DISCONNECTED: 1896 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1897 link->expire_time = TCP_EXPIRE_DEAD; 1898 else 1899 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1900 break; 1901 case ALIAS_TCP_STATE_CONNECTED: 1902 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1903 link->expire_time = TCP_EXPIRE_CONNECTED; 1904 break; 1905 default: 1906 abort(); 1907 } 1908 link->data.tcp->state.in = state; 1909 } 1910 1911 1912 void 1913 SetStateOut(struct alias_link *link, int state) 1914 { 1915 /* TCP output state */ 1916 switch (state) { 1917 case ALIAS_TCP_STATE_DISCONNECTED: 1918 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1919 link->expire_time = TCP_EXPIRE_DEAD; 1920 else 1921 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1922 break; 1923 case ALIAS_TCP_STATE_CONNECTED: 1924 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1925 link->expire_time = TCP_EXPIRE_CONNECTED; 1926 break; 1927 default: 1928 abort(); 1929 } 1930 link->data.tcp->state.out = state; 1931 } 1932 1933 1934 int 1935 GetStateIn(struct alias_link *link) 1936 { 1937 /* TCP input state */ 1938 return link->data.tcp->state.in; 1939 } 1940 1941 1942 int 1943 GetStateOut(struct alias_link *link) 1944 { 1945 /* TCP output state */ 1946 return link->data.tcp->state.out; 1947 } 1948 1949 1950 struct in_addr 1951 GetOriginalAddress(struct alias_link *link) 1952 { 1953 if (link->src_addr.s_addr == INADDR_ANY) 1954 return aliasAddress; 1955 else 1956 return(link->src_addr); 1957 } 1958 1959 1960 struct in_addr 1961 GetDestAddress(struct alias_link *link) 1962 { 1963 return(link->dst_addr); 1964 } 1965 1966 1967 struct in_addr 1968 GetAliasAddress(struct alias_link *link) 1969 { 1970 if (link->alias_addr.s_addr == INADDR_ANY) 1971 return aliasAddress; 1972 else 1973 return link->alias_addr; 1974 } 1975 1976 1977 struct in_addr 1978 GetDefaultAliasAddress(void) 1979 { 1980 return aliasAddress; 1981 } 1982 1983 1984 void 1985 SetDefaultAliasAddress(struct in_addr alias_addr) 1986 { 1987 aliasAddress = alias_addr; 1988 } 1989 1990 1991 u_short 1992 GetOriginalPort(struct alias_link *link) 1993 { 1994 return(link->src_port); 1995 } 1996 1997 1998 u_short 1999 GetAliasPort(struct alias_link *link) 2000 { 2001 return(link->alias_port); 2002 } 2003 2004 #ifndef NO_FW_PUNCH 2005 static u_short 2006 GetDestPort(struct alias_link *link) 2007 { 2008 return(link->dst_port); 2009 } 2010 #endif 2011 2012 void 2013 SetAckModified(struct alias_link *link) 2014 { 2015 /* Indicate that ACK numbers have been modified in a TCP connection */ 2016 link->data.tcp->state.ack_modified = 1; 2017 } 2018 2019 2020 struct in_addr 2021 GetProxyAddress(struct alias_link *link) 2022 { 2023 return link->proxy_addr; 2024 } 2025 2026 2027 void 2028 SetProxyAddress(struct alias_link *link, struct in_addr addr) 2029 { 2030 link->proxy_addr = addr; 2031 } 2032 2033 2034 u_short 2035 GetProxyPort(struct alias_link *link) 2036 { 2037 return link->proxy_port; 2038 } 2039 2040 2041 void 2042 SetProxyPort(struct alias_link *link, u_short port) 2043 { 2044 link->proxy_port = port; 2045 } 2046 2047 2048 int 2049 GetAckModified(struct alias_link *link) 2050 { 2051 /* See if ACK numbers have been modified */ 2052 return link->data.tcp->state.ack_modified; 2053 } 2054 2055 2056 int 2057 GetDeltaAckIn(struct ip *pip, struct alias_link *link) 2058 { 2059 /* 2060 Find out how much the ACK number has been altered for an incoming 2061 TCP packet. To do this, a circular list of ACK numbers where the TCP 2062 packet size was altered is searched. 2063 */ 2064 2065 int i; 2066 struct tcphdr *tc; 2067 int delta, ack_diff_min; 2068 u_long ack; 2069 2070 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2071 ack = tc->th_ack; 2072 2073 delta = 0; 2074 ack_diff_min = -1; 2075 for (i=0; i<N_LINK_TCP_DATA; i++) 2076 { 2077 struct ack_data_record x; 2078 2079 x = link->data.tcp->ack[i]; 2080 if (x.active == 1) 2081 { 2082 int ack_diff; 2083 2084 ack_diff = SeqDiff(x.ack_new, ack); 2085 if (ack_diff >= 0) 2086 { 2087 if (ack_diff_min >= 0) 2088 { 2089 if (ack_diff < ack_diff_min) 2090 { 2091 delta = x.delta; 2092 ack_diff_min = ack_diff; 2093 } 2094 } 2095 else 2096 { 2097 delta = x.delta; 2098 ack_diff_min = ack_diff; 2099 } 2100 } 2101 } 2102 } 2103 return (delta); 2104 } 2105 2106 2107 int 2108 GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 2109 { 2110 /* 2111 Find out how much the sequence number has been altered for an outgoing 2112 TCP packet. To do this, a circular list of ACK numbers where the TCP 2113 packet size was altered is searched. 2114 */ 2115 2116 int i; 2117 struct tcphdr *tc; 2118 int delta, seq_diff_min; 2119 u_long seq; 2120 2121 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2122 seq = tc->th_seq; 2123 2124 delta = 0; 2125 seq_diff_min = -1; 2126 for (i=0; i<N_LINK_TCP_DATA; i++) 2127 { 2128 struct ack_data_record x; 2129 2130 x = link->data.tcp->ack[i]; 2131 if (x.active == 1) 2132 { 2133 int seq_diff; 2134 2135 seq_diff = SeqDiff(x.ack_old, seq); 2136 if (seq_diff >= 0) 2137 { 2138 if (seq_diff_min >= 0) 2139 { 2140 if (seq_diff < seq_diff_min) 2141 { 2142 delta = x.delta; 2143 seq_diff_min = seq_diff; 2144 } 2145 } 2146 else 2147 { 2148 delta = x.delta; 2149 seq_diff_min = seq_diff; 2150 } 2151 } 2152 } 2153 } 2154 return (delta); 2155 } 2156 2157 2158 void 2159 AddSeq(struct ip *pip, struct alias_link *link, int delta) 2160 { 2161 /* 2162 When a TCP packet has been altered in length, save this 2163 information in a circular list. If enough packets have 2164 been altered, then this list will begin to overwrite itself. 2165 */ 2166 2167 struct tcphdr *tc; 2168 struct ack_data_record x; 2169 int hlen, tlen, dlen; 2170 int i; 2171 2172 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2173 2174 hlen = (pip->ip_hl + tc->th_off) << 2; 2175 tlen = ntohs(pip->ip_len); 2176 dlen = tlen - hlen; 2177 2178 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 2179 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 2180 x.delta = delta; 2181 x.active = 1; 2182 2183 i = link->data.tcp->state.index; 2184 link->data.tcp->ack[i] = x; 2185 2186 i++; 2187 if (i == N_LINK_TCP_DATA) 2188 link->data.tcp->state.index = 0; 2189 else 2190 link->data.tcp->state.index = i; 2191 } 2192 2193 void 2194 SetExpire(struct alias_link *link, int expire) 2195 { 2196 if (expire == 0) 2197 { 2198 link->flags &= ~LINK_PERMANENT; 2199 DeleteLink(link); 2200 } 2201 else if (expire == -1) 2202 { 2203 link->flags |= LINK_PERMANENT; 2204 } 2205 else if (expire > 0) 2206 { 2207 link->expire_time = expire; 2208 } 2209 else 2210 { 2211 #ifdef DEBUG 2212 fprintf(stderr, "PacketAlias/SetExpire(): "); 2213 fprintf(stderr, "error in expire parameter\n"); 2214 #endif 2215 } 2216 } 2217 2218 void 2219 ClearCheckNewLink(void) 2220 { 2221 newDefaultLink = 0; 2222 } 2223 2224 void 2225 SetLastLineCrlfTermed(struct alias_link *link, int yes) 2226 { 2227 2228 if (yes) 2229 link->flags |= LINK_LAST_LINE_CRLF_TERMED; 2230 else 2231 link->flags &= ~LINK_LAST_LINE_CRLF_TERMED; 2232 } 2233 2234 int 2235 GetLastLineCrlfTermed(struct alias_link *link) 2236 { 2237 2238 return (link->flags & LINK_LAST_LINE_CRLF_TERMED); 2239 } 2240 2241 void 2242 SetDestCallId(struct alias_link *link, u_int16_t cid) 2243 { 2244 2245 deleteAllLinks = 1; 2246 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr, 2247 link->src_port, cid, link->alias_port, link->link_type); 2248 deleteAllLinks = 0; 2249 } 2250 2251 2252 /* Miscellaneous Functions 2253 2254 HouseKeeping() 2255 InitPacketAliasLog() 2256 UninitPacketAliasLog() 2257 */ 2258 2259 /* 2260 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2261 is called to find and remove timed-out aliasing links. Logic exists 2262 to sweep through the entire table and linked list structure 2263 every 60 seconds. 2264 2265 (prototype in alias_local.h) 2266 */ 2267 2268 void 2269 HouseKeeping(void) 2270 { 2271 int i, n, n100; 2272 struct timeval tv; 2273 struct timezone tz; 2274 2275 /* 2276 * Save system time (seconds) in global variable timeStamp for 2277 * use by other functions. This is done so as not to unnecessarily 2278 * waste timeline by making system calls. 2279 */ 2280 gettimeofday(&tv, &tz); 2281 timeStamp = tv.tv_sec; 2282 2283 /* Compute number of spokes (output table link chains) to cover */ 2284 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 2285 n100 *= timeStamp - lastCleanupTime; 2286 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 2287 2288 n = n100/100; 2289 2290 /* Handle different cases */ 2291 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2292 { 2293 n = ALIAS_CLEANUP_MAX_SPOKES; 2294 lastCleanupTime = timeStamp; 2295 houseKeepingResidual = 0; 2296 2297 for (i=0; i<n; i++) 2298 IncrementalCleanup(); 2299 } 2300 else if (n > 0) 2301 { 2302 lastCleanupTime = timeStamp; 2303 houseKeepingResidual = n100 - 100*n; 2304 2305 for (i=0; i<n; i++) 2306 IncrementalCleanup(); 2307 } 2308 else if (n < 0) 2309 { 2310 #ifdef DEBUG 2311 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2312 fprintf(stderr, "something unexpected in time values\n"); 2313 #endif 2314 lastCleanupTime = timeStamp; 2315 houseKeepingResidual = 0; 2316 } 2317 } 2318 2319 2320 /* Init the log file and enable logging */ 2321 static void 2322 InitPacketAliasLog(void) 2323 { 2324 if ((~packetAliasMode & PKT_ALIAS_LOG) 2325 && (monitorFile = fopen("/var/log/alias.log", "w"))) 2326 { 2327 packetAliasMode |= PKT_ALIAS_LOG; 2328 fprintf(monitorFile, 2329 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2330 } 2331 } 2332 2333 2334 /* Close the log-file and disable logging. */ 2335 static void 2336 UninitPacketAliasLog(void) 2337 { 2338 if (monitorFile) { 2339 fclose(monitorFile); 2340 monitorFile = NULL; 2341 } 2342 packetAliasMode &= ~PKT_ALIAS_LOG; 2343 } 2344 2345 2346 2347 2348 2349 2350 /* Outside world interfaces 2351 2352 -- "outside world" means other than alias*.c routines -- 2353 2354 PacketAliasRedirectPort() 2355 PacketAliasAddServer() 2356 PacketAliasRedirectProto() 2357 PacketAliasRedirectAddr() 2358 PacketAliasRedirectDelete() 2359 PacketAliasSetAddress() 2360 PacketAliasInit() 2361 PacketAliasUninit() 2362 PacketAliasSetMode() 2363 2364 (prototypes in alias.h) 2365 */ 2366 2367 /* Redirection from a specific public addr:port to a 2368 private addr:port */ 2369 struct alias_link * 2370 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 2371 struct in_addr dst_addr, u_short dst_port, 2372 struct in_addr alias_addr, u_short alias_port, 2373 u_char proto) 2374 { 2375 int link_type; 2376 struct alias_link *link; 2377 2378 switch(proto) 2379 { 2380 case IPPROTO_UDP: 2381 link_type = LINK_UDP; 2382 break; 2383 case IPPROTO_TCP: 2384 link_type = LINK_TCP; 2385 break; 2386 default: 2387 #ifdef DEBUG 2388 fprintf(stderr, "PacketAliasRedirectPort(): "); 2389 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2390 #endif 2391 return NULL; 2392 } 2393 2394 link = AddLink(src_addr, dst_addr, alias_addr, 2395 src_port, dst_port, alias_port, 2396 link_type); 2397 2398 if (link != NULL) 2399 { 2400 link->flags |= LINK_PERMANENT; 2401 } 2402 #ifdef DEBUG 2403 else 2404 { 2405 fprintf(stderr, "PacketAliasRedirectPort(): " 2406 "call to AddLink() failed\n"); 2407 } 2408 #endif 2409 2410 return link; 2411 } 2412 2413 /* Add server to the pool of servers */ 2414 int 2415 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) 2416 { 2417 struct server *server; 2418 2419 server = malloc(sizeof(struct server)); 2420 2421 if (server != NULL) { 2422 struct server *head; 2423 2424 server->addr = addr; 2425 server->port = port; 2426 2427 head = link->server; 2428 if (head == NULL) 2429 server->next = server; 2430 else { 2431 struct server *s; 2432 2433 for (s = head; s->next != head; s = s->next); 2434 s->next = server; 2435 server->next = head; 2436 } 2437 link->server = server; 2438 return (0); 2439 } else 2440 return (-1); 2441 } 2442 2443 /* Redirect packets of a given IP protocol from a specific 2444 public address to a private address */ 2445 struct alias_link * 2446 PacketAliasRedirectProto(struct in_addr src_addr, 2447 struct in_addr dst_addr, 2448 struct in_addr alias_addr, 2449 u_char proto) 2450 { 2451 struct alias_link *link; 2452 2453 link = AddLink(src_addr, dst_addr, alias_addr, 2454 NO_SRC_PORT, NO_DEST_PORT, 0, 2455 proto); 2456 2457 if (link != NULL) 2458 { 2459 link->flags |= LINK_PERMANENT; 2460 } 2461 #ifdef DEBUG 2462 else 2463 { 2464 fprintf(stderr, "PacketAliasRedirectProto(): " 2465 "call to AddLink() failed\n"); 2466 } 2467 #endif 2468 2469 return link; 2470 } 2471 2472 /* Static address translation */ 2473 struct alias_link * 2474 PacketAliasRedirectAddr(struct in_addr src_addr, 2475 struct in_addr alias_addr) 2476 { 2477 struct alias_link *link; 2478 2479 link = AddLink(src_addr, nullAddress, alias_addr, 2480 0, 0, 0, 2481 LINK_ADDR); 2482 2483 if (link != NULL) 2484 { 2485 link->flags |= LINK_PERMANENT; 2486 } 2487 #ifdef DEBUG 2488 else 2489 { 2490 fprintf(stderr, "PacketAliasRedirectAddr(): " 2491 "call to AddLink() failed\n"); 2492 } 2493 #endif 2494 2495 return link; 2496 } 2497 2498 2499 void 2500 PacketAliasRedirectDelete(struct alias_link *link) 2501 { 2502 /* This is a dangerous function to put in the API, 2503 because an invalid pointer can crash the program. */ 2504 2505 deleteAllLinks = 1; 2506 DeleteLink(link); 2507 deleteAllLinks = 0; 2508 } 2509 2510 2511 void 2512 PacketAliasSetAddress(struct in_addr addr) 2513 { 2514 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2515 && aliasAddress.s_addr != addr.s_addr) 2516 CleanupAliasData(); 2517 2518 aliasAddress = addr; 2519 } 2520 2521 2522 void 2523 PacketAliasSetTarget(struct in_addr target_addr) 2524 { 2525 targetAddress = target_addr; 2526 } 2527 2528 2529 void 2530 PacketAliasInit(void) 2531 { 2532 int i; 2533 struct timeval tv; 2534 struct timezone tz; 2535 static int firstCall = 1; 2536 2537 if (firstCall == 1) 2538 { 2539 gettimeofday(&tv, &tz); 2540 timeStamp = tv.tv_sec; 2541 lastCleanupTime = tv.tv_sec; 2542 houseKeepingResidual = 0; 2543 2544 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2545 LIST_INIT(&linkTableOut[i]); 2546 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2547 LIST_INIT(&linkTableIn[i]); 2548 2549 atexit(PacketAliasUninit); 2550 firstCall = 0; 2551 } 2552 else 2553 { 2554 deleteAllLinks = 1; 2555 CleanupAliasData(); 2556 deleteAllLinks = 0; 2557 } 2558 2559 aliasAddress.s_addr = INADDR_ANY; 2560 targetAddress.s_addr = INADDR_ANY; 2561 2562 icmpLinkCount = 0; 2563 udpLinkCount = 0; 2564 tcpLinkCount = 0; 2565 pptpLinkCount = 0; 2566 protoLinkCount = 0; 2567 fragmentIdLinkCount = 0; 2568 fragmentPtrLinkCount = 0; 2569 sockCount = 0; 2570 2571 cleanupIndex =0; 2572 2573 packetAliasMode = PKT_ALIAS_SAME_PORTS 2574 | PKT_ALIAS_USE_SOCKETS 2575 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2576 } 2577 2578 void 2579 PacketAliasUninit(void) { 2580 deleteAllLinks = 1; 2581 CleanupAliasData(); 2582 deleteAllLinks = 0; 2583 UninitPacketAliasLog(); 2584 #ifndef NO_FW_PUNCH 2585 UninitPunchFW(); 2586 #endif 2587 } 2588 2589 2590 /* Change mode for some operations */ 2591 unsigned int 2592 PacketAliasSetMode( 2593 unsigned int flags, /* Which state to bring flags to */ 2594 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2595 probe for flag values) */ 2596 ) 2597 { 2598 /* Enable logging? */ 2599 if (flags & mask & PKT_ALIAS_LOG) 2600 { 2601 InitPacketAliasLog(); /* Do the enable */ 2602 } else 2603 /* _Disable_ logging? */ 2604 if (~flags & mask & PKT_ALIAS_LOG) { 2605 UninitPacketAliasLog(); 2606 } 2607 2608 #ifndef NO_FW_PUNCH 2609 /* Start punching holes in the firewall? */ 2610 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2611 InitPunchFW(); 2612 } else 2613 /* Stop punching holes in the firewall? */ 2614 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2615 UninitPunchFW(); 2616 } 2617 #endif 2618 2619 /* Other flags can be set/cleared without special action */ 2620 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2621 return packetAliasMode; 2622 } 2623 2624 2625 int 2626 PacketAliasCheckNewLink(void) 2627 { 2628 return newDefaultLink; 2629 } 2630 2631 2632 #ifndef NO_FW_PUNCH 2633 2634 /***************** 2635 Code to support firewall punching. This shouldn't really be in this 2636 file, but making variables global is evil too. 2637 ****************/ 2638 2639 /* Firewall include files */ 2640 #include <net/if.h> 2641 #include <net/ipfw/ip_fw.h> 2642 #include <string.h> 2643 #include <err.h> 2644 2645 /* 2646 * helper function, updates the pointer to cmd with the length 2647 * of the current command, and also cleans up the first word of 2648 * the new command in case it has been clobbered before. 2649 */ 2650 static ipfw_insn * 2651 next_cmd(ipfw_insn *cmd) 2652 { 2653 cmd += F_LEN(cmd); 2654 bzero(cmd, sizeof(*cmd)); 2655 return cmd; 2656 } 2657 2658 /* 2659 * A function to fill simple commands of size 1. 2660 * Existing flags are preserved. 2661 */ 2662 static ipfw_insn * 2663 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int size, 2664 int flags, u_int16_t arg) 2665 { 2666 cmd->opcode = opcode; 2667 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2668 cmd->arg1 = arg; 2669 return next_cmd(cmd); 2670 } 2671 2672 static ipfw_insn * 2673 fill_ip(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2674 { 2675 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1; 2676 2677 cmd->addr.s_addr = addr; 2678 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2679 } 2680 2681 static ipfw_insn * 2682 fill_one_port(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2683 { 2684 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1; 2685 2686 cmd->ports[0] = cmd->ports[1] = port; 2687 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2688 } 2689 2690 static int 2691 fill_rule(void *buf, int bufsize, int rulenum, 2692 enum ipfw_opcodes action, int proto, 2693 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2694 { 2695 struct ipfw_ioc_rule *rule = buf; 2696 ipfw_insn *cmd = (ipfw_insn *)rule->cmd; 2697 2698 bzero(buf, bufsize); 2699 rule->rulenum = rulenum; 2700 2701 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2702 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2703 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2704 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2705 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2706 2707 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2708 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2709 2710 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2711 2712 return ((void *)cmd - buf); 2713 } 2714 2715 static void ClearAllFWHoles(void); 2716 2717 static int fireWallBaseNum; /* The first firewall entry free for our use */ 2718 static int fireWallNumNums; /* How many entries can we use? */ 2719 static int fireWallActiveNum; /* Which entry did we last use? */ 2720 static char *fireWallField; /* bool array for entries */ 2721 2722 #define fw_setfield(field, num) \ 2723 do { \ 2724 (field)[(num) - fireWallBaseNum] = 1; \ 2725 } /*lint -save -e717 */ while(0) /*lint -restore */ 2726 #define fw_clrfield(field, num) \ 2727 do { \ 2728 (field)[(num) - fireWallBaseNum] = 0; \ 2729 } /*lint -save -e717 */ while(0) /*lint -restore */ 2730 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum]) 2731 2732 static void 2733 InitPunchFW(void) { 2734 fireWallField = malloc(fireWallNumNums); 2735 if (fireWallField) { 2736 memset(fireWallField, 0, fireWallNumNums); 2737 if (fireWallFD < 0) { 2738 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2739 } 2740 ClearAllFWHoles(); 2741 fireWallActiveNum = fireWallBaseNum; 2742 } 2743 } 2744 2745 static void 2746 UninitPunchFW(void) { 2747 ClearAllFWHoles(); 2748 if (fireWallFD >= 0) 2749 close(fireWallFD); 2750 fireWallFD = -1; 2751 if (fireWallField) 2752 free(fireWallField); 2753 fireWallField = NULL; 2754 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2755 } 2756 2757 /* Make a certain link go through the firewall */ 2758 void 2759 PunchFWHole(struct alias_link *link) { 2760 int r; /* Result code */ 2761 int fwhole; /* Where to punch hole */ 2762 2763 /* Don't do anything unless we are asked to */ 2764 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2765 fireWallFD < 0 || 2766 link->link_type != LINK_TCP) 2767 return; 2768 2769 /** Build rule **/ 2770 2771 /* Find empty slot */ 2772 for (fwhole = fireWallActiveNum; 2773 fwhole < fireWallBaseNum + fireWallNumNums && 2774 fw_tstfield(fireWallField, fwhole); 2775 fwhole++) 2776 ; 2777 if (fwhole == fireWallBaseNum + fireWallNumNums) { 2778 for (fwhole = fireWallBaseNum; 2779 fwhole < fireWallActiveNum && 2780 fw_tstfield(fireWallField, fwhole); 2781 fwhole++) 2782 ; 2783 if (fwhole == fireWallActiveNum) { 2784 /* No rule point empty - we can't punch more holes. */ 2785 fireWallActiveNum = fireWallBaseNum; 2786 #ifdef DEBUG 2787 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2788 #endif 2789 return; 2790 } 2791 } 2792 /* Start next search at next position */ 2793 fireWallActiveNum = fwhole+1; 2794 2795 /* 2796 * generate two rules of the form 2797 * 2798 * add fwhole accept tcp from OAddr OPort to DAddr DPort 2799 * add fwhole accept tcp from DAddr DPort to OAddr OPort 2800 */ 2801 if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) { 2802 u_int32_t rulebuf[IPFW_RULE_SIZE_MAX]; 2803 int i; 2804 2805 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2806 O_ACCEPT, IPPROTO_TCP, 2807 GetOriginalAddress(link), ntohs(GetOriginalPort(link)), 2808 GetDestAddress(link), ntohs(GetDestPort(link)) ); 2809 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2810 if (r) 2811 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2812 2813 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2814 O_ACCEPT, IPPROTO_TCP, 2815 GetDestAddress(link), ntohs(GetDestPort(link)), 2816 GetOriginalAddress(link), ntohs(GetOriginalPort(link)) ); 2817 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2818 if (r) 2819 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2820 } 2821 /* Indicate hole applied */ 2822 link->data.tcp->fwhole = fwhole; 2823 fw_setfield(fireWallField, fwhole); 2824 } 2825 2826 /* Remove a hole in a firewall associated with a particular alias 2827 link. Calling this too often is harmless. */ 2828 static void 2829 ClearFWHole(struct alias_link *link) { 2830 if (link->link_type == LINK_TCP) { 2831 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ 2832 2833 if (fwhole < 0) 2834 return; 2835 2836 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, 2837 &fwhole, sizeof fwhole)) 2838 ; 2839 fw_clrfield(fireWallField, fwhole); 2840 link->data.tcp->fwhole = -1; 2841 } 2842 } 2843 2844 /* Clear out the entire range dedicated to firewall holes. */ 2845 static void 2846 ClearAllFWHoles(void) { 2847 int i; 2848 2849 if (fireWallFD < 0) 2850 return; 2851 2852 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { 2853 int r = i; 2854 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)) 2855 ; 2856 } 2857 memset(fireWallField, 0, fireWallNumNums); 2858 } 2859 #endif 2860 2861 void 2862 PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2863 #ifndef NO_FW_PUNCH 2864 fireWallBaseNum = base; 2865 fireWallNumNums = num; 2866 #endif 2867 } 2868