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