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 // XXX ip free 2009 int 2010 GetDeltaAckIn(u_long ack, 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 int delta, ack_diff_min; 2020 2021 delta = 0; 2022 ack_diff_min = -1; 2023 for (i = 0; i < N_LINK_TCP_DATA; i++) { 2024 struct ack_data_record x; 2025 2026 x = lnk->data.tcp->ack[i]; 2027 if (x.active == 1) { 2028 int ack_diff; 2029 2030 ack_diff = SeqDiff(x.ack_new, ack); 2031 if (ack_diff >= 0) { 2032 if (ack_diff_min >= 0) { 2033 if (ack_diff < ack_diff_min) { 2034 delta = x.delta; 2035 ack_diff_min = ack_diff; 2036 } 2037 } else { 2038 delta = x.delta; 2039 ack_diff_min = ack_diff; 2040 } 2041 } 2042 } 2043 } 2044 return (delta); 2045 } 2046 2047 // XXX ip free 2048 int 2049 GetDeltaSeqOut(u_long seq, struct alias_link *lnk) 2050 { 2051 /* 2052 Find out how much the sequence number has been altered for an outgoing 2053 TCP packet. To do this, a circular list of ACK numbers where the TCP 2054 packet size was altered is searched. 2055 */ 2056 2057 int i; 2058 int delta, seq_diff_min; 2059 2060 delta = 0; 2061 seq_diff_min = -1; 2062 for (i = 0; i < N_LINK_TCP_DATA; i++) { 2063 struct ack_data_record x; 2064 2065 x = lnk->data.tcp->ack[i]; 2066 if (x.active == 1) { 2067 int seq_diff; 2068 2069 seq_diff = SeqDiff(x.ack_old, seq); 2070 if (seq_diff >= 0) { 2071 if (seq_diff_min >= 0) { 2072 if (seq_diff < seq_diff_min) { 2073 delta = x.delta; 2074 seq_diff_min = seq_diff; 2075 } 2076 } else { 2077 delta = x.delta; 2078 seq_diff_min = seq_diff; 2079 } 2080 } 2081 } 2082 } 2083 return (delta); 2084 } 2085 2086 // XXX ip free 2087 void 2088 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len, 2089 u_long th_seq, u_int th_off) 2090 { 2091 /* 2092 When a TCP packet has been altered in length, save this 2093 information in a circular list. If enough packets have 2094 been altered, then this list will begin to overwrite itself. 2095 */ 2096 2097 struct ack_data_record x; 2098 int hlen, tlen, dlen; 2099 int i; 2100 2101 hlen = (ip_hl + th_off) << 2; 2102 tlen = ntohs(ip_len); 2103 dlen = tlen - hlen; 2104 2105 x.ack_old = htonl(ntohl(th_seq) + dlen); 2106 x.ack_new = htonl(ntohl(th_seq) + dlen + delta); 2107 x.delta = delta; 2108 x.active = 1; 2109 2110 i = lnk->data.tcp->state.index; 2111 lnk->data.tcp->ack[i] = x; 2112 2113 i++; 2114 if (i == N_LINK_TCP_DATA) 2115 lnk->data.tcp->state.index = 0; 2116 else 2117 lnk->data.tcp->state.index = i; 2118 } 2119 2120 void 2121 SetExpire(struct alias_link *lnk, int expire) 2122 { 2123 if (expire == 0) { 2124 lnk->flags &= ~LINK_PERMANENT; 2125 DeleteLink(lnk); 2126 } else if (expire == -1) { 2127 lnk->flags |= LINK_PERMANENT; 2128 } else if (expire > 0) { 2129 lnk->expire_time = expire; 2130 } else { 2131 #ifdef LIBALIAS_DEBUG 2132 fprintf(stderr, "PacketAlias/SetExpire(): "); 2133 fprintf(stderr, "error in expire parameter\n"); 2134 #endif 2135 } 2136 } 2137 2138 void 2139 ClearCheckNewLink(struct libalias *la) 2140 { 2141 2142 LIBALIAS_LOCK_ASSERT(la); 2143 la->newDefaultLink = 0; 2144 } 2145 2146 void 2147 SetProtocolFlags(struct alias_link *lnk, int pflags) 2148 { 2149 2150 lnk->pflags = pflags;; 2151 } 2152 2153 int 2154 GetProtocolFlags(struct alias_link *lnk) 2155 { 2156 2157 return (lnk->pflags); 2158 } 2159 2160 void 2161 SetDestCallId(struct alias_link *lnk, u_int16_t cid) 2162 { 2163 struct libalias *la = lnk->la; 2164 2165 LIBALIAS_LOCK_ASSERT(la); 2166 la->deleteAllLinks = 1; 2167 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, 2168 lnk->src_port, cid, lnk->alias_port, lnk->link_type); 2169 la->deleteAllLinks = 0; 2170 } 2171 2172 2173 /* Miscellaneous Functions 2174 2175 HouseKeeping() 2176 InitPacketAliasLog() 2177 UninitPacketAliasLog() 2178 */ 2179 2180 /* 2181 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2182 is called to find and remove timed-out aliasing links. Logic exists 2183 to sweep through the entire table and linked list structure 2184 every 60 seconds. 2185 2186 (prototype in alias_local.h) 2187 */ 2188 2189 void 2190 HouseKeeping(struct libalias *la) 2191 { 2192 int i, n, n100; 2193 #ifndef _KERNEL 2194 struct timeval tv; 2195 struct timezone tz; 2196 #endif 2197 2198 LIBALIAS_LOCK_ASSERT(la); 2199 /* 2200 * Save system time (seconds) in global variable timeStamp for use 2201 * by other functions. This is done so as not to unnecessarily 2202 * waste timeline by making system calls. 2203 */ 2204 #ifdef _KERNEL 2205 la->timeStamp = time_uptime; 2206 #else 2207 gettimeofday(&tv, &tz); 2208 la->timeStamp = tv.tv_sec; 2209 #endif 2210 2211 /* Compute number of spokes (output table link chains) to cover */ 2212 n100 = LINK_TABLE_OUT_SIZE * 100 + la->houseKeepingResidual; 2213 n100 *= la->timeStamp - la->lastCleanupTime; 2214 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 2215 2216 n = n100 / 100; 2217 2218 /* Handle different cases */ 2219 if (n > ALIAS_CLEANUP_MAX_SPOKES) { 2220 n = ALIAS_CLEANUP_MAX_SPOKES; 2221 la->lastCleanupTime = la->timeStamp; 2222 la->houseKeepingResidual = 0; 2223 2224 for (i = 0; i < n; i++) 2225 IncrementalCleanup(la); 2226 } else if (n > 0) { 2227 la->lastCleanupTime = la->timeStamp; 2228 la->houseKeepingResidual = n100 - 100 * n; 2229 2230 for (i = 0; i < n; i++) 2231 IncrementalCleanup(la); 2232 } else if (n < 0) { 2233 #ifdef LIBALIAS_DEBUG 2234 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2235 fprintf(stderr, "something unexpected in time values\n"); 2236 #endif 2237 la->lastCleanupTime = la->timeStamp; 2238 la->houseKeepingResidual = 0; 2239 } 2240 } 2241 2242 /* Init the log file and enable logging */ 2243 static int 2244 InitPacketAliasLog(struct libalias *la) 2245 { 2246 2247 LIBALIAS_LOCK_ASSERT(la); 2248 if (~la->packetAliasMode & PKT_ALIAS_LOG) { 2249 #ifdef _KERNEL 2250 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE))) 2251 ; 2252 #else 2253 if ((la->logDesc = fopen("/var/log/alias.log", "w"))) 2254 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2255 #endif 2256 else 2257 return (ENOMEM); /* log initialization failed */ 2258 la->packetAliasMode |= PKT_ALIAS_LOG; 2259 } 2260 2261 return (1); 2262 } 2263 2264 /* Close the log-file and disable logging. */ 2265 static void 2266 UninitPacketAliasLog(struct libalias *la) 2267 { 2268 2269 LIBALIAS_LOCK_ASSERT(la); 2270 if (la->logDesc) { 2271 #ifdef _KERNEL 2272 free(la->logDesc); 2273 #else 2274 fclose(la->logDesc); 2275 #endif 2276 la->logDesc = NULL; 2277 } 2278 la->packetAliasMode &= ~PKT_ALIAS_LOG; 2279 } 2280 2281 /* Outside world interfaces 2282 2283 -- "outside world" means other than alias*.c routines -- 2284 2285 PacketAliasRedirectPort() 2286 PacketAliasAddServer() 2287 PacketAliasRedirectProto() 2288 PacketAliasRedirectAddr() 2289 PacketAliasRedirectDynamic() 2290 PacketAliasRedirectDelete() 2291 PacketAliasSetAddress() 2292 PacketAliasInit() 2293 PacketAliasUninit() 2294 PacketAliasSetMode() 2295 2296 (prototypes in alias.h) 2297 */ 2298 2299 /* Redirection from a specific public addr:port to a 2300 private addr:port */ 2301 struct alias_link * 2302 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2303 struct in_addr dst_addr, u_short dst_port, 2304 struct in_addr alias_addr, u_short alias_port, 2305 u_char proto) 2306 { 2307 int link_type; 2308 struct alias_link *lnk; 2309 2310 LIBALIAS_LOCK(la); 2311 switch (proto) { 2312 case IPPROTO_UDP: 2313 link_type = LINK_UDP; 2314 break; 2315 case IPPROTO_TCP: 2316 link_type = LINK_TCP; 2317 break; 2318 default: 2319 #ifdef LIBALIAS_DEBUG 2320 fprintf(stderr, "PacketAliasRedirectPort(): "); 2321 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2322 #endif 2323 lnk = NULL; 2324 goto getout; 2325 } 2326 2327 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2328 src_port, dst_port, alias_port, 2329 link_type); 2330 2331 if (lnk != NULL) { 2332 lnk->flags |= LINK_PERMANENT; 2333 } 2334 #ifdef LIBALIAS_DEBUG 2335 else { 2336 fprintf(stderr, "PacketAliasRedirectPort(): " 2337 "call to AddLink() failed\n"); 2338 } 2339 #endif 2340 2341 getout: 2342 LIBALIAS_UNLOCK(la); 2343 return (lnk); 2344 } 2345 2346 /* Add server to the pool of servers */ 2347 int 2348 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 2349 { 2350 struct server *server; 2351 int res; 2352 2353 LIBALIAS_LOCK(la); 2354 (void)la; 2355 2356 server = malloc(sizeof(struct server)); 2357 2358 if (server != NULL) { 2359 struct server *head; 2360 2361 server->addr = addr; 2362 server->port = port; 2363 2364 head = lnk->server; 2365 if (head == NULL) 2366 server->next = server; 2367 else { 2368 struct server *s; 2369 2370 for (s = head; s->next != head; s = s->next); 2371 s->next = server; 2372 server->next = head; 2373 } 2374 lnk->server = server; 2375 res = 0; 2376 } else 2377 res = -1; 2378 2379 LIBALIAS_UNLOCK(la); 2380 return (res); 2381 } 2382 2383 /* Redirect packets of a given IP protocol from a specific 2384 public address to a private address */ 2385 struct alias_link * 2386 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2387 struct in_addr dst_addr, 2388 struct in_addr alias_addr, 2389 u_char proto) 2390 { 2391 struct alias_link *lnk; 2392 2393 LIBALIAS_LOCK(la); 2394 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2395 NO_SRC_PORT, NO_DEST_PORT, 0, 2396 proto); 2397 2398 if (lnk != NULL) { 2399 lnk->flags |= LINK_PERMANENT; 2400 } 2401 #ifdef LIBALIAS_DEBUG 2402 else { 2403 fprintf(stderr, "PacketAliasRedirectProto(): " 2404 "call to AddLink() failed\n"); 2405 } 2406 #endif 2407 2408 LIBALIAS_UNLOCK(la); 2409 return (lnk); 2410 } 2411 2412 /* Static address translation */ 2413 struct alias_link * 2414 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2415 struct in_addr alias_addr) 2416 { 2417 struct alias_link *lnk; 2418 2419 LIBALIAS_LOCK(la); 2420 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr, 2421 0, 0, 0, 2422 LINK_ADDR); 2423 2424 if (lnk != NULL) { 2425 lnk->flags |= LINK_PERMANENT; 2426 } 2427 #ifdef LIBALIAS_DEBUG 2428 else { 2429 fprintf(stderr, "PacketAliasRedirectAddr(): " 2430 "call to AddLink() failed\n"); 2431 } 2432 #endif 2433 2434 LIBALIAS_UNLOCK(la); 2435 return (lnk); 2436 } 2437 2438 2439 /* Mark the aliasing link dynamic */ 2440 int 2441 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2442 { 2443 int res; 2444 2445 LIBALIAS_LOCK(la); 2446 (void)la; 2447 2448 if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2449 res = -1; 2450 else { 2451 lnk->flags &= ~LINK_PERMANENT; 2452 res = 0; 2453 } 2454 LIBALIAS_UNLOCK(la); 2455 return (res); 2456 } 2457 2458 2459 void 2460 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 2461 { 2462 /* This is a dangerous function to put in the API, 2463 because an invalid pointer can crash the program. */ 2464 2465 LIBALIAS_LOCK(la); 2466 la->deleteAllLinks = 1; 2467 DeleteLink(lnk); 2468 la->deleteAllLinks = 0; 2469 LIBALIAS_UNLOCK(la); 2470 } 2471 2472 2473 void 2474 LibAliasSetAddress(struct libalias *la, struct in_addr addr) 2475 { 2476 2477 LIBALIAS_LOCK(la); 2478 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2479 && la->aliasAddress.s_addr != addr.s_addr) 2480 CleanupAliasData(la); 2481 2482 la->aliasAddress = addr; 2483 LIBALIAS_UNLOCK(la); 2484 } 2485 2486 2487 void 2488 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 2489 { 2490 2491 LIBALIAS_LOCK(la); 2492 la->targetAddress = target_addr; 2493 LIBALIAS_UNLOCK(la); 2494 } 2495 2496 static void 2497 finishoff(void) 2498 { 2499 2500 while (!LIST_EMPTY(&instancehead)) 2501 LibAliasUninit(LIST_FIRST(&instancehead)); 2502 } 2503 2504 struct libalias * 2505 LibAliasInit(struct libalias *la) 2506 { 2507 int i; 2508 #ifndef _KERNEL 2509 struct timeval tv; 2510 struct timezone tz; 2511 #endif 2512 2513 if (la == NULL) { 2514 la = calloc(sizeof *la, 1); 2515 if (la == NULL) 2516 return (la); 2517 2518 #ifndef _KERNEL /* kernel cleans up on module unload */ 2519 if (LIST_EMPTY(&instancehead)) 2520 atexit(finishoff); 2521 #endif 2522 LIST_INSERT_HEAD(&instancehead, la, instancelist); 2523 2524 #ifdef _KERNEL 2525 la->timeStamp = time_uptime; 2526 la->lastCleanupTime = time_uptime; 2527 #else 2528 gettimeofday(&tv, &tz); 2529 la->timeStamp = tv.tv_sec; 2530 la->lastCleanupTime = tv.tv_sec; 2531 #endif 2532 la->houseKeepingResidual = 0; 2533 2534 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2535 LIST_INIT(&la->linkTableOut[i]); 2536 for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2537 LIST_INIT(&la->linkTableIn[i]); 2538 LIBALIAS_LOCK_INIT(la); 2539 LIBALIAS_LOCK(la); 2540 } else { 2541 LIBALIAS_LOCK(la); 2542 la->deleteAllLinks = 1; 2543 CleanupAliasData(la); 2544 la->deleteAllLinks = 0; 2545 } 2546 2547 la->aliasAddress.s_addr = INADDR_ANY; 2548 la->targetAddress.s_addr = INADDR_ANY; 2549 2550 la->icmpLinkCount = 0; 2551 la->udpLinkCount = 0; 2552 la->tcpLinkCount = 0; 2553 la->pptpLinkCount = 0; 2554 la->protoLinkCount = 0; 2555 la->fragmentIdLinkCount = 0; 2556 la->fragmentPtrLinkCount = 0; 2557 la->sockCount = 0; 2558 2559 la->cleanupIndex = 0; 2560 2561 la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2562 #ifndef NO_USE_SOCKETS 2563 | PKT_ALIAS_USE_SOCKETS 2564 #endif 2565 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2566 #ifndef NO_FW_PUNCH 2567 la->fireWallFD = -1; 2568 #endif 2569 #ifndef _KERNEL 2570 LibAliasRefreshModules(); 2571 #endif 2572 LIBALIAS_UNLOCK(la); 2573 return (la); 2574 } 2575 2576 void 2577 LibAliasUninit(struct libalias *la) 2578 { 2579 2580 LIBALIAS_LOCK(la); 2581 la->deleteAllLinks = 1; 2582 CleanupAliasData(la); 2583 la->deleteAllLinks = 0; 2584 UninitPacketAliasLog(la); 2585 #ifndef NO_FW_PUNCH 2586 UninitPunchFW(la); 2587 #endif 2588 LIST_REMOVE(la, instancelist); 2589 LIBALIAS_UNLOCK(la); 2590 LIBALIAS_LOCK_DESTROY(la); 2591 free(la); 2592 } 2593 2594 /* Change mode for some operations */ 2595 unsigned int 2596 LibAliasSetMode( 2597 struct libalias *la, 2598 unsigned int flags, /* Which state to bring flags to */ 2599 unsigned int mask /* Mask of which flags to affect (use 0 to 2600 * do a probe for flag values) */ 2601 ) 2602 { 2603 int res = -1; 2604 2605 LIBALIAS_LOCK(la); 2606 /* Enable logging? */ 2607 if (flags & mask & PKT_ALIAS_LOG) { 2608 /* Do the enable */ 2609 if (InitPacketAliasLog(la) == ENOMEM) 2610 goto getout; 2611 } else 2612 /* _Disable_ logging? */ 2613 if (~flags & mask & PKT_ALIAS_LOG) { 2614 UninitPacketAliasLog(la); 2615 } 2616 #ifndef NO_FW_PUNCH 2617 /* Start punching holes in the firewall? */ 2618 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2619 InitPunchFW(la); 2620 } else 2621 /* Stop punching holes in the firewall? */ 2622 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2623 UninitPunchFW(la); 2624 } 2625 #endif 2626 2627 /* Other flags can be set/cleared without special action */ 2628 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2629 res = la->packetAliasMode; 2630 getout: 2631 LIBALIAS_UNLOCK(la); 2632 return (res); 2633 } 2634 2635 2636 int 2637 LibAliasCheckNewLink(struct libalias *la) 2638 { 2639 int res; 2640 2641 LIBALIAS_LOCK(la); 2642 res = la->newDefaultLink; 2643 LIBALIAS_UNLOCK(la); 2644 return (res); 2645 } 2646 2647 2648 #ifndef NO_FW_PUNCH 2649 2650 /***************** 2651 Code to support firewall punching. This shouldn't really be in this 2652 file, but making variables global is evil too. 2653 ****************/ 2654 2655 /* Firewall include files */ 2656 #include <net/if.h> 2657 #include <netinet/ip_fw.h> 2658 #include <string.h> 2659 #include <err.h> 2660 2661 /* 2662 * helper function, updates the pointer to cmd with the length 2663 * of the current command, and also cleans up the first word of 2664 * the new command in case it has been clobbered before. 2665 */ 2666 static ipfw_insn * 2667 next_cmd(ipfw_insn * cmd) 2668 { 2669 cmd += F_LEN(cmd); 2670 bzero(cmd, sizeof(*cmd)); 2671 return (cmd); 2672 } 2673 2674 /* 2675 * A function to fill simple commands of size 1. 2676 * Existing flags are preserved. 2677 */ 2678 static ipfw_insn * 2679 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2680 int flags, u_int16_t arg) 2681 { 2682 cmd->opcode = opcode; 2683 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2684 cmd->arg1 = arg; 2685 return next_cmd(cmd); 2686 } 2687 2688 static ipfw_insn * 2689 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2690 { 2691 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1; 2692 2693 cmd->addr.s_addr = addr; 2694 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2695 } 2696 2697 static ipfw_insn * 2698 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2699 { 2700 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1; 2701 2702 cmd->ports[0] = cmd->ports[1] = port; 2703 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2704 } 2705 2706 static int 2707 fill_rule(void *buf, int bufsize, int rulenum, 2708 enum ipfw_opcodes action, int proto, 2709 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2710 { 2711 struct ip_fw *rule = (struct ip_fw *)buf; 2712 ipfw_insn *cmd = (ipfw_insn *) rule->cmd; 2713 2714 bzero(buf, bufsize); 2715 rule->rulenum = rulenum; 2716 2717 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2718 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2719 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2720 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2721 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2722 2723 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2724 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2725 2726 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2727 2728 return ((char *)cmd - (char *)buf); 2729 } 2730 2731 static void ClearAllFWHoles(struct libalias *la); 2732 2733 2734 #define fw_setfield(la, field, num) \ 2735 do { \ 2736 (field)[(num) - la->fireWallBaseNum] = 1; \ 2737 } /*lint -save -e717 */ while(0)/* lint -restore */ 2738 2739 #define fw_clrfield(la, field, num) \ 2740 do { \ 2741 (field)[(num) - la->fireWallBaseNum] = 0; \ 2742 } /*lint -save -e717 */ while(0)/* lint -restore */ 2743 2744 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2745 2746 static void 2747 InitPunchFW(struct libalias *la) 2748 { 2749 2750 LIBALIAS_LOCK_ASSERT(la); 2751 la->fireWallField = malloc(la->fireWallNumNums); 2752 if (la->fireWallField) { 2753 memset(la->fireWallField, 0, la->fireWallNumNums); 2754 if (la->fireWallFD < 0) { 2755 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2756 } 2757 ClearAllFWHoles(la); 2758 la->fireWallActiveNum = la->fireWallBaseNum; 2759 } 2760 } 2761 2762 static void 2763 UninitPunchFW(struct libalias *la) 2764 { 2765 2766 LIBALIAS_LOCK_ASSERT(la); 2767 ClearAllFWHoles(la); 2768 if (la->fireWallFD >= 0) 2769 close(la->fireWallFD); 2770 la->fireWallFD = -1; 2771 if (la->fireWallField) 2772 free(la->fireWallField); 2773 la->fireWallField = NULL; 2774 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2775 } 2776 2777 /* Make a certain link go through the firewall */ 2778 void 2779 PunchFWHole(struct alias_link *lnk) 2780 { 2781 struct libalias *la; 2782 int r; /* Result code */ 2783 struct ip_fw rule; /* On-the-fly built rule */ 2784 int fwhole; /* Where to punch hole */ 2785 2786 LIBALIAS_LOCK_ASSERT(la); 2787 la = lnk->la; 2788 2789 /* Don't do anything unless we are asked to */ 2790 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2791 la->fireWallFD < 0 || 2792 lnk->link_type != LINK_TCP) 2793 return; 2794 2795 memset(&rule, 0, sizeof rule); 2796 2797 /** Build rule **/ 2798 2799 /* Find empty slot */ 2800 for (fwhole = la->fireWallActiveNum; 2801 fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2802 fw_tstfield(la, la->fireWallField, fwhole); 2803 fwhole++); 2804 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2805 for (fwhole = la->fireWallBaseNum; 2806 fwhole < la->fireWallActiveNum && 2807 fw_tstfield(la, la->fireWallField, fwhole); 2808 fwhole++); 2809 if (fwhole == la->fireWallActiveNum) { 2810 /* No rule point empty - we can't punch more holes. */ 2811 la->fireWallActiveNum = la->fireWallBaseNum; 2812 #ifdef LIBALIAS_DEBUG 2813 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2814 #endif 2815 return; 2816 } 2817 } 2818 /* Start next search at next position */ 2819 la->fireWallActiveNum = fwhole + 1; 2820 2821 /* 2822 * generate two rules of the form 2823 * 2824 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2825 * accept tcp from DAddr DPort to OAddr OPort 2826 */ 2827 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2828 u_int32_t rulebuf[255]; 2829 int i; 2830 2831 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2832 O_ACCEPT, IPPROTO_TCP, 2833 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2834 GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2835 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2836 if (r) 2837 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2838 2839 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2840 O_ACCEPT, IPPROTO_TCP, 2841 GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2842 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2843 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2844 if (r) 2845 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2846 } 2847 2848 /* Indicate hole applied */ 2849 lnk->data.tcp->fwhole = fwhole; 2850 fw_setfield(la, la->fireWallField, fwhole); 2851 } 2852 2853 /* Remove a hole in a firewall associated with a particular alias 2854 lnk. Calling this too often is harmless. */ 2855 static void 2856 ClearFWHole(struct alias_link *lnk) 2857 { 2858 struct libalias *la; 2859 2860 LIBALIAS_LOCK_ASSERT(la); 2861 la = lnk->la; 2862 if (lnk->link_type == LINK_TCP) { 2863 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall 2864 * hole? */ 2865 struct ip_fw rule; 2866 2867 if (fwhole < 0) 2868 return; 2869 2870 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2871 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2872 &fwhole, sizeof fwhole)); 2873 fw_clrfield(la, la->fireWallField, fwhole); 2874 lnk->data.tcp->fwhole = -1; 2875 } 2876 } 2877 2878 /* Clear out the entire range dedicated to firewall holes. */ 2879 static void 2880 ClearAllFWHoles(struct libalias *la) 2881 { 2882 struct ip_fw rule; /* On-the-fly built rule */ 2883 int i; 2884 2885 LIBALIAS_LOCK_ASSERT(la); 2886 if (la->fireWallFD < 0) 2887 return; 2888 2889 memset(&rule, 0, sizeof rule); 2890 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2891 int r = i; 2892 2893 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2894 } 2895 /* XXX: third arg correct here ? /phk */ 2896 memset(la->fireWallField, 0, la->fireWallNumNums); 2897 } 2898 2899 #endif 2900 2901 void 2902 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2903 { 2904 2905 LIBALIAS_LOCK(la); 2906 #ifndef NO_FW_PUNCH 2907 la->fireWallBaseNum = base; 2908 la->fireWallNumNums = num; 2909 #endif 2910 LIBALIAS_UNLOCK(la); 2911 } 2912 2913 void 2914 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2915 { 2916 2917 LIBALIAS_LOCK(la); 2918 la->skinnyPort = port; 2919 LIBALIAS_UNLOCK(la); 2920 } 2921