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