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