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