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 *la); 358 static void UninitPunchFW(struct libalias *la); 359 static void ClearFWHole(struct alias_link *link); 360 361 #endif 362 363 /* Log file control */ 364 static void InitPacketAliasLog(struct libalias *la); 365 static void UninitPacketAliasLog(struct libalias *la); 366 367 static u_int 368 StartPointIn(struct in_addr alias_addr, 369 u_short alias_port, 370 int link_type) 371 { 372 u_int n; 373 374 n = alias_addr.s_addr; 375 if (link_type != LINK_PPTP) 376 n += alias_port; 377 n += link_type; 378 return (n % LINK_TABLE_IN_SIZE); 379 } 380 381 382 static u_int 383 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 384 u_short src_port, u_short dst_port, int link_type) 385 { 386 u_int n; 387 388 n = src_addr.s_addr; 389 n += dst_addr.s_addr; 390 if (link_type != LINK_PPTP) { 391 n += src_port; 392 n += dst_port; 393 } 394 n += link_type; 395 396 return (n % LINK_TABLE_OUT_SIZE); 397 } 398 399 400 static int 401 SeqDiff(u_long x, u_long y) 402 { 403 /* Return the difference between two TCP sequence numbers */ 404 405 /* 406 This function is encapsulated in case there are any unusual 407 arithmetic conditions that need to be considered. 408 */ 409 410 return (ntohl(y) - ntohl(x)); 411 } 412 413 414 static void 415 ShowAliasStats(struct libalias *la) 416 { 417 /* Used for debugging */ 418 419 if (la->monitorFile) { 420 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 *link, 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 = link->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 link->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, link->dst_addr, link->alias_addr, 568 link->dst_port, port_net, 569 link->link_type, 0); 570 571 if (search_result == NULL) 572 go_ahead = 1; 573 else if (!(link->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 && (link->flags & LINK_PARTIALLY_SPECIFIED) 582 && ((link->link_type == LINK_TCP) || 583 (link->link_type == LINK_UDP))) { 584 if (GetSocket(la, port_net, &link->sockfd, link->link_type)) { 585 link->alias_port = port_net; 586 return (0); 587 } 588 } else { 589 link->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 *link; 749 int i, icount; 750 751 icount = 0; 752 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { 753 link = LIST_FIRST(&la->linkTableOut[i]); 754 while (link != NULL) { 755 struct alias_link *link_next; 756 757 link_next = LIST_NEXT(link, list_out); 758 icount++; 759 DeleteLink(link); 760 link = 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 *link; 773 774 icount = 0; 775 link = LIST_FIRST(&la->linkTableOut[la->cleanupIndex++]); 776 while (link != NULL) { 777 int idelta; 778 struct alias_link *link_next; 779 780 link_next = LIST_NEXT(link, list_out); 781 idelta = la->timeStamp - link->timestamp; 782 switch (link->link_type) { 783 case LINK_TCP: 784 if (idelta > link->expire_time) { 785 struct tcp_dat *tcp_aux; 786 787 tcp_aux = link->data.tcp; 788 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 789 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) { 790 DeleteLink(link); 791 icount++; 792 } 793 } 794 break; 795 default: 796 if (idelta > link->expire_time) { 797 DeleteLink(link); 798 icount++; 799 } 800 break; 801 } 802 link = 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 *link) 811 { 812 struct libalias *la = link->la; 813 814 /* Don't do anything if the link is marked permanent */ 815 if (la->deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 816 return; 817 818 #ifndef NO_FW_PUNCH 819 /* Delete associated firewall hole, if any */ 820 ClearFWHole(link); 821 #endif 822 823 /* Free memory allocated for LSNAT server pool */ 824 if (link->server != NULL) { 825 struct server *head, *curr, *next; 826 827 head = curr = link->server; 828 do { 829 next = curr->next; 830 free(curr); 831 } while ((curr = next) != head); 832 } 833 /* Adjust output table pointers */ 834 LIST_REMOVE(link, list_out); 835 836 /* Adjust input table pointers */ 837 LIST_REMOVE(link, list_in); 838 839 /* Close socket, if one has been allocated */ 840 if (link->sockfd != -1) { 841 la->sockCount--; 842 close(link->sockfd); 843 } 844 /* Link-type dependent cleanup */ 845 switch (link->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(link->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 (link->data.frag_ptr != NULL) 865 free(link->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(link); 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 *link; 896 897 link = malloc(sizeof(struct alias_link)); 898 if (link != NULL) { 899 /* Basic initialization */ 900 link->la = la; 901 link->src_addr = src_addr; 902 link->dst_addr = dst_addr; 903 link->alias_addr = alias_addr; 904 link->proxy_addr.s_addr = INADDR_ANY; 905 link->src_port = src_port; 906 link->dst_port = dst_port; 907 link->proxy_port = 0; 908 link->server = NULL; 909 link->link_type = link_type; 910 link->sockfd = -1; 911 link->flags = 0; 912 link->pflags = 0; 913 link->timestamp = la->timeStamp; 914 915 /* Expiration time */ 916 switch (link_type) { 917 case LINK_ICMP: 918 link->expire_time = ICMP_EXPIRE_TIME; 919 break; 920 case LINK_UDP: 921 link->expire_time = UDP_EXPIRE_TIME; 922 break; 923 case LINK_TCP: 924 link->expire_time = TCP_EXPIRE_INITIAL; 925 break; 926 case LINK_PPTP: 927 link->flags |= LINK_PERMANENT; /* no timeout. */ 928 break; 929 case LINK_FRAGMENT_ID: 930 link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 931 break; 932 case LINK_FRAGMENT_PTR: 933 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 934 break; 935 case LINK_ADDR: 936 break; 937 default: 938 link->expire_time = PROTO_EXPIRE_TIME; 939 break; 940 } 941 942 /* Determine alias flags */ 943 if (dst_addr.s_addr == INADDR_ANY) 944 link->flags |= LINK_UNKNOWN_DEST_ADDR; 945 if (dst_port == 0) 946 link->flags |= LINK_UNKNOWN_DEST_PORT; 947 948 /* Determine alias port */ 949 if (GetNewPort(la, link, alias_port_param) != 0) { 950 free(link); 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 link->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(link); 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], link, list_out); 1006 1007 /* Set up pointers for input lookup table */ 1008 start_point = StartPointIn(alias_addr, link->alias_port, link_type); 1009 LIST_INSERT_HEAD(&la->linkTableIn[start_point], link, 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 (link); 1021 } 1022 1023 static struct alias_link * 1024 ReLink(struct alias_link *old_link, 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_link; /* zero, equal to alias port */ 1035 struct libalias *la = old_link->la; 1036 1037 new_link = 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_link != NULL && 1042 old_link->link_type == LINK_TCP && 1043 old_link->data.tcp->fwhole > 0) { 1044 PunchFWHole(new_link); 1045 } 1046 #endif 1047 DeleteLink(old_link); 1048 return new_link; 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 *link; 1061 1062 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1063 LIST_FOREACH(link, &la->linkTableOut[i], list_out) { 1064 if (link->src_addr.s_addr == src_addr.s_addr 1065 && link->server == NULL 1066 && link->dst_addr.s_addr == dst_addr.s_addr 1067 && link->dst_port == dst_port 1068 && link->src_port == src_port 1069 && link->link_type == link_type) { 1070 link->timestamp = la->timeStamp; 1071 break; 1072 } 1073 } 1074 1075 /* Search for partially specified links. */ 1076 if (link == NULL && replace_partial_links) { 1077 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { 1078 link = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, 1079 link_type, 0); 1080 if (link == NULL) 1081 link = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 1082 dst_port, link_type, 0); 1083 } 1084 if (link == NULL && 1085 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { 1086 link = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0, 1087 link_type, 0); 1088 } 1089 if (link != NULL) { 1090 link = ReLink(link, 1091 src_addr, dst_addr, link->alias_addr, 1092 src_port, dst_port, link->alias_port, 1093 link_type); 1094 } 1095 } 1096 return (link); 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 *link; 1108 1109 link = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, 1110 link_type, replace_partial_links); 1111 1112 if (link == 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 link = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port, 1122 link_type, replace_partial_links); 1123 } 1124 } 1125 return (link); 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 *link; 1140 struct alias_link *link_fully_specified; 1141 struct alias_link *link_unknown_all; 1142 struct alias_link *link_unknown_dst_addr; 1143 struct alias_link *link_unknown_dst_port; 1144 1145 /* Initialize pointers */ 1146 link_fully_specified = NULL; 1147 link_unknown_all = NULL; 1148 link_unknown_dst_addr = NULL; 1149 link_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(link, &la->linkTableIn[start_point], list_in) { 1163 int flags; 1164 1165 flags = flags_in | link->flags; 1166 if (!(flags & LINK_PARTIALLY_SPECIFIED)) { 1167 if (link->alias_addr.s_addr == alias_addr.s_addr 1168 && link->alias_port == alias_port 1169 && link->dst_addr.s_addr == dst_addr.s_addr 1170 && link->dst_port == dst_port 1171 && link->link_type == link_type) { 1172 link_fully_specified = link; 1173 break; 1174 } 1175 } else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1176 && (flags & LINK_UNKNOWN_DEST_PORT)) { 1177 if (link->alias_addr.s_addr == alias_addr.s_addr 1178 && link->alias_port == alias_port 1179 && link->link_type == link_type) { 1180 if (link_unknown_all == NULL) 1181 link_unknown_all = link; 1182 } 1183 } else if (flags & LINK_UNKNOWN_DEST_ADDR) { 1184 if (link->alias_addr.s_addr == alias_addr.s_addr 1185 && link->alias_port == alias_port 1186 && link->link_type == link_type 1187 && link->dst_port == dst_port) { 1188 if (link_unknown_dst_addr == NULL) 1189 link_unknown_dst_addr = link; 1190 } 1191 } else if (flags & LINK_UNKNOWN_DEST_PORT) { 1192 if (link->alias_addr.s_addr == alias_addr.s_addr 1193 && link->alias_port == alias_port 1194 && link->link_type == link_type 1195 && link->dst_addr.s_addr == dst_addr.s_addr) { 1196 if (link_unknown_dst_port == NULL) 1197 link_unknown_dst_port = link; 1198 } 1199 } 1200 } 1201 1202 1203 1204 if (link_fully_specified != NULL) { 1205 link_fully_specified->timestamp = la->timeStamp; 1206 link = link_fully_specified; 1207 } else if (link_unknown_dst_port != NULL) 1208 link = link_unknown_dst_port; 1209 else if (link_unknown_dst_addr != NULL) 1210 link = link_unknown_dst_addr; 1211 else if (link_unknown_all != NULL) 1212 link = link_unknown_all; 1213 else 1214 return (NULL); 1215 1216 if (replace_partial_links && 1217 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) { 1218 struct in_addr src_addr; 1219 u_short src_port; 1220 1221 if (link->server != NULL) { /* LSNAT link */ 1222 src_addr = link->server->addr; 1223 src_port = link->server->port; 1224 link->server = link->server->next; 1225 } else { 1226 src_addr = link->src_addr; 1227 src_port = link->src_port; 1228 } 1229 1230 link = ReLink(link, 1231 src_addr, dst_addr, alias_addr, 1232 src_port, dst_port, alias_port, 1233 link_type); 1234 } 1235 return (link); 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 *link; 1247 1248 link = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, 1249 link_type, replace_partial_links); 1250 1251 if (link == 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 link = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port, 1261 link_type, replace_partial_links); 1262 } 1263 } 1264 return (link); 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 *link; 1294 1295 link = FindLinkIn(la, dst_addr, alias_addr, 1296 NO_DEST_PORT, id_alias, 1297 LINK_ICMP, 0); 1298 if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1299 struct in_addr target_addr; 1300 1301 target_addr = FindOriginalAddress(la, alias_addr); 1302 link = AddLink(la, target_addr, dst_addr, alias_addr, 1303 id_alias, NO_DEST_PORT, id_alias, 1304 LINK_ICMP); 1305 } 1306 return (link); 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 *link; 1317 1318 link = FindLinkOut(la, src_addr, dst_addr, 1319 id, NO_DEST_PORT, 1320 LINK_ICMP, 0); 1321 if (link == NULL && create) { 1322 struct in_addr alias_addr; 1323 1324 alias_addr = FindAliasAddress(la, src_addr); 1325 link = AddLink(la, src_addr, dst_addr, alias_addr, 1326 id, NO_DEST_PORT, GET_ALIAS_ID, 1327 LINK_ICMP); 1328 } 1329 return (link); 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 *link; 1339 1340 link = FindLinkIn(la, dst_addr, alias_addr, 1341 NO_DEST_PORT, ip_id, 1342 LINK_FRAGMENT_ID, 0); 1343 1344 if (link == NULL) { 1345 link = AddLink(la, la->nullAddress, dst_addr, alias_addr, 1346 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1347 LINK_FRAGMENT_ID); 1348 } 1349 return (link); 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 *link; 1391 1392 link = FindLinkIn(la, dst_addr, alias_addr, 1393 NO_DEST_PORT, 0, 1394 proto, 1); 1395 1396 if (link == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1397 struct in_addr target_addr; 1398 1399 target_addr = FindOriginalAddress(la, alias_addr); 1400 link = AddLink(la, target_addr, dst_addr, alias_addr, 1401 NO_SRC_PORT, NO_DEST_PORT, 0, 1402 proto); 1403 } 1404 return (link); 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 *link; 1414 1415 link = FindLinkOut(la, src_addr, dst_addr, 1416 NO_SRC_PORT, NO_DEST_PORT, 1417 proto, 1); 1418 1419 if (link == NULL) { 1420 struct in_addr alias_addr; 1421 1422 alias_addr = FindAliasAddress(la, src_addr); 1423 link = AddLink(la, src_addr, dst_addr, alias_addr, 1424 NO_SRC_PORT, NO_DEST_PORT, 0, 1425 proto); 1426 } 1427 return (link); 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 *link; 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 link = FindLinkIn(la, dst_addr, alias_addr, 1455 dst_port, alias_port, 1456 link_type, create); 1457 1458 if (link == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1459 struct in_addr target_addr; 1460 1461 target_addr = FindOriginalAddress(la, alias_addr); 1462 link = AddLink(la, target_addr, dst_addr, alias_addr, 1463 alias_port, dst_port, alias_port, 1464 link_type); 1465 } 1466 return (link); 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 *link; 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 link = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); 1494 1495 if (link == NULL && create) { 1496 struct in_addr alias_addr; 1497 1498 alias_addr = FindAliasAddress(la, src_addr); 1499 link = AddLink(la, src_addr, dst_addr, alias_addr, 1500 src_port, dst_port, GET_ALIAS_PORT, 1501 link_type); 1502 } 1503 return (link); 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 *link; 1514 1515 link = AddLink(la, src_addr, dst_addr, alias_addr, 1516 src_call_id, 0, GET_ALIAS_PORT, 1517 LINK_PPTP); 1518 1519 return (link); 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 *link; 1530 1531 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1532 LIST_FOREACH(link, &la->linkTableOut[i], list_out) 1533 if (link->link_type == LINK_PPTP && 1534 link->src_addr.s_addr == src_addr.s_addr && 1535 link->dst_addr.s_addr == dst_addr.s_addr && 1536 link->src_port == src_call_id) 1537 break; 1538 1539 return (link); 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 *link; 1550 1551 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1552 LIST_FOREACH(link, &la->linkTableOut[i], list_out) 1553 if (link->link_type == LINK_PPTP && 1554 link->src_addr.s_addr == src_addr.s_addr && 1555 link->dst_addr.s_addr == dst_addr.s_addr && 1556 link->dst_port == dst_call_id) 1557 break; 1558 1559 return (link); 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 *link; 1570 1571 i = StartPointIn(alias_addr, 0, LINK_PPTP); 1572 LIST_FOREACH(link, &la->linkTableIn[i], list_in) 1573 if (link->link_type == LINK_PPTP && 1574 link->dst_addr.s_addr == dst_addr.s_addr && 1575 link->alias_addr.s_addr == alias_addr.s_addr && 1576 link->dst_port == dst_call_id) 1577 break; 1578 1579 return (link); 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 *link; 1589 1590 link = FindLinkIn(la, dst_addr, alias_addr, 1591 0 /* any */ , alias_call_id, 1592 LINK_PPTP, 0); 1593 1594 1595 return (link); 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 *link; 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 link = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); 1622 1623 if (link == NULL) { 1624 struct in_addr alias_addr; 1625 1626 alias_addr = FindAliasAddress(la, src_addr); 1627 link = AddLink(la, src_addr, dst_addr, alias_addr, 1628 src_port, 0, alias_port, 1629 link_type); 1630 } 1631 return (link); 1632 } 1633 1634 1635 struct in_addr 1636 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr) 1637 { 1638 struct alias_link *link; 1639 1640 link = FindLinkIn(la, la->nullAddress, alias_addr, 1641 0, 0, LINK_ADDR, 0); 1642 if (link == 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 (link->server != NULL) { /* LSNAT link */ 1653 struct in_addr src_addr; 1654 1655 src_addr = link->server->addr; 1656 link->server = link->server->next; 1657 return (src_addr); 1658 } else if (link->src_addr.s_addr == INADDR_ANY) 1659 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1660 la->aliasAddress : alias_addr; 1661 else 1662 return link->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 *link; 1671 1672 link = FindLinkOut(la, original_addr, la->nullAddress, 1673 0, 0, LINK_ADDR, 0); 1674 if (link == NULL) { 1675 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1676 la->aliasAddress : original_addr; 1677 } else { 1678 if (link->alias_addr.s_addr == INADDR_ANY) 1679 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1680 la->aliasAddress : original_addr; 1681 else 1682 return link->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 *link, struct in_addr src_addr) 1704 { 1705 link->data.frag_addr = src_addr; 1706 } 1707 1708 1709 void 1710 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1711 { 1712 *src_addr = link->data.frag_addr; 1713 } 1714 1715 1716 void 1717 SetFragmentPtr(struct alias_link *link, char *fptr) 1718 { 1719 link->data.frag_ptr = fptr; 1720 } 1721 1722 1723 void 1724 GetFragmentPtr(struct alias_link *link, char **fptr) 1725 { 1726 *fptr = link->data.frag_ptr; 1727 } 1728 1729 1730 void 1731 SetStateIn(struct alias_link *link, int state) 1732 { 1733 /* TCP input state */ 1734 switch (state) { 1735 case ALIAS_TCP_STATE_DISCONNECTED: 1736 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1737 link->expire_time = TCP_EXPIRE_DEAD; 1738 else 1739 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1740 break; 1741 case ALIAS_TCP_STATE_CONNECTED: 1742 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1743 link->expire_time = TCP_EXPIRE_CONNECTED; 1744 break; 1745 default: 1746 abort(); 1747 } 1748 link->data.tcp->state.in = state; 1749 } 1750 1751 1752 void 1753 SetStateOut(struct alias_link *link, int state) 1754 { 1755 /* TCP output state */ 1756 switch (state) { 1757 case ALIAS_TCP_STATE_DISCONNECTED: 1758 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1759 link->expire_time = TCP_EXPIRE_DEAD; 1760 else 1761 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1762 break; 1763 case ALIAS_TCP_STATE_CONNECTED: 1764 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1765 link->expire_time = TCP_EXPIRE_CONNECTED; 1766 break; 1767 default: 1768 abort(); 1769 } 1770 link->data.tcp->state.out = state; 1771 } 1772 1773 1774 int 1775 GetStateIn(struct alias_link *link) 1776 { 1777 /* TCP input state */ 1778 return link->data.tcp->state.in; 1779 } 1780 1781 1782 int 1783 GetStateOut(struct alias_link *link) 1784 { 1785 /* TCP output state */ 1786 return link->data.tcp->state.out; 1787 } 1788 1789 1790 struct in_addr 1791 GetOriginalAddress(struct alias_link *link) 1792 { 1793 if (link->src_addr.s_addr == INADDR_ANY) 1794 return link->la->aliasAddress; 1795 else 1796 return (link->src_addr); 1797 } 1798 1799 1800 struct in_addr 1801 GetDestAddress(struct alias_link *link) 1802 { 1803 return (link->dst_addr); 1804 } 1805 1806 1807 struct in_addr 1808 GetAliasAddress(struct alias_link *link) 1809 { 1810 if (link->alias_addr.s_addr == INADDR_ANY) 1811 return link->la->aliasAddress; 1812 else 1813 return link->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 *link) 1833 { 1834 return (link->src_port); 1835 } 1836 1837 1838 u_short 1839 GetAliasPort(struct alias_link *link) 1840 { 1841 return (link->alias_port); 1842 } 1843 1844 #ifndef NO_FW_PUNCH 1845 static u_short 1846 GetDestPort(struct alias_link *link) 1847 { 1848 return (link->dst_port); 1849 } 1850 1851 #endif 1852 1853 void 1854 SetAckModified(struct alias_link *link) 1855 { 1856 /* Indicate that ACK numbers have been modified in a TCP connection */ 1857 link->data.tcp->state.ack_modified = 1; 1858 } 1859 1860 1861 struct in_addr 1862 GetProxyAddress(struct alias_link *link) 1863 { 1864 return link->proxy_addr; 1865 } 1866 1867 1868 void 1869 SetProxyAddress(struct alias_link *link, struct in_addr addr) 1870 { 1871 link->proxy_addr = addr; 1872 } 1873 1874 1875 u_short 1876 GetProxyPort(struct alias_link *link) 1877 { 1878 return link->proxy_port; 1879 } 1880 1881 1882 void 1883 SetProxyPort(struct alias_link *link, u_short port) 1884 { 1885 link->proxy_port = port; 1886 } 1887 1888 1889 int 1890 GetAckModified(struct alias_link *link) 1891 { 1892 /* See if ACK numbers have been modified */ 1893 return link->data.tcp->state.ack_modified; 1894 } 1895 1896 1897 int 1898 GetDeltaAckIn(struct ip *pip, struct alias_link *link) 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 = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); 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 = link->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 *link) 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 = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); 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 = link->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 *link, 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 = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2)); 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 = link->data.tcp->state.index; 2011 link->data.tcp->ack[i] = x; 2012 2013 i++; 2014 if (i == N_LINK_TCP_DATA) 2015 link->data.tcp->state.index = 0; 2016 else 2017 link->data.tcp->state.index = i; 2018 } 2019 2020 void 2021 SetExpire(struct alias_link *link, int expire) 2022 { 2023 if (expire == 0) { 2024 link->flags &= ~LINK_PERMANENT; 2025 DeleteLink(link); 2026 } else if (expire == -1) { 2027 link->flags |= LINK_PERMANENT; 2028 } else if (expire > 0) { 2029 link->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 *link, int pflags) 2046 { 2047 2048 link->pflags = pflags;; 2049 } 2050 2051 int 2052 GetProtocolFlags(struct alias_link *link) 2053 { 2054 2055 return (link->pflags); 2056 } 2057 2058 void 2059 SetDestCallId(struct alias_link *link, u_int16_t cid) 2060 { 2061 struct libalias *la = link->la; 2062 2063 la->deleteAllLinks = 1; 2064 link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr, 2065 link->src_port, cid, link->alias_port, link->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 *link; 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 link = AddLink(la, src_addr, dst_addr, alias_addr, 2207 src_port, dst_port, alias_port, 2208 link_type); 2209 2210 if (link != NULL) { 2211 link->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 link; 2221 } 2222 2223 /* Add server to the pool of servers */ 2224 int 2225 LibAliasAddServer(struct libalias *la, struct alias_link *link, struct in_addr addr, u_short port) 2226 { 2227 struct server *server; 2228 2229 server = malloc(sizeof(struct server)); 2230 2231 if (server != NULL) { 2232 struct server *head; 2233 2234 server->addr = addr; 2235 server->port = port; 2236 2237 head = link->server; 2238 if (head == NULL) 2239 server->next = server; 2240 else { 2241 struct server *s; 2242 2243 for (s = head; s->next != head; s = s->next); 2244 s->next = server; 2245 server->next = head; 2246 } 2247 link->server = server; 2248 return (0); 2249 } else 2250 return (-1); 2251 } 2252 2253 /* Redirect packets of a given IP protocol from a specific 2254 public address to a private address */ 2255 struct alias_link * 2256 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2257 struct in_addr dst_addr, 2258 struct in_addr alias_addr, 2259 u_char proto) 2260 { 2261 struct alias_link *link; 2262 2263 link = AddLink(la, src_addr, dst_addr, alias_addr, 2264 NO_SRC_PORT, NO_DEST_PORT, 0, 2265 proto); 2266 2267 if (link != NULL) { 2268 link->flags |= LINK_PERMANENT; 2269 } 2270 #ifdef DEBUG 2271 else { 2272 fprintf(stderr, "PacketAliasRedirectProto(): " 2273 "call to AddLink() failed\n"); 2274 } 2275 #endif 2276 2277 return link; 2278 } 2279 2280 /* Static address translation */ 2281 struct alias_link * 2282 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2283 struct in_addr alias_addr) 2284 { 2285 struct alias_link *link; 2286 2287 link = AddLink(la, src_addr, la->nullAddress, alias_addr, 2288 0, 0, 0, 2289 LINK_ADDR); 2290 2291 if (link != NULL) { 2292 link->flags |= LINK_PERMANENT; 2293 } 2294 #ifdef DEBUG 2295 else { 2296 fprintf(stderr, "PacketAliasRedirectAddr(): " 2297 "call to AddLink() failed\n"); 2298 } 2299 #endif 2300 2301 return link; 2302 } 2303 2304 2305 /* Mark the aliasing link dynamic */ 2306 int 2307 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *link) 2308 { 2309 2310 if (link->flags & LINK_PARTIALLY_SPECIFIED) 2311 return (-1); 2312 else { 2313 link->flags &= ~LINK_PERMANENT; 2314 return (0); 2315 } 2316 } 2317 2318 2319 void 2320 LibAliasRedirectDelete(struct libalias *la, struct alias_link *link) 2321 { 2322 /* This is a dangerous function to put in the API, 2323 because an invalid pointer can crash the program. */ 2324 2325 la->deleteAllLinks = 1; 2326 DeleteLink(link); 2327 la->deleteAllLinks = 0; 2328 } 2329 2330 2331 void 2332 LibAliasSetAddress(struct libalias *la, struct in_addr addr) 2333 { 2334 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2335 && la->aliasAddress.s_addr != addr.s_addr) 2336 CleanupAliasData(la); 2337 2338 la->aliasAddress = addr; 2339 } 2340 2341 2342 void 2343 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 2344 { 2345 la->targetAddress = target_addr; 2346 } 2347 2348 static void 2349 finishoff(void) 2350 { 2351 2352 while (!LIST_EMPTY(&instancehead)) 2353 LibAliasUninit(LIST_FIRST(&instancehead)); 2354 } 2355 2356 struct libalias * 2357 LibAliasInit(struct libalias *la) 2358 { 2359 int i; 2360 struct timeval tv; 2361 struct timezone tz; 2362 2363 if (la == NULL) { 2364 la = calloc(sizeof *la, 1); 2365 if (la == NULL) 2366 return (la); 2367 if (LIST_EMPTY(&instancehead)) 2368 atexit(finishoff); 2369 LIST_INSERT_HEAD(&instancehead, la, instancelist); 2370 2371 gettimeofday(&tv, &tz); 2372 la->timeStamp = tv.tv_sec; 2373 la->lastCleanupTime = tv.tv_sec; 2374 la->houseKeepingResidual = 0; 2375 2376 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2377 LIST_INIT(&la->linkTableOut[i]); 2378 for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2379 LIST_INIT(&la->linkTableIn[i]); 2380 2381 } else { 2382 la->deleteAllLinks = 1; 2383 CleanupAliasData(la); 2384 la->deleteAllLinks = 0; 2385 } 2386 2387 la->aliasAddress.s_addr = INADDR_ANY; 2388 la->targetAddress.s_addr = INADDR_ANY; 2389 2390 la->icmpLinkCount = 0; 2391 la->udpLinkCount = 0; 2392 la->tcpLinkCount = 0; 2393 la->pptpLinkCount = 0; 2394 la->protoLinkCount = 0; 2395 la->fragmentIdLinkCount = 0; 2396 la->fragmentPtrLinkCount = 0; 2397 la->sockCount = 0; 2398 2399 la->cleanupIndex = 0; 2400 2401 la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2402 | PKT_ALIAS_USE_SOCKETS 2403 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2404 #ifndef NO_FW_PUNCH 2405 la->fireWallFD = -1; 2406 #endif 2407 return (la); 2408 } 2409 2410 void 2411 LibAliasUninit(struct libalias *la) 2412 { 2413 la->deleteAllLinks = 1; 2414 CleanupAliasData(la); 2415 la->deleteAllLinks = 0; 2416 UninitPacketAliasLog(la); 2417 #ifndef NO_FW_PUNCH 2418 UninitPunchFW(la); 2419 #endif 2420 LIST_REMOVE(la, instancelist); 2421 free(la); 2422 } 2423 2424 /* Change mode for some operations */ 2425 unsigned int 2426 LibAliasSetMode( 2427 struct libalias *la, 2428 unsigned int flags, /* Which state to bring flags to */ 2429 unsigned int mask /* Mask of which flags to affect (use 0 to 2430 * do a probe for flag values) */ 2431 ) 2432 { 2433 /* Enable logging? */ 2434 if (flags & mask & PKT_ALIAS_LOG) { 2435 InitPacketAliasLog(la); /* Do the enable */ 2436 } else 2437 /* _Disable_ logging? */ 2438 if (~flags & mask & PKT_ALIAS_LOG) { 2439 UninitPacketAliasLog(la); 2440 } 2441 #ifndef NO_FW_PUNCH 2442 /* Start punching holes in the firewall? */ 2443 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2444 InitPunchFW(la); 2445 } else 2446 /* Stop punching holes in the firewall? */ 2447 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2448 UninitPunchFW(la); 2449 } 2450 #endif 2451 2452 /* Other flags can be set/cleared without special action */ 2453 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2454 return la->packetAliasMode; 2455 } 2456 2457 2458 int 2459 LibAliasCheckNewLink(struct libalias *la) 2460 { 2461 return la->newDefaultLink; 2462 } 2463 2464 2465 #ifndef NO_FW_PUNCH 2466 2467 /***************** 2468 Code to support firewall punching. This shouldn't really be in this 2469 file, but making variables global is evil too. 2470 ****************/ 2471 2472 #ifndef IPFW2 2473 #define IPFW2 1 /* use new ipfw code */ 2474 #endif 2475 2476 /* Firewall include files */ 2477 #include <net/if.h> 2478 #include <netinet/ip_fw.h> 2479 #include <string.h> 2480 #include <err.h> 2481 2482 #if IPFW2 /* support for new firewall code */ 2483 /* 2484 * helper function, updates the pointer to cmd with the length 2485 * of the current command, and also cleans up the first word of 2486 * the new command in case it has been clobbered before. 2487 */ 2488 static ipfw_insn * 2489 next_cmd(ipfw_insn * cmd) 2490 { 2491 cmd += F_LEN(cmd); 2492 bzero(cmd, sizeof(*cmd)); 2493 return cmd; 2494 } 2495 2496 /* 2497 * A function to fill simple commands of size 1. 2498 * Existing flags are preserved. 2499 */ 2500 static ipfw_insn * 2501 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2502 int flags, u_int16_t arg) 2503 { 2504 cmd->opcode = opcode; 2505 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2506 cmd->arg1 = arg; 2507 return next_cmd(cmd); 2508 } 2509 2510 static ipfw_insn * 2511 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2512 { 2513 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1; 2514 2515 cmd->addr.s_addr = addr; 2516 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2517 } 2518 2519 static ipfw_insn * 2520 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2521 { 2522 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1; 2523 2524 cmd->ports[0] = cmd->ports[1] = port; 2525 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2526 } 2527 2528 static int 2529 fill_rule(void *buf, int bufsize, int rulenum, 2530 enum ipfw_opcodes action, int proto, 2531 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2532 { 2533 struct ip_fw *rule = (struct ip_fw *)buf; 2534 ipfw_insn *cmd = (ipfw_insn *) rule->cmd; 2535 2536 bzero(buf, bufsize); 2537 rule->rulenum = rulenum; 2538 2539 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2540 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2541 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2542 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2543 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2544 2545 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2546 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2547 2548 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2549 2550 return ((char *)cmd - (char *)buf); 2551 } 2552 2553 #endif /* IPFW2 */ 2554 2555 static void ClearAllFWHoles(struct libalias *la); 2556 2557 2558 #define fw_setfield(la, field, num) \ 2559 do { \ 2560 (field)[(num) - la->fireWallBaseNum] = 1; \ 2561 } /*lint -save -e717 */ while(0)/* lint -restore */ 2562 2563 #define fw_clrfield(la, field, num) \ 2564 do { \ 2565 (field)[(num) - la->fireWallBaseNum] = 0; \ 2566 } /*lint -save -e717 */ while(0)/* lint -restore */ 2567 2568 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2569 2570 static void 2571 InitPunchFW(struct libalias *la) 2572 { 2573 2574 la->fireWallField = malloc(la->fireWallNumNums); 2575 if (la->fireWallField) { 2576 memset(la->fireWallField, 0, la->fireWallNumNums); 2577 if (la->fireWallFD < 0) { 2578 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2579 } 2580 ClearAllFWHoles(la); 2581 la->fireWallActiveNum = la->fireWallBaseNum; 2582 } 2583 } 2584 2585 static void 2586 UninitPunchFW(struct libalias *la) 2587 { 2588 ClearAllFWHoles(la); 2589 if (la->fireWallFD >= 0) 2590 close(la->fireWallFD); 2591 la->fireWallFD = -1; 2592 if (la->fireWallField) 2593 free(la->fireWallField); 2594 la->fireWallField = NULL; 2595 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2596 } 2597 2598 /* Make a certain link go through the firewall */ 2599 void 2600 PunchFWHole(struct alias_link *link) 2601 { 2602 struct libalias *la; 2603 int r; /* Result code */ 2604 struct ip_fw rule; /* On-the-fly built rule */ 2605 int fwhole; /* Where to punch hole */ 2606 2607 la = link->la; 2608 2609 /* Don't do anything unless we are asked to */ 2610 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2611 la->fireWallFD < 0 || 2612 link->link_type != LINK_TCP) 2613 return; 2614 2615 memset(&rule, 0, sizeof rule); 2616 2617 /** Build rule **/ 2618 2619 /* Find empty slot */ 2620 for (fwhole = la->fireWallActiveNum; 2621 fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2622 fw_tstfield(la, la->fireWallField, fwhole); 2623 fwhole++); 2624 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2625 for (fwhole = la->fireWallBaseNum; 2626 fwhole < la->fireWallActiveNum && 2627 fw_tstfield(la, la->fireWallField, fwhole); 2628 fwhole++); 2629 if (fwhole == la->fireWallActiveNum) { 2630 /* No rule point empty - we can't punch more holes. */ 2631 la->fireWallActiveNum = la->fireWallBaseNum; 2632 #ifdef DEBUG 2633 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2634 #endif 2635 return; 2636 } 2637 } 2638 /* Start next search at next position */ 2639 la->fireWallActiveNum = fwhole + 1; 2640 2641 /* 2642 * generate two rules of the form 2643 * 2644 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2645 * accept tcp from DAddr DPort to OAddr OPort 2646 */ 2647 #if IPFW2 2648 if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) { 2649 u_int32_t rulebuf[255]; 2650 int i; 2651 2652 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2653 O_ACCEPT, IPPROTO_TCP, 2654 GetOriginalAddress(link), ntohs(GetOriginalPort(link)), 2655 GetDestAddress(link), ntohs(GetDestPort(link))); 2656 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2657 if (r) 2658 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2659 2660 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2661 O_ACCEPT, IPPROTO_TCP, 2662 GetDestAddress(link), ntohs(GetDestPort(link)), 2663 GetOriginalAddress(link), ntohs(GetOriginalPort(link))); 2664 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2665 if (r) 2666 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2667 } 2668 #else /* !IPFW2, old code to generate ipfw rule */ 2669 2670 /* Build generic part of the two rules */ 2671 rule.fw_number = fwhole; 2672 IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */ 2673 IP_FW_SETNDSTP(&rule, 1); /* Number of destination ports. */ 2674 rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT; 2675 rule.fw_prot = IPPROTO_TCP; 2676 rule.fw_smsk.s_addr = INADDR_BROADCAST; 2677 rule.fw_dmsk.s_addr = INADDR_BROADCAST; 2678 2679 /* Build and apply specific part of the rules */ 2680 rule.fw_src = GetOriginalAddress(link); 2681 rule.fw_dst = GetDestAddress(link); 2682 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); 2683 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); 2684 2685 /* 2686 * Skip non-bound links - XXX should not be strictly necessary, but 2687 * seems to leave hole if not done. Leak of non-bound links? (Code 2688 * should be left even if the problem is fixed - it is a clear 2689 * optimization) 2690 */ 2691 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { 2692 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2693 #ifdef DEBUG 2694 if (r) 2695 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2696 #endif 2697 rule.fw_src = GetDestAddress(link); 2698 rule.fw_dst = GetOriginalAddress(link); 2699 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); 2700 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); 2701 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2702 #ifdef DEBUG 2703 if (r) 2704 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2705 #endif 2706 } 2707 #endif /* !IPFW2 */ 2708 /* Indicate hole applied */ 2709 link->data.tcp->fwhole = fwhole; 2710 fw_setfield(la, la->fireWallField, fwhole); 2711 } 2712 2713 /* Remove a hole in a firewall associated with a particular alias 2714 link. Calling this too often is harmless. */ 2715 static void 2716 ClearFWHole(struct alias_link *link) 2717 { 2718 2719 struct libalias *la; 2720 2721 la = link->la; 2722 if (link->link_type == LINK_TCP) { 2723 int fwhole = link->data.tcp->fwhole; /* Where is the firewall 2724 * hole? */ 2725 struct ip_fw rule; 2726 2727 if (fwhole < 0) 2728 return; 2729 2730 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2731 #if IPFW2 2732 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2733 &fwhole, sizeof fwhole)); 2734 #else /* !IPFW2 */ 2735 rule.fw_number = fwhole; 2736 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, 2737 &rule, sizeof rule)); 2738 #endif /* !IPFW2 */ 2739 fw_clrfield(la, la->fireWallField, fwhole); 2740 link->data.tcp->fwhole = -1; 2741 } 2742 } 2743 2744 /* Clear out the entire range dedicated to firewall holes. */ 2745 static void 2746 ClearAllFWHoles(struct libalias *la) 2747 { 2748 struct ip_fw rule; /* On-the-fly built rule */ 2749 int i; 2750 2751 if (la->fireWallFD < 0) 2752 return; 2753 2754 memset(&rule, 0, sizeof rule); 2755 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2756 #if IPFW2 2757 int r = i; 2758 2759 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2760 #else /* !IPFW2 */ 2761 rule.fw_number = i; 2762 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)); 2763 #endif /* !IPFW2 */ 2764 } 2765 /* XXX: third arg correct here ? /phk */ 2766 memset(la->fireWallField, 0, la->fireWallNumNums); 2767 } 2768 2769 #endif 2770 2771 void 2772 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2773 { 2774 #ifndef NO_FW_PUNCH 2775 la->fireWallBaseNum = base; 2776 la->fireWallNumNums = num; 2777 #endif 2778 } 2779 2780 void 2781 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2782 { 2783 la->skinnyPort = port; 2784 } 2785