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