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