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