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