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