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 186 struct 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 194 struct 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 */ 205 struct tcp_dat 206 { 207 struct tcp_state state; 208 struct ack_data_record ack[N_LINK_TCP_DATA]; 209 }; 210 211 struct 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 struct in_addr frag_addr; 253 char *frag_ptr; 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 269 int packetAliasMode; /* Mode flags */ 270 /* - documented in alias.h */ 271 272 static struct in_addr aliasAddress; /* Address written onto source */ 273 /* field of IP packet. */ 274 275 static struct in_addr targetAddress; /* IP address incoming packets */ 276 /* are sent to if no aliasing */ 277 /* link already exists */ 278 279 static struct in_addr nullAddress; /* Used as a dummy parameter for */ 280 /* some function calls */ 281 static struct alias_link * 282 linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ 283 /* chains of link records. Each */ 284 static struct alias_link * /* link record is doubly indexed */ 285 linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ 286 /* tables. */ 287 288 static int icmpLinkCount; /* Link statistics */ 289 static int udpLinkCount; 290 static int tcpLinkCount; 291 static int fragmentIdLinkCount; 292 static int fragmentPtrLinkCount; 293 static int sockCount; 294 295 static int cleanupIndex; /* Index to chain of link table */ 296 /* being inspected for old links */ 297 298 static int timeStamp; /* System time in seconds for */ 299 /* current packet */ 300 301 static int lastCleanupTime; /* Last time IncrementalCleanup() */ 302 /* was called */ 303 304 static int houseKeepingResidual; /* used by HouseKeeping() */ 305 306 static int deleteAllLinks; /* If equal to zero, DeleteLink() */ 307 /* will not remove permanent links */ 308 309 static FILE *monitorFile; /* File descriptor for link */ 310 /* statistics monitoring file */ 311 312 static int firstCall = 1; /* Needed by InitAlias() */ 313 314 static 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 325 Lookup 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 331 Miscellaneous: 332 SeqDiff() -- difference between two TCP sequences 333 ShowAliasStats() -- send alias statistics to a monitor file 334 */ 335 336 337 /* Local prototypes */ 338 static u_int StartPointIn(struct in_addr, u_short, int); 339 340 static u_int StartPointOut(struct in_addr, struct in_addr, 341 u_short, u_short, int); 342 343 static int SeqDiff(u_long, u_long); 344 345 static void ShowAliasStats(void); 346 347 348 static u_int 349 StartPointIn(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 362 static u_int 363 StartPointOut(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 378 static int 379 SeqDiff(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 392 static void 393 ShowAliasStats(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 423 Port Allocation: 424 GetNewPort() -- find and reserve new alias port number 425 GetSocket() -- try to allocate a socket for a given port 426 427 Link 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 433 Link search: 434 FindLinkOut() - find link for outgoing packets 435 FindLinkIn() - find link for incoming packets 436 */ 437 438 /* Local prototypes */ 439 static int GetNewPort(struct alias_link *, int); 440 441 static u_short GetSocket(u_short, int *, int); 442 443 static void CleanupAliasData(void); 444 445 static void IncrementalCleanup(void); 446 447 static void DeleteLink(struct alias_link *); 448 449 static struct alias_link * 450 AddLink(struct in_addr, struct in_addr, struct in_addr, 451 u_short, u_short, int, int); 452 453 static struct alias_link * 454 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int); 455 456 static struct alias_link * 457 FindLinkIn(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 472 static int 473 GetNewPort(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 579 static u_short 580 GetSocket(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 return(0); 620 } 621 } 622 623 624 static void 625 CleanupAliasData(void) 626 { 627 struct alias_link *link; 628 int i, icount; 629 630 icount = 0; 631 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 632 { 633 link = linkTableOut[i]; 634 linkTableOut[i] = NULL; 635 while (link != NULL) 636 { 637 struct alias_link *link_next; 638 link_next = link->next_out; 639 icount++; 640 DeleteLink(link); 641 link = link_next; 642 } 643 } 644 645 cleanupIndex =0; 646 } 647 648 649 static void 650 IncrementalCleanup(void) 651 { 652 int icount; 653 struct alias_link *link; 654 655 icount = 0; 656 link = linkTableOut[cleanupIndex++]; 657 while (link != NULL) 658 { 659 int idelta; 660 struct alias_link *link_next; 661 662 link_next = link->next_out; 663 idelta = timeStamp - link->timestamp; 664 switch (link->link_type) 665 { 666 case LINK_ICMP: 667 case LINK_UDP: 668 case LINK_FRAGMENT_ID: 669 case LINK_FRAGMENT_PTR: 670 if (idelta > link->expire_time) 671 { 672 DeleteLink(link); 673 icount++; 674 } 675 break; 676 case LINK_TCP: 677 if (idelta > link->expire_time) 678 { 679 struct tcp_dat *tcp_aux; 680 681 tcp_aux = link->data.tcp; 682 if (tcp_aux->state.in != 1 683 || tcp_aux->state.out != 1) 684 { 685 DeleteLink(link); 686 icount++; 687 } 688 } 689 break; 690 } 691 link = link_next; 692 } 693 694 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 695 cleanupIndex = 0; 696 } 697 698 void 699 DeleteLink(struct alias_link *link) 700 { 701 struct alias_link *link_last; 702 struct alias_link *link_next; 703 704 /* Don't do anything if the link is marked permanent */ 705 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 706 return; 707 708 /* Adjust output table pointers */ 709 link_last = link->last_out; 710 link_next = link->next_out; 711 712 if (link_last != NULL) 713 link_last->next_out = link_next; 714 else 715 linkTableOut[link->start_point_out] = link_next; 716 717 if (link_next != NULL) 718 link_next->last_out = link_last; 719 720 /* Adjust input table pointers */ 721 link_last = link->last_in; 722 link_next = link->next_in; 723 724 if (link_last != NULL) 725 link_last->next_in = link_next; 726 else 727 linkTableIn[link->start_point_in] = link_next; 728 729 if (link_next != NULL) 730 link_next->last_in = link_last; 731 732 /* Close socket, if one has been allocated */ 733 if (link->sockfd != -1) 734 { 735 sockCount--; 736 close(link->sockfd); 737 } 738 739 /* Link-type dependent cleanup */ 740 switch(link->link_type) 741 { 742 case LINK_ICMP: 743 icmpLinkCount--; 744 break; 745 case LINK_UDP: 746 udpLinkCount--; 747 break; 748 case LINK_TCP: 749 tcpLinkCount--; 750 if (link->data.tcp != NULL) 751 free(link->data.tcp); 752 break; 753 case LINK_FRAGMENT_ID: 754 fragmentIdLinkCount--; 755 break; 756 case LINK_FRAGMENT_PTR: 757 fragmentPtrLinkCount--; 758 break; 759 } 760 761 /* Free memory */ 762 free(link); 763 764 /* Write statistics, if logging enabled */ 765 if (packetAliasMode & PKT_ALIAS_LOG) 766 { 767 ShowAliasStats(); 768 } 769 } 770 771 772 static struct alias_link * 773 AddLink(struct in_addr src_addr, 774 struct in_addr dst_addr, 775 struct in_addr alias_addr, 776 u_short src_port, 777 u_short dst_port, 778 int alias_port_param, /* if less than zero, alias */ 779 int link_type) /* port will be automatically */ 780 { /* chosen. If greater than */ 781 u_int start_point; /* zero, equal to alias port */ 782 struct alias_link *link; 783 struct alias_link *first_link; 784 785 link = malloc(sizeof(struct alias_link)); 786 if (link != NULL) 787 { 788 /* If either the aliasing address or source address are 789 equal to the default device address (equal to the 790 global variable aliasAddress), then set the alias 791 address field of the link record to zero */ 792 793 if (src_addr.s_addr == aliasAddress.s_addr) 794 src_addr.s_addr = 0; 795 796 if (alias_addr.s_addr == aliasAddress.s_addr) 797 alias_addr.s_addr = 0; 798 799 /* Basic initialization */ 800 link->src_addr = src_addr; 801 link->dst_addr = dst_addr; 802 link->src_port = src_port; 803 link->alias_addr = alias_addr; 804 link->dst_port = dst_port; 805 link->link_type = link_type; 806 link->sockfd = -1; 807 link->flags = 0; 808 link->timestamp = timeStamp; 809 810 /* Expiration time */ 811 switch (link_type) 812 { 813 case LINK_ICMP: 814 link->expire_time = ICMP_EXPIRE_TIME; 815 break; 816 case LINK_UDP: 817 link->expire_time = UDP_EXPIRE_TIME; 818 break; 819 case LINK_TCP: 820 link->expire_time = TCP_EXPIRE_TIME; 821 break; 822 case LINK_FRAGMENT_ID: 823 link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 824 break; 825 case LINK_FRAGMENT_PTR: 826 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 827 break; 828 } 829 830 /* Determine alias flags */ 831 if (dst_addr.s_addr == 0) 832 link->flags |= LINK_UNKNOWN_DEST_ADDR; 833 if (dst_port == 0) 834 link->flags |= LINK_UNKNOWN_DEST_PORT; 835 836 /* Determine alias port */ 837 if (GetNewPort(link, alias_port_param) != 0) 838 { 839 free(link); 840 return(NULL); 841 } 842 843 /* Set up pointers for output lookup table */ 844 start_point = StartPointOut(src_addr, dst_addr, 845 src_port, dst_port, link_type); 846 first_link = linkTableOut[start_point]; 847 848 link->last_out = NULL; 849 link->next_out = first_link; 850 link->start_point_out = start_point; 851 852 if (first_link != NULL) 853 first_link->last_out = link; 854 855 linkTableOut[start_point] = link; 856 857 /* Set up pointers for input lookup table */ 858 start_point = StartPointIn(alias_addr, link->alias_port, link_type); 859 first_link = linkTableIn[start_point]; 860 861 link->last_in = NULL; 862 link->next_in = first_link; 863 link->start_point_in = start_point; 864 865 if (first_link != NULL) 866 first_link->last_in = link; 867 868 linkTableIn[start_point] = link; 869 870 /* Link-type dependent initialization */ 871 switch(link_type) 872 { 873 struct tcp_dat *aux_tcp; 874 875 case LINK_ICMP: 876 icmpLinkCount++; 877 break; 878 case LINK_UDP: 879 udpLinkCount++; 880 break; 881 case LINK_TCP: 882 aux_tcp = malloc(sizeof(struct tcp_dat)); 883 link->data.tcp = aux_tcp; 884 if (aux_tcp != NULL) 885 { 886 int i; 887 888 tcpLinkCount++; 889 aux_tcp->state.in = 0; 890 aux_tcp->state.out = 0; 891 aux_tcp->state.index = 0; 892 aux_tcp->state.ack_modified = 0; 893 for (i=0; i<N_LINK_TCP_DATA; i++) 894 aux_tcp->ack[i].active = 0; 895 } 896 else 897 { 898 fprintf(stderr, "PacketAlias/AddLink: "); 899 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 900 } 901 break; 902 case LINK_FRAGMENT_ID: 903 fragmentIdLinkCount++; 904 break; 905 case LINK_FRAGMENT_PTR: 906 fragmentPtrLinkCount++; 907 break; 908 } 909 } 910 else 911 { 912 fprintf(stderr, "PacketAlias/AddLink(): "); 913 fprintf(stderr, "malloc() call failed.\n"); 914 } 915 916 if (packetAliasMode & PKT_ALIAS_LOG) 917 { 918 ShowAliasStats(); 919 } 920 921 return(link); 922 } 923 924 925 static struct alias_link * 926 FindLinkOut(struct in_addr src_addr, 927 struct in_addr dst_addr, 928 u_short src_port, 929 u_short dst_port, 930 int link_type) 931 { 932 u_int i; 933 struct alias_link *link; 934 935 if (src_addr.s_addr == aliasAddress.s_addr) 936 src_addr.s_addr = 0; 937 938 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 939 link = linkTableOut[i]; 940 while (link != NULL) 941 { 942 if (link->src_addr.s_addr == src_addr.s_addr 943 && link->dst_addr.s_addr == dst_addr.s_addr 944 && link->dst_port == dst_port 945 && link->src_port == src_port 946 && link->link_type == link_type) 947 { 948 link->timestamp = timeStamp; 949 break; 950 } 951 link = link->next_out; 952 } 953 954 return(link); 955 } 956 957 958 struct alias_link * 959 FindLinkIn(struct in_addr dst_addr, 960 struct in_addr alias_addr, 961 u_short dst_port, 962 u_short alias_port, 963 int link_type, 964 int replace_partial_links) 965 { 966 int flags_in; 967 u_int start_point; 968 struct alias_link *link; 969 struct alias_link *link_fully_specified; 970 struct alias_link *link_unknown_all; 971 struct alias_link *link_unknown_dst_addr; 972 struct alias_link *link_unknown_dst_port; 973 974 /* Initialize pointers */ 975 link_fully_specified = NULL; 976 link_unknown_all = NULL; 977 link_unknown_dst_addr = NULL; 978 link_unknown_dst_port = NULL; 979 980 /* If either the dest addr or port is unknown, the search 981 loop will have to know about this. */ 982 983 flags_in = 0; 984 if (dst_addr.s_addr == 0) 985 flags_in |= LINK_UNKNOWN_DEST_ADDR; 986 if (dst_port == 0) 987 flags_in |= LINK_UNKNOWN_DEST_PORT; 988 989 /* The following allows permanent links to be 990 be specified as using the default aliasing address 991 (i.e. device interface address) without knowing 992 in advance what that address is. */ 993 994 if (alias_addr.s_addr == aliasAddress.s_addr) 995 alias_addr.s_addr = 0; 996 997 /* Search loop */ 998 start_point = StartPointIn(alias_addr, alias_port, link_type); 999 link = linkTableIn[start_point]; 1000 while (link != NULL) 1001 { 1002 int flags; 1003 1004 flags = flags_in | link->flags; 1005 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1006 { 1007 if (link->alias_addr.s_addr == alias_addr.s_addr 1008 && link->alias_port == alias_port 1009 && link->dst_addr.s_addr == dst_addr.s_addr 1010 && link->dst_port == dst_port 1011 && link->link_type == link_type) 1012 { 1013 link_fully_specified = link; 1014 break; 1015 } 1016 } 1017 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1018 && (flags & LINK_UNKNOWN_DEST_PORT)) 1019 { 1020 if (link->alias_addr.s_addr == alias_addr.s_addr 1021 && link->alias_port == alias_port 1022 && link->link_type == link_type) 1023 { 1024 if (link_unknown_all == NULL) 1025 link_unknown_all = link; 1026 } 1027 } 1028 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1029 { 1030 if (link->alias_addr.s_addr == alias_addr.s_addr 1031 && link->alias_port == alias_port 1032 && link->link_type == link_type 1033 && link->dst_port == dst_port) 1034 { 1035 if (link_unknown_dst_addr == NULL) 1036 link_unknown_dst_addr = link; 1037 } 1038 } 1039 else if (flags & LINK_UNKNOWN_DEST_PORT) 1040 { 1041 if (link->alias_addr.s_addr == alias_addr.s_addr 1042 && link->alias_port == alias_port 1043 && link->link_type == link_type 1044 && link->dst_addr.s_addr == dst_addr.s_addr) 1045 { 1046 if (link_unknown_dst_port == NULL) 1047 link_unknown_dst_port = link; 1048 } 1049 } 1050 link = link->next_in; 1051 } 1052 1053 1054 1055 if (link_fully_specified != NULL) 1056 { 1057 return (link_fully_specified); 1058 } 1059 else if (link_unknown_dst_port != NULL) 1060 { 1061 if (replace_partial_links) 1062 { 1063 link = AddLink(link_unknown_dst_port->src_addr, dst_addr, 1064 alias_addr, 1065 link_unknown_dst_port->src_port, dst_port, 1066 alias_port, link_type); 1067 DeleteLink(link_unknown_dst_port); 1068 return(link); 1069 } 1070 else 1071 { 1072 return(link_unknown_dst_port); 1073 } 1074 } 1075 else if (link_unknown_dst_addr != NULL) 1076 { 1077 if (replace_partial_links) 1078 { 1079 link = AddLink(link_unknown_dst_addr->src_addr, dst_addr, 1080 alias_addr, 1081 link_unknown_dst_addr->src_port, dst_port, 1082 alias_port, link_type); 1083 DeleteLink(link_unknown_dst_addr); 1084 return(link); 1085 } 1086 else 1087 { 1088 return(link_unknown_dst_addr); 1089 } 1090 } 1091 else if (link_unknown_all != NULL) 1092 { 1093 if (replace_partial_links) 1094 { 1095 link = AddLink(link_unknown_all->src_addr, dst_addr, 1096 alias_addr, 1097 link_unknown_all->src_port, dst_port, 1098 alias_port, link_type); 1099 DeleteLink(link_unknown_all); 1100 return(link); 1101 } 1102 else 1103 { 1104 return(link_unknown_all); 1105 } 1106 } 1107 else 1108 { 1109 return(NULL); 1110 } 1111 } 1112 1113 1114 1115 1116 /* External routines for finding/adding links 1117 1118 -- "external" means outside alias_db.c, but within alias*.c -- 1119 1120 FindIcmpIn(), FindIcmpOut() 1121 FindFragmentIn1(), FindFragmentIn2() 1122 AddFragmentPtrLink(), FindFragmentPtr() 1123 FindUdpTcpIn(), FindUdpTcpOut() 1124 FindOriginalAddress(), FindAliasAddress() 1125 1126 (prototypes in alias_local.h) 1127 */ 1128 1129 1130 struct alias_link * 1131 FindIcmpIn(struct in_addr dst_addr, 1132 struct in_addr alias_addr, 1133 u_short id_alias) 1134 { 1135 return FindLinkIn(dst_addr, alias_addr, 1136 NO_DEST_PORT, id_alias, 1137 LINK_ICMP, 0); 1138 } 1139 1140 1141 struct alias_link * 1142 FindIcmpOut(struct in_addr src_addr, 1143 struct in_addr dst_addr, 1144 u_short id) 1145 { 1146 struct alias_link * link; 1147 1148 link = FindLinkOut(src_addr, dst_addr, 1149 id, NO_DEST_PORT, 1150 LINK_ICMP); 1151 if (link == NULL) 1152 { 1153 struct in_addr alias_addr; 1154 1155 alias_addr = FindAliasAddress(src_addr); 1156 link = AddLink(src_addr, dst_addr, alias_addr, 1157 id, NO_DEST_PORT, GET_ALIAS_ID, 1158 LINK_ICMP); 1159 } 1160 1161 return(link); 1162 } 1163 1164 1165 struct alias_link * 1166 FindFragmentIn1(struct in_addr dst_addr, 1167 struct in_addr alias_addr, 1168 u_short ip_id) 1169 { 1170 struct alias_link *link; 1171 1172 link = FindLinkIn(dst_addr, alias_addr, 1173 NO_DEST_PORT, ip_id, 1174 LINK_FRAGMENT_ID, 0); 1175 1176 if (link == NULL) 1177 { 1178 link = AddLink(nullAddress, dst_addr, alias_addr, 1179 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1180 LINK_FRAGMENT_ID); 1181 } 1182 1183 return(link); 1184 } 1185 1186 1187 struct alias_link * 1188 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1189 struct in_addr alias_addr, /* is not found. */ 1190 u_short ip_id) 1191 { 1192 return FindLinkIn(dst_addr, alias_addr, 1193 NO_DEST_PORT, ip_id, 1194 LINK_FRAGMENT_ID, 0); 1195 } 1196 1197 1198 struct alias_link * 1199 AddFragmentPtrLink(struct in_addr dst_addr, 1200 u_short ip_id) 1201 { 1202 return AddLink(nullAddress, dst_addr, nullAddress, 1203 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1204 LINK_FRAGMENT_PTR); 1205 } 1206 1207 1208 struct alias_link * 1209 FindFragmentPtr(struct in_addr dst_addr, 1210 u_short ip_id) 1211 { 1212 return FindLinkIn(dst_addr, nullAddress, 1213 NO_DEST_PORT, ip_id, 1214 LINK_FRAGMENT_PTR, 0); 1215 } 1216 1217 1218 struct alias_link * 1219 FindUdpTcpIn(struct in_addr dst_addr, 1220 struct in_addr alias_addr, 1221 u_short dst_port, 1222 u_short alias_port, 1223 u_char proto) 1224 { 1225 int link_type; 1226 struct alias_link *link; 1227 1228 switch (proto) 1229 { 1230 case IPPROTO_UDP: 1231 link_type = LINK_UDP; 1232 break; 1233 case IPPROTO_TCP: 1234 link_type = LINK_TCP; 1235 break; 1236 default: 1237 return NULL; 1238 break; 1239 } 1240 1241 link = FindLinkIn(dst_addr, alias_addr, 1242 dst_port, alias_port, 1243 link_type, 1); 1244 1245 if ( !(packetAliasMode & PKT_ALIAS_DENY_INCOMING) && link == NULL) 1246 { 1247 struct in_addr target_addr; 1248 1249 target_addr = FindOriginalAddress(alias_addr); 1250 link = AddLink(target_addr, dst_addr, alias_addr, 1251 alias_port, dst_port, alias_port, 1252 link_type); 1253 } 1254 1255 return(link); 1256 } 1257 1258 1259 struct alias_link * 1260 FindUdpTcpOut(struct in_addr src_addr, 1261 struct in_addr dst_addr, 1262 u_short src_port, 1263 u_short dst_port, 1264 u_char proto) 1265 { 1266 int link_type; 1267 struct alias_link *link; 1268 1269 switch (proto) 1270 { 1271 case IPPROTO_UDP: 1272 link_type = LINK_UDP; 1273 break; 1274 case IPPROTO_TCP: 1275 link_type = LINK_TCP; 1276 break; 1277 default: 1278 return NULL; 1279 break; 1280 } 1281 1282 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type); 1283 1284 if (link == NULL) 1285 { 1286 struct in_addr alias_addr; 1287 1288 alias_addr = FindAliasAddress(src_addr); 1289 link = AddLink(src_addr, dst_addr, alias_addr, 1290 src_port, dst_port, GET_ALIAS_PORT, 1291 link_type); 1292 } 1293 1294 return(link); 1295 } 1296 1297 1298 struct in_addr 1299 FindOriginalAddress(struct in_addr alias_addr) 1300 { 1301 struct alias_link *link; 1302 1303 link = FindLinkIn(nullAddress, alias_addr, 1304 0, 0, LINK_ADDR, 0); 1305 if (link == NULL) 1306 { 1307 newDefaultLink = 1; 1308 if (targetAddress.s_addr != 0) 1309 return targetAddress; 1310 else 1311 return alias_addr; 1312 } 1313 else 1314 { 1315 if (link->src_addr.s_addr == 0) 1316 return aliasAddress; 1317 else 1318 return link->src_addr; 1319 } 1320 } 1321 1322 1323 struct in_addr 1324 FindAliasAddress(struct in_addr original_addr) 1325 { 1326 struct alias_link *link; 1327 1328 link = FindLinkOut(original_addr, nullAddress, 1329 0, 0, LINK_ADDR); 1330 if (link == NULL) 1331 { 1332 return aliasAddress; 1333 } 1334 else 1335 { 1336 if (link->alias_addr.s_addr == 0) 1337 return aliasAddress; 1338 else 1339 return link->alias_addr; 1340 } 1341 } 1342 1343 1344 /* External routines for getting or changing link data 1345 (external to alias_db.c, but internal to alias*.c) 1346 1347 SetFragmentData(), GetFragmentData() 1348 SetFragmentPtr(), GetFragmentPtr() 1349 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1350 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1351 GetOriginalPort(), GetAliasPort() 1352 SetAckModified(), GetAckModified() 1353 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1354 ClearNewLink() 1355 CheckNewLink() 1356 */ 1357 1358 1359 void 1360 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1361 { 1362 link->data.frag_addr = src_addr; 1363 } 1364 1365 1366 void 1367 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1368 { 1369 *src_addr = link->data.frag_addr; 1370 } 1371 1372 1373 void 1374 SetFragmentPtr(struct alias_link *link, char *fptr) 1375 { 1376 link->data.frag_ptr = fptr; 1377 } 1378 1379 1380 void 1381 GetFragmentPtr(struct alias_link *link, char **fptr) 1382 { 1383 *fptr = link->data.frag_ptr; 1384 } 1385 1386 1387 void 1388 SetStateIn(struct alias_link *link, int state) 1389 { 1390 /* TCP input state */ 1391 (link->data.tcp)->state.in = state; 1392 } 1393 1394 1395 void 1396 SetStateOut(struct alias_link *link, int state) 1397 { 1398 /* TCP output state */ 1399 (link->data.tcp)->state.out = state; 1400 } 1401 1402 1403 int 1404 GetStateIn(struct alias_link *link) 1405 { 1406 /* TCP input state */ 1407 return( (link->data.tcp)->state.in); 1408 } 1409 1410 1411 int 1412 GetStateOut(struct alias_link *link) 1413 { 1414 /* TCP output state */ 1415 return( (link->data.tcp)->state.out); 1416 } 1417 1418 1419 struct in_addr 1420 GetOriginalAddress(struct alias_link *link) 1421 { 1422 if (link->src_addr.s_addr == 0) 1423 return aliasAddress; 1424 else 1425 return(link->src_addr); 1426 } 1427 1428 1429 struct in_addr 1430 GetDestAddress(struct alias_link *link) 1431 { 1432 return(link->dst_addr); 1433 } 1434 1435 1436 struct in_addr 1437 GetAliasAddress(struct alias_link *link) 1438 { 1439 if (link->alias_addr.s_addr == 0) 1440 return aliasAddress; 1441 else 1442 return link->alias_addr; 1443 } 1444 1445 1446 struct in_addr 1447 GetDefaultAliasAddress() 1448 { 1449 return aliasAddress; 1450 } 1451 1452 1453 void 1454 SetDefaultAliasAddress(struct in_addr alias_addr) 1455 { 1456 aliasAddress = alias_addr; 1457 } 1458 1459 1460 void 1461 SetDefaultTargetAddress(struct in_addr target_addr) 1462 { 1463 targetAddress = target_addr; 1464 } 1465 1466 1467 void ClearDefaultTargetAddress(void) 1468 { 1469 targetAddress.s_addr = 0; 1470 } 1471 1472 1473 u_short 1474 GetOriginalPort(struct alias_link *link) 1475 { 1476 return(link->src_port); 1477 } 1478 1479 1480 u_short 1481 GetAliasPort(struct alias_link *link) 1482 { 1483 return(link->alias_port); 1484 } 1485 1486 1487 void 1488 SetAckModified(struct alias_link *link) 1489 { 1490 /* Indicate that ack numbers have been modified in a TCP connection */ 1491 (link->data.tcp)->state.ack_modified = 1; 1492 } 1493 1494 1495 int 1496 GetAckModified(struct alias_link *link) 1497 { 1498 /* See if ack numbers have been modified */ 1499 return( (link->data.tcp)->state.ack_modified ); 1500 } 1501 1502 1503 int 1504 GetDeltaAckIn(struct ip *pip, struct alias_link *link) 1505 { 1506 /* 1507 Find out how much the ack number has been altered for an incoming 1508 TCP packet. To do this, a circular list is ack numbers where the TCP 1509 packet size was altered is searched. 1510 */ 1511 1512 int i; 1513 struct tcphdr *tc; 1514 int delta, ack_diff_min; 1515 u_long ack; 1516 1517 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1518 ack = tc->th_ack; 1519 1520 delta = 0; 1521 ack_diff_min = -1; 1522 for (i=0; i<N_LINK_TCP_DATA; i++) 1523 { 1524 struct ack_data_record x; 1525 1526 x = (link->data.tcp)->ack[i]; 1527 if (x.active == 1) 1528 { 1529 int ack_diff; 1530 1531 ack_diff = SeqDiff(x.ack_new, ack); 1532 if (ack_diff >= 0) 1533 { 1534 if (ack_diff_min >= 0) 1535 { 1536 if (ack_diff < ack_diff_min) 1537 { 1538 delta = x.delta; 1539 ack_diff_min = ack_diff; 1540 } 1541 } 1542 else 1543 { 1544 delta = x.delta; 1545 ack_diff_min = ack_diff; 1546 } 1547 } 1548 } 1549 } 1550 return (delta); 1551 } 1552 1553 1554 int 1555 GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 1556 { 1557 /* 1558 Find out how much the seq number has been altered for an outgoing 1559 TCP packet. To do this, a circular list is ack numbers where the TCP 1560 packet size was altered is searched. 1561 */ 1562 1563 int i; 1564 struct tcphdr *tc; 1565 int delta, seq_diff_min; 1566 u_long seq; 1567 1568 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1569 seq = tc->th_seq; 1570 1571 delta = 0; 1572 seq_diff_min = -1; 1573 for (i=0; i<N_LINK_TCP_DATA; i++) 1574 { 1575 struct ack_data_record x; 1576 1577 x = (link->data.tcp)->ack[i]; 1578 if (x.active == 1) 1579 { 1580 int seq_diff; 1581 1582 seq_diff = SeqDiff(x.ack_old, seq); 1583 if (seq_diff >= 0) 1584 { 1585 if (seq_diff_min >= 0) 1586 { 1587 if (seq_diff < seq_diff_min) 1588 { 1589 delta = x.delta; 1590 seq_diff_min = seq_diff; 1591 } 1592 } 1593 else 1594 { 1595 delta = x.delta; 1596 seq_diff_min = seq_diff; 1597 } 1598 } 1599 } 1600 } 1601 return (delta); 1602 } 1603 1604 1605 void 1606 AddSeq(struct ip *pip, struct alias_link *link, int delta) 1607 { 1608 /* 1609 When a TCP packet has been altered in length, save this 1610 information in a circular list. If enough packets have 1611 been altered, then this list will begin to overwrite itself. 1612 */ 1613 1614 struct tcphdr *tc; 1615 struct ack_data_record x; 1616 int hlen, tlen, dlen; 1617 int i; 1618 1619 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1620 1621 hlen = (pip->ip_hl + tc->th_off) << 2; 1622 tlen = ntohs(pip->ip_len); 1623 dlen = tlen - hlen; 1624 1625 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 1626 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 1627 x.delta = delta; 1628 x.active = 1; 1629 1630 i = (link->data.tcp)->state.index; 1631 (link->data.tcp)->ack[i] = x; 1632 1633 i++; 1634 if (i == N_LINK_TCP_DATA) 1635 (link->data.tcp)->state.index = 0; 1636 else 1637 (link->data.tcp)->state.index = i; 1638 } 1639 1640 void 1641 SetExpire(struct alias_link *link, int expire) 1642 { 1643 if (expire == 0) 1644 { 1645 link->flags &= ~LINK_PERMANENT; 1646 DeleteLink(link); 1647 } 1648 else if (expire == -1) 1649 { 1650 link->flags |= LINK_PERMANENT; 1651 } 1652 else if (expire > 0) 1653 { 1654 link->expire_time = expire; 1655 } 1656 else 1657 { 1658 fprintf(stderr, "PacketAlias/SetExpire(): "); 1659 fprintf(stderr, "error in expire parameter\n"); 1660 } 1661 } 1662 1663 void 1664 ClearNewDefaultLink(void) 1665 { 1666 newDefaultLink = 0; 1667 } 1668 1669 1670 int 1671 CheckNewDefaultLink(void) 1672 { 1673 return newDefaultLink; 1674 } 1675 1676 1677 1678 /* 1679 Whenever an outgoing or incoming packet is handled, HouseKeeping() 1680 is called to find and remove timed-out aliasing links. Logic exists 1681 to sweep through the entire table and linked list structure 1682 every 60 seconds. 1683 1684 (prototype in alias_local.h) 1685 */ 1686 1687 void 1688 HouseKeeping(void) 1689 { 1690 int i, n, n100; 1691 struct timeval tv; 1692 struct timezone tz; 1693 1694 /* 1695 * Save system time (seconds) in global variable timeStamp for 1696 * use by other functions. This is done so as not to unnecessarily 1697 * waste timeline by making system calls. 1698 */ 1699 gettimeofday(&tv, &tz); 1700 timeStamp = tv.tv_sec; 1701 1702 /* Compute number of spokes (output table link chains) to cover */ 1703 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 1704 n100 *= timeStamp - lastCleanupTime; 1705 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 1706 1707 n = n100/100; 1708 1709 /* Handle different cases */ 1710 if (n > ALIAS_CLEANUP_MAX_SPOKES) 1711 { 1712 n = ALIAS_CLEANUP_MAX_SPOKES; 1713 lastCleanupTime = timeStamp; 1714 houseKeepingResidual = 0; 1715 1716 for (i=0; i<n; i++) 1717 IncrementalCleanup(); 1718 } 1719 else if (n > 0) 1720 { 1721 lastCleanupTime = timeStamp; 1722 houseKeepingResidual = n100 - 100*n; 1723 1724 for (i=0; i<n; i++) 1725 IncrementalCleanup(); 1726 } 1727 else if (n < 0) 1728 { 1729 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 1730 fprintf(stderr, "something unexpected in time values\n"); 1731 lastCleanupTime = timeStamp; 1732 houseKeepingResidual = 0; 1733 } 1734 } 1735 1736 1737 1738 1739 1740 /* Outside world interfaces 1741 1742 -- "outside world" means other than alias*.c routines -- 1743 1744 PacketAliasRedirectPort() 1745 PacketAliasRedirectAddr() 1746 SetPacketAliasAddress() 1747 InitPacketAliasLog() 1748 UninitPacketAliasLog() 1749 InitPacketAlias() 1750 SetPacketAliasMode() 1751 1752 (prototypes in alias.h) 1753 */ 1754 1755 /* Redirection from a specific public addr:port to a 1756 a private addr:port */ 1757 struct alias_link * 1758 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 1759 struct in_addr dst_addr, u_short dst_port, 1760 struct in_addr alias_addr, u_short alias_port, 1761 u_char proto) 1762 { 1763 int link_type; 1764 struct alias_link *link; 1765 1766 switch(proto) 1767 { 1768 case IPPROTO_UDP: 1769 link_type = LINK_UDP; 1770 break; 1771 case IPPROTO_TCP: 1772 link_type = LINK_TCP; 1773 break; 1774 default: 1775 fprintf(stderr, "PacketAliasRedirectPort(): "); 1776 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 1777 return NULL; 1778 } 1779 1780 link = AddLink(src_addr, dst_addr, alias_addr, 1781 src_port, dst_port, alias_port, 1782 link_type); 1783 1784 if (link != NULL) 1785 { 1786 link->flags |= LINK_PERMANENT; 1787 } 1788 else 1789 { 1790 fprintf(stderr, "PacketAliasRedirectPort(): " 1791 "call to AddLink() failed\n"); 1792 } 1793 1794 return link; 1795 } 1796 1797 1798 /* This function is slightly less generalized than 1799 PacketAliasRedirectPort and is included for backwards 1800 compatibility */ 1801 int 1802 PacketAliasPermanentLink(struct in_addr src_addr, u_short src_port, 1803 struct in_addr dst_addr, u_short dst_port, 1804 u_short alias_port, u_char proto) 1805 { 1806 struct alias_link *link; 1807 1808 link = PacketAliasRedirectPort(src_addr, src_port, 1809 dst_addr, dst_port, 1810 nullAddress, alias_port, 1811 proto); 1812 1813 if (link == NULL) 1814 return -1; 1815 else 1816 return 0; 1817 } 1818 1819 1820 /* Static address translation */ 1821 struct alias_link * 1822 PacketAliasRedirectAddr(struct in_addr src_addr, 1823 struct in_addr alias_addr) 1824 { 1825 struct alias_link *link; 1826 1827 link = AddLink(src_addr, nullAddress, alias_addr, 1828 0, 0, 0, 1829 LINK_ADDR); 1830 1831 if (link != NULL) 1832 { 1833 link->flags |= LINK_PERMANENT; 1834 } 1835 else 1836 { 1837 fprintf(stderr, "PacketAliasRedirectAddr(): " 1838 "call to AddLink() failed\n"); 1839 } 1840 1841 return link; 1842 } 1843 1844 1845 void 1846 PacketAliasRedirectDelete(struct alias_link *link) 1847 { 1848 /* This is a very dangerous function to put in the API, 1849 because an invalid pointer can crash the program. */ 1850 1851 deleteAllLinks = 1; 1852 DeleteLink(link); 1853 deleteAllLinks = 0; 1854 } 1855 1856 1857 void 1858 SetPacketAliasAddress(struct in_addr addr) 1859 { 1860 if (aliasAddress.s_addr != addr.s_addr) 1861 { 1862 CleanupAliasData(); 1863 aliasAddress = addr; 1864 } 1865 } 1866 1867 1868 /* Init the log file and enable logging */ 1869 void 1870 InitPacketAliasLog(void) 1871 { 1872 if ((~packetAliasMode & PKT_ALIAS_LOG) 1873 && (monitorFile = fopen("/var/log/alias.log", "w"))) 1874 { 1875 packetAliasMode |= PKT_ALIAS_LOG; 1876 fprintf(monitorFile, 1877 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 1878 } 1879 } 1880 1881 1882 /* Close the log-file and disable logging. */ 1883 void 1884 UninitPacketAliasLog(void) 1885 { 1886 if( monitorFile ) 1887 fclose(monitorFile); 1888 packetAliasMode &= ~PKT_ALIAS_LOG; 1889 } 1890 1891 1892 void 1893 InitPacketAlias(void) 1894 { 1895 int i; 1896 struct timeval tv; 1897 struct timezone tz; 1898 1899 if (firstCall == 1) 1900 { 1901 gettimeofday(&tv, &tz); 1902 timeStamp = tv.tv_sec; 1903 lastCleanupTime = tv.tv_sec; 1904 houseKeepingResidual = 0; 1905 1906 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 1907 linkTableOut[i] = NULL; 1908 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 1909 linkTableIn[i] = NULL; 1910 1911 firstCall = 0; 1912 } 1913 else 1914 { 1915 deleteAllLinks = 1; 1916 CleanupAliasData(); 1917 deleteAllLinks = 0; 1918 } 1919 1920 aliasAddress.s_addr = 0; 1921 1922 icmpLinkCount = 0; 1923 udpLinkCount = 0; 1924 tcpLinkCount = 0; 1925 fragmentIdLinkCount = 0; 1926 fragmentPtrLinkCount = 0; 1927 sockCount = 0; 1928 1929 cleanupIndex =0; 1930 1931 packetAliasMode = PKT_ALIAS_SAME_PORTS 1932 | PKT_ALIAS_USE_SOCKETS; 1933 1934 if (packetAliasMode & PKT_ALIAS_LOG) 1935 { 1936 InitPacketAliasLog(); 1937 fprintf(monitorFile, "Packet aliasing initialized.\n"); 1938 } 1939 } 1940 1941 1942 /* Change mode for some operations */ 1943 unsigned int 1944 SetPacketAliasMode 1945 ( 1946 unsigned int flags, /* Which state to bring flags to */ 1947 unsigned int mask /* Mask of which flags to affect (use 0 to do a 1948 probe for flag values) */ 1949 ) 1950 { 1951 /* Enable logging? */ 1952 if (flags & mask & PKT_ALIAS_LOG) 1953 { 1954 InitPacketAliasLog(); /* Do the enable */ 1955 } 1956 /* _Disable_ logging? */ 1957 if (~flags & mask & PKT_ALIAS_LOG) { 1958 UninitPacketAliasLog(); 1959 } 1960 1961 /* Other flags can be set/cleared without special action */ 1962 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 1963 return packetAliasMode; 1964 } 1965 1966 1967 /* 1968 Clear all packet aliasing links, but leave mode 1969 flags unchanged. Typically used when the interface 1970 address changes and all existing links become 1971 invalid. 1972 */ 1973