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