alias_db.c revision 51550
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 51550 1999-09-22 13:22:26Z 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 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 incoming packets 371 StartPointOut() -- port table initial search point for 372 outgoing 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, 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 int replace_partial_links) 1039{ 1040 u_int i; 1041 struct alias_link *link; 1042 1043 if (src_addr.s_addr == aliasAddress.s_addr) 1044 src_addr.s_addr = 0; 1045 1046 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1047 link = linkTableOut[i]; 1048 while (link != NULL) 1049 { 1050 if (link->src_addr.s_addr == src_addr.s_addr 1051 && link->dst_addr.s_addr == dst_addr.s_addr 1052 && link->dst_port == dst_port 1053 && link->src_port == src_port 1054 && link->link_type == link_type) 1055 { 1056 link->timestamp = timeStamp; 1057 break; 1058 } 1059 link = link->next_out; 1060 } 1061 1062/* Search for partially specified links. */ 1063 if (link == NULL) 1064 { 1065 if (dst_port != 0) 1066 { 1067 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 0); 1068 if (link != NULL && replace_partial_links) 1069 { 1070 link = ReLink(link, 1071 src_addr, dst_addr, link->alias_addr, 1072 src_port, dst_port, link->alias_port, 1073 link_type); 1074 } 1075 } 1076 else if (dst_addr.s_addr != 0) 1077 { 1078 link = FindLinkOut(src_addr, nullAddress, src_port, 0, link_type, 0); 1079 } 1080 } 1081 1082 return(link); 1083} 1084 1085 1086struct alias_link * 1087FindLinkIn(struct in_addr dst_addr, 1088 struct in_addr alias_addr, 1089 u_short dst_port, 1090 u_short alias_port, 1091 int link_type, 1092 int replace_partial_links) 1093{ 1094 int flags_in; 1095 u_int start_point; 1096 struct alias_link *link; 1097 struct alias_link *link_fully_specified; 1098 struct alias_link *link_unknown_all; 1099 struct alias_link *link_unknown_dst_addr; 1100 struct alias_link *link_unknown_dst_port; 1101 1102/* Initialize pointers */ 1103 link_fully_specified = NULL; 1104 link_unknown_all = NULL; 1105 link_unknown_dst_addr = NULL; 1106 link_unknown_dst_port = NULL; 1107 1108/* If either the dest addr or port is unknown, the search 1109 loop will have to know about this. */ 1110 1111 flags_in = 0; 1112 if (dst_addr.s_addr == 0) 1113 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1114 if (dst_port == 0) 1115 flags_in |= LINK_UNKNOWN_DEST_PORT; 1116 1117/* The following allows permanent links to be 1118 be specified as using the default aliasing address 1119 (i.e. device interface address) without knowing 1120 in advance what that address is. */ 1121 1122 if (alias_addr.s_addr == aliasAddress.s_addr) 1123 alias_addr.s_addr = 0; 1124 1125/* Search loop */ 1126 start_point = StartPointIn(alias_addr, alias_port, link_type); 1127 link = linkTableIn[start_point]; 1128 while (link != NULL) 1129 { 1130 int flags; 1131 1132 flags = flags_in | link->flags; 1133 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1134 { 1135 if (link->alias_addr.s_addr == alias_addr.s_addr 1136 && link->alias_port == alias_port 1137 && link->dst_addr.s_addr == dst_addr.s_addr 1138 && link->dst_port == dst_port 1139 && link->link_type == link_type) 1140 { 1141 link_fully_specified = link; 1142 break; 1143 } 1144 } 1145 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1146 && (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 { 1152 if (link_unknown_all == NULL) 1153 link_unknown_all = link; 1154 } 1155 } 1156 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1157 { 1158 if (link->alias_addr.s_addr == alias_addr.s_addr 1159 && link->alias_port == alias_port 1160 && link->link_type == link_type 1161 && link->dst_port == dst_port) 1162 { 1163 if (link_unknown_dst_addr == NULL) 1164 link_unknown_dst_addr = link; 1165 } 1166 } 1167 else if (flags & LINK_UNKNOWN_DEST_PORT) 1168 { 1169 if (link->alias_addr.s_addr == alias_addr.s_addr 1170 && link->alias_port == alias_port 1171 && link->link_type == link_type 1172 && link->dst_addr.s_addr == dst_addr.s_addr) 1173 { 1174 if (link_unknown_dst_port == NULL) 1175 link_unknown_dst_port = link; 1176 } 1177 } 1178 link = link->next_in; 1179 } 1180 1181 1182 1183 if (link_fully_specified != NULL) 1184 { 1185 link_fully_specified->timestamp = timeStamp; 1186 return link_fully_specified; 1187 } 1188 else if (link_unknown_dst_port != NULL) 1189 { 1190 return replace_partial_links 1191 ? ReLink(link_unknown_dst_port, 1192 link_unknown_dst_port->src_addr, dst_addr, alias_addr, 1193 link_unknown_dst_port->src_port, dst_port, alias_port, 1194 link_type) 1195 : link_unknown_dst_port; 1196 } 1197 else if (link_unknown_dst_addr != NULL) 1198 { 1199 return replace_partial_links 1200 ? ReLink(link_unknown_dst_addr, 1201 link_unknown_dst_addr->src_addr, dst_addr, alias_addr, 1202 link_unknown_dst_addr->src_port, dst_port, alias_port, 1203 link_type) 1204 : link_unknown_dst_addr; 1205 } 1206 else if (link_unknown_all != NULL) 1207 { 1208 return replace_partial_links 1209 ? ReLink(link_unknown_all, 1210 link_unknown_all->src_addr, dst_addr, alias_addr, 1211 link_unknown_all->src_port, dst_port, alias_port, 1212 link_type) 1213 : link_unknown_all; 1214 } 1215 else 1216 { 1217 return(NULL); 1218 } 1219} 1220 1221 1222 1223 1224/* External routines for finding/adding links 1225 1226-- "external" means outside alias_db.c, but within alias*.c -- 1227 1228 FindIcmpIn(), FindIcmpOut() 1229 FindFragmentIn1(), FindFragmentIn2() 1230 AddFragmentPtrLink(), FindFragmentPtr() 1231 FindUdpTcpIn(), FindUdpTcpOut() 1232 FindOriginalAddress(), FindAliasAddress() 1233 1234(prototypes in alias_local.h) 1235*/ 1236 1237 1238struct alias_link * 1239FindIcmpIn(struct in_addr dst_addr, 1240 struct in_addr alias_addr, 1241 u_short id_alias) 1242{ 1243 return FindLinkIn(dst_addr, alias_addr, 1244 NO_DEST_PORT, id_alias, 1245 LINK_ICMP, 0); 1246} 1247 1248 1249struct alias_link * 1250FindIcmpOut(struct in_addr src_addr, 1251 struct in_addr dst_addr, 1252 u_short id) 1253{ 1254 struct alias_link * link; 1255 1256 link = FindLinkOut(src_addr, dst_addr, 1257 id, NO_DEST_PORT, 1258 LINK_ICMP, 0); 1259 if (link == NULL) 1260 { 1261 struct in_addr alias_addr; 1262 1263 alias_addr = FindAliasAddress(src_addr); 1264 link = AddLink(src_addr, dst_addr, alias_addr, 1265 id, NO_DEST_PORT, GET_ALIAS_ID, 1266 LINK_ICMP); 1267 } 1268 1269 return(link); 1270} 1271 1272 1273struct alias_link * 1274FindFragmentIn1(struct in_addr dst_addr, 1275 struct in_addr alias_addr, 1276 u_short ip_id) 1277{ 1278 struct alias_link *link; 1279 1280 link = FindLinkIn(dst_addr, alias_addr, 1281 NO_DEST_PORT, ip_id, 1282 LINK_FRAGMENT_ID, 0); 1283 1284 if (link == NULL) 1285 { 1286 link = AddLink(nullAddress, dst_addr, alias_addr, 1287 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1288 LINK_FRAGMENT_ID); 1289 } 1290 1291 return(link); 1292} 1293 1294 1295struct alias_link * 1296FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1297 struct in_addr alias_addr, /* is not found. */ 1298 u_short ip_id) 1299{ 1300 return FindLinkIn(dst_addr, alias_addr, 1301 NO_DEST_PORT, ip_id, 1302 LINK_FRAGMENT_ID, 0); 1303} 1304 1305 1306struct alias_link * 1307AddFragmentPtrLink(struct in_addr dst_addr, 1308 u_short ip_id) 1309{ 1310 return AddLink(nullAddress, dst_addr, nullAddress, 1311 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1312 LINK_FRAGMENT_PTR); 1313} 1314 1315 1316struct alias_link * 1317FindFragmentPtr(struct in_addr dst_addr, 1318 u_short ip_id) 1319{ 1320 return FindLinkIn(dst_addr, nullAddress, 1321 NO_DEST_PORT, ip_id, 1322 LINK_FRAGMENT_PTR, 0); 1323} 1324 1325 1326struct alias_link * 1327FindUdpTcpIn(struct in_addr dst_addr, 1328 struct in_addr alias_addr, 1329 u_short dst_port, 1330 u_short alias_port, 1331 u_char proto) 1332{ 1333 int link_type; 1334 struct alias_link *link; 1335 1336 switch (proto) 1337 { 1338 case IPPROTO_UDP: 1339 link_type = LINK_UDP; 1340 break; 1341 case IPPROTO_TCP: 1342 link_type = LINK_TCP; 1343 break; 1344 default: 1345 return NULL; 1346 break; 1347 } 1348 1349 link = FindLinkIn(dst_addr, alias_addr, 1350 dst_port, alias_port, 1351 link_type, 1); 1352 1353 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING) 1354 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY) 1355 && link == NULL) 1356 { 1357 struct in_addr target_addr; 1358 1359 target_addr = FindOriginalAddress(alias_addr); 1360 link = AddLink(target_addr, dst_addr, alias_addr, 1361 alias_port, dst_port, alias_port, 1362 link_type); 1363 } 1364 1365 return(link); 1366} 1367 1368 1369struct alias_link * 1370FindUdpTcpOut(struct in_addr src_addr, 1371 struct in_addr dst_addr, 1372 u_short src_port, 1373 u_short dst_port, 1374 u_char proto) 1375{ 1376 int link_type; 1377 struct alias_link *link; 1378 1379 switch (proto) 1380 { 1381 case IPPROTO_UDP: 1382 link_type = LINK_UDP; 1383 break; 1384 case IPPROTO_TCP: 1385 link_type = LINK_TCP; 1386 break; 1387 default: 1388 return NULL; 1389 break; 1390 } 1391 1392 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, 1); 1393 1394 if (link == NULL) 1395 { 1396 struct in_addr alias_addr; 1397 1398 alias_addr = FindAliasAddress(src_addr); 1399 link = AddLink(src_addr, dst_addr, alias_addr, 1400 src_port, dst_port, GET_ALIAS_PORT, 1401 link_type); 1402 } 1403 1404 return(link); 1405} 1406 1407 1408struct in_addr 1409FindOriginalAddress(struct in_addr alias_addr) 1410{ 1411 struct alias_link *link; 1412 1413 link = FindLinkIn(nullAddress, alias_addr, 1414 0, 0, LINK_ADDR, 0); 1415 if (link == NULL) 1416 { 1417 newDefaultLink = 1; 1418 if (targetAddress.s_addr != 0) 1419 return targetAddress; 1420 else 1421 return alias_addr; 1422 } 1423 else 1424 { 1425 if (link->src_addr.s_addr == 0) 1426 return aliasAddress; 1427 else 1428 return link->src_addr; 1429 } 1430} 1431 1432 1433struct in_addr 1434FindAliasAddress(struct in_addr original_addr) 1435{ 1436 struct alias_link *link; 1437 1438 link = FindLinkOut(original_addr, nullAddress, 1439 0, 0, LINK_ADDR, 0); 1440 if (link == NULL) 1441 { 1442 return aliasAddress; 1443 } 1444 else 1445 { 1446 if (link->alias_addr.s_addr == 0) 1447 return aliasAddress; 1448 else 1449 return link->alias_addr; 1450 } 1451} 1452 1453 1454/* External routines for getting or changing link data 1455 (external to alias_db.c, but internal to alias*.c) 1456 1457 SetFragmentData(), GetFragmentData() 1458 SetFragmentPtr(), GetFragmentPtr() 1459 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1460 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1461 GetOriginalPort(), GetAliasPort() 1462 SetAckModified(), GetAckModified() 1463 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1464*/ 1465 1466 1467void 1468SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1469{ 1470 link->data.frag_addr = src_addr; 1471} 1472 1473 1474void 1475GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1476{ 1477 *src_addr = link->data.frag_addr; 1478} 1479 1480 1481void 1482SetFragmentPtr(struct alias_link *link, char *fptr) 1483{ 1484 link->data.frag_ptr = fptr; 1485} 1486 1487 1488void 1489GetFragmentPtr(struct alias_link *link, char **fptr) 1490{ 1491 *fptr = link->data.frag_ptr; 1492} 1493 1494 1495void 1496SetStateIn(struct alias_link *link, int state) 1497{ 1498 /* TCP input state */ 1499 switch (state) { 1500 case ALIAS_TCP_STATE_DISCONNECTED: 1501 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) { 1502 link->expire_time = TCP_EXPIRE_DEAD; 1503 } else { 1504 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1505 } 1506 link->data.tcp->state.in = state; 1507 break; 1508 case ALIAS_TCP_STATE_CONNECTED: 1509 link->expire_time = TCP_EXPIRE_CONNECTED; 1510 /*FALLTHROUGH*/ 1511 case ALIAS_TCP_STATE_NOT_CONNECTED: 1512 link->data.tcp->state.in = state; 1513 break; 1514 default: 1515 abort(); 1516 } 1517} 1518 1519 1520void 1521SetStateOut(struct alias_link *link, int state) 1522{ 1523 /* TCP output state */ 1524 switch (state) { 1525 case ALIAS_TCP_STATE_DISCONNECTED: 1526 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) { 1527 link->expire_time = TCP_EXPIRE_DEAD; 1528 } else { 1529 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1530 } 1531 link->data.tcp->state.out = state; 1532 break; 1533 case ALIAS_TCP_STATE_CONNECTED: 1534 link->expire_time = TCP_EXPIRE_CONNECTED; 1535 /*FALLTHROUGH*/ 1536 case ALIAS_TCP_STATE_NOT_CONNECTED: 1537 link->data.tcp->state.out = state; 1538 break; 1539 default: 1540 abort(); 1541 } 1542} 1543 1544 1545int 1546GetStateIn(struct alias_link *link) 1547{ 1548 /* TCP input state */ 1549 return link->data.tcp->state.in; 1550} 1551 1552 1553int 1554GetStateOut(struct alias_link *link) 1555{ 1556 /* TCP output state */ 1557 return link->data.tcp->state.out; 1558} 1559 1560 1561struct in_addr 1562GetOriginalAddress(struct alias_link *link) 1563{ 1564 if (link->src_addr.s_addr == 0) 1565 return aliasAddress; 1566 else 1567 return(link->src_addr); 1568} 1569 1570 1571struct in_addr 1572GetDestAddress(struct alias_link *link) 1573{ 1574 return(link->dst_addr); 1575} 1576 1577 1578struct in_addr 1579GetAliasAddress(struct alias_link *link) 1580{ 1581 if (link->alias_addr.s_addr == 0) 1582 return aliasAddress; 1583 else 1584 return link->alias_addr; 1585} 1586 1587 1588struct in_addr 1589GetDefaultAliasAddress() 1590{ 1591 return aliasAddress; 1592} 1593 1594 1595void 1596SetDefaultAliasAddress(struct in_addr alias_addr) 1597{ 1598 aliasAddress = alias_addr; 1599} 1600 1601 1602u_short 1603GetOriginalPort(struct alias_link *link) 1604{ 1605 return(link->src_port); 1606} 1607 1608 1609u_short 1610GetAliasPort(struct alias_link *link) 1611{ 1612 return(link->alias_port); 1613} 1614 1615u_short 1616GetDestPort(struct alias_link *link) 1617{ 1618 return(link->dst_port); 1619} 1620 1621void 1622SetAckModified(struct alias_link *link) 1623{ 1624/* Indicate that ack numbers have been modified in a TCP connection */ 1625 link->data.tcp->state.ack_modified = 1; 1626} 1627 1628 1629struct in_addr 1630GetProxyAddress(struct alias_link *link) 1631{ 1632 return link->proxy_addr; 1633} 1634 1635 1636void 1637SetProxyAddress(struct alias_link *link, struct in_addr addr) 1638{ 1639 link->proxy_addr = addr; 1640} 1641 1642 1643u_short 1644GetProxyPort(struct alias_link *link) 1645{ 1646 return link->proxy_port; 1647} 1648 1649 1650void 1651SetProxyPort(struct alias_link *link, u_short port) 1652{ 1653 link->proxy_port = port; 1654} 1655 1656 1657int 1658GetAckModified(struct alias_link *link) 1659{ 1660/* See if ack numbers have been modified */ 1661 return link->data.tcp->state.ack_modified; 1662} 1663 1664 1665int 1666GetDeltaAckIn(struct ip *pip, struct alias_link *link) 1667{ 1668/* 1669Find out how much the ack number has been altered for an incoming 1670TCP packet. To do this, a circular list is ack numbers where the TCP 1671packet size was altered is searched. 1672*/ 1673 1674 int i; 1675 struct tcphdr *tc; 1676 int delta, ack_diff_min; 1677 u_long ack; 1678 1679 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1680 ack = tc->th_ack; 1681 1682 delta = 0; 1683 ack_diff_min = -1; 1684 for (i=0; i<N_LINK_TCP_DATA; i++) 1685 { 1686 struct ack_data_record x; 1687 1688 x = link->data.tcp->ack[i]; 1689 if (x.active == 1) 1690 { 1691 int ack_diff; 1692 1693 ack_diff = SeqDiff(x.ack_new, ack); 1694 if (ack_diff >= 0) 1695 { 1696 if (ack_diff_min >= 0) 1697 { 1698 if (ack_diff < ack_diff_min) 1699 { 1700 delta = x.delta; 1701 ack_diff_min = ack_diff; 1702 } 1703 } 1704 else 1705 { 1706 delta = x.delta; 1707 ack_diff_min = ack_diff; 1708 } 1709 } 1710 } 1711 } 1712 return (delta); 1713} 1714 1715 1716int 1717GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 1718{ 1719/* 1720Find out how much the seq number has been altered for an outgoing 1721TCP packet. To do this, a circular list is ack numbers where the TCP 1722packet size was altered is searched. 1723*/ 1724 1725 int i; 1726 struct tcphdr *tc; 1727 int delta, seq_diff_min; 1728 u_long seq; 1729 1730 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1731 seq = tc->th_seq; 1732 1733 delta = 0; 1734 seq_diff_min = -1; 1735 for (i=0; i<N_LINK_TCP_DATA; i++) 1736 { 1737 struct ack_data_record x; 1738 1739 x = link->data.tcp->ack[i]; 1740 if (x.active == 1) 1741 { 1742 int seq_diff; 1743 1744 seq_diff = SeqDiff(x.ack_old, seq); 1745 if (seq_diff >= 0) 1746 { 1747 if (seq_diff_min >= 0) 1748 { 1749 if (seq_diff < seq_diff_min) 1750 { 1751 delta = x.delta; 1752 seq_diff_min = seq_diff; 1753 } 1754 } 1755 else 1756 { 1757 delta = x.delta; 1758 seq_diff_min = seq_diff; 1759 } 1760 } 1761 } 1762 } 1763 return (delta); 1764} 1765 1766 1767void 1768AddSeq(struct ip *pip, struct alias_link *link, int delta) 1769{ 1770/* 1771When a TCP packet has been altered in length, save this 1772information in a circular list. If enough packets have 1773been altered, then this list will begin to overwrite itself. 1774*/ 1775 1776 struct tcphdr *tc; 1777 struct ack_data_record x; 1778 int hlen, tlen, dlen; 1779 int i; 1780 1781 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1782 1783 hlen = (pip->ip_hl + tc->th_off) << 2; 1784 tlen = ntohs(pip->ip_len); 1785 dlen = tlen - hlen; 1786 1787 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 1788 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 1789 x.delta = delta; 1790 x.active = 1; 1791 1792 i = link->data.tcp->state.index; 1793 link->data.tcp->ack[i] = x; 1794 1795 i++; 1796 if (i == N_LINK_TCP_DATA) 1797 link->data.tcp->state.index = 0; 1798 else 1799 link->data.tcp->state.index = i; 1800} 1801 1802void 1803SetExpire(struct alias_link *link, int expire) 1804{ 1805 if (expire == 0) 1806 { 1807 link->flags &= ~LINK_PERMANENT; 1808 DeleteLink(link); 1809 } 1810 else if (expire == -1) 1811 { 1812 link->flags |= LINK_PERMANENT; 1813 } 1814 else if (expire > 0) 1815 { 1816 link->expire_time = expire; 1817 } 1818 else 1819 { 1820#ifdef DEBUG 1821 fprintf(stderr, "PacketAlias/SetExpire(): "); 1822 fprintf(stderr, "error in expire parameter\n"); 1823#endif 1824 } 1825} 1826 1827void 1828ClearCheckNewLink(void) 1829{ 1830 newDefaultLink = 0; 1831} 1832 1833 1834/* Miscellaneous Functions 1835 1836 HouseKeeping() 1837 InitPacketAliasLog() 1838 UninitPacketAliasLog() 1839*/ 1840 1841/* 1842 Whenever an outgoing or incoming packet is handled, HouseKeeping() 1843 is called to find and remove timed-out aliasing links. Logic exists 1844 to sweep through the entire table and linked list structure 1845 every 60 seconds. 1846 1847 (prototype in alias_local.h) 1848*/ 1849 1850void 1851HouseKeeping(void) 1852{ 1853 int i, n, n100; 1854 struct timeval tv; 1855 struct timezone tz; 1856 1857 /* 1858 * Save system time (seconds) in global variable timeStamp for 1859 * use by other functions. This is done so as not to unnecessarily 1860 * waste timeline by making system calls. 1861 */ 1862 gettimeofday(&tv, &tz); 1863 timeStamp = tv.tv_sec; 1864 1865 /* Compute number of spokes (output table link chains) to cover */ 1866 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 1867 n100 *= timeStamp - lastCleanupTime; 1868 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 1869 1870 n = n100/100; 1871 1872 /* Handle different cases */ 1873 if (n > ALIAS_CLEANUP_MAX_SPOKES) 1874 { 1875 n = ALIAS_CLEANUP_MAX_SPOKES; 1876 lastCleanupTime = timeStamp; 1877 houseKeepingResidual = 0; 1878 1879 for (i=0; i<n; i++) 1880 IncrementalCleanup(); 1881 } 1882 else if (n > 0) 1883 { 1884 lastCleanupTime = timeStamp; 1885 houseKeepingResidual = n100 - 100*n; 1886 1887 for (i=0; i<n; i++) 1888 IncrementalCleanup(); 1889 } 1890 else if (n < 0) 1891 { 1892#ifdef DEBUG 1893 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 1894 fprintf(stderr, "something unexpected in time values\n"); 1895#endif 1896 lastCleanupTime = timeStamp; 1897 houseKeepingResidual = 0; 1898 } 1899} 1900 1901 1902/* Init the log file and enable logging */ 1903static void 1904InitPacketAliasLog(void) 1905{ 1906 if ((~packetAliasMode & PKT_ALIAS_LOG) 1907 && (monitorFile = fopen("/var/log/alias.log", "w"))) 1908 { 1909 packetAliasMode |= PKT_ALIAS_LOG; 1910 fprintf(monitorFile, 1911 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 1912 } 1913} 1914 1915 1916/* Close the log-file and disable logging. */ 1917static void 1918UninitPacketAliasLog(void) 1919{ 1920 if (monitorFile) { 1921 fclose(monitorFile); 1922 monitorFile = NULL; 1923 } 1924 packetAliasMode &= ~PKT_ALIAS_LOG; 1925} 1926 1927 1928 1929 1930 1931 1932/* Outside world interfaces 1933 1934-- "outside world" means other than alias*.c routines -- 1935 1936 PacketAliasRedirectPort() 1937 PacketAliasRedirectAddr() 1938 PacketAliasRedirectDelete() 1939 PacketAliasSetAddress() 1940 PacketAliasInit() 1941 PacketAliasUninit() 1942 PacketAliasSetMode() 1943 1944(prototypes in alias.h) 1945*/ 1946 1947/* Redirection from a specific public addr:port to a 1948 a private addr:port */ 1949struct alias_link * 1950PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 1951 struct in_addr dst_addr, u_short dst_port, 1952 struct in_addr alias_addr, u_short alias_port, 1953 u_char proto) 1954{ 1955 int link_type; 1956 struct alias_link *link; 1957 1958 switch(proto) 1959 { 1960 case IPPROTO_UDP: 1961 link_type = LINK_UDP; 1962 break; 1963 case IPPROTO_TCP: 1964 link_type = LINK_TCP; 1965 break; 1966 default: 1967#ifdef DEBUG 1968 fprintf(stderr, "PacketAliasRedirectPort(): "); 1969 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 1970#endif 1971 return NULL; 1972 } 1973 1974 link = AddLink(src_addr, dst_addr, alias_addr, 1975 src_port, dst_port, alias_port, 1976 link_type); 1977 1978 if (link != NULL) 1979 { 1980 link->flags |= LINK_PERMANENT; 1981 } 1982#ifdef DEBUG 1983 else 1984 { 1985 fprintf(stderr, "PacketAliasRedirectPort(): " 1986 "call to AddLink() failed\n"); 1987 } 1988#endif 1989 1990 return link; 1991} 1992 1993/* Translate PPTP packets to a machine on the inside 1994 */ 1995int 1996PacketAliasPptp(struct in_addr src_addr) 1997{ 1998 1999 pptpAliasAddr = src_addr; /* Address of the inside PPTP machine */ 2000 pptpAliasFlag = src_addr.s_addr != INADDR_NONE; 2001 2002 return 1; 2003} 2004 2005int GetPptpAlias (struct in_addr* alias_addr) 2006{ 2007 if (pptpAliasFlag) 2008 *alias_addr = pptpAliasAddr; 2009 2010 return pptpAliasFlag; 2011} 2012 2013/* Static address translation */ 2014struct alias_link * 2015PacketAliasRedirectAddr(struct in_addr src_addr, 2016 struct in_addr alias_addr) 2017{ 2018 struct alias_link *link; 2019 2020 link = AddLink(src_addr, nullAddress, alias_addr, 2021 0, 0, 0, 2022 LINK_ADDR); 2023 2024 if (link != NULL) 2025 { 2026 link->flags |= LINK_PERMANENT; 2027 } 2028#ifdef DEBUG 2029 else 2030 { 2031 fprintf(stderr, "PacketAliasRedirectAddr(): " 2032 "call to AddLink() failed\n"); 2033 } 2034#endif 2035 2036 return link; 2037} 2038 2039 2040void 2041PacketAliasRedirectDelete(struct alias_link *link) 2042{ 2043/* This is a dangerous function to put in the API, 2044 because an invalid pointer can crash the program. */ 2045 2046 deleteAllLinks = 1; 2047 DeleteLink(link); 2048 deleteAllLinks = 0; 2049} 2050 2051 2052void 2053PacketAliasSetAddress(struct in_addr addr) 2054{ 2055 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2056 && aliasAddress.s_addr != addr.s_addr) 2057 CleanupAliasData(); 2058 2059 aliasAddress = addr; 2060} 2061 2062 2063void 2064PacketAliasSetTarget(struct in_addr target_addr) 2065{ 2066 targetAddress = target_addr; 2067} 2068 2069 2070void 2071PacketAliasInit(void) 2072{ 2073 int i; 2074 struct timeval tv; 2075 struct timezone tz; 2076 static int firstCall = 1; 2077 2078 if (firstCall == 1) 2079 { 2080 gettimeofday(&tv, &tz); 2081 timeStamp = tv.tv_sec; 2082 lastCleanupTime = tv.tv_sec; 2083 houseKeepingResidual = 0; 2084 2085 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2086 linkTableOut[i] = NULL; 2087 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2088 linkTableIn[i] = NULL; 2089 2090 atexit(PacketAliasUninit); 2091 firstCall = 0; 2092 } 2093 else 2094 { 2095 deleteAllLinks = 1; 2096 CleanupAliasData(); 2097 deleteAllLinks = 0; 2098 } 2099 2100 aliasAddress.s_addr = 0; 2101 targetAddress.s_addr = 0; 2102 2103 icmpLinkCount = 0; 2104 udpLinkCount = 0; 2105 tcpLinkCount = 0; 2106 fragmentIdLinkCount = 0; 2107 fragmentPtrLinkCount = 0; 2108 sockCount = 0; 2109 2110 cleanupIndex =0; 2111 2112 packetAliasMode = PKT_ALIAS_SAME_PORTS 2113 | PKT_ALIAS_USE_SOCKETS 2114 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2115 2116 pptpAliasFlag = 0; 2117} 2118 2119void 2120PacketAliasUninit(void) { 2121 deleteAllLinks = 1; 2122 CleanupAliasData(); 2123 deleteAllLinks = 0; 2124 UninitPacketAliasLog(); 2125#ifndef NO_FW_PUNCH 2126 UninitPunchFW(); 2127#endif 2128} 2129 2130 2131/* Change mode for some operations */ 2132unsigned int 2133PacketAliasSetMode( 2134 unsigned int flags, /* Which state to bring flags to */ 2135 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2136 probe for flag values) */ 2137) 2138{ 2139/* Enable logging? */ 2140 if (flags & mask & PKT_ALIAS_LOG) 2141 { 2142 InitPacketAliasLog(); /* Do the enable */ 2143 } else 2144/* _Disable_ logging? */ 2145 if (~flags & mask & PKT_ALIAS_LOG) { 2146 UninitPacketAliasLog(); 2147 } 2148 2149#ifndef NO_FW_PUNCH 2150/* Start punching holes in the firewall? */ 2151 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2152 InitPunchFW(); 2153 } else 2154/* Stop punching holes in the firewall? */ 2155 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2156 UninitPunchFW(); 2157 } 2158#endif 2159 2160/* Other flags can be set/cleared without special action */ 2161 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2162 return packetAliasMode; 2163} 2164 2165 2166int 2167PacketAliasCheckNewLink(void) 2168{ 2169 return newDefaultLink; 2170} 2171 2172 2173#ifndef NO_FW_PUNCH 2174 2175/***************** 2176 Code to support firewall punching. This shouldn't really be in this 2177 file, but making variables global is evil too. 2178 ****************/ 2179 2180/* Firewall include files */ 2181#include <sys/queue.h> 2182#include <net/if.h> 2183#include <netinet/ip_fw.h> 2184#include <string.h> 2185#include <err.h> 2186 2187static void ClearAllFWHoles(void); 2188 2189static int fireWallBaseNum; /* The first firewall entry free for our use */ 2190static int fireWallNumNums; /* How many entries can we use? */ 2191static int fireWallActiveNum; /* Which entry did we last use? */ 2192static char *fireWallField; /* bool array for entries */ 2193 2194#define fw_setfield(field, num) \ 2195do { \ 2196 (field)[num] = 1; \ 2197} /*lint -save -e717 */ while(0) /*lint -restore */ 2198#define fw_clrfield(field, num) \ 2199do { \ 2200 (field)[num] = 0; \ 2201} /*lint -save -e717 */ while(0) /*lint -restore */ 2202#define fw_tstfield(field, num) ((field)[num]) 2203 2204void 2205PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2206 fireWallBaseNum = base; 2207 fireWallNumNums = num; 2208} 2209 2210static void 2211InitPunchFW(void) { 2212 fireWallField = malloc(fireWallNumNums); 2213 if (fireWallField) { 2214 memset(fireWallField, 0, fireWallNumNums); 2215 if (fireWallFD < 0) { 2216 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2217 } 2218 ClearAllFWHoles(); 2219 fireWallActiveNum = fireWallBaseNum; 2220 } 2221} 2222 2223static void 2224UninitPunchFW(void) { 2225 ClearAllFWHoles(); 2226 if (fireWallFD >= 0) 2227 close(fireWallFD); 2228 fireWallFD = -1; 2229 if (fireWallField) 2230 free(fireWallField); 2231 fireWallField = NULL; 2232 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2233} 2234 2235/* Make a certain link go through the firewall */ 2236void 2237PunchFWHole(struct alias_link *link) { 2238 int r; /* Result code */ 2239 struct ip_fw rule; /* On-the-fly built rule */ 2240 int fwhole; /* Where to punch hole */ 2241 2242/* Don't do anything unless we are asked to */ 2243 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2244 fireWallFD < 0 || 2245 link->link_type != LINK_TCP || 2246 !link->data.tcp) 2247 return; 2248 2249 memset(&rule, 0, sizeof rule); 2250 2251/** Build rule **/ 2252 2253 /* Find empty slot */ 2254 for (fwhole = fireWallActiveNum; 2255 fwhole < fireWallBaseNum + fireWallNumNums && 2256 fw_tstfield(fireWallField, fwhole); 2257 fwhole++) 2258 ; 2259 if (fwhole >= fireWallBaseNum + fireWallNumNums || 2260 fw_tstfield(fireWallField, fwhole)) { 2261 for (fwhole = fireWallBaseNum; 2262 fwhole < fireWallActiveNum && 2263 fw_tstfield(fireWallField, fwhole); 2264 fwhole++) 2265 ; 2266 if (fwhole == fireWallActiveNum) { 2267 /* No rule point empty - we can't punch more holes. */ 2268 fireWallActiveNum = fireWallBaseNum; 2269#ifdef DEBUG 2270 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2271#endif 2272 return; 2273 } 2274 } 2275 /* Start next search at next position */ 2276 fireWallActiveNum = fwhole+1; 2277 2278 /* Build generic part of the two rules */ 2279 rule.fw_number = fwhole; 2280 rule.fw_nports = 1; /* Number of source ports; dest ports follow */ 2281 rule.fw_flg = IP_FW_F_ACCEPT; 2282 rule.fw_prot = IPPROTO_TCP; 2283 rule.fw_smsk.s_addr = INADDR_BROADCAST; 2284 rule.fw_dmsk.s_addr = INADDR_BROADCAST; 2285 2286 /* Build and apply specific part of the rules */ 2287 rule.fw_src = GetOriginalAddress(link); 2288 rule.fw_dst = GetDestAddress(link); 2289 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); 2290 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); 2291 2292 /* Skip non-bound links - XXX should not be strictly necessary, 2293 but seems to leave hole if not done. Leak of non-bound links? 2294 (Code should be left even if the problem is fixed - it is a 2295 clear optimization) */ 2296 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { 2297 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2298#ifdef DEBUG 2299 if (r) 2300 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2301#endif 2302 rule.fw_src = GetDestAddress(link); 2303 rule.fw_dst = GetOriginalAddress(link); 2304 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); 2305 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); 2306 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2307#ifdef DEBUG 2308 if (r) 2309 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2310#endif 2311 } 2312/* Indicate hole applied */ 2313 link->data.tcp->fwhole = fwhole; 2314 fw_setfield(fireWallField, fwhole); 2315} 2316 2317/* Remove a hole in a firewall associated with a particular alias 2318 link. Calling this too often is harmless. */ 2319static void 2320ClearFWHole(struct alias_link *link) { 2321 if (link->link_type == LINK_TCP && link->data.tcp) { 2322 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ 2323 struct ip_fw rule; 2324 2325 if (fwhole < 0) 2326 return; 2327 2328 memset(&rule, 0, sizeof rule); 2329 rule.fw_number = fwhole; 2330 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2331 ; 2332 fw_clrfield(fireWallField, fwhole); 2333 link->data.tcp->fwhole = -1; 2334 } 2335} 2336 2337/* Clear out the entire range dedicated to firewall holes. */ 2338static void 2339ClearAllFWHoles(void) { 2340 struct ip_fw rule; /* On-the-fly built rule */ 2341 int i; 2342 2343 if (fireWallFD < 0) 2344 return; 2345 2346 memset(&rule, 0, sizeof rule); 2347 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { 2348 rule.fw_number = i; 2349 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2350 ; 2351 } 2352 memset(fireWallField, 0, fireWallNumNums); 2353} 2354#endif 2355