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