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