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 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 la->newDefaultLink = 1; 1679 if (la->targetAddress.s_addr == INADDR_ANY) 1680 return (alias_addr); 1681 else if (la->targetAddress.s_addr == INADDR_NONE) 1682 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1683 la->aliasAddress : alias_addr; 1684 else 1685 return (la->targetAddress); 1686 } else { 1687 if (lnk->server != NULL) { /* LSNAT link */ 1688 struct in_addr src_addr; 1689 1690 src_addr = lnk->server->addr; 1691 lnk->server = lnk->server->next; 1692 return (src_addr); 1693 } else if (lnk->src_addr.s_addr == INADDR_ANY) 1694 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1695 la->aliasAddress : alias_addr; 1696 else 1697 return (lnk->src_addr); 1698 } 1699 } 1700 1701 struct in_addr 1702 FindAliasAddress(struct libalias *la, struct in_addr original_addr) 1703 { 1704 struct alias_link *lnk; 1705 1706 LIBALIAS_LOCK_ASSERT(la); 1707 lnk = FindLinkOut(la, original_addr, ANY_ADDR, 1708 0, 0, LINK_ADDR, 0); 1709 if (lnk == NULL) { 1710 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1711 la->aliasAddress : original_addr; 1712 } else { 1713 if (lnk->alias_addr.s_addr == INADDR_ANY) 1714 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1715 la->aliasAddress : original_addr; 1716 else 1717 return (lnk->alias_addr); 1718 } 1719 } 1720 1721 /* External routines for getting or changing link data 1722 (external to alias_db.c, but internal to alias*.c) 1723 1724 SetFragmentData(), GetFragmentData() 1725 SetFragmentPtr(), GetFragmentPtr() 1726 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1727 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1728 GetOriginalPort(), GetAliasPort() 1729 SetAckModified(), GetAckModified() 1730 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1731 SetProtocolFlags(), GetProtocolFlags() 1732 SetDestCallId() 1733 */ 1734 1735 void 1736 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr) 1737 { 1738 lnk->data.frag_addr = src_addr; 1739 } 1740 1741 void 1742 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr) 1743 { 1744 *src_addr = lnk->data.frag_addr; 1745 } 1746 1747 void 1748 SetFragmentPtr(struct alias_link *lnk, void *fptr) 1749 { 1750 lnk->data.frag_ptr = fptr; 1751 } 1752 1753 void 1754 GetFragmentPtr(struct alias_link *lnk, void **fptr) 1755 { 1756 *fptr = lnk->data.frag_ptr; 1757 } 1758 1759 void 1760 SetStateIn(struct alias_link *lnk, int state) 1761 { 1762 /* TCP input state */ 1763 switch (state) { 1764 case ALIAS_TCP_STATE_DISCONNECTED: 1765 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1766 lnk->expire_time = TCP_EXPIRE_DEAD; 1767 else 1768 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1769 break; 1770 case ALIAS_TCP_STATE_CONNECTED: 1771 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1772 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1773 break; 1774 default: 1775 #ifdef _KERNEL 1776 panic("libalias:SetStateIn() unknown state"); 1777 #else 1778 abort(); 1779 #endif 1780 } 1781 lnk->data.tcp->state.in = state; 1782 } 1783 1784 void 1785 SetStateOut(struct alias_link *lnk, int state) 1786 { 1787 /* TCP output state */ 1788 switch (state) { 1789 case ALIAS_TCP_STATE_DISCONNECTED: 1790 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1791 lnk->expire_time = TCP_EXPIRE_DEAD; 1792 else 1793 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1794 break; 1795 case ALIAS_TCP_STATE_CONNECTED: 1796 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1797 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1798 break; 1799 default: 1800 #ifdef _KERNEL 1801 panic("libalias:SetStateOut() unknown state"); 1802 #else 1803 abort(); 1804 #endif 1805 } 1806 lnk->data.tcp->state.out = state; 1807 } 1808 1809 int 1810 GetStateIn(struct alias_link *lnk) 1811 { 1812 /* TCP input state */ 1813 return (lnk->data.tcp->state.in); 1814 } 1815 1816 int 1817 GetStateOut(struct alias_link *lnk) 1818 { 1819 /* TCP output state */ 1820 return (lnk->data.tcp->state.out); 1821 } 1822 1823 struct in_addr 1824 GetOriginalAddress(struct alias_link *lnk) 1825 { 1826 if (lnk->src_addr.s_addr == INADDR_ANY) 1827 return (lnk->la->aliasAddress); 1828 else 1829 return (lnk->src_addr); 1830 } 1831 1832 struct in_addr 1833 GetDestAddress(struct alias_link *lnk) 1834 { 1835 return (lnk->dst_addr); 1836 } 1837 1838 struct in_addr 1839 GetAliasAddress(struct alias_link *lnk) 1840 { 1841 if (lnk->alias_addr.s_addr == INADDR_ANY) 1842 return (lnk->la->aliasAddress); 1843 else 1844 return (lnk->alias_addr); 1845 } 1846 1847 struct in_addr 1848 GetDefaultAliasAddress(struct libalias *la) 1849 { 1850 LIBALIAS_LOCK_ASSERT(la); 1851 return (la->aliasAddress); 1852 } 1853 1854 void 1855 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) 1856 { 1857 LIBALIAS_LOCK_ASSERT(la); 1858 la->aliasAddress = alias_addr; 1859 } 1860 1861 u_short 1862 GetOriginalPort(struct alias_link *lnk) 1863 { 1864 return (lnk->src_port); 1865 } 1866 1867 u_short 1868 GetAliasPort(struct alias_link *lnk) 1869 { 1870 return (lnk->alias_port); 1871 } 1872 1873 #ifndef NO_FW_PUNCH 1874 static u_short 1875 GetDestPort(struct alias_link *lnk) 1876 { 1877 return (lnk->dst_port); 1878 } 1879 1880 #endif 1881 1882 /* Indicate that ACK numbers have been modified in a TCP connection */ 1883 void 1884 SetAckModified(struct alias_link *lnk) 1885 { 1886 lnk->data.tcp->state.ack_modified = 1; 1887 } 1888 1889 struct in_addr 1890 GetProxyAddress(struct alias_link *lnk) 1891 { 1892 return (lnk->proxy_addr); 1893 } 1894 1895 void 1896 SetProxyAddress(struct alias_link *lnk, struct in_addr addr) 1897 { 1898 lnk->proxy_addr = addr; 1899 } 1900 1901 u_short 1902 GetProxyPort(struct alias_link *lnk) 1903 { 1904 return (lnk->proxy_port); 1905 } 1906 1907 void 1908 SetProxyPort(struct alias_link *lnk, u_short port) 1909 { 1910 lnk->proxy_port = port; 1911 } 1912 1913 /* See if ACK numbers have been modified */ 1914 int 1915 GetAckModified(struct alias_link *lnk) 1916 { 1917 return (lnk->data.tcp->state.ack_modified); 1918 } 1919 1920 /* 1921 * Find out how much the ACK number has been altered for an 1922 * incoming TCP packet. To do this, a circular list of ACK 1923 * numbers where the TCP packet size was altered is searched. 1924 */ 1925 // XXX ip free 1926 int 1927 GetDeltaAckIn(u_long ack, struct alias_link *lnk) 1928 { 1929 int i, j; 1930 int delta, ack_diff_min; 1931 1932 delta = 0; 1933 ack_diff_min = -1; 1934 i = lnk->data.tcp->state.index; 1935 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1936 struct ack_data_record x; 1937 1938 if (i == 0) 1939 i = N_LINK_TCP_DATA; 1940 i--; 1941 x = lnk->data.tcp->ack[i]; 1942 if (x.active == 1) { 1943 int ack_diff; 1944 1945 ack_diff = SeqDiff(x.ack_new, ack); 1946 if (ack_diff >= 0) { 1947 if (ack_diff_min >= 0) { 1948 if (ack_diff < ack_diff_min) { 1949 delta = x.delta; 1950 ack_diff_min = ack_diff; 1951 } 1952 } else { 1953 delta = x.delta; 1954 ack_diff_min = ack_diff; 1955 } 1956 } 1957 } 1958 } 1959 return (delta); 1960 } 1961 1962 /* 1963 * Find out how much the sequence number has been altered for an 1964 * outgoing TCP packet. To do this, a circular list of ACK numbers 1965 * where the TCP packet size was altered is searched. 1966 */ 1967 // XXX ip free 1968 int 1969 GetDeltaSeqOut(u_long seq, struct alias_link *lnk) 1970 { 1971 int i, j; 1972 int delta, seq_diff_min; 1973 1974 delta = 0; 1975 seq_diff_min = -1; 1976 i = lnk->data.tcp->state.index; 1977 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1978 struct ack_data_record x; 1979 1980 if (i == 0) 1981 i = N_LINK_TCP_DATA; 1982 i--; 1983 x = lnk->data.tcp->ack[i]; 1984 if (x.active == 1) { 1985 int seq_diff; 1986 1987 seq_diff = SeqDiff(x.ack_old, seq); 1988 if (seq_diff >= 0) { 1989 if (seq_diff_min >= 0) { 1990 if (seq_diff < seq_diff_min) { 1991 delta = x.delta; 1992 seq_diff_min = seq_diff; 1993 } 1994 } else { 1995 delta = x.delta; 1996 seq_diff_min = seq_diff; 1997 } 1998 } 1999 } 2000 } 2001 return (delta); 2002 } 2003 2004 /* 2005 * When a TCP packet has been altered in length, save this 2006 * information in a circular list. If enough packets have been 2007 * altered, then this list will begin to overwrite itself. 2008 */ 2009 // XXX ip free 2010 void 2011 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len, 2012 u_long th_seq, u_int th_off) 2013 { 2014 struct ack_data_record x; 2015 int hlen, tlen, dlen; 2016 int i; 2017 2018 hlen = (ip_hl + th_off) << 2; 2019 tlen = ntohs(ip_len); 2020 dlen = tlen - hlen; 2021 2022 x.ack_old = htonl(ntohl(th_seq) + dlen); 2023 x.ack_new = htonl(ntohl(th_seq) + dlen + delta); 2024 x.delta = delta; 2025 x.active = 1; 2026 2027 i = lnk->data.tcp->state.index; 2028 lnk->data.tcp->ack[i] = x; 2029 2030 i++; 2031 if (i == N_LINK_TCP_DATA) 2032 lnk->data.tcp->state.index = 0; 2033 else 2034 lnk->data.tcp->state.index = i; 2035 } 2036 2037 void 2038 SetExpire(struct alias_link *lnk, int expire) 2039 { 2040 if (expire == 0) { 2041 lnk->flags &= ~LINK_PERMANENT; 2042 DeleteLink(lnk); 2043 } else if (expire == -1) { 2044 lnk->flags |= LINK_PERMANENT; 2045 } else if (expire > 0) { 2046 lnk->expire_time = expire; 2047 } else { 2048 #ifdef LIBALIAS_DEBUG 2049 fprintf(stderr, "PacketAlias/SetExpire(): "); 2050 fprintf(stderr, "error in expire parameter\n"); 2051 #endif 2052 } 2053 } 2054 2055 void 2056 ClearCheckNewLink(struct libalias *la) 2057 { 2058 LIBALIAS_LOCK_ASSERT(la); 2059 la->newDefaultLink = 0; 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 int i, n; 2106 #ifndef _KERNEL 2107 struct timeval tv; 2108 #endif 2109 2110 LIBALIAS_LOCK_ASSERT(la); 2111 /* 2112 * Save system time (seconds) in global variable timeStamp for use 2113 * by other functions. This is done so as not to unnecessarily 2114 * waste timeline by making system calls. 2115 */ 2116 #ifdef _KERNEL 2117 la->timeStamp = time_uptime; 2118 #else 2119 gettimeofday(&tv, NULL); 2120 la->timeStamp = tv.tv_sec; 2121 #endif 2122 2123 /* Compute number of spokes (output table link chains) to cover */ 2124 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime); 2125 n /= ALIAS_CLEANUP_INTERVAL_SECS; 2126 2127 /* Handle different cases */ 2128 if (n > 0) { 2129 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2130 n = ALIAS_CLEANUP_MAX_SPOKES; 2131 la->lastCleanupTime = la->timeStamp; 2132 for (i = 0; i < n; i++) 2133 IncrementalCleanup(la); 2134 } else if (n < 0) { 2135 #ifdef LIBALIAS_DEBUG 2136 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2137 fprintf(stderr, "something unexpected in time values\n"); 2138 #endif 2139 la->lastCleanupTime = la->timeStamp; 2140 } 2141 } 2142 2143 /* Init the log file and enable logging */ 2144 static int 2145 InitPacketAliasLog(struct libalias *la) 2146 { 2147 LIBALIAS_LOCK_ASSERT(la); 2148 if (~la->packetAliasMode & PKT_ALIAS_LOG) { 2149 #ifdef _KERNEL 2150 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE))) 2151 ; 2152 #else 2153 if ((la->logDesc = fopen("/var/log/alias.log", "w"))) 2154 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2155 #endif 2156 else 2157 return (ENOMEM); /* log initialization failed */ 2158 la->packetAliasMode |= PKT_ALIAS_LOG; 2159 } 2160 2161 return (1); 2162 } 2163 2164 /* Close the log-file and disable logging. */ 2165 static void 2166 UninitPacketAliasLog(struct libalias *la) 2167 { 2168 LIBALIAS_LOCK_ASSERT(la); 2169 if (la->logDesc) { 2170 #ifdef _KERNEL 2171 free(la->logDesc); 2172 #else 2173 fclose(la->logDesc); 2174 #endif 2175 la->logDesc = NULL; 2176 } 2177 la->packetAliasMode &= ~PKT_ALIAS_LOG; 2178 } 2179 2180 /* Outside world interfaces 2181 2182 -- "outside world" means other than alias*.c routines -- 2183 2184 PacketAliasRedirectPort() 2185 PacketAliasAddServer() 2186 PacketAliasRedirectProto() 2187 PacketAliasRedirectAddr() 2188 PacketAliasRedirectDynamic() 2189 PacketAliasRedirectDelete() 2190 PacketAliasSetAddress() 2191 PacketAliasInit() 2192 PacketAliasUninit() 2193 PacketAliasSetMode() 2194 2195 (prototypes in alias.h) 2196 */ 2197 2198 /* Redirection from a specific public addr:port to a 2199 private addr:port */ 2200 struct alias_link * 2201 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2202 struct in_addr dst_addr, u_short dst_port, 2203 struct in_addr alias_addr, u_short alias_port, 2204 u_char proto) 2205 { 2206 int link_type; 2207 struct alias_link *lnk; 2208 2209 LIBALIAS_LOCK(la); 2210 switch (proto) { 2211 case IPPROTO_UDP: 2212 link_type = LINK_UDP; 2213 break; 2214 case IPPROTO_TCP: 2215 link_type = LINK_TCP; 2216 break; 2217 case IPPROTO_SCTP: 2218 link_type = LINK_SCTP; 2219 break; 2220 default: 2221 #ifdef LIBALIAS_DEBUG 2222 fprintf(stderr, "PacketAliasRedirectPort(): "); 2223 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n"); 2224 #endif 2225 lnk = NULL; 2226 goto getout; 2227 } 2228 2229 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2230 src_port, dst_port, alias_port, 2231 link_type); 2232 2233 if (lnk != NULL) { 2234 lnk->flags |= LINK_PERMANENT; 2235 } 2236 #ifdef LIBALIAS_DEBUG 2237 else { 2238 fprintf(stderr, "PacketAliasRedirectPort(): " 2239 "call to AddLink() failed\n"); 2240 } 2241 #endif 2242 2243 getout: 2244 LIBALIAS_UNLOCK(la); 2245 return (lnk); 2246 } 2247 2248 /* Add server to the pool of servers */ 2249 int 2250 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 2251 { 2252 struct server *server; 2253 int res; 2254 2255 LIBALIAS_LOCK(la); 2256 (void)la; 2257 2258 server = malloc(sizeof(struct server)); 2259 2260 if (server != NULL) { 2261 struct server *head; 2262 2263 server->addr = addr; 2264 server->port = port; 2265 2266 head = lnk->server; 2267 if (head == NULL) 2268 server->next = server; 2269 else { 2270 struct server *s; 2271 2272 for (s = head; s->next != head; s = s->next) 2273 ; 2274 s->next = server; 2275 server->next = head; 2276 } 2277 lnk->server = server; 2278 res = 0; 2279 } else 2280 res = -1; 2281 2282 LIBALIAS_UNLOCK(la); 2283 return (res); 2284 } 2285 2286 /* Redirect packets of a given IP protocol from a specific 2287 public address to a private address */ 2288 struct alias_link * 2289 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2290 struct in_addr dst_addr, 2291 struct in_addr alias_addr, 2292 u_char proto) 2293 { 2294 struct alias_link *lnk; 2295 2296 LIBALIAS_LOCK(la); 2297 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2298 NO_SRC_PORT, NO_DEST_PORT, 0, 2299 proto); 2300 2301 if (lnk != NULL) { 2302 lnk->flags |= LINK_PERMANENT; 2303 } 2304 #ifdef LIBALIAS_DEBUG 2305 else { 2306 fprintf(stderr, "PacketAliasRedirectProto(): " 2307 "call to AddLink() failed\n"); 2308 } 2309 #endif 2310 2311 LIBALIAS_UNLOCK(la); 2312 return (lnk); 2313 } 2314 2315 /* Static address translation */ 2316 struct alias_link * 2317 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2318 struct in_addr alias_addr) 2319 { 2320 struct alias_link *lnk; 2321 2322 LIBALIAS_LOCK(la); 2323 lnk = AddLink(la, src_addr, ANY_ADDR, alias_addr, 2324 0, 0, 0, 2325 LINK_ADDR); 2326 2327 if (lnk != NULL) { 2328 lnk->flags |= LINK_PERMANENT; 2329 } 2330 #ifdef LIBALIAS_DEBUG 2331 else { 2332 fprintf(stderr, "PacketAliasRedirectAddr(): " 2333 "call to AddLink() failed\n"); 2334 } 2335 #endif 2336 2337 LIBALIAS_UNLOCK(la); 2338 return (lnk); 2339 } 2340 2341 /* Mark the aliasing link dynamic */ 2342 int 2343 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2344 { 2345 int res; 2346 2347 LIBALIAS_LOCK(la); 2348 (void)la; 2349 2350 if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2351 res = -1; 2352 else { 2353 lnk->flags &= ~LINK_PERMANENT; 2354 res = 0; 2355 } 2356 LIBALIAS_UNLOCK(la); 2357 return (res); 2358 } 2359 2360 /* This is a dangerous function to put in the API, 2361 because an invalid pointer can crash the program. */ 2362 void 2363 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 2364 { 2365 LIBALIAS_LOCK(la); 2366 la->deleteAllLinks = 1; 2367 DeleteLink(lnk); 2368 la->deleteAllLinks = 0; 2369 LIBALIAS_UNLOCK(la); 2370 } 2371 2372 void 2373 LibAliasSetAddress(struct libalias *la, struct in_addr addr) 2374 { 2375 LIBALIAS_LOCK(la); 2376 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2377 && la->aliasAddress.s_addr != addr.s_addr) 2378 CleanupAliasData(la); 2379 2380 la->aliasAddress = addr; 2381 LIBALIAS_UNLOCK(la); 2382 } 2383 2384 void 2385 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low, 2386 u_short port_high) 2387 { 2388 LIBALIAS_LOCK(la); 2389 la->aliasPortLower = port_low; 2390 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */ 2391 la->aliasPortLength = port_high - port_low + 1; 2392 LIBALIAS_UNLOCK(la); 2393 } 2394 2395 void 2396 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 2397 { 2398 LIBALIAS_LOCK(la); 2399 la->targetAddress = target_addr; 2400 LIBALIAS_UNLOCK(la); 2401 } 2402 2403 static void 2404 finishoff(void) 2405 { 2406 while (!LIST_EMPTY(&instancehead)) 2407 LibAliasUninit(LIST_FIRST(&instancehead)); 2408 } 2409 2410 struct libalias * 2411 LibAliasInit(struct libalias *la) 2412 { 2413 int i; 2414 #ifndef _KERNEL 2415 struct timeval tv; 2416 #endif 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 la->timeStamp = time_uptime; 2437 la->lastCleanupTime = time_uptime; 2438 #else 2439 gettimeofday(&tv, NULL); 2440 la->timeStamp = tv.tv_sec; 2441 la->lastCleanupTime = tv.tv_sec; 2442 #endif 2443 2444 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2445 LIST_INIT(&la->linkTableOut[i]); 2446 for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2447 LIST_INIT(&la->linkTableIn[i]); 2448 #ifdef _KERNEL 2449 AliasSctpInit(la); 2450 #endif 2451 LIBALIAS_LOCK_INIT(la); 2452 LIBALIAS_LOCK(la); 2453 } else { 2454 LIBALIAS_LOCK(la); 2455 la->deleteAllLinks = 1; 2456 CleanupAliasData(la); 2457 la->deleteAllLinks = 0; 2458 #ifdef _KERNEL 2459 AliasSctpTerm(la); 2460 AliasSctpInit(la); 2461 #endif 2462 } 2463 2464 la->aliasAddress.s_addr = INADDR_ANY; 2465 la->targetAddress.s_addr = INADDR_ANY; 2466 2467 la->icmpLinkCount = 0; 2468 la->udpLinkCount = 0; 2469 la->tcpLinkCount = 0; 2470 la->sctpLinkCount = 0; 2471 la->pptpLinkCount = 0; 2472 la->protoLinkCount = 0; 2473 la->fragmentIdLinkCount = 0; 2474 la->fragmentPtrLinkCount = 0; 2475 la->sockCount = 0; 2476 2477 la->cleanupIndex = 0; 2478 2479 la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2480 #ifndef NO_USE_SOCKETS 2481 | PKT_ALIAS_USE_SOCKETS 2482 #endif 2483 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2484 #ifndef NO_FW_PUNCH 2485 la->fireWallFD = -1; 2486 #endif 2487 #ifndef _KERNEL 2488 LibAliasRefreshModules(); 2489 #endif 2490 LIBALIAS_UNLOCK(la); 2491 return (la); 2492 } 2493 2494 void 2495 LibAliasUninit(struct libalias *la) 2496 { 2497 LIBALIAS_LOCK(la); 2498 #ifdef _KERNEL 2499 AliasSctpTerm(la); 2500 #endif 2501 la->deleteAllLinks = 1; 2502 CleanupAliasData(la); 2503 la->deleteAllLinks = 0; 2504 UninitPacketAliasLog(la); 2505 #ifndef NO_FW_PUNCH 2506 UninitPunchFW(la); 2507 #endif 2508 LIST_REMOVE(la, instancelist); 2509 LIBALIAS_UNLOCK(la); 2510 LIBALIAS_LOCK_DESTROY(la); 2511 free(la); 2512 } 2513 2514 /* Change mode for some operations */ 2515 unsigned int 2516 LibAliasSetMode( 2517 struct libalias *la, 2518 unsigned int flags, /* Which state to bring flags to */ 2519 unsigned int mask /* Mask of which flags to affect (use 0 to 2520 * do a probe for flag values) */ 2521 ) 2522 { 2523 int res = -1; 2524 2525 LIBALIAS_LOCK(la); 2526 if (flags & mask & PKT_ALIAS_LOG) { 2527 /* Enable logging */ 2528 if (InitPacketAliasLog(la) == ENOMEM) 2529 goto getout; 2530 } else if (~flags & mask & PKT_ALIAS_LOG) 2531 /* _Disable_ logging */ 2532 UninitPacketAliasLog(la); 2533 2534 #ifndef NO_FW_PUNCH 2535 if (flags & mask & PKT_ALIAS_PUNCH_FW) 2536 /* Start punching holes in the firewall? */ 2537 InitPunchFW(la); 2538 else if (~flags & mask & PKT_ALIAS_PUNCH_FW) 2539 /* Stop punching holes in the firewall? */ 2540 UninitPunchFW(la); 2541 #endif 2542 2543 /* Other flags can be set/cleared without special action */ 2544 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2545 res = la->packetAliasMode; 2546 getout: 2547 LIBALIAS_UNLOCK(la); 2548 return (res); 2549 } 2550 2551 int 2552 LibAliasCheckNewLink(struct libalias *la) 2553 { 2554 int res; 2555 2556 LIBALIAS_LOCK(la); 2557 res = la->newDefaultLink; 2558 LIBALIAS_UNLOCK(la); 2559 return (res); 2560 } 2561 2562 #ifndef NO_FW_PUNCH 2563 2564 /***************** 2565 Code to support firewall punching. This shouldn't really be in this 2566 file, but making variables global is evil too. 2567 ****************/ 2568 2569 /* Firewall include files */ 2570 #include <net/if.h> 2571 #include <netinet/ip_fw.h> 2572 #include <string.h> 2573 #include <err.h> 2574 2575 /* 2576 * helper function, updates the pointer to cmd with the length 2577 * of the current command, and also cleans up the first word of 2578 * the new command in case it has been clobbered before. 2579 */ 2580 static ipfw_insn * 2581 next_cmd(ipfw_insn * cmd) 2582 { 2583 cmd += F_LEN(cmd); 2584 bzero(cmd, sizeof(*cmd)); 2585 return (cmd); 2586 } 2587 2588 /* 2589 * A function to fill simple commands of size 1. 2590 * Existing flags are preserved. 2591 */ 2592 static ipfw_insn * 2593 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2594 int flags, u_int16_t arg) 2595 { 2596 cmd->opcode = opcode; 2597 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2598 cmd->arg1 = arg; 2599 return next_cmd(cmd); 2600 } 2601 2602 static ipfw_insn * 2603 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2604 { 2605 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1; 2606 2607 cmd->addr.s_addr = addr; 2608 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2609 } 2610 2611 static ipfw_insn * 2612 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2613 { 2614 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1; 2615 2616 cmd->ports[0] = cmd->ports[1] = port; 2617 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2618 } 2619 2620 static int 2621 fill_rule(void *buf, int bufsize, int rulenum, 2622 enum ipfw_opcodes action, int proto, 2623 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2624 { 2625 struct ip_fw *rule = (struct ip_fw *)buf; 2626 ipfw_insn *cmd = (ipfw_insn *)rule->cmd; 2627 2628 bzero(buf, bufsize); 2629 rule->rulenum = rulenum; 2630 2631 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2632 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2633 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2634 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2635 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2636 2637 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2638 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2639 2640 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2641 2642 return ((char *)cmd - (char *)buf); 2643 } 2644 2645 static void ClearAllFWHoles(struct libalias *la); 2646 2647 #define fw_setfield(la, field, num) \ 2648 do { \ 2649 (field)[(num) - la->fireWallBaseNum] = 1; \ 2650 } /*lint -save -e717 */ while(0)/* lint -restore */ 2651 2652 #define fw_clrfield(la, field, num) \ 2653 do { \ 2654 (field)[(num) - la->fireWallBaseNum] = 0; \ 2655 } /*lint -save -e717 */ while(0)/* lint -restore */ 2656 2657 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2658 2659 static void 2660 InitPunchFW(struct libalias *la) 2661 { 2662 la->fireWallField = malloc(la->fireWallNumNums); 2663 if (la->fireWallField) { 2664 memset(la->fireWallField, 0, la->fireWallNumNums); 2665 if (la->fireWallFD < 0) { 2666 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2667 } 2668 ClearAllFWHoles(la); 2669 la->fireWallActiveNum = la->fireWallBaseNum; 2670 } 2671 } 2672 2673 static void 2674 UninitPunchFW(struct libalias *la) 2675 { 2676 ClearAllFWHoles(la); 2677 if (la->fireWallFD >= 0) 2678 close(la->fireWallFD); 2679 la->fireWallFD = -1; 2680 if (la->fireWallField) 2681 free(la->fireWallField); 2682 la->fireWallField = NULL; 2683 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2684 } 2685 2686 /* Make a certain link go through the firewall */ 2687 void 2688 PunchFWHole(struct alias_link *lnk) 2689 { 2690 struct libalias *la; 2691 int r; /* Result code */ 2692 struct ip_fw rule; /* On-the-fly built rule */ 2693 int fwhole; /* Where to punch hole */ 2694 2695 la = lnk->la; 2696 2697 /* Don't do anything unless we are asked to */ 2698 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2699 la->fireWallFD < 0 || 2700 lnk->link_type != LINK_TCP) 2701 return; 2702 2703 memset(&rule, 0, sizeof rule); 2704 2705 /** Build rule **/ 2706 2707 /* Find empty slot */ 2708 for (fwhole = la->fireWallActiveNum; 2709 fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2710 fw_tstfield(la, la->fireWallField, fwhole); 2711 fwhole++); 2712 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2713 for (fwhole = la->fireWallBaseNum; 2714 fwhole < la->fireWallActiveNum && 2715 fw_tstfield(la, la->fireWallField, fwhole); 2716 fwhole++); 2717 if (fwhole == la->fireWallActiveNum) { 2718 /* No rule point empty - we can't punch more holes. */ 2719 la->fireWallActiveNum = la->fireWallBaseNum; 2720 #ifdef LIBALIAS_DEBUG 2721 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2722 #endif 2723 return; 2724 } 2725 } 2726 /* Start next search at next position */ 2727 la->fireWallActiveNum = fwhole + 1; 2728 2729 /* 2730 * generate two rules of the form 2731 * 2732 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2733 * accept tcp from DAddr DPort to OAddr OPort 2734 */ 2735 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2736 u_int32_t rulebuf[255]; 2737 int i; 2738 2739 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2740 O_ACCEPT, IPPROTO_TCP, 2741 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2742 GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2743 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2744 if (r) 2745 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2746 2747 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2748 O_ACCEPT, IPPROTO_TCP, 2749 GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2750 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2751 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2752 if (r) 2753 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2754 } 2755 2756 /* Indicate hole applied */ 2757 lnk->data.tcp->fwhole = fwhole; 2758 fw_setfield(la, la->fireWallField, fwhole); 2759 } 2760 2761 /* Remove a hole in a firewall associated with a particular alias 2762 lnk. Calling this too often is harmless. */ 2763 static void 2764 ClearFWHole(struct alias_link *lnk) 2765 { 2766 struct libalias *la; 2767 2768 la = lnk->la; 2769 if (lnk->link_type == LINK_TCP) { 2770 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall hole? */ 2771 struct ip_fw rule; 2772 2773 if (fwhole < 0) 2774 return; 2775 2776 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2777 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2778 &fwhole, sizeof fwhole)); 2779 fw_clrfield(la, la->fireWallField, fwhole); 2780 lnk->data.tcp->fwhole = -1; 2781 } 2782 } 2783 2784 /* Clear out the entire range dedicated to firewall holes. */ 2785 static void 2786 ClearAllFWHoles(struct libalias *la) 2787 { 2788 struct ip_fw rule; /* On-the-fly built rule */ 2789 int i; 2790 2791 if (la->fireWallFD < 0) 2792 return; 2793 2794 memset(&rule, 0, sizeof rule); 2795 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2796 int r = i; 2797 2798 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2799 } 2800 /* XXX: third arg correct here ? /phk */ 2801 memset(la->fireWallField, 0, la->fireWallNumNums); 2802 } 2803 2804 #endif /* !NO_FW_PUNCH */ 2805 2806 void 2807 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2808 { 2809 LIBALIAS_LOCK(la); 2810 #ifndef NO_FW_PUNCH 2811 la->fireWallBaseNum = base; 2812 la->fireWallNumNums = num; 2813 #endif 2814 LIBALIAS_UNLOCK(la); 2815 } 2816 2817 void 2818 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2819 { 2820 LIBALIAS_LOCK(la); 2821 la->skinnyPort = port; 2822 LIBALIAS_UNLOCK(la); 2823 } 2824 2825 /* 2826 * Find the address to redirect incoming packets 2827 */ 2828 struct in_addr 2829 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm) 2830 { 2831 struct alias_link *lnk; 2832 struct in_addr redir; 2833 2834 LIBALIAS_LOCK_ASSERT(la); 2835 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2836 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1); 2837 if (lnk != NULL) { 2838 /* port redirect */ 2839 return (lnk->src_addr); 2840 } else { 2841 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst); 2842 if (redir.s_addr == la->aliasAddress.s_addr || 2843 redir.s_addr == la->targetAddress.s_addr) { 2844 /* No address found */ 2845 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2846 NO_DEST_PORT, 0, LINK_SCTP, 1); 2847 if (lnk != NULL) 2848 /* redirect proto */ 2849 return (lnk->src_addr); 2850 } 2851 return (redir); /* address redirect */ 2852 } 2853 } 2854