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