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