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 PROTO_EXPIRE_TIME 60 162 #define FRAGMENT_ID_EXPIRE_TIME 10 163 #define FRAGMENT_PTR_EXPIRE_TIME 30 164 165 /* TCP link expire time for different cases */ 166 /* When the link has been used and closed - minimal grace time to 167 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 168 #ifndef TCP_EXPIRE_DEAD 169 # define TCP_EXPIRE_DEAD 10 170 #endif 171 172 /* When the link has been used and closed on one side - the other side 173 is allowed to still send data */ 174 #ifndef TCP_EXPIRE_SINGLEDEAD 175 # define TCP_EXPIRE_SINGLEDEAD 90 176 #endif 177 178 /* When the link isn't yet up */ 179 #ifndef TCP_EXPIRE_INITIAL 180 # define TCP_EXPIRE_INITIAL 300 181 #endif 182 183 /* When the link is up */ 184 #ifndef TCP_EXPIRE_CONNECTED 185 # define TCP_EXPIRE_CONNECTED 86400 186 #endif 187 188 189 /* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 190 These constants can be anything except zero, which indicates an 191 unknown port number. */ 192 193 #define NO_DEST_PORT 1 194 #define NO_SRC_PORT 1 195 196 197 198 /* Data Structures 199 200 The fundamental data structure used in this program is 201 "struct alias_link". Whenever a TCP connection is made, 202 a UDP datagram is sent out, or an ICMP echo request is made, 203 a link record is made (if it has not already been created). 204 The link record is identified by the source address/port 205 and the destination address/port. In the case of an ICMP 206 echo request, the source port is treated as being equivalent 207 with the 16-bit ID number of the ICMP packet. 208 209 The link record also can store some auxiliary data. For 210 TCP connections that have had sequence and acknowledgment 211 modifications, data space is available to track these changes. 212 A state field is used to keep track in changes to the TCP 213 connection state. ID numbers of fragments can also be 214 stored in the auxiliary space. Pointers to unresolved 215 fragments can also be stored. 216 217 The link records support two independent chainings. Lookup 218 tables for input and out tables hold the initial pointers 219 the link chains. On input, the lookup table indexes on alias 220 port and link type. On output, the lookup table indexes on 221 source address, destination address, source port, destination 222 port and link type. 223 */ 224 225 struct ack_data_record /* used to save changes to ACK/sequence numbers */ 226 { 227 u_long ack_old; 228 u_long ack_new; 229 int delta; 230 int active; 231 }; 232 233 struct tcp_state /* Information about TCP connection */ 234 { 235 int in; /* State for outside -> inside */ 236 int out; /* State for inside -> outside */ 237 int index; /* Index to ACK data array */ 238 int ack_modified; /* Indicates whether ACK and sequence numbers */ 239 /* been modified */ 240 }; 241 242 #define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes 243 saved for a modified TCP stream */ 244 struct tcp_dat 245 { 246 struct tcp_state state; 247 struct ack_data_record ack[N_LINK_TCP_DATA]; 248 int fwhole; /* Which firewall record is used for this hole? */ 249 }; 250 251 struct server /* LSNAT server pool (circular list) */ 252 { 253 struct in_addr addr; 254 u_short port; 255 struct server *next; 256 }; 257 258 struct alias_link /* Main data structure */ 259 { 260 struct in_addr src_addr; /* Address and port information */ 261 struct in_addr dst_addr; 262 struct in_addr alias_addr; 263 struct in_addr proxy_addr; 264 u_short src_port; 265 u_short dst_port; 266 u_short alias_port; 267 u_short proxy_port; 268 struct server *server; 269 270 int link_type; /* Type of link: TCP, UDP, ICMP, proto, frag */ 271 272 /* values for link_type */ 273 #define LINK_ICMP IPPROTO_ICMP 274 #define LINK_UDP IPPROTO_UDP 275 #define LINK_TCP IPPROTO_TCP 276 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 277 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 278 #define LINK_ADDR (IPPROTO_MAX + 3) 279 #define LINK_PPTP (IPPROTO_MAX + 4) 280 281 int flags; /* indicates special characteristics */ 282 int pflags; /* protocol-specific flags */ 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 291 int timestamp; /* Time link was last accessed */ 292 int expire_time; /* Expire time for link */ 293 294 int sockfd; /* socket descriptor */ 295 296 LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for */ 297 LIST_ENTRY(alias_link) list_in; /* input and output lookup tables */ 298 299 union /* Auxiliary data */ 300 { 301 char *frag_ptr; 302 struct in_addr frag_addr; 303 struct tcp_dat *tcp; 304 } data; 305 }; 306 307 308 309 310 311 /* Global Variables 312 313 The global variables listed here are only accessed from 314 within alias_db.c and so are prefixed with the static 315 designation. 316 */ 317 318 int packetAliasMode; /* Mode flags */ 319 /* - documented in alias.h */ 320 321 static struct in_addr aliasAddress; /* Address written onto source */ 322 /* field of IP packet. */ 323 324 static struct in_addr targetAddress; /* IP address incoming packets */ 325 /* are sent to if no aliasing */ 326 /* link already exists */ 327 328 static struct in_addr nullAddress; /* Used as a dummy parameter for */ 329 /* some function calls */ 330 static LIST_HEAD(, alias_link) 331 linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ 332 /* chains of link records. Each */ 333 static LIST_HEAD(, alias_link) /* link record is doubly indexed */ 334 linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ 335 /* tables. */ 336 337 static int icmpLinkCount; /* Link statistics */ 338 static int udpLinkCount; 339 static int tcpLinkCount; 340 static int pptpLinkCount; 341 static int protoLinkCount; 342 static int fragmentIdLinkCount; 343 static int fragmentPtrLinkCount; 344 static int sockCount; 345 346 static int cleanupIndex; /* Index to chain of link table */ 347 /* being inspected for old links */ 348 349 static int timeStamp; /* System time in seconds for */ 350 /* current packet */ 351 352 static int lastCleanupTime; /* Last time IncrementalCleanup() */ 353 /* was called */ 354 355 static int houseKeepingResidual; /* used by HouseKeeping() */ 356 357 static int deleteAllLinks; /* If equal to zero, DeleteLink() */ 358 /* will not remove permanent links */ 359 360 static FILE *monitorFile; /* File descriptor for link */ 361 /* statistics monitoring file */ 362 363 static int newDefaultLink; /* Indicates if a new aliasing */ 364 /* link has been created after a */ 365 /* call to PacketAliasIn/Out(). */ 366 367 #ifndef NO_FW_PUNCH 368 static int fireWallFD = -1; /* File descriptor to be able to */ 369 /* control firewall. Opened by */ 370 /* PacketAliasSetMode on first */ 371 /* setting the PKT_ALIAS_PUNCH_FW */ 372 /* flag. */ 373 #endif 374 375 376 377 378 379 380 381 /* Internal utility routines (used only in alias_db.c) 382 383 Lookup table starting points: 384 StartPointIn() -- link table initial search point for 385 incoming packets 386 StartPointOut() -- link table initial search point for 387 outgoing packets 388 389 Miscellaneous: 390 SeqDiff() -- difference between two TCP sequences 391 ShowAliasStats() -- send alias statistics to a monitor file 392 */ 393 394 395 /* Local prototypes */ 396 static u_int StartPointIn(struct in_addr, u_short, int); 397 398 static u_int StartPointOut(struct in_addr, struct in_addr, 399 u_short, u_short, int); 400 401 static int SeqDiff(u_long, u_long); 402 403 static void ShowAliasStats(void); 404 405 #ifndef NO_FW_PUNCH 406 /* Firewall control */ 407 static void InitPunchFW(void); 408 static void UninitPunchFW(void); 409 static void ClearFWHole(struct alias_link *link); 410 #endif 411 412 /* Log file control */ 413 static void InitPacketAliasLog(void); 414 static void UninitPacketAliasLog(void); 415 416 static u_int 417 StartPointIn(struct in_addr alias_addr, 418 u_short alias_port, 419 int link_type) 420 { 421 u_int n; 422 423 n = alias_addr.s_addr; 424 if (link_type != LINK_PPTP) 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 if (link_type != LINK_PPTP) { 440 n += src_port; 441 n += dst_port; 442 } 443 n += link_type; 444 445 return(n % LINK_TABLE_OUT_SIZE); 446 } 447 448 449 static int 450 SeqDiff(u_long x, u_long y) 451 { 452 /* Return the difference between two TCP sequence numbers */ 453 454 /* 455 This function is encapsulated in case there are any unusual 456 arithmetic conditions that need to be considered. 457 */ 458 459 return (ntohl(y) - ntohl(x)); 460 } 461 462 463 static void 464 ShowAliasStats(void) 465 { 466 /* Used for debugging */ 467 468 if (monitorFile) 469 { 470 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", 471 icmpLinkCount, 472 udpLinkCount, 473 tcpLinkCount, 474 pptpLinkCount, 475 protoLinkCount, 476 fragmentIdLinkCount, 477 fragmentPtrLinkCount); 478 479 fprintf(monitorFile, " / tot=%d (sock=%d)\n", 480 icmpLinkCount + udpLinkCount 481 + tcpLinkCount 482 + pptpLinkCount 483 + protoLinkCount 484 + fragmentIdLinkCount 485 + fragmentPtrLinkCount, 486 sockCount); 487 488 fflush(monitorFile); 489 } 490 } 491 492 493 494 495 496 /* Internal routines for finding, deleting and adding links 497 498 Port Allocation: 499 GetNewPort() -- find and reserve new alias port number 500 GetSocket() -- try to allocate a socket for a given port 501 502 Link creation and deletion: 503 CleanupAliasData() - remove all link chains from lookup table 504 IncrementalCleanup() - look for stale links in a single chain 505 DeleteLink() - remove link 506 AddLink() - add link 507 ReLink() - change link 508 509 Link search: 510 FindLinkOut() - find link for outgoing packets 511 FindLinkIn() - find link for incoming packets 512 513 Port search: 514 FindNewPortGroup() - find an available group of ports 515 */ 516 517 /* Local prototypes */ 518 static int GetNewPort(struct alias_link *, int); 519 520 static u_short GetSocket(u_short, int *, int); 521 522 static void CleanupAliasData(void); 523 524 static void IncrementalCleanup(void); 525 526 static void DeleteLink(struct alias_link *); 527 528 static struct alias_link * 529 AddLink(struct in_addr, struct in_addr, struct in_addr, 530 u_short, u_short, int, int); 531 532 static struct alias_link * 533 ReLink(struct alias_link *, 534 struct in_addr, struct in_addr, struct in_addr, 535 u_short, u_short, int, int); 536 537 static struct alias_link * 538 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int); 539 540 static struct alias_link * 541 FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); 542 543 544 #define ALIAS_PORT_BASE 0x08000 545 #define ALIAS_PORT_MASK 0x07fff 546 #define ALIAS_PORT_MASK_EVEN 0x07ffe 547 #define GET_NEW_PORT_MAX_ATTEMPTS 20 548 549 #define GET_ALIAS_PORT -1 550 #define GET_ALIAS_ID GET_ALIAS_PORT 551 552 #define FIND_EVEN_ALIAS_BASE 1 553 554 /* GetNewPort() allocates port numbers. Note that if a port number 555 is already in use, that does not mean that it cannot be used by 556 another link concurrently. This is because GetNewPort() looks for 557 unused triplets: (dest addr, dest port, alias port). */ 558 559 static int 560 GetNewPort(struct alias_link *link, int alias_port_param) 561 { 562 int i; 563 int max_trials; 564 u_short port_sys; 565 u_short port_net; 566 567 /* 568 Description of alias_port_param for GetNewPort(). When 569 this parameter is zero or positive, it precisely specifies 570 the port number. GetNewPort() will return this number 571 without check that it is in use. 572 573 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly 574 selected port number. 575 */ 576 577 if (alias_port_param == GET_ALIAS_PORT) 578 { 579 /* 580 * The aliasing port is automatically selected 581 * by one of two methods below: 582 */ 583 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 584 585 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) 586 { 587 /* 588 * When the PKT_ALIAS_SAME_PORTS option is 589 * chosen, the first try will be the 590 * actual source port. If this is already 591 * in use, the remainder of the trials 592 * will be random. 593 */ 594 port_net = link->src_port; 595 port_sys = ntohs(port_net); 596 } 597 else 598 { 599 /* First trial and all subsequent are random. */ 600 port_sys = random() & ALIAS_PORT_MASK; 601 port_sys += ALIAS_PORT_BASE; 602 port_net = htons(port_sys); 603 } 604 } 605 else if (alias_port_param >= 0 && alias_port_param < 0x10000) 606 { 607 link->alias_port = (u_short) alias_port_param; 608 return(0); 609 } 610 else 611 { 612 #ifdef DEBUG 613 fprintf(stderr, "PacketAlias/GetNewPort(): "); 614 fprintf(stderr, "input parameter error\n"); 615 #endif 616 return(-1); 617 } 618 619 620 /* Port number search */ 621 for (i=0; i<max_trials; i++) 622 { 623 int go_ahead; 624 struct alias_link *search_result; 625 626 search_result = FindLinkIn(link->dst_addr, link->alias_addr, 627 link->dst_port, port_net, 628 link->link_type, 0); 629 630 if (search_result == NULL) 631 go_ahead = 1; 632 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) 633 && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 634 go_ahead = 1; 635 else 636 go_ahead = 0; 637 638 if (go_ahead) 639 { 640 if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS) 641 && (link->flags & LINK_PARTIALLY_SPECIFIED) 642 && ((link->link_type == LINK_TCP) || 643 (link->link_type == LINK_UDP))) 644 { 645 if (GetSocket(port_net, &link->sockfd, link->link_type)) 646 { 647 link->alias_port = port_net; 648 return(0); 649 } 650 } 651 else 652 { 653 link->alias_port = port_net; 654 return(0); 655 } 656 } 657 658 port_sys = random() & ALIAS_PORT_MASK; 659 port_sys += ALIAS_PORT_BASE; 660 port_net = htons(port_sys); 661 } 662 663 #ifdef DEBUG 664 fprintf(stderr, "PacketAlias/GetnewPort(): "); 665 fprintf(stderr, "could not find free port\n"); 666 #endif 667 668 return(-1); 669 } 670 671 672 static u_short 673 GetSocket(u_short port_net, int *sockfd, int link_type) 674 { 675 int err; 676 int sock; 677 struct sockaddr_in sock_addr; 678 679 if (link_type == LINK_TCP) 680 sock = socket(AF_INET, SOCK_STREAM, 0); 681 else if (link_type == LINK_UDP) 682 sock = socket(AF_INET, SOCK_DGRAM, 0); 683 else 684 { 685 #ifdef DEBUG 686 fprintf(stderr, "PacketAlias/GetSocket(): "); 687 fprintf(stderr, "incorrect link type\n"); 688 #endif 689 return(0); 690 } 691 692 if (sock < 0) 693 { 694 #ifdef DEBUG 695 fprintf(stderr, "PacketAlias/GetSocket(): "); 696 fprintf(stderr, "socket() error %d\n", *sockfd); 697 #endif 698 return(0); 699 } 700 701 sock_addr.sin_family = AF_INET; 702 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 703 sock_addr.sin_port = port_net; 704 705 err = bind(sock, 706 (struct sockaddr *) &sock_addr, 707 sizeof(sock_addr)); 708 if (err == 0) 709 { 710 sockCount++; 711 *sockfd = sock; 712 return(1); 713 } 714 else 715 { 716 close(sock); 717 return(0); 718 } 719 } 720 721 722 /* FindNewPortGroup() returns a base port number for an available 723 range of contiguous port numbers. Note that if a port number 724 is already in use, that does not mean that it cannot be used by 725 another link concurrently. This is because FindNewPortGroup() 726 looks for unused triplets: (dest addr, dest port, alias port). */ 727 728 int 729 FindNewPortGroup(struct in_addr dst_addr, 730 struct in_addr alias_addr, 731 u_short src_port, 732 u_short dst_port, 733 u_short port_count, 734 u_char proto, 735 u_char align) 736 { 737 int i, j; 738 int max_trials; 739 u_short port_sys; 740 int link_type; 741 742 /* 743 * Get link_type from protocol 744 */ 745 746 switch (proto) 747 { 748 case IPPROTO_UDP: 749 link_type = LINK_UDP; 750 break; 751 case IPPROTO_TCP: 752 link_type = LINK_TCP; 753 break; 754 default: 755 return (0); 756 break; 757 } 758 759 /* 760 * The aliasing port is automatically selected 761 * by one of two methods below: 762 */ 763 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 764 765 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) { 766 /* 767 * When the ALIAS_SAME_PORTS option is 768 * chosen, the first try will be the 769 * actual source port. If this is already 770 * in use, the remainder of the trials 771 * will be random. 772 */ 773 port_sys = ntohs(src_port); 774 775 } else { 776 777 /* First trial and all subsequent are random. */ 778 if (align == FIND_EVEN_ALIAS_BASE) 779 port_sys = random() & ALIAS_PORT_MASK_EVEN; 780 else 781 port_sys = random() & ALIAS_PORT_MASK; 782 783 port_sys += ALIAS_PORT_BASE; 784 } 785 786 /* Port number search */ 787 for (i = 0; i < max_trials; i++) { 788 789 struct alias_link *search_result; 790 791 for (j = 0; j < port_count; j++) 792 if (0 != (search_result = FindLinkIn(dst_addr, alias_addr, 793 dst_port, htons(port_sys + j), 794 link_type, 0))) 795 break; 796 797 /* Found a good range, return base */ 798 if (j == port_count) 799 return (htons(port_sys)); 800 801 /* Find a new base to try */ 802 if (align == FIND_EVEN_ALIAS_BASE) 803 port_sys = random() & ALIAS_PORT_MASK_EVEN; 804 else 805 port_sys = random() & ALIAS_PORT_MASK; 806 807 port_sys += ALIAS_PORT_BASE; 808 } 809 810 #ifdef DEBUG 811 fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 812 fprintf(stderr, "could not find free port(s)\n"); 813 #endif 814 815 return(0); 816 } 817 818 static void 819 CleanupAliasData(void) 820 { 821 struct alias_link *link; 822 int i, icount; 823 824 icount = 0; 825 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 826 { 827 link = LIST_FIRST(&linkTableOut[i]); 828 while (link != NULL) 829 { 830 struct alias_link *link_next; 831 link_next = LIST_NEXT(link, list_out); 832 icount++; 833 DeleteLink(link); 834 link = link_next; 835 } 836 } 837 838 cleanupIndex =0; 839 } 840 841 842 static void 843 IncrementalCleanup(void) 844 { 845 int icount; 846 struct alias_link *link; 847 848 icount = 0; 849 link = LIST_FIRST(&linkTableOut[cleanupIndex++]); 850 while (link != NULL) 851 { 852 int idelta; 853 struct alias_link *link_next; 854 855 link_next = LIST_NEXT(link, list_out); 856 idelta = timeStamp - link->timestamp; 857 switch (link->link_type) 858 { 859 case LINK_TCP: 860 if (idelta > link->expire_time) 861 { 862 struct tcp_dat *tcp_aux; 863 864 tcp_aux = link->data.tcp; 865 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 866 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) 867 { 868 DeleteLink(link); 869 icount++; 870 } 871 } 872 break; 873 default: 874 if (idelta > link->expire_time) 875 { 876 DeleteLink(link); 877 icount++; 878 } 879 break; 880 } 881 link = link_next; 882 } 883 884 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 885 cleanupIndex = 0; 886 } 887 888 static void 889 DeleteLink(struct alias_link *link) 890 { 891 892 /* Don't do anything if the link is marked permanent */ 893 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 894 return; 895 896 #ifndef NO_FW_PUNCH 897 /* Delete associated firewall hole, if any */ 898 ClearFWHole(link); 899 #endif 900 901 /* Free memory allocated for LSNAT server pool */ 902 if (link->server != NULL) { 903 struct server *head, *curr, *next; 904 905 head = curr = link->server; 906 do { 907 next = curr->next; 908 free(curr); 909 } while ((curr = next) != head); 910 } 911 912 /* Adjust output table pointers */ 913 LIST_REMOVE(link, list_out); 914 915 /* Adjust input table pointers */ 916 LIST_REMOVE(link, list_in); 917 918 /* Close socket, if one has been allocated */ 919 if (link->sockfd != -1) 920 { 921 sockCount--; 922 close(link->sockfd); 923 } 924 925 /* Link-type dependent cleanup */ 926 switch(link->link_type) 927 { 928 case LINK_ICMP: 929 icmpLinkCount--; 930 break; 931 case LINK_UDP: 932 udpLinkCount--; 933 break; 934 case LINK_TCP: 935 tcpLinkCount--; 936 free(link->data.tcp); 937 break; 938 case LINK_PPTP: 939 pptpLinkCount--; 940 break; 941 case LINK_FRAGMENT_ID: 942 fragmentIdLinkCount--; 943 break; 944 case LINK_FRAGMENT_PTR: 945 fragmentPtrLinkCount--; 946 if (link->data.frag_ptr != NULL) 947 free(link->data.frag_ptr); 948 break; 949 case LINK_ADDR: 950 break; 951 default: 952 protoLinkCount--; 953 break; 954 } 955 956 /* Free memory */ 957 free(link); 958 959 /* Write statistics, if logging enabled */ 960 if (packetAliasMode & PKT_ALIAS_LOG) 961 { 962 ShowAliasStats(); 963 } 964 } 965 966 967 static struct alias_link * 968 AddLink(struct in_addr src_addr, 969 struct in_addr dst_addr, 970 struct in_addr alias_addr, 971 u_short src_port, 972 u_short dst_port, 973 int alias_port_param, /* if less than zero, alias */ 974 int link_type) /* port will be automatically */ 975 { /* chosen. If greater than */ 976 u_int start_point; /* zero, equal to alias port */ 977 struct alias_link *link; 978 979 link = malloc(sizeof(struct alias_link)); 980 if (link != NULL) 981 { 982 /* Basic initialization */ 983 link->src_addr = src_addr; 984 link->dst_addr = dst_addr; 985 link->alias_addr = alias_addr; 986 link->proxy_addr.s_addr = INADDR_ANY; 987 link->src_port = src_port; 988 link->dst_port = dst_port; 989 link->proxy_port = 0; 990 link->server = NULL; 991 link->link_type = link_type; 992 link->sockfd = -1; 993 link->flags = 0; 994 link->pflags = 0; 995 link->timestamp = timeStamp; 996 997 /* Expiration time */ 998 switch (link_type) 999 { 1000 case LINK_ICMP: 1001 link->expire_time = ICMP_EXPIRE_TIME; 1002 break; 1003 case LINK_UDP: 1004 link->expire_time = UDP_EXPIRE_TIME; 1005 break; 1006 case LINK_TCP: 1007 link->expire_time = TCP_EXPIRE_INITIAL; 1008 break; 1009 case LINK_PPTP: 1010 link->flags |= LINK_PERMANENT; /* no timeout. */ 1011 break; 1012 case LINK_FRAGMENT_ID: 1013 link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 1014 break; 1015 case LINK_FRAGMENT_PTR: 1016 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 1017 break; 1018 case LINK_ADDR: 1019 break; 1020 default: 1021 link->expire_time = PROTO_EXPIRE_TIME; 1022 break; 1023 } 1024 1025 /* Determine alias flags */ 1026 if (dst_addr.s_addr == INADDR_ANY) 1027 link->flags |= LINK_UNKNOWN_DEST_ADDR; 1028 if (dst_port == 0) 1029 link->flags |= LINK_UNKNOWN_DEST_PORT; 1030 1031 /* Determine alias port */ 1032 if (GetNewPort(link, alias_port_param) != 0) 1033 { 1034 free(link); 1035 return(NULL); 1036 } 1037 1038 /* Link-type dependent initialization */ 1039 switch(link_type) 1040 { 1041 struct tcp_dat *aux_tcp; 1042 1043 case LINK_ICMP: 1044 icmpLinkCount++; 1045 break; 1046 case LINK_UDP: 1047 udpLinkCount++; 1048 break; 1049 case LINK_TCP: 1050 aux_tcp = malloc(sizeof(struct tcp_dat)); 1051 if (aux_tcp != NULL) 1052 { 1053 int i; 1054 1055 tcpLinkCount++; 1056 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 1057 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 1058 aux_tcp->state.index = 0; 1059 aux_tcp->state.ack_modified = 0; 1060 for (i=0; i<N_LINK_TCP_DATA; i++) 1061 aux_tcp->ack[i].active = 0; 1062 aux_tcp->fwhole = -1; 1063 link->data.tcp = aux_tcp; 1064 } 1065 else 1066 { 1067 #ifdef DEBUG 1068 fprintf(stderr, "PacketAlias/AddLink: "); 1069 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 1070 #endif 1071 free(link); 1072 return (NULL); 1073 } 1074 break; 1075 case LINK_PPTP: 1076 pptpLinkCount++; 1077 break; 1078 case LINK_FRAGMENT_ID: 1079 fragmentIdLinkCount++; 1080 break; 1081 case LINK_FRAGMENT_PTR: 1082 fragmentPtrLinkCount++; 1083 break; 1084 case LINK_ADDR: 1085 break; 1086 default: 1087 protoLinkCount++; 1088 break; 1089 } 1090 1091 /* Set up pointers for output lookup table */ 1092 start_point = StartPointOut(src_addr, dst_addr, 1093 src_port, dst_port, link_type); 1094 LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out); 1095 1096 /* Set up pointers for input lookup table */ 1097 start_point = StartPointIn(alias_addr, link->alias_port, link_type); 1098 LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in); 1099 } 1100 else 1101 { 1102 #ifdef DEBUG 1103 fprintf(stderr, "PacketAlias/AddLink(): "); 1104 fprintf(stderr, "malloc() call failed.\n"); 1105 #endif 1106 } 1107 1108 if (packetAliasMode & PKT_ALIAS_LOG) 1109 { 1110 ShowAliasStats(); 1111 } 1112 1113 return(link); 1114 } 1115 1116 static struct alias_link * 1117 ReLink(struct alias_link *old_link, 1118 struct in_addr src_addr, 1119 struct in_addr dst_addr, 1120 struct in_addr alias_addr, 1121 u_short src_port, 1122 u_short dst_port, 1123 int alias_port_param, /* if less than zero, alias */ 1124 int link_type) /* port will be automatically */ 1125 { /* chosen. If greater than */ 1126 struct alias_link *new_link; /* zero, equal to alias port */ 1127 1128 new_link = AddLink(src_addr, dst_addr, alias_addr, 1129 src_port, dst_port, alias_port_param, 1130 link_type); 1131 #ifndef NO_FW_PUNCH 1132 if (new_link != NULL && 1133 old_link->link_type == LINK_TCP && 1134 old_link->data.tcp->fwhole > 0) { 1135 PunchFWHole(new_link); 1136 } 1137 #endif 1138 DeleteLink(old_link); 1139 return new_link; 1140 } 1141 1142 static struct alias_link * 1143 _FindLinkOut(struct in_addr src_addr, 1144 struct in_addr dst_addr, 1145 u_short src_port, 1146 u_short dst_port, 1147 int link_type, 1148 int replace_partial_links) 1149 { 1150 u_int i; 1151 struct alias_link *link; 1152 1153 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1154 LIST_FOREACH(link, &linkTableOut[i], list_out) 1155 { 1156 if (link->src_addr.s_addr == src_addr.s_addr 1157 && link->server == NULL 1158 && link->dst_addr.s_addr == dst_addr.s_addr 1159 && link->dst_port == dst_port 1160 && link->src_port == src_port 1161 && link->link_type == link_type) 1162 { 1163 link->timestamp = timeStamp; 1164 break; 1165 } 1166 } 1167 1168 /* Search for partially specified links. */ 1169 if (link == NULL && replace_partial_links) 1170 { 1171 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) 1172 { 1173 link = _FindLinkOut(src_addr, dst_addr, src_port, 0, 1174 link_type, 0); 1175 if (link == NULL) 1176 link = _FindLinkOut(src_addr, nullAddress, src_port, 1177 dst_port, link_type, 0); 1178 } 1179 if (link == NULL && 1180 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) 1181 { 1182 link = _FindLinkOut(src_addr, nullAddress, src_port, 0, 1183 link_type, 0); 1184 } 1185 if (link != NULL) 1186 { 1187 link = ReLink(link, 1188 src_addr, dst_addr, link->alias_addr, 1189 src_port, dst_port, link->alias_port, 1190 link_type); 1191 } 1192 } 1193 1194 return(link); 1195 } 1196 1197 static struct alias_link * 1198 FindLinkOut(struct in_addr src_addr, 1199 struct in_addr dst_addr, 1200 u_short src_port, 1201 u_short dst_port, 1202 int link_type, 1203 int replace_partial_links) 1204 { 1205 struct alias_link *link; 1206 1207 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port, 1208 link_type, replace_partial_links); 1209 1210 if (link == NULL) 1211 { 1212 /* The following allows permanent links to be 1213 specified as using the default source address 1214 (i.e. device interface address) without knowing 1215 in advance what that address is. */ 1216 if (aliasAddress.s_addr != 0 && 1217 src_addr.s_addr == aliasAddress.s_addr) 1218 { 1219 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port, 1220 link_type, replace_partial_links); 1221 } 1222 } 1223 1224 return(link); 1225 } 1226 1227 1228 static struct alias_link * 1229 _FindLinkIn(struct in_addr dst_addr, 1230 struct in_addr alias_addr, 1231 u_short dst_port, 1232 u_short alias_port, 1233 int link_type, 1234 int replace_partial_links) 1235 { 1236 int flags_in; 1237 u_int start_point; 1238 struct alias_link *link; 1239 struct alias_link *link_fully_specified; 1240 struct alias_link *link_unknown_all; 1241 struct alias_link *link_unknown_dst_addr; 1242 struct alias_link *link_unknown_dst_port; 1243 1244 /* Initialize pointers */ 1245 link_fully_specified = NULL; 1246 link_unknown_all = NULL; 1247 link_unknown_dst_addr = NULL; 1248 link_unknown_dst_port = NULL; 1249 1250 /* If either the dest addr or port is unknown, the search 1251 loop will have to know about this. */ 1252 1253 flags_in = 0; 1254 if (dst_addr.s_addr == INADDR_ANY) 1255 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1256 if (dst_port == 0) 1257 flags_in |= LINK_UNKNOWN_DEST_PORT; 1258 1259 /* Search loop */ 1260 start_point = StartPointIn(alias_addr, alias_port, link_type); 1261 LIST_FOREACH(link, &linkTableIn[start_point], list_in) 1262 { 1263 int flags; 1264 1265 flags = flags_in | link->flags; 1266 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1267 { 1268 if (link->alias_addr.s_addr == alias_addr.s_addr 1269 && link->alias_port == alias_port 1270 && link->dst_addr.s_addr == dst_addr.s_addr 1271 && link->dst_port == dst_port 1272 && link->link_type == link_type) 1273 { 1274 link_fully_specified = link; 1275 break; 1276 } 1277 } 1278 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1279 && (flags & LINK_UNKNOWN_DEST_PORT)) 1280 { 1281 if (link->alias_addr.s_addr == alias_addr.s_addr 1282 && link->alias_port == alias_port 1283 && link->link_type == link_type) 1284 { 1285 if (link_unknown_all == NULL) 1286 link_unknown_all = link; 1287 } 1288 } 1289 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1290 { 1291 if (link->alias_addr.s_addr == alias_addr.s_addr 1292 && link->alias_port == alias_port 1293 && link->link_type == link_type 1294 && link->dst_port == dst_port) 1295 { 1296 if (link_unknown_dst_addr == NULL) 1297 link_unknown_dst_addr = link; 1298 } 1299 } 1300 else if (flags & LINK_UNKNOWN_DEST_PORT) 1301 { 1302 if (link->alias_addr.s_addr == alias_addr.s_addr 1303 && link->alias_port == alias_port 1304 && link->link_type == link_type 1305 && link->dst_addr.s_addr == dst_addr.s_addr) 1306 { 1307 if (link_unknown_dst_port == NULL) 1308 link_unknown_dst_port = link; 1309 } 1310 } 1311 } 1312 1313 1314 1315 if (link_fully_specified != NULL) 1316 { 1317 link_fully_specified->timestamp = timeStamp; 1318 link = link_fully_specified; 1319 } 1320 else if (link_unknown_dst_port != NULL) 1321 link = link_unknown_dst_port; 1322 else if (link_unknown_dst_addr != NULL) 1323 link = link_unknown_dst_addr; 1324 else if (link_unknown_all != NULL) 1325 link = link_unknown_all; 1326 else 1327 return (NULL); 1328 1329 if (replace_partial_links && 1330 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) 1331 { 1332 struct in_addr src_addr; 1333 u_short src_port; 1334 1335 if (link->server != NULL) { /* LSNAT link */ 1336 src_addr = link->server->addr; 1337 src_port = link->server->port; 1338 link->server = link->server->next; 1339 } else { 1340 src_addr = link->src_addr; 1341 src_port = link->src_port; 1342 } 1343 1344 link = ReLink(link, 1345 src_addr, dst_addr, alias_addr, 1346 src_port, dst_port, alias_port, 1347 link_type); 1348 } 1349 1350 return (link); 1351 } 1352 1353 static struct alias_link * 1354 FindLinkIn(struct in_addr dst_addr, 1355 struct in_addr alias_addr, 1356 u_short dst_port, 1357 u_short alias_port, 1358 int link_type, 1359 int replace_partial_links) 1360 { 1361 struct alias_link *link; 1362 1363 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, 1364 link_type, replace_partial_links); 1365 1366 if (link == NULL) 1367 { 1368 /* The following allows permanent links to be 1369 specified as using the default aliasing address 1370 (i.e. device interface address) without knowing 1371 in advance what that address is. */ 1372 if (aliasAddress.s_addr != 0 && 1373 alias_addr.s_addr == aliasAddress.s_addr) 1374 { 1375 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port, 1376 link_type, replace_partial_links); 1377 } 1378 } 1379 1380 return(link); 1381 } 1382 1383 1384 1385 1386 /* External routines for finding/adding links 1387 1388 -- "external" means outside alias_db.c, but within alias*.c -- 1389 1390 FindIcmpIn(), FindIcmpOut() 1391 FindFragmentIn1(), FindFragmentIn2() 1392 AddFragmentPtrLink(), FindFragmentPtr() 1393 FindProtoIn(), FindProtoOut() 1394 FindUdpTcpIn(), FindUdpTcpOut() 1395 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 1396 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 1397 FindOriginalAddress(), FindAliasAddress() 1398 1399 (prototypes in alias_local.h) 1400 */ 1401 1402 1403 struct alias_link * 1404 FindIcmpIn(struct in_addr dst_addr, 1405 struct in_addr alias_addr, 1406 u_short id_alias, 1407 int create) 1408 { 1409 struct alias_link *link; 1410 1411 link = FindLinkIn(dst_addr, alias_addr, 1412 NO_DEST_PORT, id_alias, 1413 LINK_ICMP, 0); 1414 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1415 { 1416 struct in_addr target_addr; 1417 1418 target_addr = FindOriginalAddress(alias_addr); 1419 link = AddLink(target_addr, dst_addr, alias_addr, 1420 id_alias, NO_DEST_PORT, id_alias, 1421 LINK_ICMP); 1422 } 1423 1424 return (link); 1425 } 1426 1427 1428 struct alias_link * 1429 FindIcmpOut(struct in_addr src_addr, 1430 struct in_addr dst_addr, 1431 u_short id, 1432 int create) 1433 { 1434 struct alias_link * link; 1435 1436 link = FindLinkOut(src_addr, dst_addr, 1437 id, NO_DEST_PORT, 1438 LINK_ICMP, 0); 1439 if (link == NULL && create) 1440 { 1441 struct in_addr alias_addr; 1442 1443 alias_addr = FindAliasAddress(src_addr); 1444 link = AddLink(src_addr, dst_addr, alias_addr, 1445 id, NO_DEST_PORT, GET_ALIAS_ID, 1446 LINK_ICMP); 1447 } 1448 1449 return(link); 1450 } 1451 1452 1453 struct alias_link * 1454 FindFragmentIn1(struct in_addr dst_addr, 1455 struct in_addr alias_addr, 1456 u_short ip_id) 1457 { 1458 struct alias_link *link; 1459 1460 link = FindLinkIn(dst_addr, alias_addr, 1461 NO_DEST_PORT, ip_id, 1462 LINK_FRAGMENT_ID, 0); 1463 1464 if (link == NULL) 1465 { 1466 link = AddLink(nullAddress, dst_addr, alias_addr, 1467 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1468 LINK_FRAGMENT_ID); 1469 } 1470 1471 return(link); 1472 } 1473 1474 1475 struct alias_link * 1476 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1477 struct in_addr alias_addr, /* is not found. */ 1478 u_short ip_id) 1479 { 1480 return FindLinkIn(dst_addr, alias_addr, 1481 NO_DEST_PORT, ip_id, 1482 LINK_FRAGMENT_ID, 0); 1483 } 1484 1485 1486 struct alias_link * 1487 AddFragmentPtrLink(struct in_addr dst_addr, 1488 u_short ip_id) 1489 { 1490 return AddLink(nullAddress, dst_addr, nullAddress, 1491 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1492 LINK_FRAGMENT_PTR); 1493 } 1494 1495 1496 struct alias_link * 1497 FindFragmentPtr(struct in_addr dst_addr, 1498 u_short ip_id) 1499 { 1500 return FindLinkIn(dst_addr, nullAddress, 1501 NO_DEST_PORT, ip_id, 1502 LINK_FRAGMENT_PTR, 0); 1503 } 1504 1505 1506 struct alias_link * 1507 FindProtoIn(struct in_addr dst_addr, 1508 struct in_addr alias_addr, 1509 u_char proto) 1510 { 1511 struct alias_link *link; 1512 1513 link = FindLinkIn(dst_addr, alias_addr, 1514 NO_DEST_PORT, 0, 1515 proto, 1); 1516 1517 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1518 { 1519 struct in_addr target_addr; 1520 1521 target_addr = FindOriginalAddress(alias_addr); 1522 link = AddLink(target_addr, dst_addr, alias_addr, 1523 NO_SRC_PORT, NO_DEST_PORT, 0, 1524 proto); 1525 } 1526 1527 return (link); 1528 } 1529 1530 1531 struct alias_link * 1532 FindProtoOut(struct in_addr src_addr, 1533 struct in_addr dst_addr, 1534 u_char proto) 1535 { 1536 struct alias_link *link; 1537 1538 link = FindLinkOut(src_addr, dst_addr, 1539 NO_SRC_PORT, NO_DEST_PORT, 1540 proto, 1); 1541 1542 if (link == NULL) 1543 { 1544 struct in_addr alias_addr; 1545 1546 alias_addr = FindAliasAddress(src_addr); 1547 link = AddLink(src_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 FindUdpTcpIn(struct in_addr dst_addr, 1558 struct in_addr alias_addr, 1559 u_short dst_port, 1560 u_short alias_port, 1561 u_char proto, 1562 int create) 1563 { 1564 int link_type; 1565 struct alias_link *link; 1566 1567 switch (proto) 1568 { 1569 case IPPROTO_UDP: 1570 link_type = LINK_UDP; 1571 break; 1572 case IPPROTO_TCP: 1573 link_type = LINK_TCP; 1574 break; 1575 default: 1576 return NULL; 1577 break; 1578 } 1579 1580 link = FindLinkIn(dst_addr, alias_addr, 1581 dst_port, alias_port, 1582 link_type, create); 1583 1584 if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1585 { 1586 struct in_addr target_addr; 1587 1588 target_addr = FindOriginalAddress(alias_addr); 1589 link = AddLink(target_addr, dst_addr, alias_addr, 1590 alias_port, dst_port, alias_port, 1591 link_type); 1592 } 1593 1594 return(link); 1595 } 1596 1597 1598 struct alias_link * 1599 FindUdpTcpOut(struct in_addr src_addr, 1600 struct in_addr dst_addr, 1601 u_short src_port, 1602 u_short dst_port, 1603 u_char proto, 1604 int create) 1605 { 1606 int link_type; 1607 struct alias_link *link; 1608 1609 switch (proto) 1610 { 1611 case IPPROTO_UDP: 1612 link_type = LINK_UDP; 1613 break; 1614 case IPPROTO_TCP: 1615 link_type = LINK_TCP; 1616 break; 1617 default: 1618 return NULL; 1619 break; 1620 } 1621 1622 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create); 1623 1624 if (link == NULL && create) 1625 { 1626 struct in_addr alias_addr; 1627 1628 alias_addr = FindAliasAddress(src_addr); 1629 link = AddLink(src_addr, dst_addr, alias_addr, 1630 src_port, dst_port, GET_ALIAS_PORT, 1631 link_type); 1632 } 1633 1634 return(link); 1635 } 1636 1637 1638 struct alias_link * 1639 AddPptp(struct in_addr src_addr, 1640 struct in_addr dst_addr, 1641 struct in_addr alias_addr, 1642 u_int16_t src_call_id) 1643 { 1644 struct alias_link *link; 1645 1646 link = AddLink(src_addr, dst_addr, alias_addr, 1647 src_call_id, 0, GET_ALIAS_PORT, 1648 LINK_PPTP); 1649 1650 return (link); 1651 } 1652 1653 1654 struct alias_link * 1655 FindPptpOutByCallId(struct in_addr src_addr, 1656 struct in_addr dst_addr, 1657 u_int16_t src_call_id) 1658 { 1659 u_int i; 1660 struct alias_link *link; 1661 1662 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1663 LIST_FOREACH(link, &linkTableOut[i], list_out) 1664 if (link->link_type == LINK_PPTP && 1665 link->src_addr.s_addr == src_addr.s_addr && 1666 link->dst_addr.s_addr == dst_addr.s_addr && 1667 link->src_port == src_call_id) 1668 break; 1669 1670 return (link); 1671 } 1672 1673 1674 struct alias_link * 1675 FindPptpOutByPeerCallId(struct in_addr src_addr, 1676 struct in_addr dst_addr, 1677 u_int16_t dst_call_id) 1678 { 1679 u_int i; 1680 struct alias_link *link; 1681 1682 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1683 LIST_FOREACH(link, &linkTableOut[i], list_out) 1684 if (link->link_type == LINK_PPTP && 1685 link->src_addr.s_addr == src_addr.s_addr && 1686 link->dst_addr.s_addr == dst_addr.s_addr && 1687 link->dst_port == dst_call_id) 1688 break; 1689 1690 return (link); 1691 } 1692 1693 1694 struct alias_link * 1695 FindPptpInByCallId(struct in_addr dst_addr, 1696 struct in_addr alias_addr, 1697 u_int16_t dst_call_id) 1698 { 1699 u_int i; 1700 struct alias_link *link; 1701 1702 i = StartPointIn(alias_addr, 0, LINK_PPTP); 1703 LIST_FOREACH(link, &linkTableIn[i], list_in) 1704 if (link->link_type == LINK_PPTP && 1705 link->dst_addr.s_addr == dst_addr.s_addr && 1706 link->alias_addr.s_addr == alias_addr.s_addr && 1707 link->dst_port == dst_call_id) 1708 break; 1709 1710 return (link); 1711 } 1712 1713 1714 struct alias_link * 1715 FindPptpInByPeerCallId(struct in_addr dst_addr, 1716 struct in_addr alias_addr, 1717 u_int16_t alias_call_id) 1718 { 1719 struct alias_link *link; 1720 1721 link = FindLinkIn(dst_addr, alias_addr, 1722 0/* any */, alias_call_id, 1723 LINK_PPTP, 0); 1724 1725 1726 return (link); 1727 } 1728 1729 1730 struct alias_link * 1731 FindRtspOut(struct in_addr src_addr, 1732 struct in_addr dst_addr, 1733 u_short src_port, 1734 u_short alias_port, 1735 u_char proto) 1736 { 1737 int link_type; 1738 struct alias_link *link; 1739 1740 switch (proto) 1741 { 1742 case IPPROTO_UDP: 1743 link_type = LINK_UDP; 1744 break; 1745 case IPPROTO_TCP: 1746 link_type = LINK_TCP; 1747 break; 1748 default: 1749 return NULL; 1750 break; 1751 } 1752 1753 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1); 1754 1755 if (link == NULL) 1756 { 1757 struct in_addr alias_addr; 1758 1759 alias_addr = FindAliasAddress(src_addr); 1760 link = AddLink(src_addr, dst_addr, alias_addr, 1761 src_port, 0, alias_port, 1762 link_type); 1763 } 1764 1765 return(link); 1766 } 1767 1768 1769 struct in_addr 1770 FindOriginalAddress(struct in_addr alias_addr) 1771 { 1772 struct alias_link *link; 1773 1774 link = FindLinkIn(nullAddress, alias_addr, 1775 0, 0, LINK_ADDR, 0); 1776 if (link == NULL) 1777 { 1778 newDefaultLink = 1; 1779 if (targetAddress.s_addr == INADDR_ANY) 1780 return alias_addr; 1781 else if (targetAddress.s_addr == INADDR_NONE) 1782 return aliasAddress; 1783 else 1784 return targetAddress; 1785 } 1786 else 1787 { 1788 if (link->server != NULL) { /* LSNAT link */ 1789 struct in_addr src_addr; 1790 1791 src_addr = link->server->addr; 1792 link->server = link->server->next; 1793 return (src_addr); 1794 } else if (link->src_addr.s_addr == INADDR_ANY) 1795 return aliasAddress; 1796 else 1797 return link->src_addr; 1798 } 1799 } 1800 1801 1802 struct in_addr 1803 FindAliasAddress(struct in_addr original_addr) 1804 { 1805 struct alias_link *link; 1806 1807 link = FindLinkOut(original_addr, nullAddress, 1808 0, 0, LINK_ADDR, 0); 1809 if (link == NULL) 1810 { 1811 return aliasAddress; 1812 } 1813 else 1814 { 1815 if (link->alias_addr.s_addr == INADDR_ANY) 1816 return aliasAddress; 1817 else 1818 return link->alias_addr; 1819 } 1820 } 1821 1822 1823 /* External routines for getting or changing link data 1824 (external to alias_db.c, but internal to alias*.c) 1825 1826 SetFragmentData(), GetFragmentData() 1827 SetFragmentPtr(), GetFragmentPtr() 1828 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1829 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1830 GetOriginalPort(), GetAliasPort() 1831 SetAckModified(), GetAckModified() 1832 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1833 SetProtocolFlags(), GetProtocolFlags() 1834 SetDestCallId() 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 SetProtocolFlags(struct alias_link *link, int pflags) 2202 { 2203 2204 link->pflags = pflags;; 2205 } 2206 2207 int 2208 GetProtocolFlags(struct alias_link *link) 2209 { 2210 2211 return (link->pflags); 2212 } 2213 2214 void 2215 SetDestCallId(struct alias_link *link, u_int16_t cid) 2216 { 2217 2218 deleteAllLinks = 1; 2219 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr, 2220 link->src_port, cid, link->alias_port, link->link_type); 2221 deleteAllLinks = 0; 2222 } 2223 2224 2225 /* Miscellaneous Functions 2226 2227 HouseKeeping() 2228 InitPacketAliasLog() 2229 UninitPacketAliasLog() 2230 */ 2231 2232 /* 2233 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2234 is called to find and remove timed-out aliasing links. Logic exists 2235 to sweep through the entire table and linked list structure 2236 every 60 seconds. 2237 2238 (prototype in alias_local.h) 2239 */ 2240 2241 void 2242 HouseKeeping(void) 2243 { 2244 int i, n, n100; 2245 struct timeval tv; 2246 struct timezone tz; 2247 2248 /* 2249 * Save system time (seconds) in global variable timeStamp for 2250 * use by other functions. This is done so as not to unnecessarily 2251 * waste timeline by making system calls. 2252 */ 2253 gettimeofday(&tv, &tz); 2254 timeStamp = tv.tv_sec; 2255 2256 /* Compute number of spokes (output table link chains) to cover */ 2257 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 2258 n100 *= timeStamp - lastCleanupTime; 2259 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 2260 2261 n = n100/100; 2262 2263 /* Handle different cases */ 2264 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2265 { 2266 n = ALIAS_CLEANUP_MAX_SPOKES; 2267 lastCleanupTime = timeStamp; 2268 houseKeepingResidual = 0; 2269 2270 for (i=0; i<n; i++) 2271 IncrementalCleanup(); 2272 } 2273 else if (n > 0) 2274 { 2275 lastCleanupTime = timeStamp; 2276 houseKeepingResidual = n100 - 100*n; 2277 2278 for (i=0; i<n; i++) 2279 IncrementalCleanup(); 2280 } 2281 else if (n < 0) 2282 { 2283 #ifdef DEBUG 2284 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2285 fprintf(stderr, "something unexpected in time values\n"); 2286 #endif 2287 lastCleanupTime = timeStamp; 2288 houseKeepingResidual = 0; 2289 } 2290 } 2291 2292 2293 /* Init the log file and enable logging */ 2294 static void 2295 InitPacketAliasLog(void) 2296 { 2297 if ((~packetAliasMode & PKT_ALIAS_LOG) 2298 && (monitorFile = fopen("/var/log/alias.log", "w"))) 2299 { 2300 packetAliasMode |= PKT_ALIAS_LOG; 2301 fprintf(monitorFile, 2302 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2303 } 2304 } 2305 2306 2307 /* Close the log-file and disable logging. */ 2308 static void 2309 UninitPacketAliasLog(void) 2310 { 2311 if (monitorFile) { 2312 fclose(monitorFile); 2313 monitorFile = NULL; 2314 } 2315 packetAliasMode &= ~PKT_ALIAS_LOG; 2316 } 2317 2318 2319 2320 2321 2322 2323 /* Outside world interfaces 2324 2325 -- "outside world" means other than alias*.c routines -- 2326 2327 PacketAliasRedirectPort() 2328 PacketAliasAddServer() 2329 PacketAliasRedirectProto() 2330 PacketAliasRedirectAddr() 2331 PacketAliasRedirectDelete() 2332 PacketAliasSetAddress() 2333 PacketAliasInit() 2334 PacketAliasUninit() 2335 PacketAliasSetMode() 2336 2337 (prototypes in alias.h) 2338 */ 2339 2340 /* Redirection from a specific public addr:port to a 2341 private addr:port */ 2342 struct alias_link * 2343 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 2344 struct in_addr dst_addr, u_short dst_port, 2345 struct in_addr alias_addr, u_short alias_port, 2346 u_char proto) 2347 { 2348 int link_type; 2349 struct alias_link *link; 2350 2351 switch(proto) 2352 { 2353 case IPPROTO_UDP: 2354 link_type = LINK_UDP; 2355 break; 2356 case IPPROTO_TCP: 2357 link_type = LINK_TCP; 2358 break; 2359 default: 2360 #ifdef DEBUG 2361 fprintf(stderr, "PacketAliasRedirectPort(): "); 2362 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2363 #endif 2364 return NULL; 2365 } 2366 2367 link = AddLink(src_addr, dst_addr, alias_addr, 2368 src_port, dst_port, alias_port, 2369 link_type); 2370 2371 if (link != NULL) 2372 { 2373 link->flags |= LINK_PERMANENT; 2374 } 2375 #ifdef DEBUG 2376 else 2377 { 2378 fprintf(stderr, "PacketAliasRedirectPort(): " 2379 "call to AddLink() failed\n"); 2380 } 2381 #endif 2382 2383 return link; 2384 } 2385 2386 /* Add server to the pool of servers */ 2387 int 2388 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) 2389 { 2390 struct server *server; 2391 2392 server = malloc(sizeof(struct server)); 2393 2394 if (server != NULL) { 2395 struct server *head; 2396 2397 server->addr = addr; 2398 server->port = port; 2399 2400 head = link->server; 2401 if (head == NULL) 2402 server->next = server; 2403 else { 2404 struct server *s; 2405 2406 for (s = head; s->next != head; s = s->next); 2407 s->next = server; 2408 server->next = head; 2409 } 2410 link->server = server; 2411 return (0); 2412 } else 2413 return (-1); 2414 } 2415 2416 /* Redirect packets of a given IP protocol from a specific 2417 public address to a private address */ 2418 struct alias_link * 2419 PacketAliasRedirectProto(struct in_addr src_addr, 2420 struct in_addr dst_addr, 2421 struct in_addr alias_addr, 2422 u_char proto) 2423 { 2424 struct alias_link *link; 2425 2426 link = AddLink(src_addr, dst_addr, alias_addr, 2427 NO_SRC_PORT, NO_DEST_PORT, 0, 2428 proto); 2429 2430 if (link != NULL) 2431 { 2432 link->flags |= LINK_PERMANENT; 2433 } 2434 #ifdef DEBUG 2435 else 2436 { 2437 fprintf(stderr, "PacketAliasRedirectProto(): " 2438 "call to AddLink() failed\n"); 2439 } 2440 #endif 2441 2442 return link; 2443 } 2444 2445 /* Static address translation */ 2446 struct alias_link * 2447 PacketAliasRedirectAddr(struct in_addr src_addr, 2448 struct in_addr alias_addr) 2449 { 2450 struct alias_link *link; 2451 2452 link = AddLink(src_addr, nullAddress, alias_addr, 2453 0, 0, 0, 2454 LINK_ADDR); 2455 2456 if (link != NULL) 2457 { 2458 link->flags |= LINK_PERMANENT; 2459 } 2460 #ifdef DEBUG 2461 else 2462 { 2463 fprintf(stderr, "PacketAliasRedirectAddr(): " 2464 "call to AddLink() failed\n"); 2465 } 2466 #endif 2467 2468 return link; 2469 } 2470 2471 2472 void 2473 PacketAliasRedirectDelete(struct alias_link *link) 2474 { 2475 /* This is a dangerous function to put in the API, 2476 because an invalid pointer can crash the program. */ 2477 2478 deleteAllLinks = 1; 2479 DeleteLink(link); 2480 deleteAllLinks = 0; 2481 } 2482 2483 2484 void 2485 PacketAliasSetAddress(struct in_addr addr) 2486 { 2487 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2488 && aliasAddress.s_addr != addr.s_addr) 2489 CleanupAliasData(); 2490 2491 aliasAddress = addr; 2492 } 2493 2494 2495 void 2496 PacketAliasSetTarget(struct in_addr target_addr) 2497 { 2498 targetAddress = target_addr; 2499 } 2500 2501 2502 void 2503 PacketAliasInit(void) 2504 { 2505 int i; 2506 struct timeval tv; 2507 struct timezone tz; 2508 static int firstCall = 1; 2509 2510 if (firstCall == 1) 2511 { 2512 gettimeofday(&tv, &tz); 2513 timeStamp = tv.tv_sec; 2514 lastCleanupTime = tv.tv_sec; 2515 houseKeepingResidual = 0; 2516 2517 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2518 LIST_INIT(&linkTableOut[i]); 2519 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2520 LIST_INIT(&linkTableIn[i]); 2521 2522 atexit(PacketAliasUninit); 2523 firstCall = 0; 2524 } 2525 else 2526 { 2527 deleteAllLinks = 1; 2528 CleanupAliasData(); 2529 deleteAllLinks = 0; 2530 } 2531 2532 aliasAddress.s_addr = INADDR_ANY; 2533 targetAddress.s_addr = INADDR_ANY; 2534 2535 icmpLinkCount = 0; 2536 udpLinkCount = 0; 2537 tcpLinkCount = 0; 2538 pptpLinkCount = 0; 2539 protoLinkCount = 0; 2540 fragmentIdLinkCount = 0; 2541 fragmentPtrLinkCount = 0; 2542 sockCount = 0; 2543 2544 cleanupIndex =0; 2545 2546 packetAliasMode = PKT_ALIAS_SAME_PORTS 2547 | PKT_ALIAS_USE_SOCKETS 2548 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2549 } 2550 2551 void 2552 PacketAliasUninit(void) { 2553 deleteAllLinks = 1; 2554 CleanupAliasData(); 2555 deleteAllLinks = 0; 2556 UninitPacketAliasLog(); 2557 #ifndef NO_FW_PUNCH 2558 UninitPunchFW(); 2559 #endif 2560 } 2561 2562 2563 /* Change mode for some operations */ 2564 unsigned int 2565 PacketAliasSetMode( 2566 unsigned int flags, /* Which state to bring flags to */ 2567 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2568 probe for flag values) */ 2569 ) 2570 { 2571 /* Enable logging? */ 2572 if (flags & mask & PKT_ALIAS_LOG) 2573 { 2574 InitPacketAliasLog(); /* Do the enable */ 2575 } else 2576 /* _Disable_ logging? */ 2577 if (~flags & mask & PKT_ALIAS_LOG) { 2578 UninitPacketAliasLog(); 2579 } 2580 2581 #ifndef NO_FW_PUNCH 2582 /* Start punching holes in the firewall? */ 2583 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2584 InitPunchFW(); 2585 } else 2586 /* Stop punching holes in the firewall? */ 2587 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2588 UninitPunchFW(); 2589 } 2590 #endif 2591 2592 /* Other flags can be set/cleared without special action */ 2593 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2594 return packetAliasMode; 2595 } 2596 2597 2598 int 2599 PacketAliasCheckNewLink(void) 2600 { 2601 return newDefaultLink; 2602 } 2603 2604 2605 #ifndef NO_FW_PUNCH 2606 2607 /***************** 2608 Code to support firewall punching. This shouldn't really be in this 2609 file, but making variables global is evil too. 2610 ****************/ 2611 2612 /* Firewall include files */ 2613 #include <net/if.h> 2614 #include <netinet/ip_fw.h> 2615 #include <string.h> 2616 #include <err.h> 2617 2618 static void ClearAllFWHoles(void); 2619 2620 static int fireWallBaseNum; /* The first firewall entry free for our use */ 2621 static int fireWallNumNums; /* How many entries can we use? */ 2622 static int fireWallActiveNum; /* Which entry did we last use? */ 2623 static char *fireWallField; /* bool array for entries */ 2624 2625 #define fw_setfield(field, num) \ 2626 do { \ 2627 (field)[(num) - fireWallBaseNum] = 1; \ 2628 } /*lint -save -e717 */ while(0) /*lint -restore */ 2629 #define fw_clrfield(field, num) \ 2630 do { \ 2631 (field)[(num) - fireWallBaseNum] = 0; \ 2632 } /*lint -save -e717 */ while(0) /*lint -restore */ 2633 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum]) 2634 2635 static void 2636 InitPunchFW(void) { 2637 fireWallField = malloc(fireWallNumNums); 2638 if (fireWallField) { 2639 memset(fireWallField, 0, fireWallNumNums); 2640 if (fireWallFD < 0) { 2641 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2642 } 2643 ClearAllFWHoles(); 2644 fireWallActiveNum = fireWallBaseNum; 2645 } 2646 } 2647 2648 static void 2649 UninitPunchFW(void) { 2650 ClearAllFWHoles(); 2651 if (fireWallFD >= 0) 2652 close(fireWallFD); 2653 fireWallFD = -1; 2654 if (fireWallField) 2655 free(fireWallField); 2656 fireWallField = NULL; 2657 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2658 } 2659 2660 /* Make a certain link go through the firewall */ 2661 void 2662 PunchFWHole(struct alias_link *link) { 2663 int r; /* Result code */ 2664 struct ip_fw rule; /* On-the-fly built rule */ 2665 int fwhole; /* Where to punch hole */ 2666 2667 /* Don't do anything unless we are asked to */ 2668 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2669 fireWallFD < 0 || 2670 link->link_type != LINK_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) { 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 2780 void 2781 PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2782 #ifndef NO_FW_PUNCH 2783 fireWallBaseNum = base; 2784 fireWallNumNums = num; 2785 #endif 2786 } 2787