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