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