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