alias_db.c revision 28084
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. Eiklund 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 107 108/* System include files */ 109#include <stdlib.h> 110#include <stdio.h> 111#include <unistd.h> 112 113#include <sys/errno.h> 114#include <sys/socket.h> 115#include <sys/time.h> 116#include <sys/types.h> 117 118/* BSD network include files */ 119#include <netinet/in_systm.h> 120#include <netinet/in.h> 121#include <netinet/ip.h> 122#include <netinet/tcp.h> 123#include <arpa/inet.h> 124 125#include "alias.h" 126#include "alias_local.h" 127 128 129 130/* 131 Constants (note: constants are also defined 132 near relevant functions or structs) 133*/ 134 135/* Sizes of input and output link tables */ 136#define LINK_TABLE_OUT_SIZE 101 137#define LINK_TABLE_IN_SIZE 4001 138 139/* Parameters used for cleanup of expired links */ 140#define ALIAS_CLEANUP_INTERVAL_SECS 60 141#define ALIAS_CLEANUP_MAX_SPOKES 30 142 143/* Timouts (in seconds) for different link types) */ 144#define ICMP_EXPIRE_TIME 60 145#define UDP_EXPIRE_TIME 60 146#define TCP_EXPIRE_TIME 90 147#define FRAGMENT_ID_EXPIRE_TIME 10 148#define FRAGMENT_PTR_EXPIRE_TIME 30 149 150/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 151 These constants can be anything except zero, which indicates an 152 unknown port numbea. */ 153 154#define NO_DEST_PORT 1 155#define NO_SRC_PORT 1 156 157 158 159/* Data Structures 160 161 The fundamental data structure used in this program is 162 "struct alias_link". Whenever a TCP connection is made, 163 a UDP datagram is sent out, or an ICMP echo request is made, 164 a link record is made (if it has not already been created). 165 The link record is identified by the source address/port 166 and the destination address/port. In the case of an ICMP 167 echo request, the source port is treated as being equivalent 168 with the 16-bit id number of the ICMP packet. 169 170 The link record also can store some auxiliary data. For 171 TCP connections that have had sequence and acknowledgment 172 modifications, data space is available to track these changes. 173 A state field is used to keep track in changes to the tcp 174 connection state. Id numbers of fragments can also be 175 stored in the auxiliary space. Pointers to unresolved 176 framgents can also be stored. 177 178 The link records support two independent chainings. Lookup 179 tables for input and out tables hold the initial pointers 180 the link chains. On input, the lookup table indexes on alias 181 port and link type. On output, the lookup table indexes on 182 source addreess, destination address, source port, destination 183 port and link type. 184*/ 185 186struct ack_data_record /* used to save changes to ack/seq numbers */ 187{ 188 u_long ack_old; 189 u_long ack_new; 190 int delta; 191 int active; 192}; 193 194struct tcp_state /* Information about tcp connection */ 195{ 196 int in; /* State for outside -> inside */ 197 int out; /* State for inside -> outside */ 198 int index; /* Index to ack data array */ 199 int ack_modified; /* Indicates whether ack and seq numbers */ 200 /* been modified */ 201}; 202 203#define N_LINK_TCP_DATA 3 /* Number of distinct ack number changes 204 saved for a modified TCP stream */ 205struct tcp_dat 206{ 207 struct tcp_state state; 208 struct ack_data_record ack[N_LINK_TCP_DATA]; 209}; 210 211struct alias_link /* Main data structure */ 212{ 213 struct in_addr src_addr; /* Address and port information */ 214 struct in_addr dst_addr; /* . */ 215 struct in_addr alias_addr; /* . */ 216 u_short src_port; /* . */ 217 u_short dst_port; /* . */ 218 u_short alias_port; /* . */ 219 220 int link_type; /* Type of link: tcp, udp, icmp, frag */ 221 222/* values for link_type */ 223#define LINK_ICMP 1 224#define LINK_UDP 2 225#define LINK_TCP 3 226#define LINK_FRAGMENT_ID 4 227#define LINK_FRAGMENT_PTR 5 228#define LINK_ADDR 6 229 230 int flags; /* indicates special characteristics */ 231 232/* flag bits */ 233#define LINK_UNKNOWN_DEST_PORT 0x01 234#define LINK_UNKNOWN_DEST_ADDR 0x02 235#define LINK_PERMANENT 0x04 236#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 237 238 int timestamp; /* Time link was last accessed */ 239 int expire_time; /* Expire time for link */ 240 241 int sockfd; /* socket descriptor */ 242 243 u_int start_point_out; /* Index number in output lookup table */ 244 u_int start_point_in; 245 struct alias_link *next_out; /* Linked list pointers for input and */ 246 struct alias_link *last_out; /* output tables */ 247 struct alias_link *next_in; /* . */ 248 struct alias_link *last_in; /* . */ 249 250 union /* Auxiliary data */ 251 { 252 char *frag_ptr; 253 struct in_addr frag_addr; 254 struct tcp_dat *tcp; 255 } data; 256}; 257 258 259 260 261 262/* Global Variables 263 264 The global variables listed here are only accessed from 265 within alias_db.c and so are prefixed with the static 266 designation. 267*/ 268 269int packetAliasMode; /* Mode flags */ 270 /* - documented in alias.h */ 271 272static struct in_addr aliasAddress; /* Address written onto source */ 273 /* field of IP packet. */ 274 275static struct in_addr targetAddress; /* IP address incoming packets */ 276 /* are sent to if no aliasing */ 277 /* link already exists */ 278 279static struct in_addr nullAddress; /* Used as a dummy parameter for */ 280 /* some function calls */ 281static struct alias_link * 282linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ 283 /* chains of link records. Each */ 284static struct alias_link * /* link record is doubly indexed */ 285linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ 286 /* tables. */ 287 288static int icmpLinkCount; /* Link statistics */ 289static int udpLinkCount; 290static int tcpLinkCount; 291static int fragmentIdLinkCount; 292static int fragmentPtrLinkCount; 293static int sockCount; 294 295static int cleanupIndex; /* Index to chain of link table */ 296 /* being inspected for old links */ 297 298static int timeStamp; /* System time in seconds for */ 299 /* current packet */ 300 301static int lastCleanupTime; /* Last time IncrementalCleanup() */ 302 /* was called */ 303 304static int houseKeepingResidual; /* used by HouseKeeping() */ 305 306static int deleteAllLinks; /* If equal to zero, DeleteLink() */ 307 /* will not remove permanent links */ 308 309static FILE *monitorFile; /* File descriptor for link */ 310 /* statistics monitoring file */ 311 312static int firstCall = 1; /* Needed by InitAlias() */ 313 314static int newDefaultLink; /* Indicates if a new aliasing */ 315 /* link has been created after a */ 316 /* call to PacketAliasIn/Out(). */ 317 318 319 320 321 322 323/* Internal utility routines (used only in alias_db.c) 324 325Lookup table starting points: 326 StartPointIn() -- link table initial search point for 327 outgoing packets 328 StartPointOut() -- port table initial search point for 329 incoming packets 330 331Miscellaneous: 332 SeqDiff() -- difference between two TCP sequences 333 ShowAliasStats() -- send alias statistics to a monitor file 334*/ 335 336 337/* Local prototypes */ 338static u_int StartPointIn(struct in_addr, u_short, int); 339 340static u_int StartPointOut(struct in_addr, struct in_addr, 341 u_short, u_short, int); 342 343static int SeqDiff(u_long, u_long); 344 345static void ShowAliasStats(void); 346 347 348static u_int 349StartPointIn(struct in_addr alias_addr, 350 u_short alias_port, 351 int link_type) 352{ 353 u_int n; 354 355 n = alias_addr.s_addr; 356 n += alias_port; 357 n += link_type; 358 return(n % LINK_TABLE_IN_SIZE); 359} 360 361 362static u_int 363StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 364 u_short src_port, u_short dst_port, int link_type) 365{ 366 u_int n; 367 368 n = src_addr.s_addr; 369 n += dst_addr.s_addr; 370 n += src_port; 371 n += dst_port; 372 n += link_type; 373 374 return(n % LINK_TABLE_OUT_SIZE); 375} 376 377 378static int 379SeqDiff(u_long x, u_long y) 380{ 381/* Return the difference between two TCP sequence numbers */ 382 383/* 384 This function is encapsulated in case there are any unusual 385 arithmetic conditions that need to be considered. 386*/ 387 388 return (ntohl(y) - ntohl(x)); 389} 390 391 392static void 393ShowAliasStats(void) 394{ 395/* Used for debugging */ 396 397 if (packetAliasMode & PKT_ALIAS_LOG) 398 { 399 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d", 400 icmpLinkCount, 401 udpLinkCount, 402 tcpLinkCount, 403 fragmentIdLinkCount, 404 fragmentPtrLinkCount); 405 406 fprintf(monitorFile, " / tot=%d (sock=%d)\n", 407 icmpLinkCount + udpLinkCount 408 + tcpLinkCount 409 + fragmentIdLinkCount 410 + fragmentPtrLinkCount, 411 sockCount); 412 413 fflush(monitorFile); 414 } 415} 416 417 418 419 420 421/* Internal routines for finding, deleting and adding links 422 423Port Allocation: 424 GetNewPort() -- find and reserve new alias port number 425 GetSocket() -- try to allocate a socket for a given port 426 427Link creation and deletion: 428 CleanupAliasData() - remove all link chains from lookup table 429 IncrementalCleanup() - look for stale links in a single chain 430 DeleteLink() - remove link 431 AddLink() - add link 432 433Link search: 434 FindLinkOut() - find link for outgoing packets 435 FindLinkIn() - find link for incoming packets 436*/ 437 438/* Local prototypes */ 439static int GetNewPort(struct alias_link *, int); 440 441static u_short GetSocket(u_short, int *, int); 442 443static void CleanupAliasData(void); 444 445static void IncrementalCleanup(void); 446 447static void DeleteLink(struct alias_link *); 448 449static struct alias_link * 450AddLink(struct in_addr, struct in_addr, struct in_addr, 451 u_short, u_short, int, int); 452 453static struct alias_link * 454FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int); 455 456static struct alias_link * 457FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); 458 459 460#define ALIAS_PORT_BASE 0x08000 461#define ALIAS_PORT_MASK 0x07fff 462#define GET_NEW_PORT_MAX_ATTEMPTS 20 463 464#define GET_ALIAS_PORT -1 465#define GET_ALIAS_ID GET_ALIAS_PORT 466 467/* GetNewPort() allocates port numbers. Note that if a port number 468 is already in use, that does not mean that it cannot be used by 469 another link concurrently. This is because GetNewPort() looks for 470 unused triplets: (dest addr, dest port, alias port). */ 471 472static int 473GetNewPort(struct alias_link *link, int alias_port_param) 474{ 475 int i; 476 int max_trials; 477 u_short port_sys; 478 u_short port_net; 479 480/* 481 Description of alias_port_param for GetNewPort(). When 482 this parameter is zero or positive, it precisely specifies 483 the port number. GetNewPort() will return this number 484 without check that it is in use. 485 486 Whis this parameter is -1, it indicates to get a randomly 487 selected port number. 488*/ 489 490 if (alias_port_param == GET_ALIAS_PORT) 491 { 492 /* 493 * The aliasing port is automatically selected 494 * by one of two methods below: 495 */ 496 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 497 498 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) 499 { 500 /* 501 * When the ALIAS_SAME_PORTS option is 502 * chosen, the first try will be the 503 * actual source port. If this is already 504 * in use, the remainder of the trials 505 * will be random. 506 */ 507 port_net = link->src_port; 508 port_sys = ntohs(port_net); 509 } 510 else 511 { 512 /* First trial and all subsequent are random. */ 513 port_sys = random() & ALIAS_PORT_MASK; 514 port_sys += ALIAS_PORT_BASE; 515 port_net = htons(port_sys); 516 } 517 } 518 else if (alias_port_param >= 0 && alias_port_param < 0x10000) 519 { 520 link->alias_port = (u_short) alias_port_param; 521 return(0); 522 } 523 else 524 { 525 fprintf(stderr, "PacketAlias/GetNewPort(): "); 526 fprintf(stderr, "input parameter error\n"); 527 return(-1); 528 } 529 530 531/* Port number search */ 532 for (i=0; i<max_trials; i++) 533 { 534 int go_ahead; 535 struct alias_link *search_result; 536 537 search_result = FindLinkIn(link->dst_addr, link->alias_addr, 538 link->dst_port, port_net, 539 link->link_type, 0); 540 541 if (search_result == NULL) 542 go_ahead = 1; 543 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) 544 && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 545 go_ahead = 1; 546 else 547 go_ahead = 0; 548 549 if (go_ahead) 550 { 551 if ((packetAliasMode && PKT_ALIAS_USE_SOCKETS) 552 && (link->flags & LINK_PARTIALLY_SPECIFIED)) 553 { 554 if (GetSocket(port_net, &link->sockfd, link->link_type)) 555 { 556 link->alias_port = port_net; 557 return(0); 558 } 559 } 560 else 561 { 562 link->alias_port = port_net; 563 return(0); 564 } 565 } 566 567 port_sys = random() & ALIAS_PORT_MASK; 568 port_sys += ALIAS_PORT_BASE; 569 port_net = htons(port_sys); 570 } 571 572 fprintf(stderr, "PacketAlias/GetnewPort(): "); 573 fprintf(stderr, "could not find free port\n"); 574 575 return(-1); 576} 577 578 579static u_short 580GetSocket(u_short port_net, int *sockfd, int link_type) 581{ 582 int err; 583 int sock; 584 struct sockaddr_in sock_addr; 585 586 if (link_type == LINK_TCP) 587 sock = socket(AF_INET, SOCK_STREAM, 0); 588 else if (link_type == LINK_UDP) 589 sock = socket(AF_INET, SOCK_DGRAM, 0); 590 else 591 { 592 fprintf(stderr, "PacketAlias/GetSocket(): "); 593 fprintf(stderr, "incorrect link type\n"); 594 return(0); 595 } 596 597 if (sock < 0) 598 { 599 fprintf(stderr, "PacketAlias/GetSocket(): "); 600 fprintf(stderr, "socket() error %d\n", *sockfd); 601 return(0); 602 } 603 604 sock_addr.sin_family = AF_INET; 605 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 606 sock_addr.sin_port = port_net; 607 608 err = bind(sock, 609 (struct sockaddr *) &sock_addr, 610 sizeof(sock_addr)); 611 if (err == 0) 612 { 613 sockCount++; 614 *sockfd = sock; 615 return(1); 616 } 617 else 618 { 619 close(sock); 620 return(0); 621 } 622} 623 624 625static void 626CleanupAliasData(void) 627{ 628 struct alias_link *link; 629 int i, icount; 630 631 icount = 0; 632 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 633 { 634 link = linkTableOut[i]; 635 linkTableOut[i] = NULL; 636 while (link != NULL) 637 { 638 struct alias_link *link_next; 639 link_next = link->next_out; 640 icount++; 641 DeleteLink(link); 642 link = link_next; 643 } 644 } 645 646 cleanupIndex =0; 647} 648 649 650static void 651IncrementalCleanup(void) 652{ 653 int icount; 654 struct alias_link *link; 655 656 icount = 0; 657 link = linkTableOut[cleanupIndex++]; 658 while (link != NULL) 659 { 660 int idelta; 661 struct alias_link *link_next; 662 663 link_next = link->next_out; 664 idelta = timeStamp - link->timestamp; 665 switch (link->link_type) 666 { 667 case LINK_ICMP: 668 case LINK_UDP: 669 case LINK_FRAGMENT_ID: 670 case LINK_FRAGMENT_PTR: 671 if (idelta > link->expire_time) 672 { 673 DeleteLink(link); 674 icount++; 675 } 676 break; 677 case LINK_TCP: 678 if (idelta > link->expire_time) 679 { 680 struct tcp_dat *tcp_aux; 681 682 tcp_aux = link->data.tcp; 683 if (tcp_aux->state.in != 1 684 || tcp_aux->state.out != 1) 685 { 686 DeleteLink(link); 687 icount++; 688 } 689 } 690 break; 691 } 692 link = link_next; 693 } 694 695 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 696 cleanupIndex = 0; 697} 698 699void 700DeleteLink(struct alias_link *link) 701{ 702 struct alias_link *link_last; 703 struct alias_link *link_next; 704 705/* Don't do anything if the link is marked permanent */ 706 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 707 return; 708 709/* Adjust output table pointers */ 710 link_last = link->last_out; 711 link_next = link->next_out; 712 713 if (link_last != NULL) 714 link_last->next_out = link_next; 715 else 716 linkTableOut[link->start_point_out] = link_next; 717 718 if (link_next != NULL) 719 link_next->last_out = link_last; 720 721/* Adjust input table pointers */ 722 link_last = link->last_in; 723 link_next = link->next_in; 724 725 if (link_last != NULL) 726 link_last->next_in = link_next; 727 else 728 linkTableIn[link->start_point_in] = link_next; 729 730 if (link_next != NULL) 731 link_next->last_in = link_last; 732 733/* Close socket, if one has been allocated */ 734 if (link->sockfd != -1) 735 { 736 sockCount--; 737 close(link->sockfd); 738 } 739 740/* Link-type dependent cleanup */ 741 switch(link->link_type) 742 { 743 case LINK_ICMP: 744 icmpLinkCount--; 745 break; 746 case LINK_UDP: 747 udpLinkCount--; 748 break; 749 case LINK_TCP: 750 tcpLinkCount--; 751 if (link->data.tcp != NULL) 752 free(link->data.tcp); 753 break; 754 case LINK_FRAGMENT_ID: 755 fragmentIdLinkCount--; 756 break; 757 case LINK_FRAGMENT_PTR: 758 fragmentPtrLinkCount--; 759 if (link->data.frag_ptr != NULL) 760 free(link->data.frag_ptr); 761 break; 762 } 763 764/* Free memory */ 765 free(link); 766 767/* Write statistics, if logging enabled */ 768 if (packetAliasMode & PKT_ALIAS_LOG) 769 { 770 ShowAliasStats(); 771 } 772} 773 774 775static struct alias_link * 776AddLink(struct in_addr src_addr, 777 struct in_addr dst_addr, 778 struct in_addr alias_addr, 779 u_short src_port, 780 u_short dst_port, 781 int alias_port_param, /* if less than zero, alias */ 782 int link_type) /* port will be automatically */ 783{ /* chosen. If greater than */ 784 u_int start_point; /* zero, equal to alias port */ 785 struct alias_link *link; 786 struct alias_link *first_link; 787 788 link = malloc(sizeof(struct alias_link)); 789 if (link != NULL) 790 { 791 /* If either the aliasing address or source address are 792 equal to the default device address (equal to the 793 global variable aliasAddress), then set the alias 794 address field of the link record to zero */ 795 796 if (src_addr.s_addr == aliasAddress.s_addr) 797 src_addr.s_addr = 0; 798 799 if (alias_addr.s_addr == aliasAddress.s_addr) 800 alias_addr.s_addr = 0; 801 802 /* Basic initialization */ 803 link->src_addr = src_addr; 804 link->dst_addr = dst_addr; 805 link->src_port = src_port; 806 link->alias_addr = alias_addr; 807 link->dst_port = dst_port; 808 link->link_type = link_type; 809 link->sockfd = -1; 810 link->flags = 0; 811 link->timestamp = timeStamp; 812 813 /* Expiration time */ 814 switch (link_type) 815 { 816 case LINK_ICMP: 817 link->expire_time = ICMP_EXPIRE_TIME; 818 break; 819 case LINK_UDP: 820 link->expire_time = UDP_EXPIRE_TIME; 821 break; 822 case LINK_TCP: 823 link->expire_time = TCP_EXPIRE_TIME; 824 break; 825 case LINK_FRAGMENT_ID: 826 link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 827 break; 828 case LINK_FRAGMENT_PTR: 829 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 830 break; 831 } 832 833 /* Determine alias flags */ 834 if (dst_addr.s_addr == 0) 835 link->flags |= LINK_UNKNOWN_DEST_ADDR; 836 if (dst_port == 0) 837 link->flags |= LINK_UNKNOWN_DEST_PORT; 838 839 /* Determine alias port */ 840 if (GetNewPort(link, alias_port_param) != 0) 841 { 842 free(link); 843 return(NULL); 844 } 845 846 /* Set up pointers for output lookup table */ 847 start_point = StartPointOut(src_addr, dst_addr, 848 src_port, dst_port, link_type); 849 first_link = linkTableOut[start_point]; 850 851 link->last_out = NULL; 852 link->next_out = first_link; 853 link->start_point_out = start_point; 854 855 if (first_link != NULL) 856 first_link->last_out = link; 857 858 linkTableOut[start_point] = link; 859 860 /* Set up pointers for input lookup table */ 861 start_point = StartPointIn(alias_addr, link->alias_port, link_type); 862 first_link = linkTableIn[start_point]; 863 864 link->last_in = NULL; 865 link->next_in = first_link; 866 link->start_point_in = start_point; 867 868 if (first_link != NULL) 869 first_link->last_in = link; 870 871 linkTableIn[start_point] = link; 872 873 /* Link-type dependent initialization */ 874 switch(link_type) 875 { 876 struct tcp_dat *aux_tcp; 877 878 case LINK_ICMP: 879 icmpLinkCount++; 880 break; 881 case LINK_UDP: 882 udpLinkCount++; 883 break; 884 case LINK_TCP: 885 aux_tcp = malloc(sizeof(struct tcp_dat)); 886 link->data.tcp = aux_tcp; 887 if (aux_tcp != NULL) 888 { 889 int i; 890 891 tcpLinkCount++; 892 aux_tcp->state.in = 0; 893 aux_tcp->state.out = 0; 894 aux_tcp->state.index = 0; 895 aux_tcp->state.ack_modified = 0; 896 for (i=0; i<N_LINK_TCP_DATA; i++) 897 aux_tcp->ack[i].active = 0; 898 } 899 else 900 { 901 fprintf(stderr, "PacketAlias/AddLink: "); 902 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 903 } 904 break; 905 case LINK_FRAGMENT_ID: 906 fragmentIdLinkCount++; 907 break; 908 case LINK_FRAGMENT_PTR: 909 fragmentPtrLinkCount++; 910 break; 911 } 912 } 913 else 914 { 915 fprintf(stderr, "PacketAlias/AddLink(): "); 916 fprintf(stderr, "malloc() call failed.\n"); 917 } 918 919 if (packetAliasMode & PKT_ALIAS_LOG) 920 { 921 ShowAliasStats(); 922 } 923 924 return(link); 925} 926 927 928static struct alias_link * 929FindLinkOut(struct in_addr src_addr, 930 struct in_addr dst_addr, 931 u_short src_port, 932 u_short dst_port, 933 int link_type) 934{ 935 u_int i; 936 struct alias_link *link; 937 938 if (src_addr.s_addr == aliasAddress.s_addr) 939 src_addr.s_addr = 0; 940 941 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 942 link = linkTableOut[i]; 943 while (link != NULL) 944 { 945 if (link->src_addr.s_addr == src_addr.s_addr 946 && link->dst_addr.s_addr == dst_addr.s_addr 947 && link->dst_port == dst_port 948 && link->src_port == src_port 949 && link->link_type == link_type) 950 { 951 link->timestamp = timeStamp; 952 break; 953 } 954 link = link->next_out; 955 } 956 957 return(link); 958} 959 960 961struct alias_link * 962FindLinkIn(struct in_addr dst_addr, 963 struct in_addr alias_addr, 964 u_short dst_port, 965 u_short alias_port, 966 int link_type, 967 int replace_partial_links) 968{ 969 int flags_in; 970 u_int start_point; 971 struct alias_link *link; 972 struct alias_link *link_fully_specified; 973 struct alias_link *link_unknown_all; 974 struct alias_link *link_unknown_dst_addr; 975 struct alias_link *link_unknown_dst_port; 976 977/* Initialize pointers */ 978 link_fully_specified = NULL; 979 link_unknown_all = NULL; 980 link_unknown_dst_addr = NULL; 981 link_unknown_dst_port = NULL; 982 983/* If either the dest addr or port is unknown, the search 984 loop will have to know about this. */ 985 986 flags_in = 0; 987 if (dst_addr.s_addr == 0) 988 flags_in |= LINK_UNKNOWN_DEST_ADDR; 989 if (dst_port == 0) 990 flags_in |= LINK_UNKNOWN_DEST_PORT; 991 992/* The following allows permanent links to be 993 be specified as using the default aliasing address 994 (i.e. device interface address) without knowing 995 in advance what that address is. */ 996 997 if (alias_addr.s_addr == aliasAddress.s_addr) 998 alias_addr.s_addr = 0; 999 1000/* Search loop */ 1001 start_point = StartPointIn(alias_addr, alias_port, link_type); 1002 link = linkTableIn[start_point]; 1003 while (link != NULL) 1004 { 1005 int flags; 1006 1007 flags = flags_in | link->flags; 1008 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1009 { 1010 if (link->alias_addr.s_addr == alias_addr.s_addr 1011 && link->alias_port == alias_port 1012 && link->dst_addr.s_addr == dst_addr.s_addr 1013 && link->dst_port == dst_port 1014 && link->link_type == link_type) 1015 { 1016 link_fully_specified = link; 1017 break; 1018 } 1019 } 1020 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1021 && (flags & LINK_UNKNOWN_DEST_PORT)) 1022 { 1023 if (link->alias_addr.s_addr == alias_addr.s_addr 1024 && link->alias_port == alias_port 1025 && link->link_type == link_type) 1026 { 1027 if (link_unknown_all == NULL) 1028 link_unknown_all = link; 1029 } 1030 } 1031 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1032 { 1033 if (link->alias_addr.s_addr == alias_addr.s_addr 1034 && link->alias_port == alias_port 1035 && link->link_type == link_type 1036 && link->dst_port == dst_port) 1037 { 1038 if (link_unknown_dst_addr == NULL) 1039 link_unknown_dst_addr = link; 1040 } 1041 } 1042 else if (flags & LINK_UNKNOWN_DEST_PORT) 1043 { 1044 if (link->alias_addr.s_addr == alias_addr.s_addr 1045 && link->alias_port == alias_port 1046 && link->link_type == link_type 1047 && link->dst_addr.s_addr == dst_addr.s_addr) 1048 { 1049 if (link_unknown_dst_port == NULL) 1050 link_unknown_dst_port = link; 1051 } 1052 } 1053 link = link->next_in; 1054 } 1055 1056 1057 1058 if (link_fully_specified != NULL) 1059 { 1060 return (link_fully_specified); 1061 } 1062 else if (link_unknown_dst_port != NULL) 1063 { 1064 if (replace_partial_links) 1065 { 1066 link = AddLink(link_unknown_dst_port->src_addr, dst_addr, 1067 alias_addr, 1068 link_unknown_dst_port->src_port, dst_port, 1069 alias_port, link_type); 1070 DeleteLink(link_unknown_dst_port); 1071 return(link); 1072 } 1073 else 1074 { 1075 return(link_unknown_dst_port); 1076 } 1077 } 1078 else if (link_unknown_dst_addr != NULL) 1079 { 1080 if (replace_partial_links) 1081 { 1082 link = AddLink(link_unknown_dst_addr->src_addr, dst_addr, 1083 alias_addr, 1084 link_unknown_dst_addr->src_port, dst_port, 1085 alias_port, link_type); 1086 DeleteLink(link_unknown_dst_addr); 1087 return(link); 1088 } 1089 else 1090 { 1091 return(link_unknown_dst_addr); 1092 } 1093 } 1094 else if (link_unknown_all != NULL) 1095 { 1096 if (replace_partial_links) 1097 { 1098 link = AddLink(link_unknown_all->src_addr, dst_addr, 1099 alias_addr, 1100 link_unknown_all->src_port, dst_port, 1101 alias_port, link_type); 1102 DeleteLink(link_unknown_all); 1103 return(link); 1104 } 1105 else 1106 { 1107 return(link_unknown_all); 1108 } 1109 } 1110 else 1111 { 1112 return(NULL); 1113 } 1114} 1115 1116 1117 1118 1119/* External routines for finding/adding links 1120 1121-- "external" means outside alias_db.c, but within alias*.c -- 1122 1123 FindIcmpIn(), FindIcmpOut() 1124 FindFragmentIn1(), FindFragmentIn2() 1125 AddFragmentPtrLink(), FindFragmentPtr() 1126 FindUdpTcpIn(), FindUdpTcpOut() 1127 FindOriginalAddress(), FindAliasAddress() 1128 1129(prototypes in alias_local.h) 1130*/ 1131 1132 1133struct alias_link * 1134FindIcmpIn(struct in_addr dst_addr, 1135 struct in_addr alias_addr, 1136 u_short id_alias) 1137{ 1138 return FindLinkIn(dst_addr, alias_addr, 1139 NO_DEST_PORT, id_alias, 1140 LINK_ICMP, 0); 1141} 1142 1143 1144struct alias_link * 1145FindIcmpOut(struct in_addr src_addr, 1146 struct in_addr dst_addr, 1147 u_short id) 1148{ 1149 struct alias_link * link; 1150 1151 link = FindLinkOut(src_addr, dst_addr, 1152 id, NO_DEST_PORT, 1153 LINK_ICMP); 1154 if (link == NULL) 1155 { 1156 struct in_addr alias_addr; 1157 1158 alias_addr = FindAliasAddress(src_addr); 1159 link = AddLink(src_addr, dst_addr, alias_addr, 1160 id, NO_DEST_PORT, GET_ALIAS_ID, 1161 LINK_ICMP); 1162 } 1163 1164 return(link); 1165} 1166 1167 1168struct alias_link * 1169FindFragmentIn1(struct in_addr dst_addr, 1170 struct in_addr alias_addr, 1171 u_short ip_id) 1172{ 1173 struct alias_link *link; 1174 1175 link = FindLinkIn(dst_addr, alias_addr, 1176 NO_DEST_PORT, ip_id, 1177 LINK_FRAGMENT_ID, 0); 1178 1179 if (link == NULL) 1180 { 1181 link = AddLink(nullAddress, dst_addr, alias_addr, 1182 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1183 LINK_FRAGMENT_ID); 1184 } 1185 1186 return(link); 1187} 1188 1189 1190struct alias_link * 1191FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1192 struct in_addr alias_addr, /* is not found. */ 1193 u_short ip_id) 1194{ 1195 return FindLinkIn(dst_addr, alias_addr, 1196 NO_DEST_PORT, ip_id, 1197 LINK_FRAGMENT_ID, 0); 1198} 1199 1200 1201struct alias_link * 1202AddFragmentPtrLink(struct in_addr dst_addr, 1203 u_short ip_id) 1204{ 1205 return AddLink(nullAddress, dst_addr, nullAddress, 1206 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1207 LINK_FRAGMENT_PTR); 1208} 1209 1210 1211struct alias_link * 1212FindFragmentPtr(struct in_addr dst_addr, 1213 u_short ip_id) 1214{ 1215 return FindLinkIn(dst_addr, nullAddress, 1216 NO_DEST_PORT, ip_id, 1217 LINK_FRAGMENT_PTR, 0); 1218} 1219 1220 1221struct alias_link * 1222FindUdpTcpIn(struct in_addr dst_addr, 1223 struct in_addr alias_addr, 1224 u_short dst_port, 1225 u_short alias_port, 1226 u_char proto) 1227{ 1228 int link_type; 1229 struct alias_link *link; 1230 1231 switch (proto) 1232 { 1233 case IPPROTO_UDP: 1234 link_type = LINK_UDP; 1235 break; 1236 case IPPROTO_TCP: 1237 link_type = LINK_TCP; 1238 break; 1239 default: 1240 return NULL; 1241 break; 1242 } 1243 1244 link = FindLinkIn(dst_addr, alias_addr, 1245 dst_port, alias_port, 1246 link_type, 1); 1247 1248 if ( !(packetAliasMode & PKT_ALIAS_DENY_INCOMING) && link == NULL) 1249 { 1250 struct in_addr target_addr; 1251 1252 target_addr = FindOriginalAddress(alias_addr); 1253 link = AddLink(target_addr, dst_addr, alias_addr, 1254 alias_port, dst_port, alias_port, 1255 link_type); 1256 } 1257 1258 return(link); 1259} 1260 1261 1262struct alias_link * 1263FindUdpTcpOut(struct in_addr src_addr, 1264 struct in_addr dst_addr, 1265 u_short src_port, 1266 u_short dst_port, 1267 u_char proto) 1268{ 1269 int link_type; 1270 struct alias_link *link; 1271 1272 switch (proto) 1273 { 1274 case IPPROTO_UDP: 1275 link_type = LINK_UDP; 1276 break; 1277 case IPPROTO_TCP: 1278 link_type = LINK_TCP; 1279 break; 1280 default: 1281 return NULL; 1282 break; 1283 } 1284 1285 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type); 1286 1287 if (link == NULL) 1288 { 1289 struct in_addr alias_addr; 1290 1291 alias_addr = FindAliasAddress(src_addr); 1292 link = AddLink(src_addr, dst_addr, alias_addr, 1293 src_port, dst_port, GET_ALIAS_PORT, 1294 link_type); 1295 } 1296 1297 return(link); 1298} 1299 1300 1301struct in_addr 1302FindOriginalAddress(struct in_addr alias_addr) 1303{ 1304 struct alias_link *link; 1305 1306 link = FindLinkIn(nullAddress, alias_addr, 1307 0, 0, LINK_ADDR, 0); 1308 if (link == NULL) 1309 { 1310 newDefaultLink = 1; 1311 if (targetAddress.s_addr != 0) 1312 return targetAddress; 1313 else 1314 return alias_addr; 1315 } 1316 else 1317 { 1318 if (link->src_addr.s_addr == 0) 1319 return aliasAddress; 1320 else 1321 return link->src_addr; 1322 } 1323} 1324 1325 1326struct in_addr 1327FindAliasAddress(struct in_addr original_addr) 1328{ 1329 struct alias_link *link; 1330 1331 link = FindLinkOut(original_addr, nullAddress, 1332 0, 0, LINK_ADDR); 1333 if (link == NULL) 1334 { 1335 return aliasAddress; 1336 } 1337 else 1338 { 1339 if (link->alias_addr.s_addr == 0) 1340 return aliasAddress; 1341 else 1342 return link->alias_addr; 1343 } 1344} 1345 1346 1347/* External routines for getting or changing link data 1348 (external to alias_db.c, but internal to alias*.c) 1349 1350 SetFragmentData(), GetFragmentData() 1351 SetFragmentPtr(), GetFragmentPtr() 1352 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1353 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1354 GetOriginalPort(), GetAliasPort() 1355 SetAckModified(), GetAckModified() 1356 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1357*/ 1358 1359 1360void 1361SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1362{ 1363 link->data.frag_addr = src_addr; 1364} 1365 1366 1367void 1368GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1369{ 1370 *src_addr = link->data.frag_addr; 1371} 1372 1373 1374void 1375SetFragmentPtr(struct alias_link *link, char *fptr) 1376{ 1377 link->data.frag_ptr = fptr; 1378} 1379 1380 1381void 1382GetFragmentPtr(struct alias_link *link, char **fptr) 1383{ 1384 *fptr = link->data.frag_ptr; 1385} 1386 1387 1388void 1389SetStateIn(struct alias_link *link, int state) 1390{ 1391 /* TCP input state */ 1392 (link->data.tcp)->state.in = state; 1393} 1394 1395 1396void 1397SetStateOut(struct alias_link *link, int state) 1398{ 1399 /* TCP output state */ 1400 (link->data.tcp)->state.out = state; 1401} 1402 1403 1404int 1405GetStateIn(struct alias_link *link) 1406{ 1407 /* TCP input state */ 1408 return( (link->data.tcp)->state.in); 1409} 1410 1411 1412int 1413GetStateOut(struct alias_link *link) 1414{ 1415 /* TCP output state */ 1416 return( (link->data.tcp)->state.out); 1417} 1418 1419 1420struct in_addr 1421GetOriginalAddress(struct alias_link *link) 1422{ 1423 if (link->src_addr.s_addr == 0) 1424 return aliasAddress; 1425 else 1426 return(link->src_addr); 1427} 1428 1429 1430struct in_addr 1431GetDestAddress(struct alias_link *link) 1432{ 1433 return(link->dst_addr); 1434} 1435 1436 1437struct in_addr 1438GetAliasAddress(struct alias_link *link) 1439{ 1440 if (link->alias_addr.s_addr == 0) 1441 return aliasAddress; 1442 else 1443 return link->alias_addr; 1444} 1445 1446 1447struct in_addr 1448GetDefaultAliasAddress() 1449{ 1450 return aliasAddress; 1451} 1452 1453 1454void 1455SetDefaultAliasAddress(struct in_addr alias_addr) 1456{ 1457 aliasAddress = alias_addr; 1458} 1459 1460 1461u_short 1462GetOriginalPort(struct alias_link *link) 1463{ 1464 return(link->src_port); 1465} 1466 1467 1468u_short 1469GetAliasPort(struct alias_link *link) 1470{ 1471 return(link->alias_port); 1472} 1473 1474 1475void 1476SetAckModified(struct alias_link *link) 1477{ 1478/* Indicate that ack numbers have been modified in a TCP connection */ 1479 (link->data.tcp)->state.ack_modified = 1; 1480} 1481 1482 1483int 1484GetAckModified(struct alias_link *link) 1485{ 1486/* See if ack numbers have been modified */ 1487 return( (link->data.tcp)->state.ack_modified ); 1488} 1489 1490 1491int 1492GetDeltaAckIn(struct ip *pip, struct alias_link *link) 1493{ 1494/* 1495Find out how much the ack number has been altered for an incoming 1496TCP packet. To do this, a circular list is ack numbers where the TCP 1497packet size was altered is searched. 1498*/ 1499 1500 int i; 1501 struct tcphdr *tc; 1502 int delta, ack_diff_min; 1503 u_long ack; 1504 1505 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1506 ack = tc->th_ack; 1507 1508 delta = 0; 1509 ack_diff_min = -1; 1510 for (i=0; i<N_LINK_TCP_DATA; i++) 1511 { 1512 struct ack_data_record x; 1513 1514 x = (link->data.tcp)->ack[i]; 1515 if (x.active == 1) 1516 { 1517 int ack_diff; 1518 1519 ack_diff = SeqDiff(x.ack_new, ack); 1520 if (ack_diff >= 0) 1521 { 1522 if (ack_diff_min >= 0) 1523 { 1524 if (ack_diff < ack_diff_min) 1525 { 1526 delta = x.delta; 1527 ack_diff_min = ack_diff; 1528 } 1529 } 1530 else 1531 { 1532 delta = x.delta; 1533 ack_diff_min = ack_diff; 1534 } 1535 } 1536 } 1537 } 1538 return (delta); 1539} 1540 1541 1542int 1543GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 1544{ 1545/* 1546Find out how much the seq number has been altered for an outgoing 1547TCP packet. To do this, a circular list is ack numbers where the TCP 1548packet size was altered is searched. 1549*/ 1550 1551 int i; 1552 struct tcphdr *tc; 1553 int delta, seq_diff_min; 1554 u_long seq; 1555 1556 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1557 seq = tc->th_seq; 1558 1559 delta = 0; 1560 seq_diff_min = -1; 1561 for (i=0; i<N_LINK_TCP_DATA; i++) 1562 { 1563 struct ack_data_record x; 1564 1565 x = (link->data.tcp)->ack[i]; 1566 if (x.active == 1) 1567 { 1568 int seq_diff; 1569 1570 seq_diff = SeqDiff(x.ack_old, seq); 1571 if (seq_diff >= 0) 1572 { 1573 if (seq_diff_min >= 0) 1574 { 1575 if (seq_diff < seq_diff_min) 1576 { 1577 delta = x.delta; 1578 seq_diff_min = seq_diff; 1579 } 1580 } 1581 else 1582 { 1583 delta = x.delta; 1584 seq_diff_min = seq_diff; 1585 } 1586 } 1587 } 1588 } 1589 return (delta); 1590} 1591 1592 1593void 1594AddSeq(struct ip *pip, struct alias_link *link, int delta) 1595{ 1596/* 1597When a TCP packet has been altered in length, save this 1598information in a circular list. If enough packets have 1599been altered, then this list will begin to overwrite itself. 1600*/ 1601 1602 struct tcphdr *tc; 1603 struct ack_data_record x; 1604 int hlen, tlen, dlen; 1605 int i; 1606 1607 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1608 1609 hlen = (pip->ip_hl + tc->th_off) << 2; 1610 tlen = ntohs(pip->ip_len); 1611 dlen = tlen - hlen; 1612 1613 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 1614 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 1615 x.delta = delta; 1616 x.active = 1; 1617 1618 i = (link->data.tcp)->state.index; 1619 (link->data.tcp)->ack[i] = x; 1620 1621 i++; 1622 if (i == N_LINK_TCP_DATA) 1623 (link->data.tcp)->state.index = 0; 1624 else 1625 (link->data.tcp)->state.index = i; 1626} 1627 1628void 1629SetExpire(struct alias_link *link, int expire) 1630{ 1631 if (expire == 0) 1632 { 1633 link->flags &= ~LINK_PERMANENT; 1634 DeleteLink(link); 1635 } 1636 else if (expire == -1) 1637 { 1638 link->flags |= LINK_PERMANENT; 1639 } 1640 else if (expire > 0) 1641 { 1642 link->expire_time = expire; 1643 } 1644 else 1645 { 1646 fprintf(stderr, "PacketAlias/SetExpire(): "); 1647 fprintf(stderr, "error in expire parameter\n"); 1648 } 1649} 1650 1651void 1652ClearCheckNewLink(void) 1653{ 1654 newDefaultLink = 0; 1655} 1656 1657 1658/* Miscellaneous Functions 1659 1660 HouseKeeping() 1661 InitPacketAliasLog() 1662 UninitPacketAliasLog() 1663*/ 1664 1665/* 1666 Whenever an outgoing or incoming packet is handled, HouseKeeping() 1667 is called to find and remove timed-out aliasing links. Logic exists 1668 to sweep through the entire table and linked list structure 1669 every 60 seconds. 1670 1671 (prototype in alias_local.h) 1672*/ 1673 1674void 1675HouseKeeping(void) 1676{ 1677 int i, n, n100; 1678 struct timeval tv; 1679 struct timezone tz; 1680 1681 /* 1682 * Save system time (seconds) in global variable timeStamp for 1683 * use by other functions. This is done so as not to unnecessarily 1684 * waste timeline by making system calls. 1685 */ 1686 gettimeofday(&tv, &tz); 1687 timeStamp = tv.tv_sec; 1688 1689 /* Compute number of spokes (output table link chains) to cover */ 1690 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 1691 n100 *= timeStamp - lastCleanupTime; 1692 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 1693 1694 n = n100/100; 1695 1696 /* Handle different cases */ 1697 if (n > ALIAS_CLEANUP_MAX_SPOKES) 1698 { 1699 n = ALIAS_CLEANUP_MAX_SPOKES; 1700 lastCleanupTime = timeStamp; 1701 houseKeepingResidual = 0; 1702 1703 for (i=0; i<n; i++) 1704 IncrementalCleanup(); 1705 } 1706 else if (n > 0) 1707 { 1708 lastCleanupTime = timeStamp; 1709 houseKeepingResidual = n100 - 100*n; 1710 1711 for (i=0; i<n; i++) 1712 IncrementalCleanup(); 1713 } 1714 else if (n < 0) 1715 { 1716 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 1717 fprintf(stderr, "something unexpected in time values\n"); 1718 lastCleanupTime = timeStamp; 1719 houseKeepingResidual = 0; 1720 } 1721} 1722 1723 1724/* Init the log file and enable logging */ 1725void 1726InitPacketAliasLog(void) 1727{ 1728 if ((~packetAliasMode & PKT_ALIAS_LOG) 1729 && (monitorFile = fopen("/var/log/alias.log", "w"))) 1730 { 1731 packetAliasMode |= PKT_ALIAS_LOG; 1732 fprintf(monitorFile, 1733 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 1734 } 1735} 1736 1737 1738/* Close the log-file and disable logging. */ 1739void 1740UninitPacketAliasLog(void) 1741{ 1742 if( monitorFile ) 1743 fclose(monitorFile); 1744 packetAliasMode &= ~PKT_ALIAS_LOG; 1745} 1746 1747 1748 1749 1750 1751 1752/* Outside world interfaces 1753 1754-- "outside world" means other than alias*.c routines -- 1755 1756 PacketAliasRedirectPort() 1757 PacketAliasRedirectAddr() 1758 PacketAliasRedirectDelete() 1759 PacketAliasSetAddress() 1760 PacketAliasInit() 1761 PacketAliasSetMode() 1762 1763(prototypes in alias.h) 1764*/ 1765 1766/* Redirection from a specific public addr:port to a 1767 a private addr:port */ 1768struct alias_link * 1769PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 1770 struct in_addr dst_addr, u_short dst_port, 1771 struct in_addr alias_addr, u_short alias_port, 1772 u_char proto) 1773{ 1774 int link_type; 1775 struct alias_link *link; 1776 1777 switch(proto) 1778 { 1779 case IPPROTO_UDP: 1780 link_type = LINK_UDP; 1781 break; 1782 case IPPROTO_TCP: 1783 link_type = LINK_TCP; 1784 break; 1785 default: 1786 fprintf(stderr, "PacketAliasRedirectPort(): "); 1787 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 1788 return NULL; 1789 } 1790 1791 link = AddLink(src_addr, dst_addr, alias_addr, 1792 src_port, dst_port, alias_port, 1793 link_type); 1794 1795 if (link != NULL) 1796 { 1797 link->flags |= LINK_PERMANENT; 1798 } 1799 else 1800 { 1801 fprintf(stderr, "PacketAliasRedirectPort(): " 1802 "call to AddLink() failed\n"); 1803 } 1804 1805 return link; 1806} 1807 1808 1809/* Static address translation */ 1810struct alias_link * 1811PacketAliasRedirectAddr(struct in_addr src_addr, 1812 struct in_addr alias_addr) 1813{ 1814 struct alias_link *link; 1815 1816 link = AddLink(src_addr, nullAddress, alias_addr, 1817 0, 0, 0, 1818 LINK_ADDR); 1819 1820 if (link != NULL) 1821 { 1822 link->flags |= LINK_PERMANENT; 1823 } 1824 else 1825 { 1826 fprintf(stderr, "PacketAliasRedirectAddr(): " 1827 "call to AddLink() failed\n"); 1828 } 1829 1830 return link; 1831} 1832 1833 1834void 1835PacketAliasRedirectDelete(struct alias_link *link) 1836{ 1837/* This is a dangerous function to put in the API, 1838 because an invalid pointer can crash the program. */ 1839 1840 deleteAllLinks = 1; 1841 DeleteLink(link); 1842 deleteAllLinks = 0; 1843} 1844 1845 1846void 1847PacketAliasSetAddress(struct in_addr addr) 1848{ 1849 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 1850 && aliasAddress.s_addr != addr.s_addr) 1851 { 1852 CleanupAliasData(); 1853 aliasAddress = addr; 1854 } 1855} 1856 1857 1858void 1859PacketAliasSetTarget(struct in_addr target_addr) 1860{ 1861 targetAddress = target_addr; 1862} 1863 1864 1865void 1866PacketAliasInit(void) 1867{ 1868 int i; 1869 struct timeval tv; 1870 struct timezone tz; 1871 1872 if (firstCall == 1) 1873 { 1874 gettimeofday(&tv, &tz); 1875 timeStamp = tv.tv_sec; 1876 lastCleanupTime = tv.tv_sec; 1877 houseKeepingResidual = 0; 1878 1879 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 1880 linkTableOut[i] = NULL; 1881 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 1882 linkTableIn[i] = NULL; 1883 1884 firstCall = 0; 1885 } 1886 else 1887 { 1888 deleteAllLinks = 1; 1889 CleanupAliasData(); 1890 deleteAllLinks = 0; 1891 } 1892 1893 aliasAddress.s_addr = 0; 1894 targetAddress.s_addr = 0; 1895 1896 icmpLinkCount = 0; 1897 udpLinkCount = 0; 1898 tcpLinkCount = 0; 1899 fragmentIdLinkCount = 0; 1900 fragmentPtrLinkCount = 0; 1901 sockCount = 0; 1902 1903 cleanupIndex =0; 1904 1905 packetAliasMode = PKT_ALIAS_SAME_PORTS 1906 | PKT_ALIAS_USE_SOCKETS 1907 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 1908} 1909 1910 1911/* Change mode for some operations */ 1912unsigned int 1913PacketAliasSetMode 1914( 1915 unsigned int flags, /* Which state to bring flags to */ 1916 unsigned int mask /* Mask of which flags to affect (use 0 to do a 1917 probe for flag values) */ 1918) 1919{ 1920/* Enable logging? */ 1921 if (flags & mask & PKT_ALIAS_LOG) 1922 { 1923 InitPacketAliasLog(); /* Do the enable */ 1924 } 1925/* _Disable_ logging? */ 1926 if (~flags & mask & PKT_ALIAS_LOG) { 1927 UninitPacketAliasLog(); 1928 } 1929 1930/* Other flags can be set/cleared without special action */ 1931 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 1932 return packetAliasMode; 1933} 1934 1935 1936int 1937PacketAliasCheckNewLink(void) 1938{ 1939 return newDefaultLink; 1940} 1941