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