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