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