alias_db.c revision 59356
1/* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- 2 Alias_db.c encapsulates all data structures used for storing 3 packet aliasing data. Other parts of the aliasing software 4 access data through functions provided in this file. 5 6 Data storage is based on the notion of a "link", which is 7 established for ICMP echo/reply packets, UDP datagrams and 8 TCP stream connections. A link stores the original source 9 and destination addresses. For UDP and TCP, it also stores 10 source and destination port numbers, as well as an alias 11 port number. Links are also used to store information about 12 fragments. 13 14 There is a facility for sweeping through and deleting old 15 links as new packets are sent through. A simple timeout is 16 used for ICMP and UDP links. TCP links are left alone unless 17 there is an incomplete connection, in which case the link 18 can be deleted after a certain amount of time. 19 20 21 This software is placed into the public domain with no restrictions 22 on its distribution. 23 24 Initial version: August, 1996 (cjm) 25 26 Version 1.4: September 16, 1996 (cjm) 27 Facility for handling incoming links added. 28 29 Version 1.6: September 18, 1996 (cjm) 30 ICMP data handling simplified. 31 32 Version 1.7: January 9, 1997 (cjm) 33 Fragment handling simplified. 34 Saves pointers for unresolved fragments. 35 Permits links for unspecified remote ports 36 or unspecified remote addresses. 37 Fixed bug which did not properly zero port 38 table entries after a link was deleted. 39 Cleaned up some obsolete comments. 40 41 Version 1.8: January 14, 1997 (cjm) 42 Fixed data type error in StartPoint(). 43 (This error did not exist prior to v1.7 44 and was discovered and fixed by Ari Suutari) 45 46 Version 1.9: February 1, 1997 47 Optionally, connections initiated from packet aliasing host 48 machine will will not have their port number aliased unless it 49 conflicts with an aliasing port already being used. (cjm) 50 51 All options earlier being #ifdef'ed are now available through 52 a new interface, SetPacketAliasMode(). This allows run time 53 control (which is now available in PPP+pktAlias through the 54 'alias' keyword). (ee) 55 56 Added ability to create an alias port without 57 either destination address or port specified. 58 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) 59 60 Removed K&R style function headers 61 and general cleanup. (ee) 62 63 Added packetAliasMode to replace compiler #defines's (ee) 64 65 Allocates sockets for partially specified 66 ports if ALIAS_USE_SOCKETS defined. (cjm) 67 68 Version 2.0: March, 1997 69 SetAliasAddress() will now clean up alias links 70 if the aliasing address is changed. (cjm) 71 72 PacketAliasPermanentLink() function added to support permanent 73 links. (J. Fortes suggested the need for this.) 74 Examples: 75 76 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port 77 78 (192.168.0.2, port 21) <-> alias port 3604, known dest addr 79 unknown dest port 80 81 These permanent links allow for incoming connections to 82 machines on the local network. They can be given with a 83 user-chosen amount of specificity, with increasing specificity 84 meaning more security. (cjm) 85 86 Quite a bit of rework to the basic engine. The portTable[] 87 array, which kept track of which ports were in use was replaced 88 by a table/linked list structure. (cjm) 89 90 SetExpire() function added. (cjm) 91 92 DeleteLink() no longer frees memory association with a pointer 93 to a fragment (this bug was first recognized by E. Eklund in 94 v1.9). 95 96 Version 2.1: May, 1997 (cjm) 97 Packet aliasing engine reworked so that it can handle 98 multiple external addresses rather than just a single 99 host address. 100 101 PacketAliasRedirectPort() and PacketAliasRedirectAddr() 102 added to the API. The first function is a more generalized 103 version of PacketAliasPermanentLink(). The second function 104 implements static network address translation. 105 106 See HISTORY file for additional revisions. 107 108 $FreeBSD: head/sys/netinet/libalias/alias_db.c 59356 2000-04-18 10:18:21Z ru $ 109*/ 110 111 112/* System include files */ 113#include <errno.h> 114#include <stdlib.h> 115#include <stdio.h> 116#include <unistd.h> 117 118#include <sys/socket.h> 119#include <sys/time.h> 120#include <sys/types.h> 121 122/* BSD network include files */ 123#include <netinet/in_systm.h> 124#include <netinet/in.h> 125#include <netinet/ip.h> 126#include <netinet/tcp.h> 127#include <arpa/inet.h> 128 129#include "alias.h" 130#include "alias_local.h" 131 132 133 134/* 135 Constants (note: constants are also defined 136 near relevant functions or structs) 137*/ 138 139/* Sizes of input and output link tables */ 140#define LINK_TABLE_OUT_SIZE 101 141#define LINK_TABLE_IN_SIZE 4001 142 143/* Parameters used for cleanup of expired links */ 144#define ALIAS_CLEANUP_INTERVAL_SECS 60 145#define ALIAS_CLEANUP_MAX_SPOKES 30 146 147/* Timeouts (in seconds) for different link types */ 148#define ICMP_EXPIRE_TIME 60 149#define UDP_EXPIRE_TIME 60 150#define PPTP_EXPIRE_TIME 60 151#define FRAGMENT_ID_EXPIRE_TIME 10 152#define FRAGMENT_PTR_EXPIRE_TIME 30 153 154/* TCP link expire time for different cases */ 155/* When the link has been used and closed - minimal grace time to 156 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 157#ifndef TCP_EXPIRE_DEAD 158# define TCP_EXPIRE_DEAD 10 159#endif 160 161/* When the link has been used and closed on one side - the other side 162 is allowed to still send data */ 163#ifndef TCP_EXPIRE_SINGLEDEAD 164# define TCP_EXPIRE_SINGLEDEAD 90 165#endif 166 167/* When the link isn't yet up */ 168#ifndef TCP_EXPIRE_INITIAL 169# define TCP_EXPIRE_INITIAL 300 170#endif 171 172/* When the link is up */ 173#ifndef TCP_EXPIRE_CONNECTED 174# define TCP_EXPIRE_CONNECTED 86400 175#endif 176 177 178/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 179 These constants can be anything except zero, which indicates an 180 unknown port number. */ 181 182#define NO_DEST_PORT 1 183#define NO_SRC_PORT 1 184 185 186 187/* Data Structures 188 189 The fundamental data structure used in this program is 190 "struct alias_link". Whenever a TCP connection is made, 191 a UDP datagram is sent out, or an ICMP echo request is made, 192 a link record is made (if it has not already been created). 193 The link record is identified by the source address/port 194 and the destination address/port. In the case of an ICMP 195 echo request, the source port is treated as being equivalent 196 with the 16-bit ID number of the ICMP packet. 197 198 The link record also can store some auxiliary data. For 199 TCP connections that have had sequence and acknowledgment 200 modifications, data space is available to track these changes. 201 A state field is used to keep track in changes to the TCP 202 connection state. ID numbers of fragments can also be 203 stored in the auxiliary space. Pointers to unresolved 204 fragments can also be stored. 205 206 The link records support two independent chainings. Lookup 207 tables for input and out tables hold the initial pointers 208 the link chains. On input, the lookup table indexes on alias 209 port and link type. On output, the lookup table indexes on 210 source address, destination address, source port, destination 211 port and link type. 212*/ 213 214struct ack_data_record /* used to save changes to ACK/sequence numbers */ 215{ 216 u_long ack_old; 217 u_long ack_new; 218 int delta; 219 int active; 220}; 221 222struct tcp_state /* Information about TCP connection */ 223{ 224 int in; /* State for outside -> inside */ 225 int out; /* State for inside -> outside */ 226 int index; /* Index to ACK data array */ 227 int ack_modified; /* Indicates whether ACK and sequence numbers */ 228 /* been modified */ 229}; 230 231#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes 232 saved for a modified TCP stream */ 233struct tcp_dat 234{ 235 struct tcp_state state; 236 struct ack_data_record ack[N_LINK_TCP_DATA]; 237 int fwhole; /* Which firewall record is used for this hole? */ 238}; 239 240struct alias_link /* Main data structure */ 241{ 242 struct in_addr src_addr; /* Address and port information */ 243 struct in_addr dst_addr; 244 struct in_addr alias_addr; 245 struct in_addr proxy_addr; 246 u_short src_port; 247 u_short dst_port; 248 u_short alias_port; 249 u_short proxy_port; 250 251 int link_type; /* Type of link: TCP, UDP, ICMP, PPTP, frag */ 252 253/* values for link_type */ 254#define LINK_ICMP 1 255#define LINK_UDP 2 256#define LINK_TCP 3 257#define LINK_FRAGMENT_ID 4 258#define LINK_FRAGMENT_PTR 5 259#define LINK_ADDR 6 260#define LINK_PPTP 7 261 262 int flags; /* indicates special characteristics */ 263 264/* flag bits */ 265#define LINK_UNKNOWN_DEST_PORT 0x01 266#define LINK_UNKNOWN_DEST_ADDR 0x02 267#define LINK_PERMANENT 0x04 268#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 269#define LINK_UNFIREWALLED 0x08 270 271 int timestamp; /* Time link was last accessed */ 272 int expire_time; /* Expire time for link */ 273 274 int sockfd; /* socket descriptor */ 275 276 u_int start_point_out; /* Index number in output lookup table */ 277 u_int start_point_in; 278 struct alias_link *next_out; /* Linked list pointers for input and */ 279 struct alias_link *last_out; /* output tables */ 280 struct alias_link *next_in; /* . */ 281 struct alias_link *last_in; /* . */ 282 283 union /* Auxiliary data */ 284 { 285 char *frag_ptr; 286 struct in_addr frag_addr; 287 struct tcp_dat *tcp; 288 } data; 289}; 290 291 292 293 294 295/* Global Variables 296 297 The global variables listed here are only accessed from 298 within alias_db.c and so are prefixed with the static 299 designation. 300*/ 301 302int packetAliasMode; /* Mode flags */ 303 /* - documented in alias.h */ 304 305static struct in_addr aliasAddress; /* Address written onto source */ 306 /* field of IP packet. */ 307 308static struct in_addr targetAddress; /* IP address incoming packets */ 309 /* are sent to if no aliasing */ 310 /* link already exists */ 311 312static struct in_addr nullAddress; /* Used as a dummy parameter for */ 313 /* some function calls */ 314static struct alias_link * 315linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ 316 /* chains of link records. Each */ 317static struct alias_link * /* link record is doubly indexed */ 318linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ 319 /* tables. */ 320 321static int icmpLinkCount; /* Link statistics */ 322static int udpLinkCount; 323static int tcpLinkCount; 324static int pptpLinkCount; 325static int fragmentIdLinkCount; 326static int fragmentPtrLinkCount; 327static int sockCount; 328 329static int cleanupIndex; /* Index to chain of link table */ 330 /* being inspected for old links */ 331 332static int timeStamp; /* System time in seconds for */ 333 /* current packet */ 334 335static int lastCleanupTime; /* Last time IncrementalCleanup() */ 336 /* was called */ 337 338static int houseKeepingResidual; /* used by HouseKeeping() */ 339 340static int deleteAllLinks; /* If equal to zero, DeleteLink() */ 341 /* will not remove permanent links */ 342 343static FILE *monitorFile; /* File descriptor for link */ 344 /* statistics monitoring file */ 345 346static int newDefaultLink; /* Indicates if a new aliasing */ 347 /* link has been created after a */ 348 /* call to PacketAliasIn/Out(). */ 349 350#ifndef NO_FW_PUNCH 351static int fireWallFD = -1; /* File descriptor to be able to */ 352 /* control firewall. Opened by */ 353 /* PacketAliasSetMode on first */ 354 /* setting the PKT_ALIAS_PUNCH_FW */ 355 /* flag. */ 356#endif 357 358 359 360 361 362 363 364/* Internal utility routines (used only in alias_db.c) 365 366Lookup table starting points: 367 StartPointIn() -- link table initial search point for 368 incoming packets 369 StartPointOut() -- link table initial search point for 370 outgoing packets 371 372Miscellaneous: 373 SeqDiff() -- difference between two TCP sequences 374 ShowAliasStats() -- send alias statistics to a monitor file 375*/ 376 377 378/* Local prototypes */ 379static u_int StartPointIn(struct in_addr, u_short, int); 380 381static u_int StartPointOut(struct in_addr, struct in_addr, 382 u_short, u_short, int); 383 384static int SeqDiff(u_long, u_long); 385 386static void ShowAliasStats(void); 387 388#ifndef NO_FW_PUNCH 389/* Firewall control */ 390static void InitPunchFW(void); 391static void UninitPunchFW(void); 392static void ClearFWHole(struct alias_link *link); 393#endif 394 395/* Log file control */ 396static void InitPacketAliasLog(void); 397static void UninitPacketAliasLog(void); 398 399static u_int 400StartPointIn(struct in_addr alias_addr, 401 u_short alias_port, 402 int link_type) 403{ 404 u_int n; 405 406 n = alias_addr.s_addr; 407 n += alias_port; 408 n += link_type; 409 return(n % LINK_TABLE_IN_SIZE); 410} 411 412 413static u_int 414StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 415 u_short src_port, u_short dst_port, int link_type) 416{ 417 u_int n; 418 419 n = src_addr.s_addr; 420 n += dst_addr.s_addr; 421 n += src_port; 422 n += dst_port; 423 n += link_type; 424 425 return(n % LINK_TABLE_OUT_SIZE); 426} 427 428 429static int 430SeqDiff(u_long x, u_long y) 431{ 432/* Return the difference between two TCP sequence numbers */ 433 434/* 435 This function is encapsulated in case there are any unusual 436 arithmetic conditions that need to be considered. 437*/ 438 439 return (ntohl(y) - ntohl(x)); 440} 441 442 443static void 444ShowAliasStats(void) 445{ 446/* Used for debugging */ 447 448 if (monitorFile) 449 { 450 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, frag_id=%d frag_ptr=%d", 451 icmpLinkCount, 452 udpLinkCount, 453 tcpLinkCount, 454 pptpLinkCount, 455 fragmentIdLinkCount, 456 fragmentPtrLinkCount); 457 458 fprintf(monitorFile, " / tot=%d (sock=%d)\n", 459 icmpLinkCount + udpLinkCount 460 + tcpLinkCount 461 + pptpLinkCount 462 + fragmentIdLinkCount 463 + fragmentPtrLinkCount, 464 sockCount); 465 466 fflush(monitorFile); 467 } 468} 469 470 471 472 473 474/* Internal routines for finding, deleting and adding links 475 476Port Allocation: 477 GetNewPort() -- find and reserve new alias port number 478 GetSocket() -- try to allocate a socket for a given port 479 480Link creation and deletion: 481 CleanupAliasData() - remove all link chains from lookup table 482 IncrementalCleanup() - look for stale links in a single chain 483 DeleteLink() - remove link 484 AddLink() - add link 485 ReLink() - change link 486 487Link search: 488 FindLinkOut() - find link for outgoing packets 489 FindLinkIn() - find link for incoming packets 490*/ 491 492/* Local prototypes */ 493static int GetNewPort(struct alias_link *, int); 494 495static u_short GetSocket(u_short, int *, int); 496 497static void CleanupAliasData(void); 498 499static void IncrementalCleanup(void); 500 501static void DeleteLink(struct alias_link *); 502 503static struct alias_link * 504AddLink(struct in_addr, struct in_addr, struct in_addr, 505 u_short, u_short, int, int); 506 507static struct alias_link * 508ReLink(struct alias_link *, 509 struct in_addr, struct in_addr, struct in_addr, 510 u_short, u_short, int, int); 511 512static struct alias_link * 513FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int); 514 515static struct alias_link * 516FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); 517 518 519#define ALIAS_PORT_BASE 0x08000 520#define ALIAS_PORT_MASK 0x07fff 521#define GET_NEW_PORT_MAX_ATTEMPTS 20 522 523#define GET_ALIAS_PORT -1 524#define GET_ALIAS_ID GET_ALIAS_PORT 525 526/* GetNewPort() allocates port numbers. Note that if a port number 527 is already in use, that does not mean that it cannot be used by 528 another link concurrently. This is because GetNewPort() looks for 529 unused triplets: (dest addr, dest port, alias port). */ 530 531static int 532GetNewPort(struct alias_link *link, int alias_port_param) 533{ 534 int i; 535 int max_trials; 536 u_short port_sys; 537 u_short port_net; 538 539/* 540 Description of alias_port_param for GetNewPort(). When 541 this parameter is zero or positive, it precisely specifies 542 the port number. GetNewPort() will return this number 543 without check that it is in use. 544 545 When this parameter is -1, it indicates to get a randomly 546 selected port number. 547*/ 548 549 if (alias_port_param == GET_ALIAS_PORT) 550 { 551 /* 552 * The aliasing port is automatically selected 553 * by one of two methods below: 554 */ 555 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 556 557 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) 558 { 559 /* 560 * When the PKT_ALIAS_SAME_PORTS option is 561 * chosen, the first try will be the 562 * actual source port. If this is already 563 * in use, the remainder of the trials 564 * will be random. 565 */ 566 port_net = link->src_port; 567 port_sys = ntohs(port_net); 568 } 569 else 570 { 571 /* First trial and all subsequent are random. */ 572 port_sys = random() & ALIAS_PORT_MASK; 573 port_sys += ALIAS_PORT_BASE; 574 port_net = htons(port_sys); 575 } 576 } 577 else if (alias_port_param >= 0 && alias_port_param < 0x10000) 578 { 579 link->alias_port = (u_short) alias_port_param; 580 return(0); 581 } 582 else 583 { 584#ifdef DEBUG 585 fprintf(stderr, "PacketAlias/GetNewPort(): "); 586 fprintf(stderr, "input parameter error\n"); 587#endif 588 return(-1); 589 } 590 591 592/* Port number search */ 593 for (i=0; i<max_trials; i++) 594 { 595 int go_ahead; 596 struct alias_link *search_result; 597 598 search_result = FindLinkIn(link->dst_addr, link->alias_addr, 599 link->dst_port, port_net, 600 link->link_type, 0); 601 602 if (search_result == NULL) 603 go_ahead = 1; 604 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) 605 && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 606 go_ahead = 1; 607 else 608 go_ahead = 0; 609 610 if (go_ahead) 611 { 612 if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS) 613 && (link->flags & LINK_PARTIALLY_SPECIFIED)) 614 { 615 if (GetSocket(port_net, &link->sockfd, link->link_type)) 616 { 617 link->alias_port = port_net; 618 return(0); 619 } 620 } 621 else 622 { 623 link->alias_port = port_net; 624 return(0); 625 } 626 } 627 628 port_sys = random() & ALIAS_PORT_MASK; 629 port_sys += ALIAS_PORT_BASE; 630 port_net = htons(port_sys); 631 } 632 633#ifdef DEBUG 634 fprintf(stderr, "PacketAlias/GetnewPort(): "); 635 fprintf(stderr, "could not find free port\n"); 636#endif 637 638 return(-1); 639} 640 641 642static u_short 643GetSocket(u_short port_net, int *sockfd, int link_type) 644{ 645 int err; 646 int sock; 647 struct sockaddr_in sock_addr; 648 649 if (link_type == LINK_TCP) 650 sock = socket(AF_INET, SOCK_STREAM, 0); 651 else if (link_type == LINK_UDP) 652 sock = socket(AF_INET, SOCK_DGRAM, 0); 653 else 654 { 655#ifdef DEBUG 656 fprintf(stderr, "PacketAlias/GetSocket(): "); 657 fprintf(stderr, "incorrect link type\n"); 658#endif 659 return(0); 660 } 661 662 if (sock < 0) 663 { 664#ifdef DEBUG 665 fprintf(stderr, "PacketAlias/GetSocket(): "); 666 fprintf(stderr, "socket() error %d\n", *sockfd); 667#endif 668 return(0); 669 } 670 671 sock_addr.sin_family = AF_INET; 672 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 673 sock_addr.sin_port = port_net; 674 675 err = bind(sock, 676 (struct sockaddr *) &sock_addr, 677 sizeof(sock_addr)); 678 if (err == 0) 679 { 680 sockCount++; 681 *sockfd = sock; 682 return(1); 683 } 684 else 685 { 686 close(sock); 687 return(0); 688 } 689} 690 691 692static void 693CleanupAliasData(void) 694{ 695 struct alias_link *link; 696 int i, icount; 697 698 icount = 0; 699 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 700 { 701 link = linkTableOut[i]; 702 while (link != NULL) 703 { 704 struct alias_link *link_next; 705 link_next = link->next_out; 706 icount++; 707 DeleteLink(link); 708 link = link_next; 709 } 710 } 711 712 cleanupIndex =0; 713} 714 715 716static void 717IncrementalCleanup(void) 718{ 719 int icount; 720 struct alias_link *link; 721 722 icount = 0; 723 link = linkTableOut[cleanupIndex++]; 724 while (link != NULL) 725 { 726 int idelta; 727 struct alias_link *link_next; 728 729 link_next = link->next_out; 730 idelta = timeStamp - link->timestamp; 731 switch (link->link_type) 732 { 733 case LINK_ICMP: 734 case LINK_UDP: 735 case LINK_FRAGMENT_ID: 736 case LINK_FRAGMENT_PTR: 737 case LINK_PPTP: 738 if (idelta > link->expire_time) 739 { 740 DeleteLink(link); 741 icount++; 742 } 743 break; 744 case LINK_TCP: 745 if (idelta > link->expire_time) 746 { 747 struct tcp_dat *tcp_aux; 748 749 tcp_aux = link->data.tcp; 750 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 751 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) 752 { 753 DeleteLink(link); 754 icount++; 755 } 756 } 757 break; 758 } 759 link = link_next; 760 } 761 762 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 763 cleanupIndex = 0; 764} 765 766void 767DeleteLink(struct alias_link *link) 768{ 769 struct alias_link *link_last; 770 struct alias_link *link_next; 771 772/* Don't do anything if the link is marked permanent */ 773 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 774 return; 775 776#ifndef NO_FW_PUNCH 777/* Delete associated firewall hole, if any */ 778 ClearFWHole(link); 779#endif 780 781/* Adjust output table pointers */ 782 link_last = link->last_out; 783 link_next = link->next_out; 784 785 if (link_last != NULL) 786 link_last->next_out = link_next; 787 else 788 linkTableOut[link->start_point_out] = link_next; 789 790 if (link_next != NULL) 791 link_next->last_out = link_last; 792 793/* Adjust input table pointers */ 794 link_last = link->last_in; 795 link_next = link->next_in; 796 797 if (link_last != NULL) 798 link_last->next_in = link_next; 799 else 800 linkTableIn[link->start_point_in] = link_next; 801 802 if (link_next != NULL) 803 link_next->last_in = link_last; 804 805/* Close socket, if one has been allocated */ 806 if (link->sockfd != -1) 807 { 808 sockCount--; 809 close(link->sockfd); 810 } 811 812/* Link-type dependent cleanup */ 813 switch(link->link_type) 814 { 815 case LINK_ICMP: 816 icmpLinkCount--; 817 break; 818 case LINK_UDP: 819 udpLinkCount--; 820 break; 821 case LINK_TCP: 822 tcpLinkCount--; 823 if (link->data.tcp != NULL) 824 free(link->data.tcp); 825 break; 826 case LINK_PPTP: 827 pptpLinkCount--; 828 break; 829 case LINK_FRAGMENT_ID: 830 fragmentIdLinkCount--; 831 break; 832 case LINK_FRAGMENT_PTR: 833 fragmentPtrLinkCount--; 834 if (link->data.frag_ptr != NULL) 835 free(link->data.frag_ptr); 836 break; 837 } 838 839/* Free memory */ 840 free(link); 841 842/* Write statistics, if logging enabled */ 843 if (packetAliasMode & PKT_ALIAS_LOG) 844 { 845 ShowAliasStats(); 846 } 847} 848 849 850static struct alias_link * 851AddLink(struct in_addr src_addr, 852 struct in_addr dst_addr, 853 struct in_addr alias_addr, 854 u_short src_port, 855 u_short dst_port, 856 int alias_port_param, /* if less than zero, alias */ 857 int link_type) /* port will be automatically */ 858{ /* chosen. If greater than */ 859 u_int start_point; /* zero, equal to alias port */ 860 struct alias_link *link; 861 struct alias_link *first_link; 862 863 link = malloc(sizeof(struct alias_link)); 864 if (link != NULL) 865 { 866 /* Basic initialization */ 867 link->src_addr = src_addr; 868 link->dst_addr = dst_addr; 869 link->alias_addr = alias_addr; 870 link->proxy_addr.s_addr = INADDR_ANY; 871 link->src_port = src_port; 872 link->dst_port = dst_port; 873 link->proxy_port = 0; 874 link->link_type = link_type; 875 link->sockfd = -1; 876 link->flags = 0; 877 link->timestamp = timeStamp; 878 879 /* Expiration time */ 880 switch (link_type) 881 { 882 case LINK_ICMP: 883 link->expire_time = ICMP_EXPIRE_TIME; 884 break; 885 case LINK_UDP: 886 link->expire_time = UDP_EXPIRE_TIME; 887 break; 888 case LINK_TCP: 889 link->expire_time = TCP_EXPIRE_INITIAL; 890 break; 891 case LINK_PPTP: 892 link->expire_time = PPTP_EXPIRE_TIME; 893 break; 894 case LINK_FRAGMENT_ID: 895 link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 896 break; 897 case LINK_FRAGMENT_PTR: 898 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 899 break; 900 } 901 902 /* Determine alias flags */ 903 if (dst_addr.s_addr == INADDR_ANY) 904 link->flags |= LINK_UNKNOWN_DEST_ADDR; 905 if (dst_port == 0) 906 link->flags |= LINK_UNKNOWN_DEST_PORT; 907 908 /* Determine alias port */ 909 if (GetNewPort(link, alias_port_param) != 0) 910 { 911 free(link); 912 return(NULL); 913 } 914 915 /* Set up pointers for output lookup table */ 916 start_point = StartPointOut(src_addr, dst_addr, 917 src_port, dst_port, link_type); 918 first_link = linkTableOut[start_point]; 919 920 link->last_out = NULL; 921 link->next_out = first_link; 922 link->start_point_out = start_point; 923 924 if (first_link != NULL) 925 first_link->last_out = link; 926 927 linkTableOut[start_point] = link; 928 929 /* Set up pointers for input lookup table */ 930 start_point = StartPointIn(alias_addr, link->alias_port, link_type); 931 first_link = linkTableIn[start_point]; 932 933 link->last_in = NULL; 934 link->next_in = first_link; 935 link->start_point_in = start_point; 936 937 if (first_link != NULL) 938 first_link->last_in = link; 939 940 linkTableIn[start_point] = link; 941 942 /* Link-type dependent initialization */ 943 switch(link_type) 944 { 945 struct tcp_dat *aux_tcp; 946 947 case LINK_ICMP: 948 icmpLinkCount++; 949 break; 950 case LINK_UDP: 951 udpLinkCount++; 952 break; 953 case LINK_TCP: 954 aux_tcp = malloc(sizeof(struct tcp_dat)); 955 link->data.tcp = aux_tcp; 956 if (aux_tcp != NULL) 957 { 958 int i; 959 960 tcpLinkCount++; 961 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 962 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 963 aux_tcp->state.index = 0; 964 aux_tcp->state.ack_modified = 0; 965 for (i=0; i<N_LINK_TCP_DATA; i++) 966 aux_tcp->ack[i].active = 0; 967 aux_tcp->fwhole = -1; 968 } 969 else 970 { 971#ifdef DEBUG 972 fprintf(stderr, "PacketAlias/AddLink: "); 973 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 974#endif 975 } 976 break; 977 case LINK_PPTP: 978 pptpLinkCount++; 979 break; 980 case LINK_FRAGMENT_ID: 981 fragmentIdLinkCount++; 982 break; 983 case LINK_FRAGMENT_PTR: 984 fragmentPtrLinkCount++; 985 break; 986 } 987 } 988 else 989 { 990#ifdef DEBUG 991 fprintf(stderr, "PacketAlias/AddLink(): "); 992 fprintf(stderr, "malloc() call failed.\n"); 993#endif 994 } 995 996 if (packetAliasMode & PKT_ALIAS_LOG) 997 { 998 ShowAliasStats(); 999 } 1000 1001 return(link); 1002} 1003 1004static struct alias_link * 1005ReLink(struct alias_link *old_link, 1006 struct in_addr src_addr, 1007 struct in_addr dst_addr, 1008 struct in_addr alias_addr, 1009 u_short src_port, 1010 u_short dst_port, 1011 int alias_port_param, /* if less than zero, alias */ 1012 int link_type) /* port will be automatically */ 1013{ /* chosen. If greater than */ 1014 struct alias_link *new_link; /* zero, equal to alias port */ 1015 1016 new_link = AddLink(src_addr, dst_addr, alias_addr, 1017 src_port, dst_port, alias_port_param, 1018 link_type); 1019#ifndef NO_FW_PUNCH 1020 if (new_link != NULL && 1021 old_link->link_type == LINK_TCP && 1022 old_link->data.tcp && 1023 old_link->data.tcp->fwhole > 0) { 1024 PunchFWHole(new_link); 1025 } 1026#endif 1027 DeleteLink(old_link); 1028 return new_link; 1029} 1030 1031static struct alias_link * 1032_FindLinkOut(struct in_addr src_addr, 1033 struct in_addr dst_addr, 1034 u_short src_port, 1035 u_short dst_port, 1036 int link_type, 1037 int replace_partial_links) 1038{ 1039 u_int i; 1040 struct alias_link *link; 1041 1042 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1043 link = linkTableOut[i]; 1044 while (link != NULL) 1045 { 1046 if (link->src_addr.s_addr == src_addr.s_addr 1047 && link->dst_addr.s_addr == dst_addr.s_addr 1048 && link->dst_port == dst_port 1049 && link->src_port == src_port 1050 && link->link_type == link_type) 1051 { 1052 link->timestamp = timeStamp; 1053 break; 1054 } 1055 link = link->next_out; 1056 } 1057 1058/* Search for partially specified links. */ 1059 if (link == NULL && replace_partial_links) 1060 { 1061 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) 1062 { 1063 link = _FindLinkOut(src_addr, dst_addr, src_port, 0, 1064 link_type, 0); 1065 if (link == NULL) 1066 link = _FindLinkOut(src_addr, nullAddress, src_port, 1067 dst_port, link_type, 0); 1068 } 1069 if (link == NULL && 1070 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) 1071 { 1072 link = _FindLinkOut(src_addr, nullAddress, src_port, 0, 1073 link_type, 0); 1074 } 1075 if (link != NULL) 1076 { 1077 link = ReLink(link, 1078 src_addr, dst_addr, link->alias_addr, 1079 src_port, dst_port, link->alias_port, 1080 link_type); 1081 } 1082 } 1083 1084 return(link); 1085} 1086 1087static struct alias_link * 1088FindLinkOut(struct in_addr src_addr, 1089 struct in_addr dst_addr, 1090 u_short src_port, 1091 u_short dst_port, 1092 int link_type, 1093 int replace_partial_links) 1094{ 1095 struct alias_link *link; 1096 1097 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port, 1098 link_type, replace_partial_links); 1099 1100 if (link == NULL) 1101 { 1102 /* The following allows permanent links to be 1103 specified as using the default source address 1104 (i.e. device interface address) without knowing 1105 in advance what that address is. */ 1106 if (aliasAddress.s_addr != 0 && 1107 src_addr.s_addr == aliasAddress.s_addr) 1108 { 1109 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port, 1110 link_type, replace_partial_links); 1111 } 1112 } 1113 1114 return(link); 1115} 1116 1117 1118static struct alias_link * 1119_FindLinkIn(struct in_addr dst_addr, 1120 struct in_addr alias_addr, 1121 u_short dst_port, 1122 u_short alias_port, 1123 int link_type, 1124 int replace_partial_links) 1125{ 1126 int flags_in; 1127 u_int start_point; 1128 struct alias_link *link; 1129 struct alias_link *link_fully_specified; 1130 struct alias_link *link_unknown_all; 1131 struct alias_link *link_unknown_dst_addr; 1132 struct alias_link *link_unknown_dst_port; 1133 1134/* Initialize pointers */ 1135 link_fully_specified = NULL; 1136 link_unknown_all = NULL; 1137 link_unknown_dst_addr = NULL; 1138 link_unknown_dst_port = NULL; 1139 1140/* If either the dest addr or port is unknown, the search 1141 loop will have to know about this. */ 1142 1143 flags_in = 0; 1144 if (dst_addr.s_addr == INADDR_ANY) 1145 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1146 if (dst_port == 0) 1147 flags_in |= LINK_UNKNOWN_DEST_PORT; 1148 1149/* Search loop */ 1150 start_point = StartPointIn(alias_addr, alias_port, link_type); 1151 link = linkTableIn[start_point]; 1152 while (link != NULL) 1153 { 1154 int flags; 1155 1156 flags = flags_in | link->flags; 1157 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1158 { 1159 if (link->alias_addr.s_addr == alias_addr.s_addr 1160 && link->alias_port == alias_port 1161 && link->dst_addr.s_addr == dst_addr.s_addr 1162 && link->dst_port == dst_port 1163 && link->link_type == link_type) 1164 { 1165 link_fully_specified = link; 1166 break; 1167 } 1168 } 1169 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1170 && (flags & LINK_UNKNOWN_DEST_PORT)) 1171 { 1172 if (link->alias_addr.s_addr == alias_addr.s_addr 1173 && link->alias_port == alias_port 1174 && link->link_type == link_type) 1175 { 1176 if (link_unknown_all == NULL) 1177 link_unknown_all = link; 1178 } 1179 } 1180 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1181 { 1182 if (link->alias_addr.s_addr == alias_addr.s_addr 1183 && link->alias_port == alias_port 1184 && link->link_type == link_type 1185 && link->dst_port == dst_port) 1186 { 1187 if (link_unknown_dst_addr == NULL) 1188 link_unknown_dst_addr = link; 1189 } 1190 } 1191 else if (flags & LINK_UNKNOWN_DEST_PORT) 1192 { 1193 if (link->alias_addr.s_addr == alias_addr.s_addr 1194 && link->alias_port == alias_port 1195 && link->link_type == link_type 1196 && link->dst_addr.s_addr == dst_addr.s_addr) 1197 { 1198 if (link_unknown_dst_port == NULL) 1199 link_unknown_dst_port = link; 1200 } 1201 } 1202 link = link->next_in; 1203 } 1204 1205 1206 1207 if (link_fully_specified != NULL) 1208 { 1209 link_fully_specified->timestamp = timeStamp; 1210 return link_fully_specified; 1211 } 1212 else if (link_unknown_dst_port != NULL) 1213 { 1214 return replace_partial_links 1215 ? ReLink(link_unknown_dst_port, 1216 link_unknown_dst_port->src_addr, dst_addr, alias_addr, 1217 link_unknown_dst_port->src_port, dst_port, alias_port, 1218 link_type) 1219 : link_unknown_dst_port; 1220 } 1221 else if (link_unknown_dst_addr != NULL) 1222 { 1223 return replace_partial_links 1224 ? ReLink(link_unknown_dst_addr, 1225 link_unknown_dst_addr->src_addr, dst_addr, alias_addr, 1226 link_unknown_dst_addr->src_port, dst_port, alias_port, 1227 link_type) 1228 : link_unknown_dst_addr; 1229 } 1230 else if (link_unknown_all != NULL) 1231 { 1232 return replace_partial_links 1233 ? ReLink(link_unknown_all, 1234 link_unknown_all->src_addr, dst_addr, alias_addr, 1235 link_unknown_all->src_port, dst_port, alias_port, 1236 link_type) 1237 : link_unknown_all; 1238 } 1239 else 1240 { 1241 return(NULL); 1242 } 1243} 1244 1245static struct alias_link * 1246FindLinkIn(struct in_addr dst_addr, 1247 struct in_addr alias_addr, 1248 u_short dst_port, 1249 u_short alias_port, 1250 int link_type, 1251 int replace_partial_links) 1252{ 1253 struct alias_link *link; 1254 1255 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, 1256 link_type, replace_partial_links); 1257 1258 if (link == NULL) 1259 { 1260 /* The following allows permanent links to be 1261 specified as using the default aliasing address 1262 (i.e. device interface address) without knowing 1263 in advance what that address is. */ 1264 if (aliasAddress.s_addr != 0 && 1265 alias_addr.s_addr == aliasAddress.s_addr) 1266 { 1267 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port, 1268 link_type, replace_partial_links); 1269 } 1270 } 1271 1272 return(link); 1273} 1274 1275 1276 1277 1278/* External routines for finding/adding links 1279 1280-- "external" means outside alias_db.c, but within alias*.c -- 1281 1282 FindIcmpIn(), FindIcmpOut() 1283 FindFragmentIn1(), FindFragmentIn2() 1284 AddFragmentPtrLink(), FindFragmentPtr() 1285 FindPptpIn(), FindPptpOut() 1286 FindUdpTcpIn(), FindUdpTcpOut() 1287 FindOriginalAddress(), FindAliasAddress() 1288 1289(prototypes in alias_local.h) 1290*/ 1291 1292 1293struct alias_link * 1294FindIcmpIn(struct in_addr dst_addr, 1295 struct in_addr alias_addr, 1296 u_short id_alias) 1297{ 1298 return FindLinkIn(dst_addr, alias_addr, 1299 NO_DEST_PORT, id_alias, 1300 LINK_ICMP, 0); 1301} 1302 1303 1304struct alias_link * 1305FindIcmpOut(struct in_addr src_addr, 1306 struct in_addr dst_addr, 1307 u_short id) 1308{ 1309 struct alias_link * link; 1310 1311 link = FindLinkOut(src_addr, dst_addr, 1312 id, NO_DEST_PORT, 1313 LINK_ICMP, 0); 1314 if (link == NULL) 1315 { 1316 struct in_addr alias_addr; 1317 1318 alias_addr = FindAliasAddress(src_addr); 1319 link = AddLink(src_addr, dst_addr, alias_addr, 1320 id, NO_DEST_PORT, GET_ALIAS_ID, 1321 LINK_ICMP); 1322 } 1323 1324 return(link); 1325} 1326 1327 1328struct alias_link * 1329FindFragmentIn1(struct in_addr dst_addr, 1330 struct in_addr alias_addr, 1331 u_short ip_id) 1332{ 1333 struct alias_link *link; 1334 1335 link = FindLinkIn(dst_addr, alias_addr, 1336 NO_DEST_PORT, ip_id, 1337 LINK_FRAGMENT_ID, 0); 1338 1339 if (link == NULL) 1340 { 1341 link = AddLink(nullAddress, dst_addr, alias_addr, 1342 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1343 LINK_FRAGMENT_ID); 1344 } 1345 1346 return(link); 1347} 1348 1349 1350struct alias_link * 1351FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1352 struct in_addr alias_addr, /* is not found. */ 1353 u_short ip_id) 1354{ 1355 return FindLinkIn(dst_addr, alias_addr, 1356 NO_DEST_PORT, ip_id, 1357 LINK_FRAGMENT_ID, 0); 1358} 1359 1360 1361struct alias_link * 1362AddFragmentPtrLink(struct in_addr dst_addr, 1363 u_short ip_id) 1364{ 1365 return AddLink(nullAddress, dst_addr, nullAddress, 1366 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1367 LINK_FRAGMENT_PTR); 1368} 1369 1370 1371struct alias_link * 1372FindFragmentPtr(struct in_addr dst_addr, 1373 u_short ip_id) 1374{ 1375 return FindLinkIn(dst_addr, nullAddress, 1376 NO_DEST_PORT, ip_id, 1377 LINK_FRAGMENT_PTR, 0); 1378} 1379 1380 1381struct alias_link * 1382FindPptpIn(struct in_addr dst_addr, 1383 struct in_addr alias_addr) 1384{ 1385 struct alias_link *link; 1386 1387 link = FindLinkIn(dst_addr, alias_addr, 1388 NO_DEST_PORT, 0, 1389 LINK_PPTP, 1); 1390 1391 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1392 { 1393 struct in_addr target_addr; 1394 1395 target_addr = FindOriginalAddress(alias_addr); 1396 link = AddLink(target_addr, dst_addr, alias_addr, 1397 NO_SRC_PORT, NO_DEST_PORT, 0, 1398 LINK_PPTP); 1399 } 1400 1401 return (link); 1402} 1403 1404 1405struct alias_link * 1406FindPptpOut(struct in_addr src_addr, 1407 struct in_addr dst_addr) 1408{ 1409 struct alias_link *link; 1410 1411 link = FindLinkOut(src_addr, dst_addr, 1412 NO_SRC_PORT, NO_DEST_PORT, 1413 LINK_PPTP, 1); 1414 1415 if (link == NULL) 1416 { 1417 struct in_addr alias_addr; 1418 1419 alias_addr = FindAliasAddress(src_addr); 1420 link = AddLink(src_addr, dst_addr, alias_addr, 1421 NO_SRC_PORT, NO_DEST_PORT, 0, 1422 LINK_PPTP); 1423 } 1424 1425 return (link); 1426} 1427 1428 1429struct alias_link * 1430FindUdpTcpIn(struct in_addr dst_addr, 1431 struct in_addr alias_addr, 1432 u_short dst_port, 1433 u_short alias_port, 1434 u_char proto) 1435{ 1436 int link_type; 1437 struct alias_link *link; 1438 1439 switch (proto) 1440 { 1441 case IPPROTO_UDP: 1442 link_type = LINK_UDP; 1443 break; 1444 case IPPROTO_TCP: 1445 link_type = LINK_TCP; 1446 break; 1447 default: 1448 return NULL; 1449 break; 1450 } 1451 1452 link = FindLinkIn(dst_addr, alias_addr, 1453 dst_port, alias_port, 1454 link_type, 1); 1455 1456 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING) 1457 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY) 1458 && link == NULL) 1459 { 1460 struct in_addr target_addr; 1461 1462 target_addr = FindOriginalAddress(alias_addr); 1463 link = AddLink(target_addr, dst_addr, alias_addr, 1464 alias_port, dst_port, alias_port, 1465 link_type); 1466 } 1467 1468 return(link); 1469} 1470 1471 1472struct alias_link * 1473FindUdpTcpOut(struct in_addr src_addr, 1474 struct in_addr dst_addr, 1475 u_short src_port, 1476 u_short dst_port, 1477 u_char proto) 1478{ 1479 int link_type; 1480 struct alias_link *link; 1481 1482 switch (proto) 1483 { 1484 case IPPROTO_UDP: 1485 link_type = LINK_UDP; 1486 break; 1487 case IPPROTO_TCP: 1488 link_type = LINK_TCP; 1489 break; 1490 default: 1491 return NULL; 1492 break; 1493 } 1494 1495 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, 1); 1496 1497 if (link == NULL) 1498 { 1499 struct in_addr alias_addr; 1500 1501 alias_addr = FindAliasAddress(src_addr); 1502 link = AddLink(src_addr, dst_addr, alias_addr, 1503 src_port, dst_port, GET_ALIAS_PORT, 1504 link_type); 1505 } 1506 1507 return(link); 1508} 1509 1510 1511struct in_addr 1512FindOriginalAddress(struct in_addr alias_addr) 1513{ 1514 struct alias_link *link; 1515 1516 link = FindLinkIn(nullAddress, alias_addr, 1517 0, 0, LINK_ADDR, 0); 1518 if (link == NULL) 1519 { 1520 newDefaultLink = 1; 1521 if (targetAddress.s_addr == INADDR_ANY) 1522 return alias_addr; 1523 else if (targetAddress.s_addr == INADDR_NONE) 1524 return aliasAddress; 1525 else 1526 return targetAddress; 1527 } 1528 else 1529 { 1530 if (link->src_addr.s_addr == INADDR_ANY) 1531 return aliasAddress; 1532 else 1533 return link->src_addr; 1534 } 1535} 1536 1537 1538struct in_addr 1539FindAliasAddress(struct in_addr original_addr) 1540{ 1541 struct alias_link *link; 1542 1543 link = FindLinkOut(original_addr, nullAddress, 1544 0, 0, LINK_ADDR, 0); 1545 if (link == NULL) 1546 { 1547 return aliasAddress; 1548 } 1549 else 1550 { 1551 if (link->alias_addr.s_addr == INADDR_ANY) 1552 return aliasAddress; 1553 else 1554 return link->alias_addr; 1555 } 1556} 1557 1558 1559/* External routines for getting or changing link data 1560 (external to alias_db.c, but internal to alias*.c) 1561 1562 SetFragmentData(), GetFragmentData() 1563 SetFragmentPtr(), GetFragmentPtr() 1564 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1565 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1566 GetOriginalPort(), GetAliasPort() 1567 SetAckModified(), GetAckModified() 1568 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1569*/ 1570 1571 1572void 1573SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1574{ 1575 link->data.frag_addr = src_addr; 1576} 1577 1578 1579void 1580GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1581{ 1582 *src_addr = link->data.frag_addr; 1583} 1584 1585 1586void 1587SetFragmentPtr(struct alias_link *link, char *fptr) 1588{ 1589 link->data.frag_ptr = fptr; 1590} 1591 1592 1593void 1594GetFragmentPtr(struct alias_link *link, char **fptr) 1595{ 1596 *fptr = link->data.frag_ptr; 1597} 1598 1599 1600void 1601SetStateIn(struct alias_link *link, int state) 1602{ 1603 /* TCP input state */ 1604 switch (state) { 1605 case ALIAS_TCP_STATE_DISCONNECTED: 1606 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1607 link->expire_time = TCP_EXPIRE_DEAD; 1608 else 1609 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1610 break; 1611 case ALIAS_TCP_STATE_CONNECTED: 1612 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1613 link->expire_time = TCP_EXPIRE_CONNECTED; 1614 break; 1615 default: 1616 abort(); 1617 } 1618 link->data.tcp->state.in = state; 1619} 1620 1621 1622void 1623SetStateOut(struct alias_link *link, int state) 1624{ 1625 /* TCP output state */ 1626 switch (state) { 1627 case ALIAS_TCP_STATE_DISCONNECTED: 1628 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1629 link->expire_time = TCP_EXPIRE_DEAD; 1630 else 1631 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1632 break; 1633 case ALIAS_TCP_STATE_CONNECTED: 1634 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1635 link->expire_time = TCP_EXPIRE_CONNECTED; 1636 break; 1637 default: 1638 abort(); 1639 } 1640 link->data.tcp->state.out = state; 1641} 1642 1643 1644int 1645GetStateIn(struct alias_link *link) 1646{ 1647 /* TCP input state */ 1648 return link->data.tcp->state.in; 1649} 1650 1651 1652int 1653GetStateOut(struct alias_link *link) 1654{ 1655 /* TCP output state */ 1656 return link->data.tcp->state.out; 1657} 1658 1659 1660struct in_addr 1661GetOriginalAddress(struct alias_link *link) 1662{ 1663 if (link->src_addr.s_addr == INADDR_ANY) 1664 return aliasAddress; 1665 else 1666 return(link->src_addr); 1667} 1668 1669 1670struct in_addr 1671GetDestAddress(struct alias_link *link) 1672{ 1673 return(link->dst_addr); 1674} 1675 1676 1677struct in_addr 1678GetAliasAddress(struct alias_link *link) 1679{ 1680 if (link->alias_addr.s_addr == INADDR_ANY) 1681 return aliasAddress; 1682 else 1683 return link->alias_addr; 1684} 1685 1686 1687struct in_addr 1688GetDefaultAliasAddress() 1689{ 1690 return aliasAddress; 1691} 1692 1693 1694void 1695SetDefaultAliasAddress(struct in_addr alias_addr) 1696{ 1697 aliasAddress = alias_addr; 1698} 1699 1700 1701u_short 1702GetOriginalPort(struct alias_link *link) 1703{ 1704 return(link->src_port); 1705} 1706 1707 1708u_short 1709GetAliasPort(struct alias_link *link) 1710{ 1711 return(link->alias_port); 1712} 1713 1714#ifndef NO_FW_PUNCH 1715static u_short 1716GetDestPort(struct alias_link *link) 1717{ 1718 return(link->dst_port); 1719} 1720#endif 1721 1722void 1723SetAckModified(struct alias_link *link) 1724{ 1725/* Indicate that ACK numbers have been modified in a TCP connection */ 1726 link->data.tcp->state.ack_modified = 1; 1727} 1728 1729 1730struct in_addr 1731GetProxyAddress(struct alias_link *link) 1732{ 1733 return link->proxy_addr; 1734} 1735 1736 1737void 1738SetProxyAddress(struct alias_link *link, struct in_addr addr) 1739{ 1740 link->proxy_addr = addr; 1741} 1742 1743 1744u_short 1745GetProxyPort(struct alias_link *link) 1746{ 1747 return link->proxy_port; 1748} 1749 1750 1751void 1752SetProxyPort(struct alias_link *link, u_short port) 1753{ 1754 link->proxy_port = port; 1755} 1756 1757 1758int 1759GetAckModified(struct alias_link *link) 1760{ 1761/* See if ACK numbers have been modified */ 1762 return link->data.tcp->state.ack_modified; 1763} 1764 1765 1766int 1767GetDeltaAckIn(struct ip *pip, struct alias_link *link) 1768{ 1769/* 1770Find out how much the ACK number has been altered for an incoming 1771TCP packet. To do this, a circular list of ACK numbers where the TCP 1772packet size was altered is searched. 1773*/ 1774 1775 int i; 1776 struct tcphdr *tc; 1777 int delta, ack_diff_min; 1778 u_long ack; 1779 1780 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1781 ack = tc->th_ack; 1782 1783 delta = 0; 1784 ack_diff_min = -1; 1785 for (i=0; i<N_LINK_TCP_DATA; i++) 1786 { 1787 struct ack_data_record x; 1788 1789 x = link->data.tcp->ack[i]; 1790 if (x.active == 1) 1791 { 1792 int ack_diff; 1793 1794 ack_diff = SeqDiff(x.ack_new, ack); 1795 if (ack_diff >= 0) 1796 { 1797 if (ack_diff_min >= 0) 1798 { 1799 if (ack_diff < ack_diff_min) 1800 { 1801 delta = x.delta; 1802 ack_diff_min = ack_diff; 1803 } 1804 } 1805 else 1806 { 1807 delta = x.delta; 1808 ack_diff_min = ack_diff; 1809 } 1810 } 1811 } 1812 } 1813 return (delta); 1814} 1815 1816 1817int 1818GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 1819{ 1820/* 1821Find out how much the sequence number has been altered for an outgoing 1822TCP packet. To do this, a circular list of ACK numbers where the TCP 1823packet size was altered is searched. 1824*/ 1825 1826 int i; 1827 struct tcphdr *tc; 1828 int delta, seq_diff_min; 1829 u_long seq; 1830 1831 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1832 seq = tc->th_seq; 1833 1834 delta = 0; 1835 seq_diff_min = -1; 1836 for (i=0; i<N_LINK_TCP_DATA; i++) 1837 { 1838 struct ack_data_record x; 1839 1840 x = link->data.tcp->ack[i]; 1841 if (x.active == 1) 1842 { 1843 int seq_diff; 1844 1845 seq_diff = SeqDiff(x.ack_old, seq); 1846 if (seq_diff >= 0) 1847 { 1848 if (seq_diff_min >= 0) 1849 { 1850 if (seq_diff < seq_diff_min) 1851 { 1852 delta = x.delta; 1853 seq_diff_min = seq_diff; 1854 } 1855 } 1856 else 1857 { 1858 delta = x.delta; 1859 seq_diff_min = seq_diff; 1860 } 1861 } 1862 } 1863 } 1864 return (delta); 1865} 1866 1867 1868void 1869AddSeq(struct ip *pip, struct alias_link *link, int delta) 1870{ 1871/* 1872When a TCP packet has been altered in length, save this 1873information in a circular list. If enough packets have 1874been altered, then this list will begin to overwrite itself. 1875*/ 1876 1877 struct tcphdr *tc; 1878 struct ack_data_record x; 1879 int hlen, tlen, dlen; 1880 int i; 1881 1882 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1883 1884 hlen = (pip->ip_hl + tc->th_off) << 2; 1885 tlen = ntohs(pip->ip_len); 1886 dlen = tlen - hlen; 1887 1888 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 1889 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 1890 x.delta = delta; 1891 x.active = 1; 1892 1893 i = link->data.tcp->state.index; 1894 link->data.tcp->ack[i] = x; 1895 1896 i++; 1897 if (i == N_LINK_TCP_DATA) 1898 link->data.tcp->state.index = 0; 1899 else 1900 link->data.tcp->state.index = i; 1901} 1902 1903void 1904SetExpire(struct alias_link *link, int expire) 1905{ 1906 if (expire == 0) 1907 { 1908 link->flags &= ~LINK_PERMANENT; 1909 DeleteLink(link); 1910 } 1911 else if (expire == -1) 1912 { 1913 link->flags |= LINK_PERMANENT; 1914 } 1915 else if (expire > 0) 1916 { 1917 link->expire_time = expire; 1918 } 1919 else 1920 { 1921#ifdef DEBUG 1922 fprintf(stderr, "PacketAlias/SetExpire(): "); 1923 fprintf(stderr, "error in expire parameter\n"); 1924#endif 1925 } 1926} 1927 1928void 1929ClearCheckNewLink(void) 1930{ 1931 newDefaultLink = 0; 1932} 1933 1934 1935/* Miscellaneous Functions 1936 1937 HouseKeeping() 1938 InitPacketAliasLog() 1939 UninitPacketAliasLog() 1940*/ 1941 1942/* 1943 Whenever an outgoing or incoming packet is handled, HouseKeeping() 1944 is called to find and remove timed-out aliasing links. Logic exists 1945 to sweep through the entire table and linked list structure 1946 every 60 seconds. 1947 1948 (prototype in alias_local.h) 1949*/ 1950 1951void 1952HouseKeeping(void) 1953{ 1954 int i, n, n100; 1955 struct timeval tv; 1956 struct timezone tz; 1957 1958 /* 1959 * Save system time (seconds) in global variable timeStamp for 1960 * use by other functions. This is done so as not to unnecessarily 1961 * waste timeline by making system calls. 1962 */ 1963 gettimeofday(&tv, &tz); 1964 timeStamp = tv.tv_sec; 1965 1966 /* Compute number of spokes (output table link chains) to cover */ 1967 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 1968 n100 *= timeStamp - lastCleanupTime; 1969 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 1970 1971 n = n100/100; 1972 1973 /* Handle different cases */ 1974 if (n > ALIAS_CLEANUP_MAX_SPOKES) 1975 { 1976 n = ALIAS_CLEANUP_MAX_SPOKES; 1977 lastCleanupTime = timeStamp; 1978 houseKeepingResidual = 0; 1979 1980 for (i=0; i<n; i++) 1981 IncrementalCleanup(); 1982 } 1983 else if (n > 0) 1984 { 1985 lastCleanupTime = timeStamp; 1986 houseKeepingResidual = n100 - 100*n; 1987 1988 for (i=0; i<n; i++) 1989 IncrementalCleanup(); 1990 } 1991 else if (n < 0) 1992 { 1993#ifdef DEBUG 1994 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 1995 fprintf(stderr, "something unexpected in time values\n"); 1996#endif 1997 lastCleanupTime = timeStamp; 1998 houseKeepingResidual = 0; 1999 } 2000} 2001 2002 2003/* Init the log file and enable logging */ 2004static void 2005InitPacketAliasLog(void) 2006{ 2007 if ((~packetAliasMode & PKT_ALIAS_LOG) 2008 && (monitorFile = fopen("/var/log/alias.log", "w"))) 2009 { 2010 packetAliasMode |= PKT_ALIAS_LOG; 2011 fprintf(monitorFile, 2012 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2013 } 2014} 2015 2016 2017/* Close the log-file and disable logging. */ 2018static void 2019UninitPacketAliasLog(void) 2020{ 2021 if (monitorFile) { 2022 fclose(monitorFile); 2023 monitorFile = NULL; 2024 } 2025 packetAliasMode &= ~PKT_ALIAS_LOG; 2026} 2027 2028 2029 2030 2031 2032 2033/* Outside world interfaces 2034 2035-- "outside world" means other than alias*.c routines -- 2036 2037 PacketAliasRedirectPort() 2038 PacketAliasRedirectPptp() 2039 PacketAliasRedirectAddr() 2040 PacketAliasRedirectDelete() 2041 PacketAliasSetAddress() 2042 PacketAliasInit() 2043 PacketAliasUninit() 2044 PacketAliasSetMode() 2045 2046(prototypes in alias.h) 2047*/ 2048 2049/* Redirection from a specific public addr:port to a 2050 private addr:port */ 2051struct alias_link * 2052PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 2053 struct in_addr dst_addr, u_short dst_port, 2054 struct in_addr alias_addr, u_short alias_port, 2055 u_char proto) 2056{ 2057 int link_type; 2058 struct alias_link *link; 2059 2060 switch(proto) 2061 { 2062 case IPPROTO_UDP: 2063 link_type = LINK_UDP; 2064 break; 2065 case IPPROTO_TCP: 2066 link_type = LINK_TCP; 2067 break; 2068 default: 2069#ifdef DEBUG 2070 fprintf(stderr, "PacketAliasRedirectPort(): "); 2071 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2072#endif 2073 return NULL; 2074 } 2075 2076 link = AddLink(src_addr, dst_addr, alias_addr, 2077 src_port, dst_port, alias_port, 2078 link_type); 2079 2080 if (link != NULL) 2081 { 2082 link->flags |= LINK_PERMANENT; 2083 } 2084#ifdef DEBUG 2085 else 2086 { 2087 fprintf(stderr, "PacketAliasRedirectPort(): " 2088 "call to AddLink() failed\n"); 2089 } 2090#endif 2091 2092 return link; 2093} 2094 2095/* Translate PPTP packets to a machine on the inside 2096 * XXX This function is made obsolete by PacketAliasRedirectPptp(). 2097 */ 2098int 2099PacketAliasPptp(struct in_addr src_addr) 2100{ 2101 2102 if (src_addr.s_addr == INADDR_NONE) 2103 packetAliasMode |= PKT_ALIAS_DENY_PPTP; 2104 else 2105 (void)PacketAliasRedirectPptp(src_addr, nullAddress, nullAddress); 2106 2107 return 1; 2108} 2109 2110/* Redirect PPTP packets from a specific 2111 public address to a private address */ 2112struct alias_link * 2113PacketAliasRedirectPptp(struct in_addr src_addr, 2114 struct in_addr dst_addr, 2115 struct in_addr alias_addr) 2116{ 2117 struct alias_link *link; 2118 2119 link = AddLink(src_addr, dst_addr, alias_addr, 2120 NO_SRC_PORT, NO_DEST_PORT, 0, 2121 LINK_PPTP); 2122 2123 if (link != NULL) 2124 { 2125 link->flags |= LINK_PERMANENT; 2126 } 2127#ifdef DEBUG 2128 else 2129 { 2130 fprintf(stderr, "PacketAliasRedirectPptp(): " 2131 "call to AddLink() failed\n"); 2132 } 2133#endif 2134 2135 return link; 2136} 2137 2138/* Static address translation */ 2139struct alias_link * 2140PacketAliasRedirectAddr(struct in_addr src_addr, 2141 struct in_addr alias_addr) 2142{ 2143 struct alias_link *link; 2144 2145 link = AddLink(src_addr, nullAddress, alias_addr, 2146 0, 0, 0, 2147 LINK_ADDR); 2148 2149 if (link != NULL) 2150 { 2151 link->flags |= LINK_PERMANENT; 2152 } 2153#ifdef DEBUG 2154 else 2155 { 2156 fprintf(stderr, "PacketAliasRedirectAddr(): " 2157 "call to AddLink() failed\n"); 2158 } 2159#endif 2160 2161 return link; 2162} 2163 2164 2165void 2166PacketAliasRedirectDelete(struct alias_link *link) 2167{ 2168/* This is a dangerous function to put in the API, 2169 because an invalid pointer can crash the program. */ 2170 2171 deleteAllLinks = 1; 2172 DeleteLink(link); 2173 deleteAllLinks = 0; 2174} 2175 2176 2177void 2178PacketAliasSetAddress(struct in_addr addr) 2179{ 2180 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2181 && aliasAddress.s_addr != addr.s_addr) 2182 CleanupAliasData(); 2183 2184 aliasAddress = addr; 2185} 2186 2187 2188void 2189PacketAliasSetTarget(struct in_addr target_addr) 2190{ 2191 targetAddress = target_addr; 2192} 2193 2194 2195void 2196PacketAliasInit(void) 2197{ 2198 int i; 2199 struct timeval tv; 2200 struct timezone tz; 2201 static int firstCall = 1; 2202 2203 if (firstCall == 1) 2204 { 2205 gettimeofday(&tv, &tz); 2206 timeStamp = tv.tv_sec; 2207 lastCleanupTime = tv.tv_sec; 2208 houseKeepingResidual = 0; 2209 2210 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2211 linkTableOut[i] = NULL; 2212 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2213 linkTableIn[i] = NULL; 2214 2215 atexit(PacketAliasUninit); 2216 firstCall = 0; 2217 } 2218 else 2219 { 2220 deleteAllLinks = 1; 2221 CleanupAliasData(); 2222 deleteAllLinks = 0; 2223 } 2224 2225 aliasAddress.s_addr = INADDR_ANY; 2226 targetAddress.s_addr = INADDR_NONE; 2227 2228 icmpLinkCount = 0; 2229 udpLinkCount = 0; 2230 tcpLinkCount = 0; 2231 pptpLinkCount = 0; 2232 fragmentIdLinkCount = 0; 2233 fragmentPtrLinkCount = 0; 2234 sockCount = 0; 2235 2236 cleanupIndex =0; 2237 2238 packetAliasMode = PKT_ALIAS_SAME_PORTS 2239 | PKT_ALIAS_USE_SOCKETS 2240 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2241} 2242 2243void 2244PacketAliasUninit(void) { 2245 deleteAllLinks = 1; 2246 CleanupAliasData(); 2247 deleteAllLinks = 0; 2248 UninitPacketAliasLog(); 2249#ifndef NO_FW_PUNCH 2250 UninitPunchFW(); 2251#endif 2252} 2253 2254 2255/* Change mode for some operations */ 2256unsigned int 2257PacketAliasSetMode( 2258 unsigned int flags, /* Which state to bring flags to */ 2259 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2260 probe for flag values) */ 2261) 2262{ 2263/* Enable logging? */ 2264 if (flags & mask & PKT_ALIAS_LOG) 2265 { 2266 InitPacketAliasLog(); /* Do the enable */ 2267 } else 2268/* _Disable_ logging? */ 2269 if (~flags & mask & PKT_ALIAS_LOG) { 2270 UninitPacketAliasLog(); 2271 } 2272 2273#ifndef NO_FW_PUNCH 2274/* Start punching holes in the firewall? */ 2275 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2276 InitPunchFW(); 2277 } else 2278/* Stop punching holes in the firewall? */ 2279 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2280 UninitPunchFW(); 2281 } 2282#endif 2283 2284/* Other flags can be set/cleared without special action */ 2285 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2286 return packetAliasMode; 2287} 2288 2289 2290int 2291PacketAliasCheckNewLink(void) 2292{ 2293 return newDefaultLink; 2294} 2295 2296 2297#ifndef NO_FW_PUNCH 2298 2299/***************** 2300 Code to support firewall punching. This shouldn't really be in this 2301 file, but making variables global is evil too. 2302 ****************/ 2303 2304/* Firewall include files */ 2305#include <sys/queue.h> 2306#include <net/if.h> 2307#include <netinet/ip_fw.h> 2308#include <string.h> 2309#include <err.h> 2310 2311static void ClearAllFWHoles(void); 2312 2313static int fireWallBaseNum; /* The first firewall entry free for our use */ 2314static int fireWallNumNums; /* How many entries can we use? */ 2315static int fireWallActiveNum; /* Which entry did we last use? */ 2316static char *fireWallField; /* bool array for entries */ 2317 2318#define fw_setfield(field, num) \ 2319do { \ 2320 (field)[num] = 1; \ 2321} /*lint -save -e717 */ while(0) /*lint -restore */ 2322#define fw_clrfield(field, num) \ 2323do { \ 2324 (field)[num] = 0; \ 2325} /*lint -save -e717 */ while(0) /*lint -restore */ 2326#define fw_tstfield(field, num) ((field)[num]) 2327 2328void 2329PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2330 fireWallBaseNum = base; 2331 fireWallNumNums = num; 2332} 2333 2334static void 2335InitPunchFW(void) { 2336 fireWallField = malloc(fireWallNumNums); 2337 if (fireWallField) { 2338 memset(fireWallField, 0, fireWallNumNums); 2339 if (fireWallFD < 0) { 2340 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2341 } 2342 ClearAllFWHoles(); 2343 fireWallActiveNum = fireWallBaseNum; 2344 } 2345} 2346 2347static void 2348UninitPunchFW(void) { 2349 ClearAllFWHoles(); 2350 if (fireWallFD >= 0) 2351 close(fireWallFD); 2352 fireWallFD = -1; 2353 if (fireWallField) 2354 free(fireWallField); 2355 fireWallField = NULL; 2356 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2357} 2358 2359/* Make a certain link go through the firewall */ 2360void 2361PunchFWHole(struct alias_link *link) { 2362 int r; /* Result code */ 2363 struct ip_fw rule; /* On-the-fly built rule */ 2364 int fwhole; /* Where to punch hole */ 2365 2366/* Don't do anything unless we are asked to */ 2367 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2368 fireWallFD < 0 || 2369 link->link_type != LINK_TCP || 2370 !link->data.tcp) 2371 return; 2372 2373 memset(&rule, 0, sizeof rule); 2374 2375/** Build rule **/ 2376 2377 /* Find empty slot */ 2378 for (fwhole = fireWallActiveNum; 2379 fwhole < fireWallBaseNum + fireWallNumNums && 2380 fw_tstfield(fireWallField, fwhole); 2381 fwhole++) 2382 ; 2383 if (fwhole >= fireWallBaseNum + fireWallNumNums || 2384 fw_tstfield(fireWallField, fwhole)) { 2385 for (fwhole = fireWallBaseNum; 2386 fwhole < fireWallActiveNum && 2387 fw_tstfield(fireWallField, fwhole); 2388 fwhole++) 2389 ; 2390 if (fwhole == fireWallActiveNum) { 2391 /* No rule point empty - we can't punch more holes. */ 2392 fireWallActiveNum = fireWallBaseNum; 2393#ifdef DEBUG 2394 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2395#endif 2396 return; 2397 } 2398 } 2399 /* Start next search at next position */ 2400 fireWallActiveNum = fwhole+1; 2401 2402 /* Build generic part of the two rules */ 2403 rule.fw_number = fwhole; 2404 rule.fw_nports = 1; /* Number of source ports; dest ports follow */ 2405 rule.fw_flg = IP_FW_F_ACCEPT; 2406 rule.fw_prot = IPPROTO_TCP; 2407 rule.fw_smsk.s_addr = INADDR_BROADCAST; 2408 rule.fw_dmsk.s_addr = INADDR_BROADCAST; 2409 2410 /* Build and apply specific part of the rules */ 2411 rule.fw_src = GetOriginalAddress(link); 2412 rule.fw_dst = GetDestAddress(link); 2413 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); 2414 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); 2415 2416 /* Skip non-bound links - XXX should not be strictly necessary, 2417 but seems to leave hole if not done. Leak of non-bound links? 2418 (Code should be left even if the problem is fixed - it is a 2419 clear optimization) */ 2420 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { 2421 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2422#ifdef DEBUG 2423 if (r) 2424 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2425#endif 2426 rule.fw_src = GetDestAddress(link); 2427 rule.fw_dst = GetOriginalAddress(link); 2428 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); 2429 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); 2430 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2431#ifdef DEBUG 2432 if (r) 2433 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2434#endif 2435 } 2436/* Indicate hole applied */ 2437 link->data.tcp->fwhole = fwhole; 2438 fw_setfield(fireWallField, fwhole); 2439} 2440 2441/* Remove a hole in a firewall associated with a particular alias 2442 link. Calling this too often is harmless. */ 2443static void 2444ClearFWHole(struct alias_link *link) { 2445 if (link->link_type == LINK_TCP && link->data.tcp) { 2446 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ 2447 struct ip_fw rule; 2448 2449 if (fwhole < 0) 2450 return; 2451 2452 memset(&rule, 0, sizeof rule); 2453 rule.fw_number = fwhole; 2454 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2455 ; 2456 fw_clrfield(fireWallField, fwhole); 2457 link->data.tcp->fwhole = -1; 2458 } 2459} 2460 2461/* Clear out the entire range dedicated to firewall holes. */ 2462static void 2463ClearAllFWHoles(void) { 2464 struct ip_fw rule; /* On-the-fly built rule */ 2465 int i; 2466 2467 if (fireWallFD < 0) 2468 return; 2469 2470 memset(&rule, 0, sizeof rule); 2471 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { 2472 rule.fw_number = i; 2473 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2474 ; 2475 } 2476 memset(fireWallField, 0, fireWallNumNums); 2477} 2478#endif 2479