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, j; 1941 int delta, ack_diff_min; 1942 1943 delta = 0; 1944 ack_diff_min = -1; 1945 i = lnk->data.tcp->state.index; 1946 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1947 struct ack_data_record x; 1948 1949 if (i == 0) 1950 i = N_LINK_TCP_DATA; 1951 i--; 1952 x = lnk->data.tcp->ack[i]; 1953 if (x.active == 1) { 1954 int ack_diff; 1955 1956 ack_diff = SeqDiff(x.ack_new, ack); 1957 if (ack_diff >= 0) { 1958 if (ack_diff_min >= 0) { 1959 if (ack_diff < ack_diff_min) { 1960 delta = x.delta; 1961 ack_diff_min = ack_diff; 1962 } 1963 } else { 1964 delta = x.delta; 1965 ack_diff_min = ack_diff; 1966 } 1967 } 1968 } 1969 } 1970 return (delta); 1971 } 1972 1973 // XXX ip free 1974 int 1975 GetDeltaSeqOut(u_long seq, struct alias_link *lnk) 1976 { 1977 /* 1978 Find out how much the sequence number has been altered for an outgoing 1979 TCP packet. To do this, a circular list of ACK numbers where the TCP 1980 packet size was altered is searched. 1981 */ 1982 1983 int i, j; 1984 int delta, seq_diff_min; 1985 1986 delta = 0; 1987 seq_diff_min = -1; 1988 i = lnk->data.tcp->state.index; 1989 for (j = 0; j < N_LINK_TCP_DATA; j++) { 1990 struct ack_data_record x; 1991 1992 if (i == 0) 1993 i = N_LINK_TCP_DATA; 1994 i--; 1995 x = lnk->data.tcp->ack[i]; 1996 if (x.active == 1) { 1997 int seq_diff; 1998 1999 seq_diff = SeqDiff(x.ack_old, seq); 2000 if (seq_diff >= 0) { 2001 if (seq_diff_min >= 0) { 2002 if (seq_diff < seq_diff_min) { 2003 delta = x.delta; 2004 seq_diff_min = seq_diff; 2005 } 2006 } else { 2007 delta = x.delta; 2008 seq_diff_min = seq_diff; 2009 } 2010 } 2011 } 2012 } 2013 return (delta); 2014 } 2015 2016 // XXX ip free 2017 void 2018 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len, 2019 u_long th_seq, u_int th_off) 2020 { 2021 /* 2022 When a TCP packet has been altered in length, save this 2023 information in a circular list. If enough packets have 2024 been altered, then this list will begin to overwrite itself. 2025 */ 2026 2027 struct ack_data_record x; 2028 int hlen, tlen, dlen; 2029 int i; 2030 2031 hlen = (ip_hl + th_off) << 2; 2032 tlen = ntohs(ip_len); 2033 dlen = tlen - hlen; 2034 2035 x.ack_old = htonl(ntohl(th_seq) + dlen); 2036 x.ack_new = htonl(ntohl(th_seq) + dlen + delta); 2037 x.delta = delta; 2038 x.active = 1; 2039 2040 i = lnk->data.tcp->state.index; 2041 lnk->data.tcp->ack[i] = x; 2042 2043 i++; 2044 if (i == N_LINK_TCP_DATA) 2045 lnk->data.tcp->state.index = 0; 2046 else 2047 lnk->data.tcp->state.index = i; 2048 } 2049 2050 void 2051 SetExpire(struct alias_link *lnk, int expire) 2052 { 2053 if (expire == 0) { 2054 lnk->flags &= ~LINK_PERMANENT; 2055 DeleteLink(lnk); 2056 } else if (expire == -1) { 2057 lnk->flags |= LINK_PERMANENT; 2058 } else if (expire > 0) { 2059 lnk->expire_time = expire; 2060 } else { 2061 #ifdef LIBALIAS_DEBUG 2062 fprintf(stderr, "PacketAlias/SetExpire(): "); 2063 fprintf(stderr, "error in expire parameter\n"); 2064 #endif 2065 } 2066 } 2067 2068 void 2069 ClearCheckNewLink(struct libalias *la) 2070 { 2071 2072 LIBALIAS_LOCK_ASSERT(la); 2073 la->newDefaultLink = 0; 2074 } 2075 2076 void 2077 SetProtocolFlags(struct alias_link *lnk, int pflags) 2078 { 2079 2080 lnk->pflags = pflags; 2081 } 2082 2083 int 2084 GetProtocolFlags(struct alias_link *lnk) 2085 { 2086 2087 return (lnk->pflags); 2088 } 2089 2090 void 2091 SetDestCallId(struct alias_link *lnk, u_int16_t cid) 2092 { 2093 struct libalias *la = lnk->la; 2094 2095 LIBALIAS_LOCK_ASSERT(la); 2096 la->deleteAllLinks = 1; 2097 ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr, 2098 lnk->src_port, cid, lnk->alias_port, lnk->link_type); 2099 la->deleteAllLinks = 0; 2100 } 2101 2102 /* Miscellaneous Functions 2103 2104 HouseKeeping() 2105 InitPacketAliasLog() 2106 UninitPacketAliasLog() 2107 */ 2108 2109 /* 2110 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2111 is called to find and remove timed-out aliasing links. Logic exists 2112 to sweep through the entire table and linked list structure 2113 every 60 seconds. 2114 2115 (prototype in alias_local.h) 2116 */ 2117 2118 void 2119 HouseKeeping(struct libalias *la) 2120 { 2121 int i, n; 2122 #ifndef _KERNEL 2123 struct timeval tv; 2124 #endif 2125 2126 LIBALIAS_LOCK_ASSERT(la); 2127 /* 2128 * Save system time (seconds) in global variable timeStamp for use 2129 * by other functions. This is done so as not to unnecessarily 2130 * waste timeline by making system calls. 2131 */ 2132 #ifdef _KERNEL 2133 la->timeStamp = time_uptime; 2134 #else 2135 gettimeofday(&tv, NULL); 2136 la->timeStamp = tv.tv_sec; 2137 #endif 2138 2139 /* Compute number of spokes (output table link chains) to cover */ 2140 n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime); 2141 n /= ALIAS_CLEANUP_INTERVAL_SECS; 2142 2143 /* Handle different cases */ 2144 if (n > 0) { 2145 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2146 n = ALIAS_CLEANUP_MAX_SPOKES; 2147 la->lastCleanupTime = la->timeStamp; 2148 for (i = 0; i < n; i++) 2149 IncrementalCleanup(la); 2150 } else if (n < 0) { 2151 #ifdef LIBALIAS_DEBUG 2152 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2153 fprintf(stderr, "something unexpected in time values\n"); 2154 #endif 2155 la->lastCleanupTime = la->timeStamp; 2156 } 2157 } 2158 2159 /* Init the log file and enable logging */ 2160 static int 2161 InitPacketAliasLog(struct libalias *la) 2162 { 2163 2164 LIBALIAS_LOCK_ASSERT(la); 2165 if (~la->packetAliasMode & PKT_ALIAS_LOG) { 2166 #ifdef _KERNEL 2167 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE))) 2168 ; 2169 #else 2170 if ((la->logDesc = fopen("/var/log/alias.log", "w"))) 2171 fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2172 #endif 2173 else 2174 return (ENOMEM); /* log initialization failed */ 2175 la->packetAliasMode |= PKT_ALIAS_LOG; 2176 } 2177 2178 return (1); 2179 } 2180 2181 /* Close the log-file and disable logging. */ 2182 static void 2183 UninitPacketAliasLog(struct libalias *la) 2184 { 2185 2186 LIBALIAS_LOCK_ASSERT(la); 2187 if (la->logDesc) { 2188 #ifdef _KERNEL 2189 free(la->logDesc); 2190 #else 2191 fclose(la->logDesc); 2192 #endif 2193 la->logDesc = NULL; 2194 } 2195 la->packetAliasMode &= ~PKT_ALIAS_LOG; 2196 } 2197 2198 /* Outside world interfaces 2199 2200 -- "outside world" means other than alias*.c routines -- 2201 2202 PacketAliasRedirectPort() 2203 PacketAliasAddServer() 2204 PacketAliasRedirectProto() 2205 PacketAliasRedirectAddr() 2206 PacketAliasRedirectDynamic() 2207 PacketAliasRedirectDelete() 2208 PacketAliasSetAddress() 2209 PacketAliasInit() 2210 PacketAliasUninit() 2211 PacketAliasSetMode() 2212 2213 (prototypes in alias.h) 2214 */ 2215 2216 /* Redirection from a specific public addr:port to a 2217 private addr:port */ 2218 struct alias_link * 2219 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port, 2220 struct in_addr dst_addr, u_short dst_port, 2221 struct in_addr alias_addr, u_short alias_port, 2222 u_char proto) 2223 { 2224 int link_type; 2225 struct alias_link *lnk; 2226 2227 LIBALIAS_LOCK(la); 2228 switch (proto) { 2229 case IPPROTO_UDP: 2230 link_type = LINK_UDP; 2231 break; 2232 case IPPROTO_TCP: 2233 link_type = LINK_TCP; 2234 break; 2235 case IPPROTO_SCTP: 2236 link_type = LINK_SCTP; 2237 break; 2238 default: 2239 #ifdef LIBALIAS_DEBUG 2240 fprintf(stderr, "PacketAliasRedirectPort(): "); 2241 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n"); 2242 #endif 2243 lnk = NULL; 2244 goto getout; 2245 } 2246 2247 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2248 src_port, dst_port, alias_port, 2249 link_type); 2250 2251 if (lnk != NULL) { 2252 lnk->flags |= LINK_PERMANENT; 2253 } 2254 #ifdef LIBALIAS_DEBUG 2255 else { 2256 fprintf(stderr, "PacketAliasRedirectPort(): " 2257 "call to AddLink() failed\n"); 2258 } 2259 #endif 2260 2261 getout: 2262 LIBALIAS_UNLOCK(la); 2263 return (lnk); 2264 } 2265 2266 /* Add server to the pool of servers */ 2267 int 2268 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port) 2269 { 2270 struct server *server; 2271 int res; 2272 2273 LIBALIAS_LOCK(la); 2274 (void)la; 2275 2276 server = malloc(sizeof(struct server)); 2277 2278 if (server != NULL) { 2279 struct server *head; 2280 2281 server->addr = addr; 2282 server->port = port; 2283 2284 head = lnk->server; 2285 if (head == NULL) 2286 server->next = server; 2287 else { 2288 struct server *s; 2289 2290 for (s = head; s->next != head; s = s->next); 2291 s->next = server; 2292 server->next = head; 2293 } 2294 lnk->server = server; 2295 res = 0; 2296 } else 2297 res = -1; 2298 2299 LIBALIAS_UNLOCK(la); 2300 return (res); 2301 } 2302 2303 /* Redirect packets of a given IP protocol from a specific 2304 public address to a private address */ 2305 struct alias_link * 2306 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr, 2307 struct in_addr dst_addr, 2308 struct in_addr alias_addr, 2309 u_char proto) 2310 { 2311 struct alias_link *lnk; 2312 2313 LIBALIAS_LOCK(la); 2314 lnk = AddLink(la, src_addr, dst_addr, alias_addr, 2315 NO_SRC_PORT, NO_DEST_PORT, 0, 2316 proto); 2317 2318 if (lnk != NULL) { 2319 lnk->flags |= LINK_PERMANENT; 2320 } 2321 #ifdef LIBALIAS_DEBUG 2322 else { 2323 fprintf(stderr, "PacketAliasRedirectProto(): " 2324 "call to AddLink() failed\n"); 2325 } 2326 #endif 2327 2328 LIBALIAS_UNLOCK(la); 2329 return (lnk); 2330 } 2331 2332 /* Static address translation */ 2333 struct alias_link * 2334 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr, 2335 struct in_addr alias_addr) 2336 { 2337 struct alias_link *lnk; 2338 2339 LIBALIAS_LOCK(la); 2340 lnk = AddLink(la, src_addr, la->nullAddress, alias_addr, 2341 0, 0, 0, 2342 LINK_ADDR); 2343 2344 if (lnk != NULL) { 2345 lnk->flags |= LINK_PERMANENT; 2346 } 2347 #ifdef LIBALIAS_DEBUG 2348 else { 2349 fprintf(stderr, "PacketAliasRedirectAddr(): " 2350 "call to AddLink() failed\n"); 2351 } 2352 #endif 2353 2354 LIBALIAS_UNLOCK(la); 2355 return (lnk); 2356 } 2357 2358 /* Mark the aliasing link dynamic */ 2359 int 2360 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk) 2361 { 2362 int res; 2363 2364 LIBALIAS_LOCK(la); 2365 (void)la; 2366 2367 if (lnk->flags & LINK_PARTIALLY_SPECIFIED) 2368 res = -1; 2369 else { 2370 lnk->flags &= ~LINK_PERMANENT; 2371 res = 0; 2372 } 2373 LIBALIAS_UNLOCK(la); 2374 return (res); 2375 } 2376 2377 void 2378 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk) 2379 { 2380 /* This is a dangerous function to put in the API, 2381 because an invalid pointer can crash the program. */ 2382 2383 LIBALIAS_LOCK(la); 2384 la->deleteAllLinks = 1; 2385 DeleteLink(lnk); 2386 la->deleteAllLinks = 0; 2387 LIBALIAS_UNLOCK(la); 2388 } 2389 2390 void 2391 LibAliasSetAddress(struct libalias *la, struct in_addr addr) 2392 { 2393 2394 LIBALIAS_LOCK(la); 2395 if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2396 && la->aliasAddress.s_addr != addr.s_addr) 2397 CleanupAliasData(la); 2398 2399 la->aliasAddress = addr; 2400 LIBALIAS_UNLOCK(la); 2401 } 2402 2403 2404 void 2405 LibAliasSetAliasPortRange(struct libalias *la, u_short port_low, 2406 u_short port_high) 2407 { 2408 2409 LIBALIAS_LOCK(la); 2410 la->aliasPortLower = port_low; 2411 /* Add 1 to the aliasPortLength as modulo has range of 1 to n-1 */ 2412 la->aliasPortLength = port_high - port_low + 1; 2413 LIBALIAS_UNLOCK(la); 2414 } 2415 2416 void 2417 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr) 2418 { 2419 2420 LIBALIAS_LOCK(la); 2421 la->targetAddress = target_addr; 2422 LIBALIAS_UNLOCK(la); 2423 } 2424 2425 static void 2426 finishoff(void) 2427 { 2428 2429 while (!LIST_EMPTY(&instancehead)) 2430 LibAliasUninit(LIST_FIRST(&instancehead)); 2431 } 2432 2433 struct libalias * 2434 LibAliasInit(struct libalias *la) 2435 { 2436 int i; 2437 #ifndef _KERNEL 2438 struct timeval tv; 2439 #endif 2440 2441 if (la == NULL) { 2442 #ifdef _KERNEL 2443 #undef malloc /* XXX: ugly */ 2444 la = malloc(sizeof *la, M_ALIAS, M_WAITOK | M_ZERO); 2445 #else 2446 la = calloc(sizeof *la, 1); 2447 if (la == NULL) 2448 return (la); 2449 #endif 2450 2451 #ifndef _KERNEL /* kernel cleans up on module unload */ 2452 if (LIST_EMPTY(&instancehead)) 2453 atexit(finishoff); 2454 #endif 2455 LIST_INSERT_HEAD(&instancehead, la, instancelist); 2456 2457 #ifdef _KERNEL 2458 la->timeStamp = time_uptime; 2459 la->lastCleanupTime = time_uptime; 2460 #else 2461 gettimeofday(&tv, NULL); 2462 la->timeStamp = tv.tv_sec; 2463 la->lastCleanupTime = tv.tv_sec; 2464 #endif 2465 2466 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) 2467 LIST_INIT(&la->linkTableOut[i]); 2468 for (i = 0; i < LINK_TABLE_IN_SIZE; i++) 2469 LIST_INIT(&la->linkTableIn[i]); 2470 #ifdef _KERNEL 2471 AliasSctpInit(la); 2472 #endif 2473 LIBALIAS_LOCK_INIT(la); 2474 LIBALIAS_LOCK(la); 2475 } else { 2476 LIBALIAS_LOCK(la); 2477 la->deleteAllLinks = 1; 2478 CleanupAliasData(la); 2479 la->deleteAllLinks = 0; 2480 #ifdef _KERNEL 2481 AliasSctpTerm(la); 2482 AliasSctpInit(la); 2483 #endif 2484 } 2485 2486 la->aliasAddress.s_addr = INADDR_ANY; 2487 la->targetAddress.s_addr = INADDR_ANY; 2488 2489 la->icmpLinkCount = 0; 2490 la->udpLinkCount = 0; 2491 la->tcpLinkCount = 0; 2492 la->sctpLinkCount = 0; 2493 la->pptpLinkCount = 0; 2494 la->protoLinkCount = 0; 2495 la->fragmentIdLinkCount = 0; 2496 la->fragmentPtrLinkCount = 0; 2497 la->sockCount = 0; 2498 2499 la->cleanupIndex = 0; 2500 2501 la->packetAliasMode = PKT_ALIAS_SAME_PORTS 2502 #ifndef NO_USE_SOCKETS 2503 | PKT_ALIAS_USE_SOCKETS 2504 #endif 2505 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2506 #ifndef NO_FW_PUNCH 2507 la->fireWallFD = -1; 2508 #endif 2509 #ifndef _KERNEL 2510 LibAliasRefreshModules(); 2511 #endif 2512 LIBALIAS_UNLOCK(la); 2513 return (la); 2514 } 2515 2516 void 2517 LibAliasUninit(struct libalias *la) 2518 { 2519 2520 LIBALIAS_LOCK(la); 2521 #ifdef _KERNEL 2522 AliasSctpTerm(la); 2523 #endif 2524 la->deleteAllLinks = 1; 2525 CleanupAliasData(la); 2526 la->deleteAllLinks = 0; 2527 UninitPacketAliasLog(la); 2528 #ifndef NO_FW_PUNCH 2529 UninitPunchFW(la); 2530 #endif 2531 LIST_REMOVE(la, instancelist); 2532 LIBALIAS_UNLOCK(la); 2533 LIBALIAS_LOCK_DESTROY(la); 2534 free(la); 2535 } 2536 2537 /* Change mode for some operations */ 2538 unsigned int 2539 LibAliasSetMode( 2540 struct libalias *la, 2541 unsigned int flags, /* Which state to bring flags to */ 2542 unsigned int mask /* Mask of which flags to affect (use 0 to 2543 * do a probe for flag values) */ 2544 ) 2545 { 2546 int res = -1; 2547 2548 LIBALIAS_LOCK(la); 2549 /* Enable logging? */ 2550 if (flags & mask & PKT_ALIAS_LOG) { 2551 /* Do the enable */ 2552 if (InitPacketAliasLog(la) == ENOMEM) 2553 goto getout; 2554 } else 2555 /* _Disable_ logging? */ 2556 if (~flags & mask & PKT_ALIAS_LOG) { 2557 UninitPacketAliasLog(la); 2558 } 2559 #ifndef NO_FW_PUNCH 2560 /* Start punching holes in the firewall? */ 2561 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2562 InitPunchFW(la); 2563 } else 2564 /* Stop punching holes in the firewall? */ 2565 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2566 UninitPunchFW(la); 2567 } 2568 #endif 2569 2570 /* Other flags can be set/cleared without special action */ 2571 la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask); 2572 res = la->packetAliasMode; 2573 getout: 2574 LIBALIAS_UNLOCK(la); 2575 return (res); 2576 } 2577 2578 int 2579 LibAliasCheckNewLink(struct libalias *la) 2580 { 2581 int res; 2582 2583 LIBALIAS_LOCK(la); 2584 res = la->newDefaultLink; 2585 LIBALIAS_UNLOCK(la); 2586 return (res); 2587 } 2588 2589 #ifndef NO_FW_PUNCH 2590 2591 /***************** 2592 Code to support firewall punching. This shouldn't really be in this 2593 file, but making variables global is evil too. 2594 ****************/ 2595 2596 /* Firewall include files */ 2597 #include <net/if.h> 2598 #include <netinet/ip_fw.h> 2599 #include <string.h> 2600 #include <err.h> 2601 2602 /* 2603 * helper function, updates the pointer to cmd with the length 2604 * of the current command, and also cleans up the first word of 2605 * the new command in case it has been clobbered before. 2606 */ 2607 static ipfw_insn * 2608 next_cmd(ipfw_insn * cmd) 2609 { 2610 cmd += F_LEN(cmd); 2611 bzero(cmd, sizeof(*cmd)); 2612 return (cmd); 2613 } 2614 2615 /* 2616 * A function to fill simple commands of size 1. 2617 * Existing flags are preserved. 2618 */ 2619 static ipfw_insn * 2620 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size, 2621 int flags, u_int16_t arg) 2622 { 2623 cmd->opcode = opcode; 2624 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK); 2625 cmd->arg1 = arg; 2626 return next_cmd(cmd); 2627 } 2628 2629 static ipfw_insn * 2630 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr) 2631 { 2632 ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1; 2633 2634 cmd->addr.s_addr = addr; 2635 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0); 2636 } 2637 2638 static ipfw_insn * 2639 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port) 2640 { 2641 ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1; 2642 2643 cmd->ports[0] = cmd->ports[1] = port; 2644 return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0); 2645 } 2646 2647 static int 2648 fill_rule(void *buf, int bufsize, int rulenum, 2649 enum ipfw_opcodes action, int proto, 2650 struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp) 2651 { 2652 struct ip_fw *rule = (struct ip_fw *)buf; 2653 ipfw_insn *cmd = (ipfw_insn *) rule->cmd; 2654 2655 bzero(buf, bufsize); 2656 rule->rulenum = rulenum; 2657 2658 cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto); 2659 cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr); 2660 cmd = fill_one_port(cmd, O_IP_SRCPORT, sp); 2661 cmd = fill_ip(cmd, O_IP_DST, da.s_addr); 2662 cmd = fill_one_port(cmd, O_IP_DSTPORT, dp); 2663 2664 rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2665 cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0); 2666 2667 rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd; 2668 2669 return ((char *)cmd - (char *)buf); 2670 } 2671 2672 static void ClearAllFWHoles(struct libalias *la); 2673 2674 #define fw_setfield(la, field, num) \ 2675 do { \ 2676 (field)[(num) - la->fireWallBaseNum] = 1; \ 2677 } /*lint -save -e717 */ while(0)/* lint -restore */ 2678 2679 #define fw_clrfield(la, field, num) \ 2680 do { \ 2681 (field)[(num) - la->fireWallBaseNum] = 0; \ 2682 } /*lint -save -e717 */ while(0)/* lint -restore */ 2683 2684 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum]) 2685 2686 static void 2687 InitPunchFW(struct libalias *la) 2688 { 2689 2690 la->fireWallField = malloc(la->fireWallNumNums); 2691 if (la->fireWallField) { 2692 memset(la->fireWallField, 0, la->fireWallNumNums); 2693 if (la->fireWallFD < 0) { 2694 la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2695 } 2696 ClearAllFWHoles(la); 2697 la->fireWallActiveNum = la->fireWallBaseNum; 2698 } 2699 } 2700 2701 static void 2702 UninitPunchFW(struct libalias *la) 2703 { 2704 2705 ClearAllFWHoles(la); 2706 if (la->fireWallFD >= 0) 2707 close(la->fireWallFD); 2708 la->fireWallFD = -1; 2709 if (la->fireWallField) 2710 free(la->fireWallField); 2711 la->fireWallField = NULL; 2712 la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2713 } 2714 2715 /* Make a certain link go through the firewall */ 2716 void 2717 PunchFWHole(struct alias_link *lnk) 2718 { 2719 struct libalias *la; 2720 int r; /* Result code */ 2721 struct ip_fw rule; /* On-the-fly built rule */ 2722 int fwhole; /* Where to punch hole */ 2723 2724 la = lnk->la; 2725 2726 /* Don't do anything unless we are asked to */ 2727 if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2728 la->fireWallFD < 0 || 2729 lnk->link_type != LINK_TCP) 2730 return; 2731 2732 memset(&rule, 0, sizeof rule); 2733 2734 /** Build rule **/ 2735 2736 /* Find empty slot */ 2737 for (fwhole = la->fireWallActiveNum; 2738 fwhole < la->fireWallBaseNum + la->fireWallNumNums && 2739 fw_tstfield(la, la->fireWallField, fwhole); 2740 fwhole++); 2741 if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) { 2742 for (fwhole = la->fireWallBaseNum; 2743 fwhole < la->fireWallActiveNum && 2744 fw_tstfield(la, la->fireWallField, fwhole); 2745 fwhole++); 2746 if (fwhole == la->fireWallActiveNum) { 2747 /* No rule point empty - we can't punch more holes. */ 2748 la->fireWallActiveNum = la->fireWallBaseNum; 2749 #ifdef LIBALIAS_DEBUG 2750 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2751 #endif 2752 return; 2753 } 2754 } 2755 /* Start next search at next position */ 2756 la->fireWallActiveNum = fwhole + 1; 2757 2758 /* 2759 * generate two rules of the form 2760 * 2761 * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole 2762 * accept tcp from DAddr DPort to OAddr OPort 2763 */ 2764 if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) { 2765 u_int32_t rulebuf[255]; 2766 int i; 2767 2768 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2769 O_ACCEPT, IPPROTO_TCP, 2770 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)), 2771 GetDestAddress(lnk), ntohs(GetDestPort(lnk))); 2772 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2773 if (r) 2774 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2775 2776 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole, 2777 O_ACCEPT, IPPROTO_TCP, 2778 GetDestAddress(lnk), ntohs(GetDestPort(lnk)), 2779 GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk))); 2780 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i); 2781 if (r) 2782 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2783 } 2784 2785 /* Indicate hole applied */ 2786 lnk->data.tcp->fwhole = fwhole; 2787 fw_setfield(la, la->fireWallField, fwhole); 2788 } 2789 2790 /* Remove a hole in a firewall associated with a particular alias 2791 lnk. Calling this too often is harmless. */ 2792 static void 2793 ClearFWHole(struct alias_link *lnk) 2794 { 2795 struct libalias *la; 2796 2797 la = lnk->la; 2798 if (lnk->link_type == LINK_TCP) { 2799 int fwhole = lnk->data.tcp->fwhole; /* Where is the firewall 2800 * hole? */ 2801 struct ip_fw rule; 2802 2803 if (fwhole < 0) 2804 return; 2805 2806 memset(&rule, 0, sizeof rule); /* useless for ipfw2 */ 2807 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, 2808 &fwhole, sizeof fwhole)); 2809 fw_clrfield(la, la->fireWallField, fwhole); 2810 lnk->data.tcp->fwhole = -1; 2811 } 2812 } 2813 2814 /* Clear out the entire range dedicated to firewall holes. */ 2815 static void 2816 ClearAllFWHoles(struct libalias *la) 2817 { 2818 struct ip_fw rule; /* On-the-fly built rule */ 2819 int i; 2820 2821 if (la->fireWallFD < 0) 2822 return; 2823 2824 memset(&rule, 0, sizeof rule); 2825 for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) { 2826 int r = i; 2827 2828 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r)); 2829 } 2830 /* XXX: third arg correct here ? /phk */ 2831 memset(la->fireWallField, 0, la->fireWallNumNums); 2832 } 2833 2834 #endif /* !NO_FW_PUNCH */ 2835 2836 void 2837 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num) 2838 { 2839 2840 LIBALIAS_LOCK(la); 2841 #ifndef NO_FW_PUNCH 2842 la->fireWallBaseNum = base; 2843 la->fireWallNumNums = num; 2844 #endif 2845 LIBALIAS_UNLOCK(la); 2846 } 2847 2848 void 2849 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port) 2850 { 2851 2852 LIBALIAS_LOCK(la); 2853 la->skinnyPort = port; 2854 LIBALIAS_UNLOCK(la); 2855 } 2856 2857 /* 2858 * Find the address to redirect incoming packets 2859 */ 2860 struct in_addr 2861 FindSctpRedirectAddress(struct libalias *la, struct sctp_nat_msg *sm) 2862 { 2863 struct alias_link *lnk; 2864 struct in_addr redir; 2865 2866 LIBALIAS_LOCK_ASSERT(la); 2867 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2868 sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1); 2869 if (lnk != NULL) { 2870 return(lnk->src_addr); /* port redirect */ 2871 } else { 2872 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst); 2873 if (redir.s_addr == la->aliasAddress.s_addr || 2874 redir.s_addr == la->targetAddress.s_addr) { /* No address found */ 2875 lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst, 2876 NO_DEST_PORT, 0, LINK_SCTP, 1); 2877 if (lnk != NULL) 2878 return(lnk->src_addr); /* redirect proto */ 2879 } 2880 return(redir); /* address redirect */ 2881 } 2882 } 2883