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