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 /* Data Structures 228 229 The fundamental data structure used in this program is 230 "struct alias_link". Whenever a TCP connection is made, 231 a UDP datagram is sent out, or an ICMP echo request is made, 232 a link record is made (if it has not already been created). 233 The link record is identified by the source address/port 234 and the destination address/port. In the case of an ICMP 235 echo request, the source port is treated as being equivalent 236 with the 16-bit ID number of the ICMP packet. 237 238 The link record also can store some auxiliary data. For 239 TCP connections that have had sequence and acknowledgment 240 modifications, data space is available to track these changes. 241 A state field is used to keep track in changes to the TCP 242 connection state. ID numbers of fragments can also be 243 stored in the auxiliary space. Pointers to unresolved 244 fragments can also be stored. 245 246 The link records support two independent chainings. Lookup 247 tables for input and out tables hold the initial pointers 248 the link chains. On input, the lookup table indexes on alias 249 port and link type. On output, the lookup table indexes on 250 source address, destination address, source port, destination 251 port and link type. 252 */ 253 254 /* used to save changes to ACK/sequence numbers */ 255 struct ack_data_record { 256 u_long ack_old; 257 u_long ack_new; 258 int delta; 259 int active; 260 }; 261 262 /* Information about TCP connection */ 263 struct tcp_state { 264 int in; /* State for outside -> inside */ 265 int out; /* State for inside -> outside */ 266 int index; /* Index to ACK data array */ 267 /* Indicates whether ACK and sequence numbers been modified */ 268 int ack_modified; 269 }; 270 271 /* Number of distinct ACK number changes 272 * saved for a modified TCP stream */ 273 #define N_LINK_TCP_DATA 3 274 struct tcp_dat { 275 struct tcp_state state; 276 struct ack_data_record ack[N_LINK_TCP_DATA]; 277 /* Which firewall record is used for this hole? */ 278 int fwhole; 279 }; 280 281 /* LSNAT server pool (circular list) */ 282 struct server { 283 struct in_addr addr; 284 u_short port; 285 struct server *next; 286 }; 287 288 /* Main data structure */ 289 struct alias_link { 290 struct libalias *la; 291 /* Address and port information */ 292 struct in_addr src_addr; 293 struct in_addr dst_addr; 294 struct in_addr alias_addr; 295 struct in_addr proxy_addr; 296 u_short src_port; 297 u_short dst_port; 298 u_short alias_port; 299 u_short proxy_port; 300 struct server *server; 301 /* Type of link: TCP, UDP, ICMP, proto, frag */ 302 int link_type; 303 /* values for link_type */ 304 #define LINK_ICMP IPPROTO_ICMP 305 #define LINK_UDP IPPROTO_UDP 306 #define LINK_TCP IPPROTO_TCP 307 #define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 308 #define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 309 #define LINK_ADDR (IPPROTO_MAX + 3) 310 #define LINK_PPTP (IPPROTO_MAX + 4) 311 312 int flags; /* indicates special characteristics */ 313 int pflags; /* protocol-specific flags */ 314 /* flag bits */ 315 #define LINK_UNKNOWN_DEST_PORT 0x01 316 #define LINK_UNKNOWN_DEST_ADDR 0x02 317 #define LINK_PERMANENT 0x04 318 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 319 #define LINK_UNFIREWALLED 0x08 320 321 int timestamp; /* Time link was last accessed */ 322 int expire_time; /* Expire time for link */ 323 #ifndef NO_USE_SOCKETS 324 int sockfd; /* socket descriptor */ 325 #endif 326 /* Linked list of pointers for input and output lookup tables */ 327 LIST_ENTRY (alias_link) list_out; 328 LIST_ENTRY (alias_link) list_in; 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 IncrementalCleanup() - look for stale links in a single chain 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 IncrementalCleanup(struct libalias *); 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; 808 int i; 809 810 LIBALIAS_LOCK_ASSERT(la); 811 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) { 812 lnk = LIST_FIRST(&la->linkTableOut[i]); 813 while (lnk != NULL) { 814 struct alias_link *link_next = LIST_NEXT(lnk, list_out); 815 DeleteLink(lnk); 816 lnk = link_next; 817 } 818 } 819 820 la->cleanupIndex = 0; 821 } 822 823 static void 824 IncrementalCleanup(struct libalias *la) 825 { 826 struct alias_link *lnk, *lnk_tmp; 827 828 LIBALIAS_LOCK_ASSERT(la); 829 LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++], 830 list_out, lnk_tmp) { 831 if (la->timeStamp - lnk->timestamp > lnk->expire_time) 832 DeleteLink(lnk); 833 } 834 835 if (la->cleanupIndex == LINK_TABLE_OUT_SIZE) 836 la->cleanupIndex = 0; 837 } 838 839 static void 840 DeleteLink(struct alias_link *lnk) 841 { 842 struct libalias *la = lnk->la; 843 844 LIBALIAS_LOCK_ASSERT(la); 845 /* Don't do anything if the link is marked permanent */ 846 if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT) 847 return; 848 849 #ifndef NO_FW_PUNCH 850 /* Delete associated firewall hole, if any */ 851 ClearFWHole(lnk); 852 #endif 853 854 /* Free memory allocated for LSNAT server pool */ 855 if (lnk->server != NULL) { 856 struct server *head, *curr, *next; 857 858 head = curr = lnk->server; 859 do { 860 next = curr->next; 861 free(curr); 862 } while ((curr = next) != head); 863 } 864 /* Adjust output table pointers */ 865 LIST_REMOVE(lnk, list_out); 866 867 /* Adjust input table pointers */ 868 LIST_REMOVE(lnk, list_in); 869 #ifndef NO_USE_SOCKETS 870 /* Close socket, if one has been allocated */ 871 if (lnk->sockfd != -1) { 872 la->sockCount--; 873 close(lnk->sockfd); 874 } 875 #endif 876 /* Link-type dependent cleanup */ 877 switch (lnk->link_type) { 878 case LINK_ICMP: 879 la->icmpLinkCount--; 880 break; 881 case LINK_UDP: 882 la->udpLinkCount--; 883 break; 884 case LINK_TCP: 885 la->tcpLinkCount--; 886 free(lnk->data.tcp); 887 break; 888 case LINK_PPTP: 889 la->pptpLinkCount--; 890 break; 891 case LINK_FRAGMENT_ID: 892 la->fragmentIdLinkCount--; 893 break; 894 case LINK_FRAGMENT_PTR: 895 la->fragmentPtrLinkCount--; 896 if (lnk->data.frag_ptr != NULL) 897 free(lnk->data.frag_ptr); 898 break; 899 case LINK_ADDR: 900 break; 901 default: 902 la->protoLinkCount--; 903 break; 904 } 905 906 /* Free memory */ 907 free(lnk); 908 909 /* Write statistics, if logging enabled */ 910 if (la->packetAliasMode & PKT_ALIAS_LOG) { 911 ShowAliasStats(la); 912 } 913 } 914 915 struct alias_link * 916 AddLink(struct libalias *la, struct in_addr src_addr, struct in_addr dst_addr, 917 struct in_addr alias_addr, u_short src_port, u_short dst_port, 918 int alias_port_param, int link_type) 919 { 920 u_int start_point; 921 struct alias_link *lnk; 922 923 LIBALIAS_LOCK_ASSERT(la); 924 lnk = malloc(sizeof(struct alias_link)); 925 if (lnk != NULL) { 926 /* Basic initialization */ 927 lnk->la = la; 928 lnk->src_addr = src_addr; 929 lnk->dst_addr = dst_addr; 930 lnk->alias_addr = alias_addr; 931 lnk->proxy_addr.s_addr = INADDR_ANY; 932 lnk->src_port = src_port; 933 lnk->dst_port = dst_port; 934 lnk->proxy_port = 0; 935 lnk->server = NULL; 936 lnk->link_type = link_type; 937 #ifndef NO_USE_SOCKETS 938 lnk->sockfd = -1; 939 #endif 940 lnk->flags = 0; 941 lnk->pflags = 0; 942 lnk->timestamp = la->timeStamp; 943 944 /* Expiration time */ 945 switch (link_type) { 946 case LINK_ICMP: 947 lnk->expire_time = ICMP_EXPIRE_TIME; 948 break; 949 case LINK_UDP: 950 lnk->expire_time = UDP_EXPIRE_TIME; 951 break; 952 case LINK_TCP: 953 lnk->expire_time = TCP_EXPIRE_INITIAL; 954 break; 955 case LINK_PPTP: 956 lnk->flags |= LINK_PERMANENT; /* no timeout. */ 957 break; 958 case LINK_FRAGMENT_ID: 959 lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME; 960 break; 961 case LINK_FRAGMENT_PTR: 962 lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 963 break; 964 case LINK_ADDR: 965 break; 966 default: 967 lnk->expire_time = PROTO_EXPIRE_TIME; 968 break; 969 } 970 971 /* Determine alias flags */ 972 if (dst_addr.s_addr == INADDR_ANY) 973 lnk->flags |= LINK_UNKNOWN_DEST_ADDR; 974 if (dst_port == 0) 975 lnk->flags |= LINK_UNKNOWN_DEST_PORT; 976 977 /* Determine alias port */ 978 if (GetNewPort(la, lnk, alias_port_param) != 0) { 979 free(lnk); 980 return (NULL); 981 } 982 /* Link-type dependent initialization */ 983 switch (link_type) { 984 struct tcp_dat *aux_tcp; 985 986 case LINK_ICMP: 987 la->icmpLinkCount++; 988 break; 989 case LINK_UDP: 990 la->udpLinkCount++; 991 break; 992 case LINK_TCP: 993 aux_tcp = malloc(sizeof(struct tcp_dat)); 994 if (aux_tcp != NULL) { 995 int i; 996 997 la->tcpLinkCount++; 998 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 999 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 1000 aux_tcp->state.index = 0; 1001 aux_tcp->state.ack_modified = 0; 1002 for (i = 0; i < N_LINK_TCP_DATA; i++) 1003 aux_tcp->ack[i].active = 0; 1004 aux_tcp->fwhole = -1; 1005 lnk->data.tcp = aux_tcp; 1006 } else { 1007 #ifdef LIBALIAS_DEBUG 1008 fprintf(stderr, "PacketAlias/AddLink: "); 1009 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 1010 #endif 1011 free(lnk); 1012 return (NULL); 1013 } 1014 break; 1015 case LINK_PPTP: 1016 la->pptpLinkCount++; 1017 break; 1018 case LINK_FRAGMENT_ID: 1019 la->fragmentIdLinkCount++; 1020 break; 1021 case LINK_FRAGMENT_PTR: 1022 la->fragmentPtrLinkCount++; 1023 break; 1024 case LINK_ADDR: 1025 break; 1026 default: 1027 la->protoLinkCount++; 1028 break; 1029 } 1030 1031 /* Set up pointers for output lookup table */ 1032 start_point = StartPointOut(src_addr, dst_addr, 1033 src_port, dst_port, link_type); 1034 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out); 1035 1036 /* Set up pointers for input lookup table */ 1037 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type); 1038 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in); 1039 } else { 1040 #ifdef LIBALIAS_DEBUG 1041 fprintf(stderr, "PacketAlias/AddLink(): "); 1042 fprintf(stderr, "malloc() call failed.\n"); 1043 #endif 1044 } 1045 if (la->packetAliasMode & PKT_ALIAS_LOG) { 1046 ShowAliasStats(la); 1047 } 1048 return (lnk); 1049 } 1050 1051 /* 1052 * If alias_port_param is less than zero, alias port will be automatically 1053 * chosen. If greater than zero, equal to alias port 1054 */ 1055 static struct alias_link * 1056 ReLink(struct alias_link *old_lnk, 1057 struct in_addr src_addr, 1058 struct in_addr dst_addr, 1059 struct in_addr alias_addr, 1060 u_short src_port, 1061 u_short dst_port, 1062 int alias_port_param, 1063 int link_type) 1064 { 1065 struct alias_link *new_lnk; 1066 struct libalias *la = old_lnk->la; 1067 1068 LIBALIAS_LOCK_ASSERT(la); 1069 new_lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1070 src_port, dst_port, alias_port_param, 1071 link_type); 1072 #ifndef NO_FW_PUNCH 1073 if (new_lnk != NULL && 1074 old_lnk->link_type == LINK_TCP && 1075 old_lnk->data.tcp->fwhole > 0) { 1076 PunchFWHole(new_lnk); 1077 } 1078 #endif 1079 DeleteLink(old_lnk); 1080 return (new_lnk); 1081 } 1082 1083 static struct alias_link * 1084 _FindLinkOut(struct libalias *la, struct in_addr src_addr, 1085 struct in_addr dst_addr, 1086 u_short src_port, 1087 u_short dst_port, 1088 int link_type, 1089 int replace_partial_links) 1090 { 1091 u_int i; 1092 struct alias_link *lnk; 1093 1094 LIBALIAS_LOCK_ASSERT(la); 1095 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1096 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) { 1097 if (lnk->dst_addr.s_addr == dst_addr.s_addr && 1098 lnk->src_addr.s_addr == src_addr.s_addr && 1099 lnk->src_port == src_port && 1100 lnk->dst_port == dst_port && 1101 lnk->link_type == link_type && 1102 lnk->server == NULL) { 1103 lnk->timestamp = la->timeStamp; 1104 break; 1105 } 1106 } 1107 1108 /* Search for partially specified links. */ 1109 if (lnk == NULL && replace_partial_links) { 1110 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) { 1111 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0, 1112 link_type, 0); 1113 if (lnk == NULL) 1114 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 1115 dst_port, link_type, 0); 1116 } 1117 if (lnk == NULL && 1118 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) { 1119 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0, 1120 link_type, 0); 1121 } 1122 if (lnk != NULL) { 1123 lnk = ReLink(lnk, 1124 src_addr, dst_addr, lnk->alias_addr, 1125 src_port, dst_port, lnk->alias_port, 1126 link_type); 1127 } 1128 } 1129 return (lnk); 1130 } 1131 1132 static struct alias_link * 1133 FindLinkOut(struct libalias *la, struct in_addr src_addr, 1134 struct in_addr dst_addr, 1135 u_short src_port, 1136 u_short dst_port, 1137 int link_type, 1138 int replace_partial_links) 1139 { 1140 struct alias_link *lnk; 1141 1142 LIBALIAS_LOCK_ASSERT(la); 1143 lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, 1144 link_type, replace_partial_links); 1145 1146 if (lnk == NULL) { 1147 /* 1148 * The following allows permanent links to be specified as 1149 * using the default source address (i.e. device interface 1150 * address) without knowing in advance what that address 1151 * is. 1152 */ 1153 if (la->aliasAddress.s_addr != INADDR_ANY && 1154 src_addr.s_addr == la->aliasAddress.s_addr) { 1155 lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port, 1156 link_type, replace_partial_links); 1157 } 1158 } 1159 return (lnk); 1160 } 1161 1162 static struct alias_link * 1163 _FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1164 struct in_addr alias_addr, 1165 u_short dst_port, 1166 u_short alias_port, 1167 int link_type, 1168 int replace_partial_links) 1169 { 1170 int flags_in; 1171 u_int start_point; 1172 struct alias_link *lnk; 1173 struct alias_link *lnk_fully_specified; 1174 struct alias_link *lnk_unknown_all; 1175 struct alias_link *lnk_unknown_dst_addr; 1176 struct alias_link *lnk_unknown_dst_port; 1177 1178 LIBALIAS_LOCK_ASSERT(la); 1179 /* Initialize pointers */ 1180 lnk_fully_specified = NULL; 1181 lnk_unknown_all = NULL; 1182 lnk_unknown_dst_addr = NULL; 1183 lnk_unknown_dst_port = NULL; 1184 1185 /* If either the dest addr or port is unknown, the search 1186 * loop will have to know about this. */ 1187 flags_in = 0; 1188 if (dst_addr.s_addr == INADDR_ANY) 1189 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1190 if (dst_port == 0) 1191 flags_in |= LINK_UNKNOWN_DEST_PORT; 1192 1193 /* Search loop */ 1194 start_point = StartPointIn(alias_addr, alias_port, link_type); 1195 LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) { 1196 int flags; 1197 1198 flags = flags_in | lnk->flags; 1199 if (!(flags & LINK_PARTIALLY_SPECIFIED)) { 1200 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1201 && lnk->alias_port == alias_port 1202 && lnk->dst_addr.s_addr == dst_addr.s_addr 1203 && lnk->dst_port == dst_port 1204 && lnk->link_type == link_type) { 1205 lnk_fully_specified = lnk; 1206 break; 1207 } 1208 } else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1209 && (flags & LINK_UNKNOWN_DEST_PORT)) { 1210 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1211 && lnk->alias_port == alias_port 1212 && lnk->link_type == link_type) { 1213 if (lnk_unknown_all == NULL) 1214 lnk_unknown_all = lnk; 1215 } 1216 } else if (flags & LINK_UNKNOWN_DEST_ADDR) { 1217 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1218 && lnk->alias_port == alias_port 1219 && lnk->link_type == link_type 1220 && lnk->dst_port == dst_port) { 1221 if (lnk_unknown_dst_addr == NULL) 1222 lnk_unknown_dst_addr = lnk; 1223 } 1224 } else if (flags & LINK_UNKNOWN_DEST_PORT) { 1225 if (lnk->alias_addr.s_addr == alias_addr.s_addr 1226 && lnk->alias_port == alias_port 1227 && lnk->link_type == link_type 1228 && lnk->dst_addr.s_addr == dst_addr.s_addr) { 1229 if (lnk_unknown_dst_port == NULL) 1230 lnk_unknown_dst_port = lnk; 1231 } 1232 } 1233 } 1234 1235 if (lnk_fully_specified != NULL) { 1236 lnk_fully_specified->timestamp = la->timeStamp; 1237 lnk = lnk_fully_specified; 1238 } else if (lnk_unknown_dst_port != NULL) 1239 lnk = lnk_unknown_dst_port; 1240 else if (lnk_unknown_dst_addr != NULL) 1241 lnk = lnk_unknown_dst_addr; 1242 else if (lnk_unknown_all != NULL) 1243 lnk = lnk_unknown_all; 1244 else 1245 return (NULL); 1246 1247 if (replace_partial_links && 1248 (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) { 1249 struct in_addr src_addr; 1250 u_short src_port; 1251 1252 if (lnk->server != NULL) { /* LSNAT link */ 1253 src_addr = lnk->server->addr; 1254 src_port = lnk->server->port; 1255 lnk->server = lnk->server->next; 1256 } else { 1257 src_addr = lnk->src_addr; 1258 src_port = lnk->src_port; 1259 } 1260 1261 if (link_type == LINK_SCTP) { 1262 lnk->src_addr = src_addr; 1263 lnk->src_port = src_port; 1264 return (lnk); 1265 } 1266 lnk = ReLink(lnk, 1267 src_addr, dst_addr, alias_addr, 1268 src_port, dst_port, alias_port, 1269 link_type); 1270 } 1271 return (lnk); 1272 } 1273 1274 static struct alias_link * 1275 FindLinkIn(struct libalias *la, struct in_addr dst_addr, 1276 struct in_addr alias_addr, 1277 u_short dst_port, 1278 u_short alias_port, 1279 int link_type, 1280 int replace_partial_links) 1281 { 1282 struct alias_link *lnk; 1283 1284 LIBALIAS_LOCK_ASSERT(la); 1285 lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port, 1286 link_type, replace_partial_links); 1287 1288 if (lnk == NULL) { 1289 /* 1290 * The following allows permanent links to be specified as 1291 * using the default aliasing address (i.e. device 1292 * interface address) without knowing in advance what that 1293 * address is. 1294 */ 1295 if (la->aliasAddress.s_addr != INADDR_ANY && 1296 alias_addr.s_addr == la->aliasAddress.s_addr) { 1297 lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port, 1298 link_type, replace_partial_links); 1299 } 1300 } 1301 return (lnk); 1302 } 1303 1304 /* External routines for finding/adding links 1305 1306 -- "external" means outside alias_db.c, but within alias*.c -- 1307 1308 FindIcmpIn(), FindIcmpOut() 1309 FindFragmentIn1(), FindFragmentIn2() 1310 AddFragmentPtrLink(), FindFragmentPtr() 1311 FindProtoIn(), FindProtoOut() 1312 FindUdpTcpIn(), FindUdpTcpOut() 1313 AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(), 1314 FindPptpOutByPeerCallId(), FindPptpInByPeerCallId() 1315 FindOriginalAddress(), FindAliasAddress() 1316 1317 (prototypes in alias_local.h) 1318 */ 1319 1320 struct alias_link * 1321 FindIcmpIn(struct libalias *la, struct in_addr dst_addr, 1322 struct in_addr alias_addr, 1323 u_short id_alias, 1324 int create) 1325 { 1326 struct alias_link *lnk; 1327 1328 LIBALIAS_LOCK_ASSERT(la); 1329 lnk = FindLinkIn(la, dst_addr, alias_addr, 1330 NO_DEST_PORT, id_alias, 1331 LINK_ICMP, 0); 1332 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1333 struct in_addr target_addr; 1334 1335 target_addr = FindOriginalAddress(la, alias_addr); 1336 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1337 id_alias, NO_DEST_PORT, id_alias, 1338 LINK_ICMP); 1339 } 1340 return (lnk); 1341 } 1342 1343 struct alias_link * 1344 FindIcmpOut(struct libalias *la, struct in_addr src_addr, 1345 struct in_addr dst_addr, 1346 u_short id, 1347 int create) 1348 { 1349 struct alias_link *lnk; 1350 1351 LIBALIAS_LOCK_ASSERT(la); 1352 lnk = FindLinkOut(la, src_addr, dst_addr, 1353 id, NO_DEST_PORT, 1354 LINK_ICMP, 0); 1355 if (lnk == NULL && create) { 1356 struct in_addr alias_addr; 1357 1358 alias_addr = FindAliasAddress(la, src_addr); 1359 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1360 id, NO_DEST_PORT, GET_ALIAS_ID, 1361 LINK_ICMP); 1362 } 1363 return (lnk); 1364 } 1365 1366 struct alias_link * 1367 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr, 1368 struct in_addr alias_addr, 1369 u_short ip_id) 1370 { 1371 struct alias_link *lnk; 1372 1373 LIBALIAS_LOCK_ASSERT(la); 1374 lnk = FindLinkIn(la, dst_addr, alias_addr, 1375 NO_DEST_PORT, ip_id, 1376 LINK_FRAGMENT_ID, 0); 1377 1378 if (lnk == NULL) { 1379 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr, 1380 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1381 LINK_FRAGMENT_ID); 1382 } 1383 return (lnk); 1384 } 1385 1386 /* Doesn't add a link if one is not found. */ 1387 struct alias_link * 1388 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr, 1389 struct in_addr alias_addr, u_short ip_id) 1390 { 1391 LIBALIAS_LOCK_ASSERT(la); 1392 return FindLinkIn(la, dst_addr, alias_addr, 1393 NO_DEST_PORT, ip_id, 1394 LINK_FRAGMENT_ID, 0); 1395 } 1396 1397 struct alias_link * 1398 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr, 1399 u_short ip_id) 1400 { 1401 LIBALIAS_LOCK_ASSERT(la); 1402 return AddLink(la, la->nullAddress, dst_addr, la->nullAddress, 1403 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1404 LINK_FRAGMENT_PTR); 1405 } 1406 1407 struct alias_link * 1408 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr, 1409 u_short ip_id) 1410 { 1411 LIBALIAS_LOCK_ASSERT(la); 1412 return FindLinkIn(la, dst_addr, la->nullAddress, 1413 NO_DEST_PORT, ip_id, 1414 LINK_FRAGMENT_PTR, 0); 1415 } 1416 1417 struct alias_link * 1418 FindProtoIn(struct libalias *la, struct in_addr dst_addr, 1419 struct in_addr alias_addr, 1420 u_char proto) 1421 { 1422 struct alias_link *lnk; 1423 1424 LIBALIAS_LOCK_ASSERT(la); 1425 lnk = FindLinkIn(la, dst_addr, alias_addr, 1426 NO_DEST_PORT, 0, 1427 proto, 1); 1428 1429 if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1430 struct in_addr target_addr; 1431 1432 target_addr = FindOriginalAddress(la, alias_addr); 1433 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1434 NO_SRC_PORT, NO_DEST_PORT, 0, 1435 proto); 1436 } 1437 return (lnk); 1438 } 1439 1440 struct alias_link * 1441 FindProtoOut(struct libalias *la, struct in_addr src_addr, 1442 struct in_addr dst_addr, 1443 u_char proto) 1444 { 1445 struct alias_link *lnk; 1446 1447 LIBALIAS_LOCK_ASSERT(la); 1448 lnk = FindLinkOut(la, src_addr, dst_addr, 1449 NO_SRC_PORT, NO_DEST_PORT, 1450 proto, 1); 1451 1452 if (lnk == NULL) { 1453 struct in_addr alias_addr; 1454 1455 alias_addr = FindAliasAddress(la, src_addr); 1456 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1457 NO_SRC_PORT, NO_DEST_PORT, 0, 1458 proto); 1459 } 1460 return (lnk); 1461 } 1462 1463 struct alias_link * 1464 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr, 1465 struct in_addr alias_addr, 1466 u_short dst_port, 1467 u_short alias_port, 1468 u_char proto, 1469 int create) 1470 { 1471 int link_type; 1472 struct alias_link *lnk; 1473 1474 LIBALIAS_LOCK_ASSERT(la); 1475 switch (proto) { 1476 case IPPROTO_UDP: 1477 link_type = LINK_UDP; 1478 break; 1479 case IPPROTO_TCP: 1480 link_type = LINK_TCP; 1481 break; 1482 default: 1483 return (NULL); 1484 break; 1485 } 1486 1487 lnk = FindLinkIn(la, dst_addr, alias_addr, 1488 dst_port, alias_port, 1489 link_type, create); 1490 1491 if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) { 1492 struct in_addr target_addr; 1493 1494 target_addr = FindOriginalAddress(la, alias_addr); 1495 lnk = AddLink(la, target_addr, dst_addr, alias_addr, 1496 alias_port, dst_port, alias_port, 1497 link_type); 1498 } 1499 return (lnk); 1500 } 1501 1502 struct alias_link * 1503 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr, 1504 struct in_addr dst_addr, 1505 u_short src_port, 1506 u_short dst_port, 1507 u_char proto, 1508 int create) 1509 { 1510 int link_type; 1511 struct alias_link *lnk; 1512 1513 LIBALIAS_LOCK_ASSERT(la); 1514 switch (proto) { 1515 case IPPROTO_UDP: 1516 link_type = LINK_UDP; 1517 break; 1518 case IPPROTO_TCP: 1519 link_type = LINK_TCP; 1520 break; 1521 default: 1522 return (NULL); 1523 break; 1524 } 1525 1526 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create); 1527 1528 if (lnk == NULL && create) { 1529 struct in_addr alias_addr; 1530 1531 alias_addr = FindAliasAddress(la, src_addr); 1532 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1533 src_port, dst_port, GET_ALIAS_PORT, 1534 link_type); 1535 } 1536 return (lnk); 1537 } 1538 1539 struct alias_link * 1540 AddPptp(struct libalias *la, struct in_addr src_addr, 1541 struct in_addr dst_addr, 1542 struct in_addr alias_addr, 1543 u_int16_t src_call_id) 1544 { 1545 struct alias_link *lnk; 1546 1547 LIBALIAS_LOCK_ASSERT(la); 1548 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1549 src_call_id, 0, GET_ALIAS_PORT, 1550 LINK_PPTP); 1551 1552 return (lnk); 1553 } 1554 1555 struct alias_link * 1556 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr, 1557 struct in_addr dst_addr, 1558 u_int16_t src_call_id) 1559 { 1560 u_int i; 1561 struct alias_link *lnk; 1562 1563 LIBALIAS_LOCK_ASSERT(la); 1564 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1565 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1566 if (lnk->link_type == LINK_PPTP && 1567 lnk->src_addr.s_addr == src_addr.s_addr && 1568 lnk->dst_addr.s_addr == dst_addr.s_addr && 1569 lnk->src_port == src_call_id) 1570 break; 1571 1572 return (lnk); 1573 } 1574 1575 struct alias_link * 1576 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr, 1577 struct in_addr dst_addr, 1578 u_int16_t dst_call_id) 1579 { 1580 u_int i; 1581 struct alias_link *lnk; 1582 1583 LIBALIAS_LOCK_ASSERT(la); 1584 i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP); 1585 LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) 1586 if (lnk->link_type == LINK_PPTP && 1587 lnk->src_addr.s_addr == src_addr.s_addr && 1588 lnk->dst_addr.s_addr == dst_addr.s_addr && 1589 lnk->dst_port == dst_call_id) 1590 break; 1591 1592 return (lnk); 1593 } 1594 1595 struct alias_link * 1596 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr, 1597 struct in_addr alias_addr, 1598 u_int16_t dst_call_id) 1599 { 1600 u_int i; 1601 struct alias_link *lnk; 1602 1603 LIBALIAS_LOCK_ASSERT(la); 1604 i = StartPointIn(alias_addr, 0, LINK_PPTP); 1605 LIST_FOREACH(lnk, &la->linkTableIn[i], list_in) 1606 if (lnk->link_type == LINK_PPTP && 1607 lnk->dst_addr.s_addr == dst_addr.s_addr && 1608 lnk->alias_addr.s_addr == alias_addr.s_addr && 1609 lnk->dst_port == dst_call_id) 1610 break; 1611 1612 return (lnk); 1613 } 1614 1615 struct alias_link * 1616 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr, 1617 struct in_addr alias_addr, 1618 u_int16_t alias_call_id) 1619 { 1620 struct alias_link *lnk; 1621 1622 LIBALIAS_LOCK_ASSERT(la); 1623 lnk = FindLinkIn(la, dst_addr, alias_addr, 1624 0 /* any */ , alias_call_id, 1625 LINK_PPTP, 0); 1626 1627 return (lnk); 1628 } 1629 1630 struct alias_link * 1631 FindRtspOut(struct libalias *la, struct in_addr src_addr, 1632 struct in_addr dst_addr, 1633 u_short src_port, 1634 u_short alias_port, 1635 u_char proto) 1636 { 1637 int link_type; 1638 struct alias_link *lnk; 1639 1640 LIBALIAS_LOCK_ASSERT(la); 1641 switch (proto) { 1642 case IPPROTO_UDP: 1643 link_type = LINK_UDP; 1644 break; 1645 case IPPROTO_TCP: 1646 link_type = LINK_TCP; 1647 break; 1648 default: 1649 return (NULL); 1650 break; 1651 } 1652 1653 lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1); 1654 1655 if (lnk == NULL) { 1656 struct in_addr alias_addr; 1657 1658 alias_addr = FindAliasAddress(la, src_addr); 1659 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 1660 src_port, 0, alias_port, 1661 link_type); 1662 } 1663 return (lnk); 1664 } 1665 1666 struct in_addr 1667 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr) 1668 { 1669 struct alias_link *lnk; 1670 1671 LIBALIAS_LOCK_ASSERT(la); 1672 lnk = FindLinkIn(la, la->nullAddress, alias_addr, 1673 0, 0, LINK_ADDR, 0); 1674 if (lnk == NULL) { 1675 la->newDefaultLink = 1; 1676 if (la->targetAddress.s_addr == INADDR_ANY) 1677 return (alias_addr); 1678 else if (la->targetAddress.s_addr == INADDR_NONE) 1679 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1680 la->aliasAddress : alias_addr; 1681 else 1682 return (la->targetAddress); 1683 } else { 1684 if (lnk->server != NULL) { /* LSNAT link */ 1685 struct in_addr src_addr; 1686 1687 src_addr = lnk->server->addr; 1688 lnk->server = lnk->server->next; 1689 return (src_addr); 1690 } else if (lnk->src_addr.s_addr == INADDR_ANY) 1691 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1692 la->aliasAddress : alias_addr; 1693 else 1694 return (lnk->src_addr); 1695 } 1696 } 1697 1698 struct in_addr 1699 FindAliasAddress(struct libalias *la, struct in_addr original_addr) 1700 { 1701 struct alias_link *lnk; 1702 1703 LIBALIAS_LOCK_ASSERT(la); 1704 lnk = FindLinkOut(la, original_addr, la->nullAddress, 1705 0, 0, LINK_ADDR, 0); 1706 if (lnk == NULL) { 1707 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1708 la->aliasAddress : original_addr; 1709 } else { 1710 if (lnk->alias_addr.s_addr == INADDR_ANY) 1711 return (la->aliasAddress.s_addr != INADDR_ANY) ? 1712 la->aliasAddress : original_addr; 1713 else 1714 return (lnk->alias_addr); 1715 } 1716 } 1717 1718 /* External routines for getting or changing link data 1719 (external to alias_db.c, but internal to alias*.c) 1720 1721 SetFragmentData(), GetFragmentData() 1722 SetFragmentPtr(), GetFragmentPtr() 1723 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1724 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1725 GetOriginalPort(), GetAliasPort() 1726 SetAckModified(), GetAckModified() 1727 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1728 SetProtocolFlags(), GetProtocolFlags() 1729 SetDestCallId() 1730 */ 1731 1732 void 1733 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr) 1734 { 1735 lnk->data.frag_addr = src_addr; 1736 } 1737 1738 void 1739 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr) 1740 { 1741 *src_addr = lnk->data.frag_addr; 1742 } 1743 1744 void 1745 SetFragmentPtr(struct alias_link *lnk, void *fptr) 1746 { 1747 lnk->data.frag_ptr = fptr; 1748 } 1749 1750 void 1751 GetFragmentPtr(struct alias_link *lnk, void **fptr) 1752 { 1753 *fptr = lnk->data.frag_ptr; 1754 } 1755 1756 void 1757 SetStateIn(struct alias_link *lnk, int state) 1758 { 1759 /* TCP input state */ 1760 switch (state) { 1761 case ALIAS_TCP_STATE_DISCONNECTED: 1762 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1763 lnk->expire_time = TCP_EXPIRE_DEAD; 1764 else 1765 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1766 break; 1767 case ALIAS_TCP_STATE_CONNECTED: 1768 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1769 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1770 break; 1771 default: 1772 #ifdef _KERNEL 1773 panic("libalias:SetStateIn() unknown state"); 1774 #else 1775 abort(); 1776 #endif 1777 } 1778 lnk->data.tcp->state.in = state; 1779 } 1780 1781 void 1782 SetStateOut(struct alias_link *lnk, int state) 1783 { 1784 /* TCP output state */ 1785 switch (state) { 1786 case ALIAS_TCP_STATE_DISCONNECTED: 1787 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1788 lnk->expire_time = TCP_EXPIRE_DEAD; 1789 else 1790 lnk->expire_time = TCP_EXPIRE_SINGLEDEAD; 1791 break; 1792 case ALIAS_TCP_STATE_CONNECTED: 1793 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1794 lnk->expire_time = TCP_EXPIRE_CONNECTED; 1795 break; 1796 default: 1797 #ifdef _KERNEL 1798 panic("libalias:SetStateOut() unknown state"); 1799 #else 1800 abort(); 1801 #endif 1802 } 1803 lnk->data.tcp->state.out = state; 1804 } 1805 1806 int 1807 GetStateIn(struct alias_link *lnk) 1808 { 1809 /* TCP input state */ 1810 return (lnk->data.tcp->state.in); 1811 } 1812 1813 int 1814 GetStateOut(struct alias_link *lnk) 1815 { 1816 /* TCP output state */ 1817 return (lnk->data.tcp->state.out); 1818 } 1819 1820 struct in_addr 1821 GetOriginalAddress(struct alias_link *lnk) 1822 { 1823 if (lnk->src_addr.s_addr == INADDR_ANY) 1824 return (lnk->la->aliasAddress); 1825 else 1826 return (lnk->src_addr); 1827 } 1828 1829 struct in_addr 1830 GetDestAddress(struct alias_link *lnk) 1831 { 1832 return (lnk->dst_addr); 1833 } 1834 1835 struct in_addr 1836 GetAliasAddress(struct alias_link *lnk) 1837 { 1838 if (lnk->alias_addr.s_addr == INADDR_ANY) 1839 return (lnk->la->aliasAddress); 1840 else 1841 return (lnk->alias_addr); 1842 } 1843 1844 struct in_addr 1845 GetDefaultAliasAddress(struct libalias *la) 1846 { 1847 LIBALIAS_LOCK_ASSERT(la); 1848 return (la->aliasAddress); 1849 } 1850 1851 void 1852 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr) 1853 { 1854 LIBALIAS_LOCK_ASSERT(la); 1855 la->aliasAddress = alias_addr; 1856 } 1857 1858 u_short 1859 GetOriginalPort(struct alias_link *lnk) 1860 { 1861 return (lnk->src_port); 1862 } 1863 1864 u_short 1865 GetAliasPort(struct alias_link *lnk) 1866 { 1867 return (lnk->alias_port); 1868 } 1869 1870 #ifndef NO_FW_PUNCH 1871 static u_short 1872 GetDestPort(struct alias_link *lnk) 1873 { 1874 return (lnk->dst_port); 1875 } 1876 1877 #endif 1878 1879 /* Indicate that ACK numbers have been modified in a TCP connection */ 1880 void 1881 SetAckModified(struct alias_link *lnk) 1882 { 1883 lnk->data.tcp->state.ack_modified = 1; 1884 } 1885 1886 struct in_addr 1887 GetProxyAddress(struct alias_link *lnk) 1888 { 1889 return (lnk->proxy_addr); 1890 } 1891 1892 void 1893 SetProxyAddress(struct alias_link *lnk, struct in_addr addr) 1894 { 1895 lnk->proxy_addr = addr; 1896 } 1897 1898 u_short 1899 GetProxyPort(struct alias_link *lnk) 1900 { 1901 return (lnk->proxy_port); 1902 } 1903 1904 void 1905 SetProxyPort(struct alias_link *lnk, u_short port) 1906 { 1907 lnk->proxy_port = port; 1908 } 1909 1910 /* See if ACK numbers have been modified */ 1911 int 1912 GetAckModified(struct alias_link *lnk) 1913 { 1914 return (lnk->data.tcp->state.ack_modified); 1915 } 1916 1917 /* 1918 * Find out how much the ACK number has been altered for an 1919 * incoming TCP packet. To do this, a circular list of ACK 1920 * numbers where the TCP packet size was altered is searched. 1921 */ 1922 // XXX ip free 1923 int 1924 GetDeltaAckIn(u_long ack, struct alias_link *lnk) 1925 { 1926 int i, j; 1927 int delta, ack_diff_min; 1928 1929 delta = 0; 1930 ack_diff_min = -1; 1931 i = lnk->data.tcp->state.index; 1932 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1933 struct ack_data_record x; 1934 1935 if (i == 0) 1936 i = N_LINK_TCP_DATA; 1937 i--; 1938 x = lnk->data.tcp->ack[i]; 1939 if (x.active == 1) { 1940 int ack_diff; 1941 1942 ack_diff = SeqDiff(x.ack_new, ack); 1943 if (ack_diff >= 0) { 1944 if (ack_diff_min >= 0) { 1945 if (ack_diff < ack_diff_min) { 1946 delta = x.delta; 1947 ack_diff_min = ack_diff; 1948 } 1949 } else { 1950 delta = x.delta; 1951 ack_diff_min = ack_diff; 1952 } 1953 } 1954 } 1955 } 1956 return (delta); 1957 } 1958 1959 /* 1960 * Find out how much the sequence number has been altered for an 1961 * outgoing TCP packet. To do this, a circular list of ACK numbers 1962 * where the TCP packet size was altered is searched. 1963 */ 1964 // XXX ip free 1965 int 1966 GetDeltaSeqOut(u_long seq, struct alias_link *lnk) 1967 { 1968 int i, j; 1969 int delta, seq_diff_min; 1970 1971 delta = 0; 1972 seq_diff_min = -1; 1973 i = lnk->data.tcp->state.index; 1974 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1975 struct ack_data_record x; 1976 1977 if (i == 0) 1978 i = N_LINK_TCP_DATA; 1979 i--; 1980 x = lnk->data.tcp->ack[i]; 1981 if (x.active == 1) { 1982 int seq_diff; 1983 1984 seq_diff = SeqDiff(x.ack_old, seq); 1985 if (seq_diff >= 0) { 1986 if (seq_diff_min >= 0) { 1987 if (seq_diff < seq_diff_min) { 1988 delta = x.delta; 1989 seq_diff_min = seq_diff; 1990 } 1991 } else { 1992 delta = x.delta; 1993 seq_diff_min = seq_diff; 1994 } 1995 } 1996 } 1997 } 1998 return (delta); 1999 } 2000 2001 /* 2002 * When a TCP packet has been altered in length, save this 2003 * information in a circular list. If enough packets have been 2004 * altered, then this list will begin to overwrite itself. 2005 */ 2006 // XXX ip free 2007 void 2008 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len, 2009 u_long th_seq, u_int th_off) 2010 { 2011 struct ack_data_record x; 2012 int hlen, tlen, dlen; 2013 int i; 2014 2015 hlen = (ip_hl + th_off) << 2; 2016 tlen = ntohs(ip_len); 2017 dlen = tlen - hlen; 2018 2019 x.ack_old = htonl(ntohl(th_seq) + dlen); 2020 x.ack_new = htonl(ntohl(th_seq) + dlen + delta); 2021 x.delta = delta; 2022 x.active = 1; 2023 2024 i = lnk->data.tcp->state.index; 2025 lnk->data.tcp->ack[i] = x; 2026 2027 i++; 2028 if (i == N_LINK_TCP_DATA) 2029 lnk->data.tcp->state.index = 0; 2030 else 2031 lnk->data.tcp->state.index = i; 2032 } 2033 2034 void 2035 SetExpire(struct alias_link *lnk, int expire) 2036 { 2037 if (expire == 0) { 2038 lnk->flags &= ~LINK_PERMANENT; 2039 DeleteLink(lnk); 2040 } else if (expire == -1) { 2041 lnk->flags |= LINK_PERMANENT; 2042 } else if (expire > 0) { 2043 lnk->expire_time = expire; 2044 } else { 2045 #ifdef LIBALIAS_DEBUG 2046 fprintf(stderr, "PacketAlias/SetExpire(): "); 2047 fprintf(stderr, "error in expire parameter\n"); 2048 #endif 2049 } 2050 } 2051 2052 void 2053 ClearCheckNewLink(struct libalias *la) 2054 { 2055 LIBALIAS_LOCK_ASSERT(la); 2056 la->newDefaultLink = 0; 2057 } 2058 2059 void 2060 SetProtocolFlags(struct alias_link *lnk, int pflags) 2061 { 2062 lnk->pflags = pflags; 2063 } 2064 2065 int 2066 GetProtocolFlags(struct alias_link *lnk) 2067 { 2068 return (lnk->pflags); 2069 } 2070 2071 void 2072 SetDestCallId(struct alias_link *lnk, u_int16_t cid) 2073 { 2074 struct libalias *la = lnk->la; 2075 2076 LIBALIAS_LOCK_ASSERT(la); 2077 la->deleteAllLinks = 1; 2078 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, 2079 lnk->src_port, cid, lnk->alias_port, lnk->link_type); 2080 la->deleteAllLinks = 0; 2081 } 2082 2083 /* Miscellaneous Functions 2084 2085 HouseKeeping() 2086 InitPacketAliasLog() 2087 UninitPacketAliasLog() 2088 */ 2089 2090 /* 2091 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2092 is called to find and remove timed-out aliasing links. Logic exists 2093 to sweep through the entire table and linked list structure 2094 every 60 seconds. 2095 2096 (prototype in alias_local.h) 2097 */ 2098 2099 void 2100 HouseKeeping(struct libalias *la) 2101 { 2102 int i, n; 2103 #ifndef _KERNEL 2104 struct timeval tv; 2105 #endif 2106 2107 LIBALIAS_LOCK_ASSERT(la); 2108 /* 2109 * Save system time (seconds) in global variable timeStamp for use 2110 * by other functions. This is done so as not to unnecessarily 2111 * waste timeline by making system calls. 2112 */ 2113 #ifdef _KERNEL 2114 la->timeStamp = time_uptime; 2115 #else 2116 gettimeofday(&tv, NULL); 2117 la->timeStamp = tv.tv_sec; 2118 #endif 2119 2120 /* Compute number of spokes (output table link chains) to cover */ 2121 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime); 2122 n /= ALIAS_CLEANUP_INTERVAL_SECS; 2123 2124 /* Handle different cases */ 2125 if (n > 0) { 2126 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2127 n = ALIAS_CLEANUP_MAX_SPOKES; 2128 la->lastCleanupTime = la->timeStamp; 2129 for (i = 0; i < n; i++) 2130 IncrementalCleanup(la); 2131 } else if (n < 0) { 2132 #ifdef LIBALIAS_DEBUG 2133 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2134 fprintf(stderr, "something unexpected in time values\n"); 2135 #endif 2136 la->lastCleanupTime = la->timeStamp; 2137 } 2138 } 2139 2140 /* Init the log file and enable logging */ 2141 static int 2142 InitPacketAliasLog(struct libalias *la) 2143 { 2144 LIBALIAS_LOCK_ASSERT(la); 2145 if (~la->packetAliasMode & PKT_ALIAS_LOG) { 2146 #ifdef _KERNEL 2147 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE))) 2148 ; 2149 #else 2150 if ((la->logDesc = fopen("/var/log/alias.log", "w"))) 2151 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2152 #endif 2153 else 2154 return (ENOMEM); /* log initialization failed */ 2155 la->packetAliasMode |= PKT_ALIAS_LOG; 2156 } 2157 2158 return (1); 2159 } 2160 2161 /* Close the log-file and disable logging. */ 2162 static void 2163 UninitPacketAliasLog(struct libalias *la) 2164 { 2165 LIBALIAS_LOCK_ASSERT(la); 2166 if (la->logDesc) { 2167 #ifdef _KERNEL 2168 free(la->logDesc); 2169 #else 2170 fclose(la->logDesc); 2171 #endif 2172 la->logDesc = NULL; 2173 } 2174 la->packetAliasMode &= ~PKT_ALIAS_LOG; 2175 } 2176 2177 /* Outside world interfaces 2178 2179 -- "outside world" means other than alias*.c routines -- 2180 2181 PacketAliasRedirectPort() 2182 PacketAliasAddServer() 2183 PacketAliasRedirectProto() 2184 PacketAliasRedirectAddr() 2185 PacketAliasRedirectDynamic() 2186 PacketAliasRedirectDelete() 2187 PacketAliasSetAddress() 2188 PacketAliasInit() 2189 PacketAliasUninit() 2190 PacketAliasSetMode() 2191 2192 (prototypes in alias.h) 2193 */ 2194 2195 /* Redirection from a specific public addr:port to a 2196 private addr:port */ 2197 struct alias_link * 2198 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2199 struct in_addr dst_addr, u_short dst_port, 2200 struct in_addr alias_addr, u_short alias_port, 2201 u_char proto) 2202 { 2203 int link_type; 2204 struct alias_link *lnk; 2205 2206 LIBALIAS_LOCK(la); 2207 switch (proto) { 2208 case IPPROTO_UDP: 2209 link_type = LINK_UDP; 2210 break; 2211 case IPPROTO_TCP: 2212 link_type = LINK_TCP; 2213 break; 2214 case IPPROTO_SCTP: 2215 link_type = LINK_SCTP; 2216 break; 2217 default: 2218 #ifdef LIBALIAS_DEBUG 2219 fprintf(stderr, "PacketAliasRedirectPort(): "); 2220 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n"); 2221 #endif 2222 lnk = NULL; 2223 goto getout; 2224 } 2225 2226 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2227 src_port, dst_port, alias_port, 2228 link_type); 2229 2230 if (lnk != NULL) { 2231 lnk->flags |= LINK_PERMANENT; 2232 } 2233 #ifdef LIBALIAS_DEBUG 2234 else { 2235 fprintf(stderr, "PacketAliasRedirectPort(): " 2236 "call to AddLink() failed\n"); 2237 } 2238 #endif 2239 2240 getout: 2241 LIBALIAS_UNLOCK(la); 2242 return (lnk); 2243 } 2244 2245 /* Add server to the pool of servers */ 2246 int 2247 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 2248 { 2249 struct server *server; 2250 int res; 2251 2252 LIBALIAS_LOCK(la); 2253 (void)la; 2254 2255 server = malloc(sizeof(struct server)); 2256 2257 if (server != NULL) { 2258 struct server *head; 2259 2260 server->addr = addr; 2261 server->port = port; 2262 2263 head = lnk->server; 2264 if (head == NULL) 2265 server->next = server; 2266 else { 2267 struct server *s; 2268 2269 for (s = head; s->next != head; s = s->next) 2270 ; 2271 s->next = server; 2272 server->next = head; 2273 } 2274 lnk->server = server; 2275 res = 0; 2276 } else 2277 res = -1; 2278 2279 LIBALIAS_UNLOCK(la); 2280 return (res); 2281 } 2282 2283 /* Redirect packets of a given IP protocol from a specific 2284 public address to a private address */ 2285 struct alias_link * 2286 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2287 struct in_addr dst_addr, 2288 struct in_addr alias_addr, 2289 u_char proto) 2290 { 2291 struct alias_link *lnk; 2292 2293 LIBALIAS_LOCK(la); 2294 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2295 NO_SRC_PORT, NO_DEST_PORT, 0, 2296 proto); 2297 2298 if (lnk != NULL) { 2299 lnk->flags |= LINK_PERMANENT; 2300 } 2301 #ifdef LIBALIAS_DEBUG 2302 else { 2303 fprintf(stderr, "PacketAliasRedirectProto(): " 2304 "call to AddLink() failed\n"); 2305 } 2306 #endif 2307 2308 LIBALIAS_UNLOCK(la); 2309 return (lnk); 2310 } 2311 2312 /* Static address translation */ 2313 struct alias_link * 2314 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2315 struct in_addr alias_addr) 2316 { 2317 struct alias_link *lnk; 2318 2319 LIBALIAS_LOCK(la); 2320 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr, 2321 0, 0, 0, 2322 LINK_ADDR); 2323 2324 if (lnk != NULL) { 2325 lnk->flags |= LINK_PERMANENT; 2326 } 2327 #ifdef LIBALIAS_DEBUG 2328 else { 2329 fprintf(stderr, "PacketAliasRedirectAddr(): " 2330 "call to AddLink() failed\n"); 2331 } 2332 #endif 2333 2334 LIBALIAS_UNLOCK(la); 2335 return (lnk); 2336 } 2337 2338 /* Mark the aliasing link dynamic */ 2339 int 2340 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2341 { 2342 int res; 2343 2344 LIBALIAS_LOCK(la); 2345 (void)la; 2346 2347 if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2348 res = -1; 2349 else { 2350 lnk->flags &= ~LINK_PERMANENT; 2351 res = 0; 2352 } 2353 LIBALIAS_UNLOCK(la); 2354 return (res); 2355 } 2356 2357 /* This is a dangerous function to put in the API, 2358 because an invalid pointer can crash the program. */ 2359 void 2360 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 2361 { 2362 LIBALIAS_LOCK(la); 2363 la->deleteAllLinks = 1; 2364 DeleteLink(lnk); 2365 la->deleteAllLinks = 0; 2366 LIBALIAS_UNLOCK(la); 2367 } 2368 2369 void 2370 LibAliasSetAddress(struct libalias *la, struct in_addr addr) 2371 { 2372 LIBALIAS_LOCK(la); 2373 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2374 && la->aliasAddress.s_addr != addr.s_addr) 2375 CleanupAliasData(la); 2376 2377 la->aliasAddress = addr; 2378 LIBALIAS_UNLOCK(la); 2379 } 2380 2381 void 2382 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low, 2383 u_short port_high) 2384 { 2385 LIBALIAS_LOCK(la); 2386 la->aliasPortLower = port_low; 2387 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */ 2388 la->aliasPortLength = port_high - port_low + 1; 2389 LIBALIAS_UNLOCK(la); 2390 } 2391 2392 void 2393 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 2394 { 2395 LIBALIAS_LOCK(la); 2396 la->targetAddress = target_addr; 2397 LIBALIAS_UNLOCK(la); 2398 } 2399 2400 static void 2401 finishoff(void) 2402 { 2403 while (!LIST_EMPTY(&instancehead)) 2404 LibAliasUninit(LIST_FIRST(&instancehead)); 2405 } 2406 2407 struct libalias * 2408 LibAliasInit(struct libalias *la) 2409 { 2410 int i; 2411 #ifndef _KERNEL 2412 struct timeval tv; 2413 #endif 2414 2415 if (la == NULL) { 2416 #ifdef _KERNEL 2417 #undef malloc /* XXX: ugly */ 2418 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO); 2419 #else 2420 la = calloc(sizeof *la, 1); 2421 if (la == NULL) 2422 return (la); 2423 #endif 2424 2425 #ifndef _KERNEL 2426 /* kernel cleans up on module unload */ 2427 if (LIST_EMPTY(&instancehead)) 2428 atexit(finishoff); 2429 #endif 2430 LIST_INSERT_HEAD(&instancehead, la, instancelist); 2431 2432 #ifdef _KERNEL 2433 la->timeStamp = time_uptime; 2434 la->lastCleanupTime = time_uptime; 2435 #else 2436 gettimeofday(&tv, NULL); 2437 la->timeStamp = tv.tv_sec; 2438 la->lastCleanupTime = tv.tv_sec; 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 #ifdef _KERNEL 2446 AliasSctpInit(la); 2447 #endif 2448 LIBALIAS_LOCK_INIT(la); 2449 LIBALIAS_LOCK(la); 2450 } else { 2451 LIBALIAS_LOCK(la); 2452 la->deleteAllLinks = 1; 2453 CleanupAliasData(la); 2454 la->deleteAllLinks = 0; 2455 #ifdef _KERNEL 2456 AliasSctpTerm(la); 2457 AliasSctpInit(la); 2458 #endif 2459 } 2460 2461 la->aliasAddress.s_addr = INADDR_ANY; 2462 la->targetAddress.s_addr = INADDR_ANY; 2463 2464 la->icmpLinkCount = 0; 2465 la->udpLinkCount = 0; 2466 la->tcpLinkCount = 0; 2467 la->sctpLinkCount = 0; 2468 la->pptpLinkCount = 0; 2469 la->protoLinkCount = 0; 2470 la->fragmentIdLinkCount = 0; 2471 la->fragmentPtrLinkCount = 0; 2472 la->sockCount = 0; 2473 2474 la->cleanupIndex = 0; 2475 2476 la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2477 #ifndef NO_USE_SOCKETS 2478 | PKT_ALIAS_USE_SOCKETS 2479 #endif 2480 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2481 #ifndef NO_FW_PUNCH 2482 la->fireWallFD = -1; 2483 #endif 2484 #ifndef _KERNEL 2485 LibAliasRefreshModules(); 2486 #endif 2487 LIBALIAS_UNLOCK(la); 2488 return (la); 2489 } 2490 2491 void 2492 LibAliasUninit(struct libalias *la) 2493 { 2494 LIBALIAS_LOCK(la); 2495 #ifdef _KERNEL 2496 AliasSctpTerm(la); 2497 #endif 2498 la->deleteAllLinks = 1; 2499 CleanupAliasData(la); 2500 la->deleteAllLinks = 0; 2501 UninitPacketAliasLog(la); 2502 #ifndef NO_FW_PUNCH 2503 UninitPunchFW(la); 2504 #endif 2505 LIST_REMOVE(la, instancelist); 2506 LIBALIAS_UNLOCK(la); 2507 LIBALIAS_LOCK_DESTROY(la); 2508 free(la); 2509 } 2510 2511 /* Change mode for some operations */ 2512 unsigned int 2513 LibAliasSetMode( 2514 struct libalias *la, 2515 unsigned int flags, /* Which state to bring flags to */ 2516 unsigned int mask /* Mask of which flags to affect (use 0 to 2517 * do a probe for flag values) */ 2518 ) 2519 { 2520 int res = -1; 2521 2522 LIBALIAS_LOCK(la); 2523 if (flags & mask & PKT_ALIAS_LOG) { 2524 /* Enable logging */ 2525 if (InitPacketAliasLog(la) == ENOMEM) 2526 goto getout; 2527 } else if (~flags & mask & PKT_ALIAS_LOG) 2528 /* _Disable_ logging */ 2529 UninitPacketAliasLog(la); 2530 2531 #ifndef NO_FW_PUNCH 2532 if (flags & mask & PKT_ALIAS_PUNCH_FW) 2533 /* Start punching holes in the firewall? */ 2534 InitPunchFW(la); 2535 else if (~flags & mask & PKT_ALIAS_PUNCH_FW) 2536 /* Stop punching holes in the firewall? */ 2537 UninitPunchFW(la); 2538 #endif 2539 2540 /* Other flags can be set/cleared without special action */ 2541 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2542 res = la->packetAliasMode; 2543 getout: 2544 LIBALIAS_UNLOCK(la); 2545 return (res); 2546 } 2547 2548 int 2549 LibAliasCheckNewLink(struct libalias *la) 2550 { 2551 int res; 2552 2553 LIBALIAS_LOCK(la); 2554 res = la->newDefaultLink; 2555 LIBALIAS_UNLOCK(la); 2556 return (res); 2557 } 2558 2559 #ifndef NO_FW_PUNCH 2560 2561 /***************** 2562 Code to support firewall punching. This shouldn't really be in this 2563 file, but making variables global is evil too. 2564 ****************/ 2565 2566 /* Firewall include files */ 2567 #include <net/if.h> 2568 #include <netinet/ip_fw.h> 2569 #include <string.h> 2570 #include <err.h> 2571 2572 /* 2573 * helper function, updates the pointer to cmd with the length 2574 * of the current command, and also cleans up the first word of 2575 * the new command in case it has been clobbered before. 2576 */ 2577 static ipfw_insn * 2578 next_cmd(ipfw_insn * cmd) 2579 { 2580 cmd += F_LEN(cmd); 2581 bzero(cmd, sizeof(*cmd)); 2582 return (cmd); 2583 } 2584 2585 /* 2586 * A function to fill simple commands of size 1. 2587 * Existing flags are preserved. 2588 */ 2589 static ipfw_insn * 2590 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2591 int flags, u_int16_t arg) 2592 { 2593 cmd->opcode = opcode; 2594 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2595 cmd->arg1 = arg; 2596 return next_cmd(cmd); 2597 } 2598 2599 static ipfw_insn * 2600 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2601 { 2602 ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1; 2603 2604 cmd->addr.s_addr = addr; 2605 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2606 } 2607 2608 static ipfw_insn * 2609 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2610 { 2611 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1; 2612 2613 cmd->ports[0] = cmd->ports[1] = port; 2614 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2615 } 2616 2617 static int 2618 fill_rule(void *buf, int bufsize, int rulenum, 2619 enum ipfw_opcodes action, int proto, 2620 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2621 { 2622 struct ip_fw *rule = (struct ip_fw *)buf; 2623 ipfw_insn *cmd = (ipfw_insn *)rule->cmd; 2624 2625 bzero(buf, bufsize); 2626 rule->rulenum = rulenum; 2627 2628 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2629 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2630 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2631 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2632 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2633 2634 rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2635 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2636 2637 rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd; 2638 2639 return ((char *)cmd - (char *)buf); 2640 } 2641 2642 static void ClearAllFWHoles(struct libalias *la); 2643 2644 #define fw_setfield(la, field, num) \ 2645 do { \ 2646 (field)[(num) - la->fireWallBaseNum] = 1; \ 2647 } /*lint -save -e717 */ while(0)/* lint -restore */ 2648 2649 #define fw_clrfield(la, field, num) \ 2650 do { \ 2651 (field)[(num) - la->fireWallBaseNum] = 0; \ 2652 } /*lint -save -e717 */ while(0)/* lint -restore */ 2653 2654 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2655 2656 static void 2657 InitPunchFW(struct libalias *la) 2658 { 2659 la->fireWallField = malloc(la->fireWallNumNums); 2660 if (la->fireWallField) { 2661 memset(la->fireWallField, 0, la->fireWallNumNums); 2662 if (la->fireWallFD < 0) { 2663 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2664 } 2665 ClearAllFWHoles(la); 2666 la->fireWallActiveNum = la->fireWallBaseNum; 2667 } 2668 } 2669 2670 static void 2671 UninitPunchFW(struct libalias *la) 2672 { 2673 ClearAllFWHoles(la); 2674 if (la->fireWallFD >= 0) 2675 close(la->fireWallFD); 2676 la->fireWallFD = -1; 2677 if (la->fireWallField) 2678 free(la->fireWallField); 2679 la->fireWallField = NULL; 2680 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2681 } 2682 2683 /* Make a certain link go through the firewall */ 2684 void 2685 PunchFWHole(struct alias_link *lnk) 2686 { 2687 struct libalias *la; 2688 int r; /* Result code */ 2689 struct ip_fw rule; /* On-the-fly built rule */ 2690 int fwhole; /* Where to punch hole */ 2691 2692 la = lnk->la; 2693 2694 /* Don't do anything unless we are asked to */ 2695 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2696 la->fireWallFD < 0 || 2697 lnk->link_type != LINK_TCP) 2698 return; 2699 2700 memset(&rule, 0, sizeof rule); 2701 2702 /** Build rule **/ 2703 2704 /* Find empty slot */ 2705 for (fwhole = la->fireWallActiveNum; 2706 fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2707 fw_tstfield(la, la->fireWallField, fwhole); 2708 fwhole++); 2709 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2710 for (fwhole = la->fireWallBaseNum; 2711 fwhole < la->fireWallActiveNum && 2712 fw_tstfield(la, la->fireWallField, fwhole); 2713 fwhole++); 2714 if (fwhole == la->fireWallActiveNum) { 2715 /* No rule point empty - we can't punch more holes. */ 2716 la->fireWallActiveNum = la->fireWallBaseNum; 2717 #ifdef LIBALIAS_DEBUG 2718 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2719 #endif 2720 return; 2721 } 2722 } 2723 /* Start next search at next position */ 2724 la->fireWallActiveNum = fwhole + 1; 2725 2726 /* 2727 * generate two rules of the form 2728 * 2729 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2730 * accept tcp from DAddr DPort to OAddr OPort 2731 */ 2732 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2733 u_int32_t rulebuf[255]; 2734 int i; 2735 2736 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2737 O_ACCEPT, IPPROTO_TCP, 2738 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2739 GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2740 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2741 if (r) 2742 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2743 2744 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2745 O_ACCEPT, IPPROTO_TCP, 2746 GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2747 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2748 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2749 if (r) 2750 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2751 } 2752 2753 /* Indicate hole applied */ 2754 lnk->data.tcp->fwhole = fwhole; 2755 fw_setfield(la, la->fireWallField, fwhole); 2756 } 2757 2758 /* Remove a hole in a firewall associated with a particular alias 2759 lnk. Calling this too often is harmless. */ 2760 static void 2761 ClearFWHole(struct alias_link *lnk) 2762 { 2763 struct libalias *la; 2764 2765 la = lnk->la; 2766 if (lnk->link_type == LINK_TCP) { 2767 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall hole? */ 2768 struct ip_fw rule; 2769 2770 if (fwhole < 0) 2771 return; 2772 2773 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2774 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2775 &fwhole, sizeof fwhole)); 2776 fw_clrfield(la, la->fireWallField, fwhole); 2777 lnk->data.tcp->fwhole = -1; 2778 } 2779 } 2780 2781 /* Clear out the entire range dedicated to firewall holes. */ 2782 static void 2783 ClearAllFWHoles(struct libalias *la) 2784 { 2785 struct ip_fw rule; /* On-the-fly built rule */ 2786 int i; 2787 2788 if (la->fireWallFD < 0) 2789 return; 2790 2791 memset(&rule, 0, sizeof rule); 2792 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2793 int r = i; 2794 2795 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2796 } 2797 /* XXX: third arg correct here ? /phk */ 2798 memset(la->fireWallField, 0, la->fireWallNumNums); 2799 } 2800 2801 #endif /* !NO_FW_PUNCH */ 2802 2803 void 2804 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2805 { 2806 LIBALIAS_LOCK(la); 2807 #ifndef NO_FW_PUNCH 2808 la->fireWallBaseNum = base; 2809 la->fireWallNumNums = num; 2810 #endif 2811 LIBALIAS_UNLOCK(la); 2812 } 2813 2814 void 2815 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2816 { 2817 LIBALIAS_LOCK(la); 2818 la->skinnyPort = port; 2819 LIBALIAS_UNLOCK(la); 2820 } 2821 2822 /* 2823 * Find the address to redirect incoming packets 2824 */ 2825 struct in_addr 2826 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm) 2827 { 2828 struct alias_link *lnk; 2829 struct in_addr redir; 2830 2831 LIBALIAS_LOCK_ASSERT(la); 2832 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2833 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1); 2834 if (lnk != NULL) { 2835 /* port redirect */ 2836 return (lnk->src_addr); 2837 } else { 2838 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst); 2839 if (redir.s_addr == la->aliasAddress.s_addr || 2840 redir.s_addr == la->targetAddress.s_addr) { 2841 /* No address found */ 2842 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2843 NO_DEST_PORT, 0, LINK_SCTP, 1); 2844 if (lnk != NULL) 2845 /* redirect proto */ 2846 return (lnk->src_addr); 2847 } 2848 return (redir); /* address redirect */ 2849 } 2850 } 2851