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