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