alias_db.c revision 51491
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 unspecied 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 now are available through 52 a new interface, SetPacketAliasMode(). This allow 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 permament 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 51491 1999-09-21 01:26:49Z brian $ 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/* Timouts (in seconds) for different link types) */ 148#define ICMP_EXPIRE_TIME 60 149#define UDP_EXPIRE_TIME 60 150#define FRAGMENT_ID_EXPIRE_TIME 10 151#define FRAGMENT_PTR_EXPIRE_TIME 30 152 153/* TCP link expire time for different cases */ 154/* When the link has been used and closed - minimal grace time to 155 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 156#ifndef TCP_EXPIRE_DEAD 157# define TCP_EXPIRE_DEAD 10 158#endif 159 160/* When the link has been used and closed on one side - the other side 161 is allowed to still send data */ 162#ifndef TCP_EXPIRE_SINGLEDEAD 163# define TCP_EXPIRE_SINGLEDEAD 90 164#endif 165 166/* When the link isn't yet up */ 167#ifndef TCP_EXPIRE_INITIAL 168# define TCP_EXPIRE_INITIAL 300 169#endif 170 171/* When the link is up */ 172#ifndef TCP_EXPIRE_CONNECTED 173# define TCP_EXPIRE_CONNECTED 86400 174#endif 175 176 177/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 178 These constants can be anything except zero, which indicates an 179 unknown port number. */ 180 181#define NO_DEST_PORT 1 182#define NO_SRC_PORT 1 183 184 185 186/* Data Structures 187 188 The fundamental data structure used in this program is 189 "struct alias_link". Whenever a TCP connection is made, 190 a UDP datagram is sent out, or an ICMP echo request is made, 191 a link record is made (if it has not already been created). 192 The link record is identified by the source address/port 193 and the destination address/port. In the case of an ICMP 194 echo request, the source port is treated as being equivalent 195 with the 16-bit id number of the ICMP packet. 196 197 The link record also can store some auxiliary data. For 198 TCP connections that have had sequence and acknowledgment 199 modifications, data space is available to track these changes. 200 A state field is used to keep track in changes to the tcp 201 connection state. Id numbers of fragments can also be 202 stored in the auxiliary space. Pointers to unresolved 203 framgents can also be stored. 204 205 The link records support two independent chainings. Lookup 206 tables for input and out tables hold the initial pointers 207 the link chains. On input, the lookup table indexes on alias 208 port and link type. On output, the lookup table indexes on 209 source addreess, destination address, source port, destination 210 port and link type. 211*/ 212 213struct ack_data_record /* used to save changes to ack/seq numbers */ 214{ 215 u_long ack_old; 216 u_long ack_new; 217 int delta; 218 int active; 219}; 220 221struct tcp_state /* Information about tcp connection */ 222{ 223 int in; /* State for outside -> inside */ 224 int out; /* State for inside -> outside */ 225 int index; /* Index to ack data array */ 226 int ack_modified; /* Indicates whether ack and seq numbers */ 227 /* been modified */ 228}; 229 230#define N_LINK_TCP_DATA 3 /* Number of distinct ack number changes 231 saved for a modified TCP stream */ 232struct tcp_dat 233{ 234 struct tcp_state state; 235 struct ack_data_record ack[N_LINK_TCP_DATA]; 236 int fwhole; /* Which firewall record is used for this hole? */ 237}; 238 239struct alias_link /* Main data structure */ 240{ 241 struct in_addr src_addr; /* Address and port information */ 242 struct in_addr dst_addr; 243 struct in_addr alias_addr; 244 struct in_addr proxy_addr; 245 u_short src_port; 246 u_short dst_port; 247 u_short alias_port; 248 u_short proxy_port; 249 250 int link_type; /* Type of link: tcp, udp, icmp, frag */ 251 252/* values for link_type */ 253#define LINK_ICMP 1 254#define LINK_UDP 2 255#define LINK_TCP 3 256#define LINK_FRAGMENT_ID 4 257#define LINK_FRAGMENT_PTR 5 258#define LINK_ADDR 6 259 260 int flags; /* indicates special characteristics */ 261 262/* flag bits */ 263#define LINK_UNKNOWN_DEST_PORT 0x01 264#define LINK_UNKNOWN_DEST_ADDR 0x02 265#define LINK_PERMANENT 0x04 266#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 267#define LINK_UNFIREWALLED 0x08 268 269 int timestamp; /* Time link was last accessed */ 270 int expire_time; /* Expire time for link */ 271 272 int sockfd; /* socket descriptor */ 273 274 u_int start_point_out; /* Index number in output lookup table */ 275 u_int start_point_in; 276 struct alias_link *next_out; /* Linked list pointers for input and */ 277 struct alias_link *last_out; /* output tables */ 278 struct alias_link *next_in; /* . */ 279 struct alias_link *last_in; /* . */ 280 281 union /* Auxiliary data */ 282 { 283 char *frag_ptr; 284 struct in_addr frag_addr; 285 struct tcp_dat *tcp; 286 } data; 287}; 288 289 290 291 292 293/* Global Variables 294 295 The global variables listed here are only accessed from 296 within alias_db.c and so are prefixed with the static 297 designation. 298*/ 299 300int packetAliasMode; /* Mode flags */ 301 /* - documented in alias.h */ 302 303static struct in_addr aliasAddress; /* Address written onto source */ 304 /* field of IP packet. */ 305 306static struct in_addr targetAddress; /* IP address incoming packets */ 307 /* are sent to if no aliasing */ 308 /* link already exists */ 309 310static struct in_addr nullAddress; /* Used as a dummy parameter for */ 311 /* some function calls */ 312static struct alias_link * 313linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ 314 /* chains of link records. Each */ 315static struct alias_link * /* link record is doubly indexed */ 316linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ 317 /* tables. */ 318 319static int icmpLinkCount; /* Link statistics */ 320static int udpLinkCount; 321static int tcpLinkCount; 322static int fragmentIdLinkCount; 323static int fragmentPtrLinkCount; 324static int sockCount; 325 326static int cleanupIndex; /* Index to chain of link table */ 327 /* being inspected for old links */ 328 329static int timeStamp; /* System time in seconds for */ 330 /* current packet */ 331 332static int lastCleanupTime; /* Last time IncrementalCleanup() */ 333 /* was called */ 334 335static int houseKeepingResidual; /* used by HouseKeeping() */ 336 337static int deleteAllLinks; /* If equal to zero, DeleteLink() */ 338 /* will not remove permanent links */ 339 340static FILE *monitorFile; /* File descriptor for link */ 341 /* statistics monitoring file */ 342 343static int newDefaultLink; /* Indicates if a new aliasing */ 344 /* link has been created after a */ 345 /* call to PacketAliasIn/Out(). */ 346 347#ifndef NO_FW_PUNCH 348static int fireWallFD = -1; /* File descriptor to be able to */ 349 /* control firewall. Opened by */ 350 /* PacketAliasSetMode on first */ 351 /* setting the PKT_ALIAS_PUNCH_FW */ 352 /* flag. */ 353#endif 354 355static int pptpAliasFlag; /* Indicates if PPTP aliasing is */ 356 /* on or off */ 357static struct in_addr pptpAliasAddr; /* Address of source of PPTP */ 358 /* packets. */ 359 360 361 362 363 364 365 366/* Internal utility routines (used only in alias_db.c) 367 368Lookup table starting points: 369 StartPointIn() -- link table initial search point for 370 outgoing packets 371 StartPointOut() -- port table initial search point for 372 incoming packets 373 374Miscellaneous: 375 SeqDiff() -- difference between two TCP sequences 376 ShowAliasStats() -- send alias statistics to a monitor file 377*/ 378 379 380/* Local prototypes */ 381static u_int StartPointIn(struct in_addr, u_short, int); 382 383static u_int StartPointOut(struct in_addr, struct in_addr, 384 u_short, u_short, int); 385 386static int SeqDiff(u_long, u_long); 387 388static void ShowAliasStats(void); 389 390#ifndef NO_FW_PUNCH 391/* Firewall control */ 392static void InitPunchFW(void); 393static void UninitPunchFW(void); 394static void ClearFWHole(struct alias_link *link); 395#endif 396 397/* Log file control */ 398static void InitPacketAliasLog(void); 399static void UninitPacketAliasLog(void); 400 401static u_int 402StartPointIn(struct in_addr alias_addr, 403 u_short alias_port, 404 int link_type) 405{ 406 u_int n; 407 408 n = alias_addr.s_addr; 409 n += alias_port; 410 n += link_type; 411 return(n % LINK_TABLE_IN_SIZE); 412} 413 414 415static u_int 416StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 417 u_short src_port, u_short dst_port, int link_type) 418{ 419 u_int n; 420 421 n = src_addr.s_addr; 422 n += dst_addr.s_addr; 423 n += src_port; 424 n += dst_port; 425 n += link_type; 426 427 return(n % LINK_TABLE_OUT_SIZE); 428} 429 430 431static int 432SeqDiff(u_long x, u_long y) 433{ 434/* Return the difference between two TCP sequence numbers */ 435 436/* 437 This function is encapsulated in case there are any unusual 438 arithmetic conditions that need to be considered. 439*/ 440 441 return (ntohl(y) - ntohl(x)); 442} 443 444 445static void 446ShowAliasStats(void) 447{ 448/* Used for debugging */ 449 450 if (monitorFile) 451 { 452 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d", 453 icmpLinkCount, 454 udpLinkCount, 455 tcpLinkCount, 456 fragmentIdLinkCount, 457 fragmentPtrLinkCount); 458 459 fprintf(monitorFile, " / tot=%d (sock=%d)\n", 460 icmpLinkCount + udpLinkCount 461 + tcpLinkCount 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); 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 Whis 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 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 if (idelta > link->expire_time) 738 { 739 DeleteLink(link); 740 icount++; 741 } 742 break; 743 case LINK_TCP: 744 if (idelta > link->expire_time) 745 { 746 struct tcp_dat *tcp_aux; 747 748 tcp_aux = link->data.tcp; 749 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 750 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) 751 { 752 DeleteLink(link); 753 icount++; 754 } 755 } 756 break; 757 } 758 link = link_next; 759 } 760 761 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 762 cleanupIndex = 0; 763} 764 765void 766DeleteLink(struct alias_link *link) 767{ 768 struct alias_link *link_last; 769 struct alias_link *link_next; 770 771/* Don't do anything if the link is marked permanent */ 772 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 773 return; 774 775#ifndef NO_FW_PUNCH 776/* Delete associatied firewall hole, if any */ 777 ClearFWHole(link); 778#endif 779 780/* Adjust output table pointers */ 781 link_last = link->last_out; 782 link_next = link->next_out; 783 784 if (link_last != NULL) 785 link_last->next_out = link_next; 786 else 787 linkTableOut[link->start_point_out] = link_next; 788 789 if (link_next != NULL) 790 link_next->last_out = link_last; 791 792/* Adjust input table pointers */ 793 link_last = link->last_in; 794 link_next = link->next_in; 795 796 if (link_last != NULL) 797 link_last->next_in = link_next; 798 else 799 linkTableIn[link->start_point_in] = link_next; 800 801 if (link_next != NULL) 802 link_next->last_in = link_last; 803 804/* Close socket, if one has been allocated */ 805 if (link->sockfd != -1) 806 { 807 sockCount--; 808 close(link->sockfd); 809 } 810 811/* Link-type dependent cleanup */ 812 switch(link->link_type) 813 { 814 case LINK_ICMP: 815 icmpLinkCount--; 816 break; 817 case LINK_UDP: 818 udpLinkCount--; 819 break; 820 case LINK_TCP: 821 tcpLinkCount--; 822 if (link->data.tcp != NULL) 823 free(link->data.tcp); 824 break; 825 case LINK_FRAGMENT_ID: 826 fragmentIdLinkCount--; 827 break; 828 case LINK_FRAGMENT_PTR: 829 fragmentPtrLinkCount--; 830 if (link->data.frag_ptr != NULL) 831 free(link->data.frag_ptr); 832 break; 833 } 834 835/* Free memory */ 836 free(link); 837 838/* Write statistics, if logging enabled */ 839 if (packetAliasMode & PKT_ALIAS_LOG) 840 { 841 ShowAliasStats(); 842 } 843} 844 845 846static struct alias_link * 847AddLink(struct in_addr src_addr, 848 struct in_addr dst_addr, 849 struct in_addr alias_addr, 850 u_short src_port, 851 u_short dst_port, 852 int alias_port_param, /* if less than zero, alias */ 853 int link_type) /* port will be automatically */ 854{ /* chosen. If greater than */ 855 u_int start_point; /* zero, equal to alias port */ 856 struct alias_link *link; 857 struct alias_link *first_link; 858 859 link = malloc(sizeof(struct alias_link)); 860 if (link != NULL) 861 { 862 /* If either the aliasing address or source address are 863 equal to the default device address (equal to the 864 global variable aliasAddress), then set the alias 865 address field of the link record to zero */ 866 867 if (src_addr.s_addr == aliasAddress.s_addr) 868 src_addr.s_addr = 0; 869 870 if (alias_addr.s_addr == aliasAddress.s_addr) 871 alias_addr.s_addr = 0; 872 873 /* Basic initialization */ 874 link->src_addr = src_addr; 875 link->dst_addr = dst_addr; 876 link->alias_addr = alias_addr; 877 link->proxy_addr.s_addr = 0; 878 link->src_port = src_port; 879 link->dst_port = dst_port; 880 link->proxy_port = 0; 881 link->link_type = link_type; 882 link->sockfd = -1; 883 link->flags = 0; 884 link->timestamp = timeStamp; 885 886 /* Expiration time */ 887 switch (link_type) 888 { 889 case LINK_ICMP: 890 link->expire_time = ICMP_EXPIRE_TIME; 891 break; 892 case LINK_UDP: 893 link->expire_time = UDP_EXPIRE_TIME; 894 break; 895 case LINK_TCP: 896 link->expire_time = TCP_EXPIRE_INITIAL; 897 break; 898 case LINK_FRAGMENT_ID: 899 link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 900 break; 901 case LINK_FRAGMENT_PTR: 902 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 903 break; 904 } 905 906 /* Determine alias flags */ 907 if (dst_addr.s_addr == 0) 908 link->flags |= LINK_UNKNOWN_DEST_ADDR; 909 if (dst_port == 0) 910 link->flags |= LINK_UNKNOWN_DEST_PORT; 911 912 /* Determine alias port */ 913 if (GetNewPort(link, alias_port_param) != 0) 914 { 915 free(link); 916 return(NULL); 917 } 918 919 /* Set up pointers for output lookup table */ 920 start_point = StartPointOut(src_addr, dst_addr, 921 src_port, dst_port, link_type); 922 first_link = linkTableOut[start_point]; 923 924 link->last_out = NULL; 925 link->next_out = first_link; 926 link->start_point_out = start_point; 927 928 if (first_link != NULL) 929 first_link->last_out = link; 930 931 linkTableOut[start_point] = link; 932 933 /* Set up pointers for input lookup table */ 934 start_point = StartPointIn(alias_addr, link->alias_port, link_type); 935 first_link = linkTableIn[start_point]; 936 937 link->last_in = NULL; 938 link->next_in = first_link; 939 link->start_point_in = start_point; 940 941 if (first_link != NULL) 942 first_link->last_in = link; 943 944 linkTableIn[start_point] = link; 945 946 /* Link-type dependent initialization */ 947 switch(link_type) 948 { 949 struct tcp_dat *aux_tcp; 950 951 case LINK_ICMP: 952 icmpLinkCount++; 953 break; 954 case LINK_UDP: 955 udpLinkCount++; 956 break; 957 case LINK_TCP: 958 aux_tcp = malloc(sizeof(struct tcp_dat)); 959 link->data.tcp = aux_tcp; 960 if (aux_tcp != NULL) 961 { 962 int i; 963 964 tcpLinkCount++; 965 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 966 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 967 aux_tcp->state.index = 0; 968 aux_tcp->state.ack_modified = 0; 969 for (i=0; i<N_LINK_TCP_DATA; i++) 970 aux_tcp->ack[i].active = 0; 971 aux_tcp->fwhole = -1; 972 } 973 else 974 { 975#ifdef DEBUG 976 fprintf(stderr, "PacketAlias/AddLink: "); 977 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 978#endif 979 } 980 break; 981 case LINK_FRAGMENT_ID: 982 fragmentIdLinkCount++; 983 break; 984 case LINK_FRAGMENT_PTR: 985 fragmentPtrLinkCount++; 986 break; 987 } 988 } 989 else 990 { 991#ifdef DEBUG 992 fprintf(stderr, "PacketAlias/AddLink(): "); 993 fprintf(stderr, "malloc() call failed.\n"); 994#endif 995 } 996 997 if (packetAliasMode & PKT_ALIAS_LOG) 998 { 999 ShowAliasStats(); 1000 } 1001 1002 return(link); 1003} 1004 1005static struct alias_link * 1006ReLink(struct alias_link *old_link, 1007 struct in_addr src_addr, 1008 struct in_addr dst_addr, 1009 struct in_addr alias_addr, 1010 u_short src_port, 1011 u_short dst_port, 1012 int alias_port_param, /* if less than zero, alias */ 1013 int link_type) /* port will be automatically */ 1014{ /* chosen. If greater than */ 1015 struct alias_link *new_link; /* zero, equal to alias port */ 1016 1017 new_link = AddLink(src_addr, dst_addr, alias_addr, 1018 src_port, dst_port, alias_port_param, 1019 link_type); 1020#ifndef NO_FW_PUNCH 1021 if (new_link != NULL && 1022 old_link->link_type == LINK_TCP && 1023 old_link->data.tcp && 1024 old_link->data.tcp->fwhole > 0) { 1025 PunchFWHole(new_link); 1026 } 1027#endif 1028 DeleteLink(old_link); 1029 return new_link; 1030} 1031 1032static struct alias_link * 1033FindLinkOut(struct in_addr src_addr, 1034 struct in_addr dst_addr, 1035 u_short src_port, 1036 u_short dst_port, 1037 int link_type) 1038{ 1039 u_int i; 1040 struct alias_link *link; 1041 1042 if (src_addr.s_addr == aliasAddress.s_addr) 1043 src_addr.s_addr = 0; 1044 1045 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1046 link = linkTableOut[i]; 1047 while (link != NULL) 1048 { 1049 if (link->src_addr.s_addr == src_addr.s_addr 1050 && link->dst_addr.s_addr == dst_addr.s_addr 1051 && link->dst_port == dst_port 1052 && link->src_port == src_port 1053 && link->link_type == link_type) 1054 { 1055 link->timestamp = timeStamp; 1056 break; 1057 } 1058 link = link->next_out; 1059 } 1060 1061 return(link); 1062} 1063 1064 1065struct alias_link * 1066FindLinkIn(struct in_addr dst_addr, 1067 struct in_addr alias_addr, 1068 u_short dst_port, 1069 u_short alias_port, 1070 int link_type, 1071 int replace_partial_links) 1072{ 1073 int flags_in; 1074 u_int start_point; 1075 struct alias_link *link; 1076 struct alias_link *link_fully_specified; 1077 struct alias_link *link_unknown_all; 1078 struct alias_link *link_unknown_dst_addr; 1079 struct alias_link *link_unknown_dst_port; 1080 1081/* Initialize pointers */ 1082 link_fully_specified = NULL; 1083 link_unknown_all = NULL; 1084 link_unknown_dst_addr = NULL; 1085 link_unknown_dst_port = NULL; 1086 1087/* If either the dest addr or port is unknown, the search 1088 loop will have to know about this. */ 1089 1090 flags_in = 0; 1091 if (dst_addr.s_addr == 0) 1092 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1093 if (dst_port == 0) 1094 flags_in |= LINK_UNKNOWN_DEST_PORT; 1095 1096/* The following allows permanent links to be 1097 be specified as using the default aliasing address 1098 (i.e. device interface address) without knowing 1099 in advance what that address is. */ 1100 1101 if (alias_addr.s_addr == aliasAddress.s_addr) 1102 alias_addr.s_addr = 0; 1103 1104/* Search loop */ 1105 start_point = StartPointIn(alias_addr, alias_port, link_type); 1106 link = linkTableIn[start_point]; 1107 while (link != NULL) 1108 { 1109 int flags; 1110 1111 flags = flags_in | link->flags; 1112 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1113 { 1114 if (link->alias_addr.s_addr == alias_addr.s_addr 1115 && link->alias_port == alias_port 1116 && link->dst_addr.s_addr == dst_addr.s_addr 1117 && link->dst_port == dst_port 1118 && link->link_type == link_type) 1119 { 1120 link_fully_specified = link; 1121 break; 1122 } 1123 } 1124 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1125 && (flags & LINK_UNKNOWN_DEST_PORT)) 1126 { 1127 if (link->alias_addr.s_addr == alias_addr.s_addr 1128 && link->alias_port == alias_port 1129 && link->link_type == link_type) 1130 { 1131 if (link_unknown_all == NULL) 1132 link_unknown_all = link; 1133 } 1134 } 1135 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1136 { 1137 if (link->alias_addr.s_addr == alias_addr.s_addr 1138 && link->alias_port == alias_port 1139 && link->link_type == link_type 1140 && link->dst_port == dst_port) 1141 { 1142 if (link_unknown_dst_addr == NULL) 1143 link_unknown_dst_addr = link; 1144 } 1145 } 1146 else if (flags & LINK_UNKNOWN_DEST_PORT) 1147 { 1148 if (link->alias_addr.s_addr == alias_addr.s_addr 1149 && link->alias_port == alias_port 1150 && link->link_type == link_type 1151 && link->dst_addr.s_addr == dst_addr.s_addr) 1152 { 1153 if (link_unknown_dst_port == NULL) 1154 link_unknown_dst_port = link; 1155 } 1156 } 1157 link = link->next_in; 1158 } 1159 1160 1161 1162 if (link_fully_specified != NULL) 1163 { 1164 link_fully_specified->timestamp = timeStamp; 1165 return link_fully_specified; 1166 } 1167 else if (link_unknown_dst_port != NULL) 1168 { 1169 return replace_partial_links 1170 ? ReLink(link_unknown_dst_port, 1171 link_unknown_dst_port->src_addr, dst_addr, alias_addr, 1172 link_unknown_dst_port->src_port, dst_port, alias_port, 1173 link_type) 1174 : link_unknown_dst_port; 1175 } 1176 else if (link_unknown_dst_addr != NULL) 1177 { 1178 return replace_partial_links 1179 ? ReLink(link_unknown_dst_addr, 1180 link_unknown_dst_addr->src_addr, dst_addr, alias_addr, 1181 link_unknown_dst_addr->src_port, dst_port, alias_port, 1182 link_type) 1183 : link_unknown_dst_addr; 1184 } 1185 else if (link_unknown_all != NULL) 1186 { 1187 return replace_partial_links 1188 ? ReLink(link_unknown_all, 1189 link_unknown_all->src_addr, dst_addr, alias_addr, 1190 link_unknown_all->src_port, dst_port, alias_port, 1191 link_type) 1192 : link_unknown_all; 1193 } 1194 else 1195 { 1196 return(NULL); 1197 } 1198} 1199 1200 1201 1202 1203/* External routines for finding/adding links 1204 1205-- "external" means outside alias_db.c, but within alias*.c -- 1206 1207 FindIcmpIn(), FindIcmpOut() 1208 FindFragmentIn1(), FindFragmentIn2() 1209 AddFragmentPtrLink(), FindFragmentPtr() 1210 FindUdpTcpIn(), FindUdpTcpOut() 1211 FindOriginalAddress(), FindAliasAddress() 1212 1213(prototypes in alias_local.h) 1214*/ 1215 1216 1217struct alias_link * 1218FindIcmpIn(struct in_addr dst_addr, 1219 struct in_addr alias_addr, 1220 u_short id_alias) 1221{ 1222 return FindLinkIn(dst_addr, alias_addr, 1223 NO_DEST_PORT, id_alias, 1224 LINK_ICMP, 0); 1225} 1226 1227 1228struct alias_link * 1229FindIcmpOut(struct in_addr src_addr, 1230 struct in_addr dst_addr, 1231 u_short id) 1232{ 1233 struct alias_link * link; 1234 1235 link = FindLinkOut(src_addr, dst_addr, 1236 id, NO_DEST_PORT, 1237 LINK_ICMP); 1238 if (link == NULL) 1239 { 1240 struct in_addr alias_addr; 1241 1242 alias_addr = FindAliasAddress(src_addr); 1243 link = AddLink(src_addr, dst_addr, alias_addr, 1244 id, NO_DEST_PORT, GET_ALIAS_ID, 1245 LINK_ICMP); 1246 } 1247 1248 return(link); 1249} 1250 1251 1252struct alias_link * 1253FindFragmentIn1(struct in_addr dst_addr, 1254 struct in_addr alias_addr, 1255 u_short ip_id) 1256{ 1257 struct alias_link *link; 1258 1259 link = FindLinkIn(dst_addr, alias_addr, 1260 NO_DEST_PORT, ip_id, 1261 LINK_FRAGMENT_ID, 0); 1262 1263 if (link == NULL) 1264 { 1265 link = AddLink(nullAddress, dst_addr, alias_addr, 1266 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1267 LINK_FRAGMENT_ID); 1268 } 1269 1270 return(link); 1271} 1272 1273 1274struct alias_link * 1275FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1276 struct in_addr alias_addr, /* is not found. */ 1277 u_short ip_id) 1278{ 1279 return FindLinkIn(dst_addr, alias_addr, 1280 NO_DEST_PORT, ip_id, 1281 LINK_FRAGMENT_ID, 0); 1282} 1283 1284 1285struct alias_link * 1286AddFragmentPtrLink(struct in_addr dst_addr, 1287 u_short ip_id) 1288{ 1289 return AddLink(nullAddress, dst_addr, nullAddress, 1290 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1291 LINK_FRAGMENT_PTR); 1292} 1293 1294 1295struct alias_link * 1296FindFragmentPtr(struct in_addr dst_addr, 1297 u_short ip_id) 1298{ 1299 return FindLinkIn(dst_addr, nullAddress, 1300 NO_DEST_PORT, ip_id, 1301 LINK_FRAGMENT_PTR, 0); 1302} 1303 1304 1305struct alias_link * 1306FindUdpTcpIn(struct in_addr dst_addr, 1307 struct in_addr alias_addr, 1308 u_short dst_port, 1309 u_short alias_port, 1310 u_char proto) 1311{ 1312 int link_type; 1313 struct alias_link *link; 1314 1315 switch (proto) 1316 { 1317 case IPPROTO_UDP: 1318 link_type = LINK_UDP; 1319 break; 1320 case IPPROTO_TCP: 1321 link_type = LINK_TCP; 1322 break; 1323 default: 1324 return NULL; 1325 break; 1326 } 1327 1328 link = FindLinkIn(dst_addr, alias_addr, 1329 dst_port, alias_port, 1330 link_type, 1); 1331 1332 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING) 1333 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY) 1334 && link == NULL) 1335 { 1336 struct in_addr target_addr; 1337 1338 target_addr = FindOriginalAddress(alias_addr); 1339 link = AddLink(target_addr, dst_addr, alias_addr, 1340 alias_port, dst_port, alias_port, 1341 link_type); 1342 } 1343 1344 return(link); 1345} 1346 1347 1348struct alias_link * 1349FindUdpTcpOut(struct in_addr src_addr, 1350 struct in_addr dst_addr, 1351 u_short src_port, 1352 u_short dst_port, 1353 u_char proto) 1354{ 1355 int link_type; 1356 struct alias_link *link; 1357 1358 switch (proto) 1359 { 1360 case IPPROTO_UDP: 1361 link_type = LINK_UDP; 1362 break; 1363 case IPPROTO_TCP: 1364 link_type = LINK_TCP; 1365 break; 1366 default: 1367 return NULL; 1368 break; 1369 } 1370 1371 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type); 1372 1373 if (link == NULL) 1374 { 1375 struct in_addr alias_addr; 1376 1377 alias_addr = FindAliasAddress(src_addr); 1378 link = AddLink(src_addr, dst_addr, alias_addr, 1379 src_port, dst_port, GET_ALIAS_PORT, 1380 link_type); 1381 } 1382 1383 return(link); 1384} 1385 1386 1387struct in_addr 1388FindOriginalAddress(struct in_addr alias_addr) 1389{ 1390 struct alias_link *link; 1391 1392 link = FindLinkIn(nullAddress, alias_addr, 1393 0, 0, LINK_ADDR, 0); 1394 if (link == NULL) 1395 { 1396 newDefaultLink = 1; 1397 if (targetAddress.s_addr != 0) 1398 return targetAddress; 1399 else 1400 return alias_addr; 1401 } 1402 else 1403 { 1404 if (link->src_addr.s_addr == 0) 1405 return aliasAddress; 1406 else 1407 return link->src_addr; 1408 } 1409} 1410 1411 1412struct in_addr 1413FindAliasAddress(struct in_addr original_addr) 1414{ 1415 struct alias_link *link; 1416 1417 link = FindLinkOut(original_addr, nullAddress, 1418 0, 0, LINK_ADDR); 1419 if (link == NULL) 1420 { 1421 return aliasAddress; 1422 } 1423 else 1424 { 1425 if (link->alias_addr.s_addr == 0) 1426 return aliasAddress; 1427 else 1428 return link->alias_addr; 1429 } 1430} 1431 1432 1433/* External routines for getting or changing link data 1434 (external to alias_db.c, but internal to alias*.c) 1435 1436 SetFragmentData(), GetFragmentData() 1437 SetFragmentPtr(), GetFragmentPtr() 1438 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1439 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1440 GetOriginalPort(), GetAliasPort() 1441 SetAckModified(), GetAckModified() 1442 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1443*/ 1444 1445 1446void 1447SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1448{ 1449 link->data.frag_addr = src_addr; 1450} 1451 1452 1453void 1454GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1455{ 1456 *src_addr = link->data.frag_addr; 1457} 1458 1459 1460void 1461SetFragmentPtr(struct alias_link *link, char *fptr) 1462{ 1463 link->data.frag_ptr = fptr; 1464} 1465 1466 1467void 1468GetFragmentPtr(struct alias_link *link, char **fptr) 1469{ 1470 *fptr = link->data.frag_ptr; 1471} 1472 1473 1474void 1475SetStateIn(struct alias_link *link, int state) 1476{ 1477 /* TCP input state */ 1478 switch (state) { 1479 case ALIAS_TCP_STATE_DISCONNECTED: 1480 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) { 1481 link->expire_time = TCP_EXPIRE_DEAD; 1482 } else { 1483 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1484 } 1485 link->data.tcp->state.in = state; 1486 break; 1487 case ALIAS_TCP_STATE_CONNECTED: 1488 link->expire_time = TCP_EXPIRE_CONNECTED; 1489 /*FALLTHROUGH*/ 1490 case ALIAS_TCP_STATE_NOT_CONNECTED: 1491 link->data.tcp->state.in = state; 1492 break; 1493 default: 1494 abort(); 1495 } 1496} 1497 1498 1499void 1500SetStateOut(struct alias_link *link, int state) 1501{ 1502 /* TCP output state */ 1503 switch (state) { 1504 case ALIAS_TCP_STATE_DISCONNECTED: 1505 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) { 1506 link->expire_time = TCP_EXPIRE_DEAD; 1507 } else { 1508 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1509 } 1510 link->data.tcp->state.out = state; 1511 break; 1512 case ALIAS_TCP_STATE_CONNECTED: 1513 link->expire_time = TCP_EXPIRE_CONNECTED; 1514 /*FALLTHROUGH*/ 1515 case ALIAS_TCP_STATE_NOT_CONNECTED: 1516 link->data.tcp->state.out = state; 1517 break; 1518 default: 1519 abort(); 1520 } 1521} 1522 1523 1524int 1525GetStateIn(struct alias_link *link) 1526{ 1527 /* TCP input state */ 1528 return link->data.tcp->state.in; 1529} 1530 1531 1532int 1533GetStateOut(struct alias_link *link) 1534{ 1535 /* TCP output state */ 1536 return link->data.tcp->state.out; 1537} 1538 1539 1540struct in_addr 1541GetOriginalAddress(struct alias_link *link) 1542{ 1543 if (link->src_addr.s_addr == 0) 1544 return aliasAddress; 1545 else 1546 return(link->src_addr); 1547} 1548 1549 1550struct in_addr 1551GetDestAddress(struct alias_link *link) 1552{ 1553 return(link->dst_addr); 1554} 1555 1556 1557struct in_addr 1558GetAliasAddress(struct alias_link *link) 1559{ 1560 if (link->alias_addr.s_addr == 0) 1561 return aliasAddress; 1562 else 1563 return link->alias_addr; 1564} 1565 1566 1567struct in_addr 1568GetDefaultAliasAddress() 1569{ 1570 return aliasAddress; 1571} 1572 1573 1574void 1575SetDefaultAliasAddress(struct in_addr alias_addr) 1576{ 1577 aliasAddress = alias_addr; 1578} 1579 1580 1581u_short 1582GetOriginalPort(struct alias_link *link) 1583{ 1584 return(link->src_port); 1585} 1586 1587 1588u_short 1589GetAliasPort(struct alias_link *link) 1590{ 1591 return(link->alias_port); 1592} 1593 1594u_short 1595GetDestPort(struct alias_link *link) 1596{ 1597 return(link->dst_port); 1598} 1599 1600void 1601SetAckModified(struct alias_link *link) 1602{ 1603/* Indicate that ack numbers have been modified in a TCP connection */ 1604 link->data.tcp->state.ack_modified = 1; 1605} 1606 1607 1608struct in_addr 1609GetProxyAddress(struct alias_link *link) 1610{ 1611 return link->proxy_addr; 1612} 1613 1614 1615void 1616SetProxyAddress(struct alias_link *link, struct in_addr addr) 1617{ 1618 link->proxy_addr = addr; 1619} 1620 1621 1622u_short 1623GetProxyPort(struct alias_link *link) 1624{ 1625 return link->proxy_port; 1626} 1627 1628 1629void 1630SetProxyPort(struct alias_link *link, u_short port) 1631{ 1632 link->proxy_port = port; 1633} 1634 1635 1636int 1637GetAckModified(struct alias_link *link) 1638{ 1639/* See if ack numbers have been modified */ 1640 return link->data.tcp->state.ack_modified; 1641} 1642 1643 1644int 1645GetDeltaAckIn(struct ip *pip, struct alias_link *link) 1646{ 1647/* 1648Find out how much the ack number has been altered for an incoming 1649TCP packet. To do this, a circular list is ack numbers where the TCP 1650packet size was altered is searched. 1651*/ 1652 1653 int i; 1654 struct tcphdr *tc; 1655 int delta, ack_diff_min; 1656 u_long ack; 1657 1658 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1659 ack = tc->th_ack; 1660 1661 delta = 0; 1662 ack_diff_min = -1; 1663 for (i=0; i<N_LINK_TCP_DATA; i++) 1664 { 1665 struct ack_data_record x; 1666 1667 x = link->data.tcp->ack[i]; 1668 if (x.active == 1) 1669 { 1670 int ack_diff; 1671 1672 ack_diff = SeqDiff(x.ack_new, ack); 1673 if (ack_diff >= 0) 1674 { 1675 if (ack_diff_min >= 0) 1676 { 1677 if (ack_diff < ack_diff_min) 1678 { 1679 delta = x.delta; 1680 ack_diff_min = ack_diff; 1681 } 1682 } 1683 else 1684 { 1685 delta = x.delta; 1686 ack_diff_min = ack_diff; 1687 } 1688 } 1689 } 1690 } 1691 return (delta); 1692} 1693 1694 1695int 1696GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 1697{ 1698/* 1699Find out how much the seq number has been altered for an outgoing 1700TCP packet. To do this, a circular list is ack numbers where the TCP 1701packet size was altered is searched. 1702*/ 1703 1704 int i; 1705 struct tcphdr *tc; 1706 int delta, seq_diff_min; 1707 u_long seq; 1708 1709 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1710 seq = tc->th_seq; 1711 1712 delta = 0; 1713 seq_diff_min = -1; 1714 for (i=0; i<N_LINK_TCP_DATA; i++) 1715 { 1716 struct ack_data_record x; 1717 1718 x = link->data.tcp->ack[i]; 1719 if (x.active == 1) 1720 { 1721 int seq_diff; 1722 1723 seq_diff = SeqDiff(x.ack_old, seq); 1724 if (seq_diff >= 0) 1725 { 1726 if (seq_diff_min >= 0) 1727 { 1728 if (seq_diff < seq_diff_min) 1729 { 1730 delta = x.delta; 1731 seq_diff_min = seq_diff; 1732 } 1733 } 1734 else 1735 { 1736 delta = x.delta; 1737 seq_diff_min = seq_diff; 1738 } 1739 } 1740 } 1741 } 1742 return (delta); 1743} 1744 1745 1746void 1747AddSeq(struct ip *pip, struct alias_link *link, int delta) 1748{ 1749/* 1750When a TCP packet has been altered in length, save this 1751information in a circular list. If enough packets have 1752been altered, then this list will begin to overwrite itself. 1753*/ 1754 1755 struct tcphdr *tc; 1756 struct ack_data_record x; 1757 int hlen, tlen, dlen; 1758 int i; 1759 1760 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1761 1762 hlen = (pip->ip_hl + tc->th_off) << 2; 1763 tlen = ntohs(pip->ip_len); 1764 dlen = tlen - hlen; 1765 1766 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 1767 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 1768 x.delta = delta; 1769 x.active = 1; 1770 1771 i = link->data.tcp->state.index; 1772 link->data.tcp->ack[i] = x; 1773 1774 i++; 1775 if (i == N_LINK_TCP_DATA) 1776 link->data.tcp->state.index = 0; 1777 else 1778 link->data.tcp->state.index = i; 1779} 1780 1781void 1782SetExpire(struct alias_link *link, int expire) 1783{ 1784 if (expire == 0) 1785 { 1786 link->flags &= ~LINK_PERMANENT; 1787 DeleteLink(link); 1788 } 1789 else if (expire == -1) 1790 { 1791 link->flags |= LINK_PERMANENT; 1792 } 1793 else if (expire > 0) 1794 { 1795 link->expire_time = expire; 1796 } 1797 else 1798 { 1799#ifdef DEBUG 1800 fprintf(stderr, "PacketAlias/SetExpire(): "); 1801 fprintf(stderr, "error in expire parameter\n"); 1802#endif 1803 } 1804} 1805 1806void 1807ClearCheckNewLink(void) 1808{ 1809 newDefaultLink = 0; 1810} 1811 1812 1813/* Miscellaneous Functions 1814 1815 HouseKeeping() 1816 InitPacketAliasLog() 1817 UninitPacketAliasLog() 1818*/ 1819 1820/* 1821 Whenever an outgoing or incoming packet is handled, HouseKeeping() 1822 is called to find and remove timed-out aliasing links. Logic exists 1823 to sweep through the entire table and linked list structure 1824 every 60 seconds. 1825 1826 (prototype in alias_local.h) 1827*/ 1828 1829void 1830HouseKeeping(void) 1831{ 1832 int i, n, n100; 1833 struct timeval tv; 1834 struct timezone tz; 1835 1836 /* 1837 * Save system time (seconds) in global variable timeStamp for 1838 * use by other functions. This is done so as not to unnecessarily 1839 * waste timeline by making system calls. 1840 */ 1841 gettimeofday(&tv, &tz); 1842 timeStamp = tv.tv_sec; 1843 1844 /* Compute number of spokes (output table link chains) to cover */ 1845 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 1846 n100 *= timeStamp - lastCleanupTime; 1847 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 1848 1849 n = n100/100; 1850 1851 /* Handle different cases */ 1852 if (n > ALIAS_CLEANUP_MAX_SPOKES) 1853 { 1854 n = ALIAS_CLEANUP_MAX_SPOKES; 1855 lastCleanupTime = timeStamp; 1856 houseKeepingResidual = 0; 1857 1858 for (i=0; i<n; i++) 1859 IncrementalCleanup(); 1860 } 1861 else if (n > 0) 1862 { 1863 lastCleanupTime = timeStamp; 1864 houseKeepingResidual = n100 - 100*n; 1865 1866 for (i=0; i<n; i++) 1867 IncrementalCleanup(); 1868 } 1869 else if (n < 0) 1870 { 1871#ifdef DEBUG 1872 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 1873 fprintf(stderr, "something unexpected in time values\n"); 1874#endif 1875 lastCleanupTime = timeStamp; 1876 houseKeepingResidual = 0; 1877 } 1878} 1879 1880 1881/* Init the log file and enable logging */ 1882static void 1883InitPacketAliasLog(void) 1884{ 1885 if ((~packetAliasMode & PKT_ALIAS_LOG) 1886 && (monitorFile = fopen("/var/log/alias.log", "w"))) 1887 { 1888 packetAliasMode |= PKT_ALIAS_LOG; 1889 fprintf(monitorFile, 1890 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 1891 } 1892} 1893 1894 1895/* Close the log-file and disable logging. */ 1896static void 1897UninitPacketAliasLog(void) 1898{ 1899 if (monitorFile) { 1900 fclose(monitorFile); 1901 monitorFile = NULL; 1902 } 1903 packetAliasMode &= ~PKT_ALIAS_LOG; 1904} 1905 1906 1907 1908 1909 1910 1911/* Outside world interfaces 1912 1913-- "outside world" means other than alias*.c routines -- 1914 1915 PacketAliasRedirectPort() 1916 PacketAliasRedirectAddr() 1917 PacketAliasRedirectDelete() 1918 PacketAliasSetAddress() 1919 PacketAliasInit() 1920 PacketAliasUninit() 1921 PacketAliasSetMode() 1922 1923(prototypes in alias.h) 1924*/ 1925 1926/* Redirection from a specific public addr:port to a 1927 a private addr:port */ 1928struct alias_link * 1929PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 1930 struct in_addr dst_addr, u_short dst_port, 1931 struct in_addr alias_addr, u_short alias_port, 1932 u_char proto) 1933{ 1934 int link_type; 1935 struct alias_link *link; 1936 1937 switch(proto) 1938 { 1939 case IPPROTO_UDP: 1940 link_type = LINK_UDP; 1941 break; 1942 case IPPROTO_TCP: 1943 link_type = LINK_TCP; 1944 break; 1945 default: 1946#ifdef DEBUG 1947 fprintf(stderr, "PacketAliasRedirectPort(): "); 1948 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 1949#endif 1950 return NULL; 1951 } 1952 1953 link = AddLink(src_addr, dst_addr, alias_addr, 1954 src_port, dst_port, alias_port, 1955 link_type); 1956 1957 if (link != NULL) 1958 { 1959 link->flags |= LINK_PERMANENT; 1960 } 1961#ifdef DEBUG 1962 else 1963 { 1964 fprintf(stderr, "PacketAliasRedirectPort(): " 1965 "call to AddLink() failed\n"); 1966 } 1967#endif 1968 1969 return link; 1970} 1971 1972/* Translate PPTP packets to a machine on the inside 1973 */ 1974int 1975PacketAliasPptp(struct in_addr src_addr) 1976{ 1977 1978 pptpAliasAddr = src_addr; /* Address of the inside PPTP machine */ 1979 pptpAliasFlag = src_addr.s_addr != INADDR_NONE; 1980 1981 return 1; 1982} 1983 1984int GetPptpAlias (struct in_addr* alias_addr) 1985{ 1986 if (pptpAliasFlag) 1987 *alias_addr = pptpAliasAddr; 1988 1989 return pptpAliasFlag; 1990} 1991 1992/* Static address translation */ 1993struct alias_link * 1994PacketAliasRedirectAddr(struct in_addr src_addr, 1995 struct in_addr alias_addr) 1996{ 1997 struct alias_link *link; 1998 1999 link = AddLink(src_addr, nullAddress, alias_addr, 2000 0, 0, 0, 2001 LINK_ADDR); 2002 2003 if (link != NULL) 2004 { 2005 link->flags |= LINK_PERMANENT; 2006 } 2007#ifdef DEBUG 2008 else 2009 { 2010 fprintf(stderr, "PacketAliasRedirectAddr(): " 2011 "call to AddLink() failed\n"); 2012 } 2013#endif 2014 2015 return link; 2016} 2017 2018 2019void 2020PacketAliasRedirectDelete(struct alias_link *link) 2021{ 2022/* This is a dangerous function to put in the API, 2023 because an invalid pointer can crash the program. */ 2024 2025 deleteAllLinks = 1; 2026 DeleteLink(link); 2027 deleteAllLinks = 0; 2028} 2029 2030 2031void 2032PacketAliasSetAddress(struct in_addr addr) 2033{ 2034 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2035 && aliasAddress.s_addr != addr.s_addr) 2036 CleanupAliasData(); 2037 2038 aliasAddress = addr; 2039} 2040 2041 2042void 2043PacketAliasSetTarget(struct in_addr target_addr) 2044{ 2045 targetAddress = target_addr; 2046} 2047 2048 2049void 2050PacketAliasInit(void) 2051{ 2052 int i; 2053 struct timeval tv; 2054 struct timezone tz; 2055 static int firstCall = 1; 2056 2057 if (firstCall == 1) 2058 { 2059 gettimeofday(&tv, &tz); 2060 timeStamp = tv.tv_sec; 2061 lastCleanupTime = tv.tv_sec; 2062 houseKeepingResidual = 0; 2063 2064 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2065 linkTableOut[i] = NULL; 2066 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2067 linkTableIn[i] = NULL; 2068 2069 atexit(PacketAliasUninit); 2070 firstCall = 0; 2071 } 2072 else 2073 { 2074 deleteAllLinks = 1; 2075 CleanupAliasData(); 2076 deleteAllLinks = 0; 2077 } 2078 2079 aliasAddress.s_addr = 0; 2080 targetAddress.s_addr = 0; 2081 2082 icmpLinkCount = 0; 2083 udpLinkCount = 0; 2084 tcpLinkCount = 0; 2085 fragmentIdLinkCount = 0; 2086 fragmentPtrLinkCount = 0; 2087 sockCount = 0; 2088 2089 cleanupIndex =0; 2090 2091 packetAliasMode = PKT_ALIAS_SAME_PORTS 2092 | PKT_ALIAS_USE_SOCKETS 2093 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2094 2095 pptpAliasFlag = 0; 2096} 2097 2098void 2099PacketAliasUninit(void) { 2100 deleteAllLinks = 1; 2101 CleanupAliasData(); 2102 deleteAllLinks = 0; 2103 UninitPacketAliasLog(); 2104#ifndef NO_FW_PUNCH 2105 UninitPunchFW(); 2106#endif 2107} 2108 2109 2110/* Change mode for some operations */ 2111unsigned int 2112PacketAliasSetMode( 2113 unsigned int flags, /* Which state to bring flags to */ 2114 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2115 probe for flag values) */ 2116) 2117{ 2118/* Enable logging? */ 2119 if (flags & mask & PKT_ALIAS_LOG) 2120 { 2121 InitPacketAliasLog(); /* Do the enable */ 2122 } else 2123/* _Disable_ logging? */ 2124 if (~flags & mask & PKT_ALIAS_LOG) { 2125 UninitPacketAliasLog(); 2126 } 2127 2128#ifndef NO_FW_PUNCH 2129/* Start punching holes in the firewall? */ 2130 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2131 InitPunchFW(); 2132 } else 2133/* Stop punching holes in the firewall? */ 2134 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2135 UninitPunchFW(); 2136 } 2137#endif 2138 2139/* Other flags can be set/cleared without special action */ 2140 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2141 return packetAliasMode; 2142} 2143 2144 2145int 2146PacketAliasCheckNewLink(void) 2147{ 2148 return newDefaultLink; 2149} 2150 2151 2152#ifndef NO_FW_PUNCH 2153 2154/***************** 2155 Code to support firewall punching. This shouldn't really be in this 2156 file, but making variables global is evil too. 2157 ****************/ 2158 2159/* Firewall include files */ 2160#include <sys/queue.h> 2161#include <net/if.h> 2162#include <netinet/ip_fw.h> 2163#include <string.h> 2164#include <err.h> 2165 2166static void ClearAllFWHoles(void); 2167 2168static int fireWallBaseNum; /* The first firewall entry free for our use */ 2169static int fireWallNumNums; /* How many entries can we use? */ 2170static int fireWallActiveNum; /* Which entry did we last use? */ 2171static char *fireWallField; /* bool array for entries */ 2172 2173#define fw_setfield(field, num) \ 2174do { \ 2175 (field)[num] = 1; \ 2176} /*lint -save -e717 */ while(0) /*lint -restore */ 2177#define fw_clrfield(field, num) \ 2178do { \ 2179 (field)[num] = 0; \ 2180} /*lint -save -e717 */ while(0) /*lint -restore */ 2181#define fw_tstfield(field, num) ((field)[num]) 2182 2183void 2184PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2185 fireWallBaseNum = base; 2186 fireWallNumNums = num; 2187} 2188 2189static void 2190InitPunchFW(void) { 2191 fireWallField = malloc(fireWallNumNums); 2192 if (fireWallField) { 2193 memset(fireWallField, 0, fireWallNumNums); 2194 if (fireWallFD < 0) { 2195 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2196 } 2197 ClearAllFWHoles(); 2198 fireWallActiveNum = fireWallBaseNum; 2199 } 2200} 2201 2202static void 2203UninitPunchFW(void) { 2204 ClearAllFWHoles(); 2205 if (fireWallFD >= 0) 2206 close(fireWallFD); 2207 fireWallFD = -1; 2208 if (fireWallField) 2209 free(fireWallField); 2210 fireWallField = NULL; 2211 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2212} 2213 2214/* Make a certain link go through the firewall */ 2215void 2216PunchFWHole(struct alias_link *link) { 2217 int r; /* Result code */ 2218 struct ip_fw rule; /* On-the-fly built rule */ 2219 int fwhole; /* Where to punch hole */ 2220 2221/* Don't do anything unless we are asked to */ 2222 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2223 fireWallFD < 0 || 2224 link->link_type != LINK_TCP || 2225 !link->data.tcp) 2226 return; 2227 2228 memset(&rule, 0, sizeof rule); 2229 2230/** Build rule **/ 2231 2232 /* Find empty slot */ 2233 for (fwhole = fireWallActiveNum; 2234 fwhole < fireWallBaseNum + fireWallNumNums && 2235 fw_tstfield(fireWallField, fwhole); 2236 fwhole++) 2237 ; 2238 if (fwhole >= fireWallBaseNum + fireWallNumNums || 2239 fw_tstfield(fireWallField, fwhole)) { 2240 for (fwhole = fireWallBaseNum; 2241 fwhole < fireWallActiveNum && 2242 fw_tstfield(fireWallField, fwhole); 2243 fwhole++) 2244 ; 2245 if (fwhole == fireWallActiveNum) { 2246 /* No rule point empty - we can't punch more holes. */ 2247 fireWallActiveNum = fireWallBaseNum; 2248#ifdef DEBUG 2249 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2250#endif 2251 return; 2252 } 2253 } 2254 /* Start next search at next position */ 2255 fireWallActiveNum = fwhole+1; 2256 2257 /* Build generic part of the two rules */ 2258 rule.fw_number = fwhole; 2259 rule.fw_nports = 1; /* Number of source ports; dest ports follow */ 2260 rule.fw_flg = IP_FW_F_ACCEPT; 2261 rule.fw_prot = IPPROTO_TCP; 2262 rule.fw_smsk.s_addr = INADDR_BROADCAST; 2263 rule.fw_dmsk.s_addr = INADDR_BROADCAST; 2264 2265 /* Build and apply specific part of the rules */ 2266 rule.fw_src = GetOriginalAddress(link); 2267 rule.fw_dst = GetDestAddress(link); 2268 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); 2269 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); 2270 2271 /* Skip non-bound links - XXX should not be strictly necessary, 2272 but seems to leave hole if not done. Leak of non-bound links? 2273 (Code should be left even if the problem is fixed - it is a 2274 clear optimization) */ 2275 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { 2276 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2277#ifdef DEBUG 2278 if (r) 2279 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2280#endif 2281 rule.fw_src = GetDestAddress(link); 2282 rule.fw_dst = GetOriginalAddress(link); 2283 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); 2284 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); 2285 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2286#ifdef DEBUG 2287 if (r) 2288 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2289#endif 2290 } 2291/* Indicate hole applied */ 2292 link->data.tcp->fwhole = fwhole; 2293 fw_setfield(fireWallField, fwhole); 2294} 2295 2296/* Remove a hole in a firewall associated with a particular alias 2297 link. Calling this too often is harmless. */ 2298static void 2299ClearFWHole(struct alias_link *link) { 2300 if (link->link_type == LINK_TCP && link->data.tcp) { 2301 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ 2302 struct ip_fw rule; 2303 2304 if (fwhole < 0) 2305 return; 2306 2307 memset(&rule, 0, sizeof rule); 2308 rule.fw_number = fwhole; 2309 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2310 ; 2311 fw_clrfield(fireWallField, fwhole); 2312 link->data.tcp->fwhole = -1; 2313 } 2314} 2315 2316/* Clear out the entire range dedicated to firewall holes. */ 2317static void 2318ClearAllFWHoles(void) { 2319 struct ip_fw rule; /* On-the-fly built rule */ 2320 int i; 2321 2322 if (fireWallFD < 0) 2323 return; 2324 2325 memset(&rule, 0, sizeof rule); 2326 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { 2327 rule.fw_number = i; 2328 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2329 ; 2330 } 2331 memset(fireWallField, 0, fireWallNumNums); 2332} 2333#endif 2334