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