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