1 /* -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- 2 Alias_db.c encapsulates all data structures used for storing 3 packet aliasing data. Other parts of the aliasing software 4 access data through functions provided in this file. 5 6 Data storage is based on the notion of a "link", which is 7 established for ICMP echo/reply packets, UDP datagrams and 8 TCP stream connections. A link stores the original source 9 and destination addresses. For UDP and TCP, it also stores 10 source and destination port numbers, as well as an alias 11 port number. Links are also used to store information about 12 fragments. 13 14 There is a facility for sweeping through and deleting old 15 links as new packets are sent through. A simple timeout is 16 used for ICMP and UDP links. TCP links are left alone unless 17 there is an incomplete connection, in which case the link 18 can be deleted after a certain amount of time. 19 20 21 This software is placed into the public domain with no restrictions 22 on its distribution. 23 24 Initial version: August, 1996 (cjm) 25 26 Version 1.4: September 16, 1996 (cjm) 27 Facility for handling incoming links added. 28 29 Version 1.6: September 18, 1996 (cjm) 30 ICMP data handling simplified. 31 32 Version 1.7: January 9, 1997 (cjm) 33 Fragment handling simplified. 34 Saves pointers for unresolved fragments. 35 Permits links for unspecied remote ports 36 or unspecified remote addresses. 37 Fixed bug which did not properly zero port 38 table entries after a link was deleted. 39 Cleaned up some obsolete comments. 40 41 Version 1.8: January 14, 1997 (cjm) 42 Fixed data type error in StartPoint(). 43 (This error did not exist prior to v1.7 44 and was discovered and fixed by Ari Suutari) 45 46 Version 1.9: February 1, 1997 47 Optionally, connections initiated from packet aliasing host 48 machine will will not have their port number aliased unless it 49 conflicts with an aliasing port already being used. (cjm) 50 51 All options earlier being #ifdef'ed now are available through 52 a new interface, SetPacketAliasMode(). This allow run time 53 control (which is now available in PPP+pktAlias through the 54 'alias' keyword). (ee) 55 56 Added ability to create an alias port without 57 either destination address or port specified. 58 port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee) 59 60 Removed K&R style function headers 61 and general cleanup. (ee) 62 63 Added packetAliasMode to replace compiler #defines's (ee) 64 65 Allocates sockets for partially specified 66 ports if ALIAS_USE_SOCKETS defined. (cjm) 67 68 Version 2.0: March, 1997 69 SetAliasAddress() will now clean up alias links 70 if the aliasing address is changed. (cjm) 71 72 PacketAliasPermanentLink() function added to support permanent 73 links. (J. Fortes suggested the need for this.) 74 Examples: 75 76 (192.168.0.1, port 23) <-> alias port 6002, unknown dest addr/port 77 78 (192.168.0.2, port 21) <-> alias port 3604, known dest addr 79 unknown dest port 80 81 These permament links allow for incoming connections to 82 machines on the local network. They can be given with a 83 user-chosen amount of specificity, with increasing specificity 84 meaning more security. (cjm) 85 86 Quite a bit of rework to the basic engine. The portTable[] 87 array, which kept track of which ports were in use was replaced 88 by a table/linked list structure. (cjm) 89 90 SetExpire() function added. (cjm) 91 92 DeleteLink() no longer frees memory association with a pointer 93 to a fragment (this bug was first recognized by E. Eklund in 94 v1.9). 95 96 Version 2.1: May, 1997 (cjm) 97 Packet aliasing engine reworked so that it can handle 98 multiple external addresses rather than just a single 99 host address. 100 101 PacketAliasRedirectPort() and PacketAliasRedirectAddr() 102 added to the API. The first function is a more generalized 103 version of PacketAliasPermanentLink(). The second function 104 implements static network address translation. 105 106 See HISTORY file for additional revisions. 107 */ 108 109 110 /* System include files */ 111 #include <stdlib.h> 112 #include <stdio.h> 113 #include <unistd.h> 114 115 #include <sys/errno.h> 116 #include <sys/socket.h> 117 #include <sys/time.h> 118 #include <sys/types.h> 119 120 /* BSD network include files */ 121 #include <netinet/in_systm.h> 122 #include <netinet/in.h> 123 #include <netinet/ip.h> 124 #include <netinet/tcp.h> 125 #include <arpa/inet.h> 126 127 #include "alias.h" 128 #include "alias_local.h" 129 130 131 132 /* 133 Constants (note: constants are also defined 134 near relevant functions or structs) 135 */ 136 137 /* Sizes of input and output link tables */ 138 #define LINK_TABLE_OUT_SIZE 101 139 #define LINK_TABLE_IN_SIZE 4001 140 141 /* Parameters used for cleanup of expired links */ 142 #define ALIAS_CLEANUP_INTERVAL_SECS 60 143 #define ALIAS_CLEANUP_MAX_SPOKES 30 144 145 /* Timouts (in seconds) for different link types) */ 146 #define ICMP_EXPIRE_TIME 60 147 #define UDP_EXPIRE_TIME 60 148 #define FRAGMENT_ID_EXPIRE_TIME 10 149 #define FRAGMENT_PTR_EXPIRE_TIME 30 150 151 /* TCP link expire time for different cases */ 152 /* When the link has been used and closed - minimal grace time to 153 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 154 #ifndef TCP_EXPIRE_DEAD 155 # define TCP_EXPIRE_DEAD 10 156 #endif 157 158 /* When the link has been used and closed on one side - the other side 159 is allowed to still send data */ 160 #ifndef TCP_EXPIRE_SINGLEDEAD 161 # define TCP_EXPIRE_SINGLEDEAD 90 162 #endif 163 164 /* When the link isn't yet up */ 165 #ifndef TCP_EXPIRE_INITIAL 166 # define TCP_EXPIRE_INITIAL 300 167 #endif 168 169 /* When the link is up */ 170 #ifndef TCP_EXPIRE_CONNECTED 171 # define TCP_EXPIRE_CONNECTED 86400 172 #endif 173 174 175 /* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 176 These constants can be anything except zero, which indicates an 177 unknown port number. */ 178 179 #define NO_DEST_PORT 1 180 #define NO_SRC_PORT 1 181 182 183 184 /* Data Structures 185 186 The fundamental data structure used in this program is 187 "struct alias_link". Whenever a TCP connection is made, 188 a UDP datagram is sent out, or an ICMP echo request is made, 189 a link record is made (if it has not already been created). 190 The link record is identified by the source address/port 191 and the destination address/port. In the case of an ICMP 192 echo request, the source port is treated as being equivalent 193 with the 16-bit id number of the ICMP packet. 194 195 The link record also can store some auxiliary data. For 196 TCP connections that have had sequence and acknowledgment 197 modifications, data space is available to track these changes. 198 A state field is used to keep track in changes to the tcp 199 connection state. Id numbers of fragments can also be 200 stored in the auxiliary space. Pointers to unresolved 201 framgents can also be stored. 202 203 The link records support two independent chainings. Lookup 204 tables for input and out tables hold the initial pointers 205 the link chains. On input, the lookup table indexes on alias 206 port and link type. On output, the lookup table indexes on 207 source addreess, destination address, source port, destination 208 port and link type. 209 */ 210 211 struct ack_data_record /* used to save changes to ack/seq numbers */ 212 { 213 u_long ack_old; 214 u_long ack_new; 215 int delta; 216 int active; 217 }; 218 219 struct tcp_state /* Information about tcp connection */ 220 { 221 int in; /* State for outside -> inside */ 222 int out; /* State for inside -> outside */ 223 int index; /* Index to ack data array */ 224 int ack_modified; /* Indicates whether ack and seq numbers */ 225 /* been modified */ 226 }; 227 228 #define N_LINK_TCP_DATA 3 /* Number of distinct ack number changes 229 saved for a modified TCP stream */ 230 struct tcp_dat 231 { 232 struct tcp_state state; 233 struct ack_data_record ack[N_LINK_TCP_DATA]; 234 int fwhole; /* Which firewall record is used for this hole? */ 235 }; 236 237 struct alias_link /* Main data structure */ 238 { 239 struct in_addr src_addr; /* Address and port information */ 240 struct in_addr dst_addr; 241 struct in_addr alias_addr; 242 struct in_addr proxy_addr; 243 u_short src_port; 244 u_short dst_port; 245 u_short alias_port; 246 u_short proxy_port; 247 248 int link_type; /* Type of link: tcp, udp, icmp, frag */ 249 250 /* values for link_type */ 251 #define LINK_ICMP 1 252 #define LINK_UDP 2 253 #define LINK_TCP 3 254 #define LINK_FRAGMENT_ID 4 255 #define LINK_FRAGMENT_PTR 5 256 #define LINK_ADDR 6 257 258 int flags; /* indicates special characteristics */ 259 260 /* flag bits */ 261 #define LINK_UNKNOWN_DEST_PORT 0x01 262 #define LINK_UNKNOWN_DEST_ADDR 0x02 263 #define LINK_PERMANENT 0x04 264 #define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 265 #define LINK_UNFIREWALLED 0x08 266 267 int timestamp; /* Time link was last accessed */ 268 int expire_time; /* Expire time for link */ 269 270 int sockfd; /* socket descriptor */ 271 272 u_int start_point_out; /* Index number in output lookup table */ 273 u_int start_point_in; 274 struct alias_link *next_out; /* Linked list pointers for input and */ 275 struct alias_link *last_out; /* output tables */ 276 struct alias_link *next_in; /* . */ 277 struct alias_link *last_in; /* . */ 278 279 union /* Auxiliary data */ 280 { 281 char *frag_ptr; 282 struct in_addr frag_addr; 283 struct tcp_dat *tcp; 284 } data; 285 }; 286 287 288 289 290 291 /* Global Variables 292 293 The global variables listed here are only accessed from 294 within alias_db.c and so are prefixed with the static 295 designation. 296 */ 297 298 int packetAliasMode; /* Mode flags */ 299 /* - documented in alias.h */ 300 301 static struct in_addr aliasAddress; /* Address written onto source */ 302 /* field of IP packet. */ 303 304 static struct in_addr targetAddress; /* IP address incoming packets */ 305 /* are sent to if no aliasing */ 306 /* link already exists */ 307 308 static struct in_addr nullAddress; /* Used as a dummy parameter for */ 309 /* some function calls */ 310 static struct alias_link * 311 linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ 312 /* chains of link records. Each */ 313 static struct alias_link * /* link record is doubly indexed */ 314 linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ 315 /* tables. */ 316 317 static int icmpLinkCount; /* Link statistics */ 318 static int udpLinkCount; 319 static int tcpLinkCount; 320 static int fragmentIdLinkCount; 321 static int fragmentPtrLinkCount; 322 static int sockCount; 323 324 static int cleanupIndex; /* Index to chain of link table */ 325 /* being inspected for old links */ 326 327 static int timeStamp; /* System time in seconds for */ 328 /* current packet */ 329 330 static int lastCleanupTime; /* Last time IncrementalCleanup() */ 331 /* was called */ 332 333 static int houseKeepingResidual; /* used by HouseKeeping() */ 334 335 static int deleteAllLinks; /* If equal to zero, DeleteLink() */ 336 /* will not remove permanent links */ 337 338 static FILE *monitorFile; /* File descriptor for link */ 339 /* statistics monitoring file */ 340 341 static int newDefaultLink; /* Indicates if a new aliasing */ 342 /* link has been created after a */ 343 /* call to PacketAliasIn/Out(). */ 344 345 #ifndef NO_FW_PUNCH 346 static int fireWallFD = -1; /* File descriptor to be able to */ 347 /* control firewall. Opened by */ 348 /* PacketAliasSetMode on first */ 349 /* setting the PKT_ALIAS_PUNCH_FW */ 350 /* flag. */ 351 #endif 352 353 static int pptpAliasFlag; /* Indicates if PPTP aliasing is */ 354 /* on or off */ 355 static struct in_addr pptpAliasAddr; /* Address of source of PPTP */ 356 /* packets. */ 357 358 359 360 361 362 363 364 /* Internal utility routines (used only in alias_db.c) 365 366 Lookup table starting points: 367 StartPointIn() -- link table initial search point for 368 outgoing packets 369 StartPointOut() -- port table initial search point for 370 incoming packets 371 372 Miscellaneous: 373 SeqDiff() -- difference between two TCP sequences 374 ShowAliasStats() -- send alias statistics to a monitor file 375 */ 376 377 378 /* Local prototypes */ 379 static u_int StartPointIn(struct in_addr, u_short, int); 380 381 static u_int StartPointOut(struct in_addr, struct in_addr, 382 u_short, u_short, int); 383 384 static int SeqDiff(u_long, u_long); 385 386 static void ShowAliasStats(void); 387 388 #ifndef NO_FW_PUNCH 389 /* Firewall control */ 390 static void InitPunchFW(void); 391 static void UninitPunchFW(void); 392 static void ClearFWHole(struct alias_link *link); 393 #endif 394 395 /* Log file control */ 396 static void InitPacketAliasLog(void); 397 static void UninitPacketAliasLog(void); 398 399 static u_int 400 StartPointIn(struct in_addr alias_addr, 401 u_short alias_port, 402 int link_type) 403 { 404 u_int n; 405 406 n = alias_addr.s_addr; 407 n += alias_port; 408 n += link_type; 409 return(n % LINK_TABLE_IN_SIZE); 410 } 411 412 413 static u_int 414 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 415 u_short src_port, u_short dst_port, int link_type) 416 { 417 u_int n; 418 419 n = src_addr.s_addr; 420 n += dst_addr.s_addr; 421 n += src_port; 422 n += dst_port; 423 n += link_type; 424 425 return(n % LINK_TABLE_OUT_SIZE); 426 } 427 428 429 static int 430 SeqDiff(u_long x, u_long y) 431 { 432 /* Return the difference between two TCP sequence numbers */ 433 434 /* 435 This function is encapsulated in case there are any unusual 436 arithmetic conditions that need to be considered. 437 */ 438 439 return (ntohl(y) - ntohl(x)); 440 } 441 442 443 static void 444 ShowAliasStats(void) 445 { 446 /* Used for debugging */ 447 448 if (monitorFile) 449 { 450 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d", 451 icmpLinkCount, 452 udpLinkCount, 453 tcpLinkCount, 454 fragmentIdLinkCount, 455 fragmentPtrLinkCount); 456 457 fprintf(monitorFile, " / tot=%d (sock=%d)\n", 458 icmpLinkCount + udpLinkCount 459 + tcpLinkCount 460 + fragmentIdLinkCount 461 + fragmentPtrLinkCount, 462 sockCount); 463 464 fflush(monitorFile); 465 } 466 } 467 468 469 470 471 472 /* Internal routines for finding, deleting and adding links 473 474 Port Allocation: 475 GetNewPort() -- find and reserve new alias port number 476 GetSocket() -- try to allocate a socket for a given port 477 478 Link creation and deletion: 479 CleanupAliasData() - remove all link chains from lookup table 480 IncrementalCleanup() - look for stale links in a single chain 481 DeleteLink() - remove link 482 AddLink() - add link 483 ReLink() - change link 484 485 Link search: 486 FindLinkOut() - find link for outgoing packets 487 FindLinkIn() - find link for incoming packets 488 */ 489 490 /* Local prototypes */ 491 static int GetNewPort(struct alias_link *, int); 492 493 static u_short GetSocket(u_short, int *, int); 494 495 static void CleanupAliasData(void); 496 497 static void IncrementalCleanup(void); 498 499 static void DeleteLink(struct alias_link *); 500 501 static struct alias_link * 502 AddLink(struct in_addr, struct in_addr, struct in_addr, 503 u_short, u_short, int, int); 504 505 static struct alias_link * 506 ReLink(struct alias_link *, 507 struct in_addr, struct in_addr, struct in_addr, 508 u_short, u_short, int, int); 509 510 static struct alias_link * 511 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int); 512 513 static struct alias_link * 514 FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); 515 516 517 #define ALIAS_PORT_BASE 0x08000 518 #define ALIAS_PORT_MASK 0x07fff 519 #define GET_NEW_PORT_MAX_ATTEMPTS 20 520 521 #define GET_ALIAS_PORT -1 522 #define GET_ALIAS_ID GET_ALIAS_PORT 523 524 /* GetNewPort() allocates port numbers. Note that if a port number 525 is already in use, that does not mean that it cannot be used by 526 another link concurrently. This is because GetNewPort() looks for 527 unused triplets: (dest addr, dest port, alias port). */ 528 529 static int 530 GetNewPort(struct alias_link *link, int alias_port_param) 531 { 532 int i; 533 int max_trials; 534 u_short port_sys; 535 u_short port_net; 536 537 /* 538 Description of alias_port_param for GetNewPort(). When 539 this parameter is zero or positive, it precisely specifies 540 the port number. GetNewPort() will return this number 541 without check that it is in use. 542 543 Whis this parameter is -1, it indicates to get a randomly 544 selected port number. 545 */ 546 547 if (alias_port_param == GET_ALIAS_PORT) 548 { 549 /* 550 * The aliasing port is automatically selected 551 * by one of two methods below: 552 */ 553 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 554 555 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) 556 { 557 /* 558 * When the ALIAS_SAME_PORTS option is 559 * chosen, the first try will be the 560 * actual source port. If this is already 561 * in use, the remainder of the trials 562 * will be random. 563 */ 564 port_net = link->src_port; 565 port_sys = ntohs(port_net); 566 } 567 else 568 { 569 /* First trial and all subsequent are random. */ 570 port_sys = random() & ALIAS_PORT_MASK; 571 port_sys += ALIAS_PORT_BASE; 572 port_net = htons(port_sys); 573 } 574 } 575 else if (alias_port_param >= 0 && alias_port_param < 0x10000) 576 { 577 link->alias_port = (u_short) alias_port_param; 578 return(0); 579 } 580 else 581 { 582 fprintf(stderr, "PacketAlias/GetNewPort(): "); 583 fprintf(stderr, "input parameter error\n"); 584 return(-1); 585 } 586 587 588 /* Port number search */ 589 for (i=0; i<max_trials; i++) 590 { 591 int go_ahead; 592 struct alias_link *search_result; 593 594 search_result = FindLinkIn(link->dst_addr, link->alias_addr, 595 link->dst_port, port_net, 596 link->link_type, 0); 597 598 if (search_result == NULL) 599 go_ahead = 1; 600 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) 601 && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 602 go_ahead = 1; 603 else 604 go_ahead = 0; 605 606 if (go_ahead) 607 { 608 if ((packetAliasMode && PKT_ALIAS_USE_SOCKETS) 609 && (link->flags & LINK_PARTIALLY_SPECIFIED)) 610 { 611 if (GetSocket(port_net, &link->sockfd, link->link_type)) 612 { 613 link->alias_port = port_net; 614 return(0); 615 } 616 } 617 else 618 { 619 link->alias_port = port_net; 620 return(0); 621 } 622 } 623 624 port_sys = random() & ALIAS_PORT_MASK; 625 port_sys += ALIAS_PORT_BASE; 626 port_net = htons(port_sys); 627 } 628 629 fprintf(stderr, "PacketAlias/GetnewPort(): "); 630 fprintf(stderr, "could not find free port\n"); 631 632 return(-1); 633 } 634 635 636 static u_short 637 GetSocket(u_short port_net, int *sockfd, int link_type) 638 { 639 int err; 640 int sock; 641 struct sockaddr_in sock_addr; 642 643 if (link_type == LINK_TCP) 644 sock = socket(AF_INET, SOCK_STREAM, 0); 645 else if (link_type == LINK_UDP) 646 sock = socket(AF_INET, SOCK_DGRAM, 0); 647 else 648 { 649 fprintf(stderr, "PacketAlias/GetSocket(): "); 650 fprintf(stderr, "incorrect link type\n"); 651 return(0); 652 } 653 654 if (sock < 0) 655 { 656 fprintf(stderr, "PacketAlias/GetSocket(): "); 657 fprintf(stderr, "socket() error %d\n", *sockfd); 658 return(0); 659 } 660 661 sock_addr.sin_family = AF_INET; 662 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 663 sock_addr.sin_port = port_net; 664 665 err = bind(sock, 666 (struct sockaddr *) &sock_addr, 667 sizeof(sock_addr)); 668 if (err == 0) 669 { 670 sockCount++; 671 *sockfd = sock; 672 return(1); 673 } 674 else 675 { 676 close(sock); 677 return(0); 678 } 679 } 680 681 682 static void 683 CleanupAliasData(void) 684 { 685 struct alias_link *link; 686 int i, icount; 687 688 icount = 0; 689 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 690 { 691 link = linkTableOut[i]; 692 while (link != NULL) 693 { 694 struct alias_link *link_next; 695 link_next = link->next_out; 696 icount++; 697 DeleteLink(link); 698 link = link_next; 699 } 700 } 701 702 cleanupIndex =0; 703 } 704 705 706 static void 707 IncrementalCleanup(void) 708 { 709 int icount; 710 struct alias_link *link; 711 712 icount = 0; 713 link = linkTableOut[cleanupIndex++]; 714 while (link != NULL) 715 { 716 int idelta; 717 struct alias_link *link_next; 718 719 link_next = link->next_out; 720 idelta = timeStamp - link->timestamp; 721 switch (link->link_type) 722 { 723 case LINK_ICMP: 724 case LINK_UDP: 725 case LINK_FRAGMENT_ID: 726 case LINK_FRAGMENT_PTR: 727 if (idelta > link->expire_time) 728 { 729 DeleteLink(link); 730 icount++; 731 } 732 break; 733 case LINK_TCP: 734 if (idelta > link->expire_time) 735 { 736 struct tcp_dat *tcp_aux; 737 738 tcp_aux = link->data.tcp; 739 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 740 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) 741 { 742 DeleteLink(link); 743 icount++; 744 } 745 } 746 break; 747 } 748 link = link_next; 749 } 750 751 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 752 cleanupIndex = 0; 753 } 754 755 void 756 DeleteLink(struct alias_link *link) 757 { 758 struct alias_link *link_last; 759 struct alias_link *link_next; 760 761 /* Don't do anything if the link is marked permanent */ 762 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 763 return; 764 765 #ifndef NO_FW_PUNCH 766 /* Delete associatied firewall hole, if any */ 767 ClearFWHole(link); 768 #endif 769 770 /* Adjust output table pointers */ 771 link_last = link->last_out; 772 link_next = link->next_out; 773 774 if (link_last != NULL) 775 link_last->next_out = link_next; 776 else 777 linkTableOut[link->start_point_out] = link_next; 778 779 if (link_next != NULL) 780 link_next->last_out = link_last; 781 782 /* Adjust input table pointers */ 783 link_last = link->last_in; 784 link_next = link->next_in; 785 786 if (link_last != NULL) 787 link_last->next_in = link_next; 788 else 789 linkTableIn[link->start_point_in] = link_next; 790 791 if (link_next != NULL) 792 link_next->last_in = link_last; 793 794 /* Close socket, if one has been allocated */ 795 if (link->sockfd != -1) 796 { 797 sockCount--; 798 close(link->sockfd); 799 } 800 801 /* Link-type dependent cleanup */ 802 switch(link->link_type) 803 { 804 case LINK_ICMP: 805 icmpLinkCount--; 806 break; 807 case LINK_UDP: 808 udpLinkCount--; 809 break; 810 case LINK_TCP: 811 tcpLinkCount--; 812 if (link->data.tcp != NULL) 813 free(link->data.tcp); 814 break; 815 case LINK_FRAGMENT_ID: 816 fragmentIdLinkCount--; 817 break; 818 case LINK_FRAGMENT_PTR: 819 fragmentPtrLinkCount--; 820 if (link->data.frag_ptr != NULL) 821 free(link->data.frag_ptr); 822 break; 823 } 824 825 /* Free memory */ 826 free(link); 827 828 /* Write statistics, if logging enabled */ 829 if (packetAliasMode & PKT_ALIAS_LOG) 830 { 831 ShowAliasStats(); 832 } 833 } 834 835 836 static struct alias_link * 837 AddLink(struct in_addr src_addr, 838 struct in_addr dst_addr, 839 struct in_addr alias_addr, 840 u_short src_port, 841 u_short dst_port, 842 int alias_port_param, /* if less than zero, alias */ 843 int link_type) /* port will be automatically */ 844 { /* chosen. If greater than */ 845 u_int start_point; /* zero, equal to alias port */ 846 struct alias_link *link; 847 struct alias_link *first_link; 848 849 link = malloc(sizeof(struct alias_link)); 850 if (link != NULL) 851 { 852 /* If either the aliasing address or source address are 853 equal to the default device address (equal to the 854 global variable aliasAddress), then set the alias 855 address field of the link record to zero */ 856 857 if (src_addr.s_addr == aliasAddress.s_addr) 858 src_addr.s_addr = 0; 859 860 if (alias_addr.s_addr == aliasAddress.s_addr) 861 alias_addr.s_addr = 0; 862 863 /* Basic initialization */ 864 link->src_addr = src_addr; 865 link->dst_addr = dst_addr; 866 link->alias_addr = alias_addr; 867 link->proxy_addr.s_addr = 0; 868 link->src_port = src_port; 869 link->dst_port = dst_port; 870 link->proxy_port = 0; 871 link->link_type = link_type; 872 link->sockfd = -1; 873 link->flags = 0; 874 link->timestamp = timeStamp; 875 876 /* Expiration time */ 877 switch (link_type) 878 { 879 case LINK_ICMP: 880 link->expire_time = ICMP_EXPIRE_TIME; 881 break; 882 case LINK_UDP: 883 link->expire_time = UDP_EXPIRE_TIME; 884 break; 885 case LINK_TCP: 886 link->expire_time = TCP_EXPIRE_INITIAL; 887 break; 888 case LINK_FRAGMENT_ID: 889 link->expire_time = FRAGMENT_ID_EXPIRE_TIME; 890 break; 891 case LINK_FRAGMENT_PTR: 892 link->expire_time = FRAGMENT_PTR_EXPIRE_TIME; 893 break; 894 } 895 896 /* Determine alias flags */ 897 if (dst_addr.s_addr == 0) 898 link->flags |= LINK_UNKNOWN_DEST_ADDR; 899 if (dst_port == 0) 900 link->flags |= LINK_UNKNOWN_DEST_PORT; 901 902 /* Determine alias port */ 903 if (GetNewPort(link, alias_port_param) != 0) 904 { 905 free(link); 906 return(NULL); 907 } 908 909 /* Set up pointers for output lookup table */ 910 start_point = StartPointOut(src_addr, dst_addr, 911 src_port, dst_port, link_type); 912 first_link = linkTableOut[start_point]; 913 914 link->last_out = NULL; 915 link->next_out = first_link; 916 link->start_point_out = start_point; 917 918 if (first_link != NULL) 919 first_link->last_out = link; 920 921 linkTableOut[start_point] = link; 922 923 /* Set up pointers for input lookup table */ 924 start_point = StartPointIn(alias_addr, link->alias_port, link_type); 925 first_link = linkTableIn[start_point]; 926 927 link->last_in = NULL; 928 link->next_in = first_link; 929 link->start_point_in = start_point; 930 931 if (first_link != NULL) 932 first_link->last_in = link; 933 934 linkTableIn[start_point] = link; 935 936 /* Link-type dependent initialization */ 937 switch(link_type) 938 { 939 struct tcp_dat *aux_tcp; 940 941 case LINK_ICMP: 942 icmpLinkCount++; 943 break; 944 case LINK_UDP: 945 udpLinkCount++; 946 break; 947 case LINK_TCP: 948 aux_tcp = malloc(sizeof(struct tcp_dat)); 949 link->data.tcp = aux_tcp; 950 if (aux_tcp != NULL) 951 { 952 int i; 953 954 tcpLinkCount++; 955 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED; 956 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED; 957 aux_tcp->state.index = 0; 958 aux_tcp->state.ack_modified = 0; 959 for (i=0; i<N_LINK_TCP_DATA; i++) 960 aux_tcp->ack[i].active = 0; 961 aux_tcp->fwhole = -1; 962 } 963 else 964 { 965 fprintf(stderr, "PacketAlias/AddLink: "); 966 fprintf(stderr, " cannot allocate auxiliary TCP data\n"); 967 } 968 break; 969 case LINK_FRAGMENT_ID: 970 fragmentIdLinkCount++; 971 break; 972 case LINK_FRAGMENT_PTR: 973 fragmentPtrLinkCount++; 974 break; 975 } 976 } 977 else 978 { 979 fprintf(stderr, "PacketAlias/AddLink(): "); 980 fprintf(stderr, "malloc() call failed.\n"); 981 } 982 983 if (packetAliasMode & PKT_ALIAS_LOG) 984 { 985 ShowAliasStats(); 986 } 987 988 return(link); 989 } 990 991 static struct alias_link * 992 ReLink(struct alias_link *old_link, 993 struct in_addr src_addr, 994 struct in_addr dst_addr, 995 struct in_addr alias_addr, 996 u_short src_port, 997 u_short dst_port, 998 int alias_port_param, /* if less than zero, alias */ 999 int link_type) /* port will be automatically */ 1000 { /* chosen. If greater than */ 1001 struct alias_link *new_link; /* zero, equal to alias port */ 1002 1003 new_link = AddLink(src_addr, dst_addr, alias_addr, 1004 src_port, dst_port, alias_port_param, 1005 link_type); 1006 #ifndef NO_FW_PUNCH 1007 if (new_link != NULL && 1008 old_link->link_type == LINK_TCP && 1009 old_link->data.tcp && 1010 old_link->data.tcp->fwhole > 0) { 1011 PunchFWHole(new_link); 1012 } 1013 #endif 1014 DeleteLink(old_link); 1015 return new_link; 1016 } 1017 1018 static struct alias_link * 1019 FindLinkOut(struct in_addr src_addr, 1020 struct in_addr dst_addr, 1021 u_short src_port, 1022 u_short dst_port, 1023 int link_type) 1024 { 1025 u_int i; 1026 struct alias_link *link; 1027 1028 if (src_addr.s_addr == aliasAddress.s_addr) 1029 src_addr.s_addr = 0; 1030 1031 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1032 link = linkTableOut[i]; 1033 while (link != NULL) 1034 { 1035 if (link->src_addr.s_addr == src_addr.s_addr 1036 && link->dst_addr.s_addr == dst_addr.s_addr 1037 && link->dst_port == dst_port 1038 && link->src_port == src_port 1039 && link->link_type == link_type) 1040 { 1041 link->timestamp = timeStamp; 1042 break; 1043 } 1044 link = link->next_out; 1045 } 1046 1047 return(link); 1048 } 1049 1050 1051 struct alias_link * 1052 FindLinkIn(struct in_addr dst_addr, 1053 struct in_addr alias_addr, 1054 u_short dst_port, 1055 u_short alias_port, 1056 int link_type, 1057 int replace_partial_links) 1058 { 1059 int flags_in; 1060 u_int start_point; 1061 struct alias_link *link; 1062 struct alias_link *link_fully_specified; 1063 struct alias_link *link_unknown_all; 1064 struct alias_link *link_unknown_dst_addr; 1065 struct alias_link *link_unknown_dst_port; 1066 1067 /* Initialize pointers */ 1068 link_fully_specified = NULL; 1069 link_unknown_all = NULL; 1070 link_unknown_dst_addr = NULL; 1071 link_unknown_dst_port = NULL; 1072 1073 /* If either the dest addr or port is unknown, the search 1074 loop will have to know about this. */ 1075 1076 flags_in = 0; 1077 if (dst_addr.s_addr == 0) 1078 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1079 if (dst_port == 0) 1080 flags_in |= LINK_UNKNOWN_DEST_PORT; 1081 1082 /* The following allows permanent links to be 1083 be specified as using the default aliasing address 1084 (i.e. device interface address) without knowing 1085 in advance what that address is. */ 1086 1087 if (alias_addr.s_addr == aliasAddress.s_addr) 1088 alias_addr.s_addr = 0; 1089 1090 /* Search loop */ 1091 start_point = StartPointIn(alias_addr, alias_port, link_type); 1092 link = linkTableIn[start_point]; 1093 while (link != NULL) 1094 { 1095 int flags; 1096 1097 flags = flags_in | link->flags; 1098 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1099 { 1100 if (link->alias_addr.s_addr == alias_addr.s_addr 1101 && link->alias_port == alias_port 1102 && link->dst_addr.s_addr == dst_addr.s_addr 1103 && link->dst_port == dst_port 1104 && link->link_type == link_type) 1105 { 1106 link_fully_specified = link; 1107 break; 1108 } 1109 } 1110 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1111 && (flags & LINK_UNKNOWN_DEST_PORT)) 1112 { 1113 if (link->alias_addr.s_addr == alias_addr.s_addr 1114 && link->alias_port == alias_port 1115 && link->link_type == link_type) 1116 { 1117 if (link_unknown_all == NULL) 1118 link_unknown_all = link; 1119 } 1120 } 1121 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1122 { 1123 if (link->alias_addr.s_addr == alias_addr.s_addr 1124 && link->alias_port == alias_port 1125 && link->link_type == link_type 1126 && link->dst_port == dst_port) 1127 { 1128 if (link_unknown_dst_addr == NULL) 1129 link_unknown_dst_addr = link; 1130 } 1131 } 1132 else if (flags & LINK_UNKNOWN_DEST_PORT) 1133 { 1134 if (link->alias_addr.s_addr == alias_addr.s_addr 1135 && link->alias_port == alias_port 1136 && link->link_type == link_type 1137 && link->dst_addr.s_addr == dst_addr.s_addr) 1138 { 1139 if (link_unknown_dst_port == NULL) 1140 link_unknown_dst_port = link; 1141 } 1142 } 1143 link = link->next_in; 1144 } 1145 1146 1147 1148 if (link_fully_specified != NULL) 1149 { 1150 return link_fully_specified; 1151 } 1152 else if (link_unknown_dst_port != NULL) 1153 { 1154 return replace_partial_links 1155 ? ReLink(link_unknown_dst_port, 1156 link_unknown_dst_port->src_addr, dst_addr, alias_addr, 1157 link_unknown_dst_port->src_port, dst_port, alias_port, 1158 link_type) 1159 : link_unknown_dst_port; 1160 } 1161 else if (link_unknown_dst_addr != NULL) 1162 { 1163 return replace_partial_links 1164 ? ReLink(link_unknown_dst_addr, 1165 link_unknown_dst_addr->src_addr, dst_addr, alias_addr, 1166 link_unknown_dst_addr->src_port, dst_port, alias_port, 1167 link_type) 1168 : link_unknown_dst_addr; 1169 } 1170 else if (link_unknown_all != NULL) 1171 { 1172 return replace_partial_links 1173 ? ReLink(link_unknown_all, 1174 link_unknown_all->src_addr, dst_addr, alias_addr, 1175 link_unknown_all->src_port, dst_port, alias_port, 1176 link_type) 1177 : link_unknown_all; 1178 } 1179 else 1180 { 1181 return(NULL); 1182 } 1183 } 1184 1185 1186 1187 1188 /* External routines for finding/adding links 1189 1190 -- "external" means outside alias_db.c, but within alias*.c -- 1191 1192 FindIcmpIn(), FindIcmpOut() 1193 FindFragmentIn1(), FindFragmentIn2() 1194 AddFragmentPtrLink(), FindFragmentPtr() 1195 FindUdpTcpIn(), FindUdpTcpOut() 1196 FindOriginalAddress(), FindAliasAddress() 1197 1198 (prototypes in alias_local.h) 1199 */ 1200 1201 1202 struct alias_link * 1203 FindIcmpIn(struct in_addr dst_addr, 1204 struct in_addr alias_addr, 1205 u_short id_alias) 1206 { 1207 return FindLinkIn(dst_addr, alias_addr, 1208 NO_DEST_PORT, id_alias, 1209 LINK_ICMP, 0); 1210 } 1211 1212 1213 struct alias_link * 1214 FindIcmpOut(struct in_addr src_addr, 1215 struct in_addr dst_addr, 1216 u_short id) 1217 { 1218 struct alias_link * link; 1219 1220 link = FindLinkOut(src_addr, dst_addr, 1221 id, NO_DEST_PORT, 1222 LINK_ICMP); 1223 if (link == NULL) 1224 { 1225 struct in_addr alias_addr; 1226 1227 alias_addr = FindAliasAddress(src_addr); 1228 link = AddLink(src_addr, dst_addr, alias_addr, 1229 id, NO_DEST_PORT, GET_ALIAS_ID, 1230 LINK_ICMP); 1231 } 1232 1233 return(link); 1234 } 1235 1236 1237 struct alias_link * 1238 FindFragmentIn1(struct in_addr dst_addr, 1239 struct in_addr alias_addr, 1240 u_short ip_id) 1241 { 1242 struct alias_link *link; 1243 1244 link = FindLinkIn(dst_addr, alias_addr, 1245 NO_DEST_PORT, ip_id, 1246 LINK_FRAGMENT_ID, 0); 1247 1248 if (link == NULL) 1249 { 1250 link = AddLink(nullAddress, dst_addr, alias_addr, 1251 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1252 LINK_FRAGMENT_ID); 1253 } 1254 1255 return(link); 1256 } 1257 1258 1259 struct alias_link * 1260 FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1261 struct in_addr alias_addr, /* is not found. */ 1262 u_short ip_id) 1263 { 1264 return FindLinkIn(dst_addr, alias_addr, 1265 NO_DEST_PORT, ip_id, 1266 LINK_FRAGMENT_ID, 0); 1267 } 1268 1269 1270 struct alias_link * 1271 AddFragmentPtrLink(struct in_addr dst_addr, 1272 u_short ip_id) 1273 { 1274 return AddLink(nullAddress, dst_addr, nullAddress, 1275 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1276 LINK_FRAGMENT_PTR); 1277 } 1278 1279 1280 struct alias_link * 1281 FindFragmentPtr(struct in_addr dst_addr, 1282 u_short ip_id) 1283 { 1284 return FindLinkIn(dst_addr, nullAddress, 1285 NO_DEST_PORT, ip_id, 1286 LINK_FRAGMENT_PTR, 0); 1287 } 1288 1289 1290 struct alias_link * 1291 FindUdpTcpIn(struct in_addr dst_addr, 1292 struct in_addr alias_addr, 1293 u_short dst_port, 1294 u_short alias_port, 1295 u_char proto) 1296 { 1297 int link_type; 1298 struct alias_link *link; 1299 1300 switch (proto) 1301 { 1302 case IPPROTO_UDP: 1303 link_type = LINK_UDP; 1304 break; 1305 case IPPROTO_TCP: 1306 link_type = LINK_TCP; 1307 break; 1308 default: 1309 return NULL; 1310 break; 1311 } 1312 1313 link = FindLinkIn(dst_addr, alias_addr, 1314 dst_port, alias_port, 1315 link_type, 1); 1316 1317 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING) 1318 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY) 1319 && link == NULL) 1320 { 1321 struct in_addr target_addr; 1322 1323 target_addr = FindOriginalAddress(alias_addr); 1324 link = AddLink(target_addr, dst_addr, alias_addr, 1325 alias_port, dst_port, alias_port, 1326 link_type); 1327 } 1328 1329 return(link); 1330 } 1331 1332 1333 struct alias_link * 1334 FindUdpTcpOut(struct in_addr src_addr, 1335 struct in_addr dst_addr, 1336 u_short src_port, 1337 u_short dst_port, 1338 u_char proto) 1339 { 1340 int link_type; 1341 struct alias_link *link; 1342 1343 switch (proto) 1344 { 1345 case IPPROTO_UDP: 1346 link_type = LINK_UDP; 1347 break; 1348 case IPPROTO_TCP: 1349 link_type = LINK_TCP; 1350 break; 1351 default: 1352 return NULL; 1353 break; 1354 } 1355 1356 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type); 1357 1358 if (link == NULL) 1359 { 1360 struct in_addr alias_addr; 1361 1362 alias_addr = FindAliasAddress(src_addr); 1363 link = AddLink(src_addr, dst_addr, alias_addr, 1364 src_port, dst_port, GET_ALIAS_PORT, 1365 link_type); 1366 } 1367 1368 return(link); 1369 } 1370 1371 1372 struct in_addr 1373 FindOriginalAddress(struct in_addr alias_addr) 1374 { 1375 struct alias_link *link; 1376 1377 link = FindLinkIn(nullAddress, alias_addr, 1378 0, 0, LINK_ADDR, 0); 1379 if (link == NULL) 1380 { 1381 newDefaultLink = 1; 1382 if (targetAddress.s_addr != 0) 1383 return targetAddress; 1384 else 1385 return alias_addr; 1386 } 1387 else 1388 { 1389 if (link->src_addr.s_addr == 0) 1390 return aliasAddress; 1391 else 1392 return link->src_addr; 1393 } 1394 } 1395 1396 1397 struct in_addr 1398 FindAliasAddress(struct in_addr original_addr) 1399 { 1400 struct alias_link *link; 1401 1402 link = FindLinkOut(original_addr, nullAddress, 1403 0, 0, LINK_ADDR); 1404 if (link == NULL) 1405 { 1406 return aliasAddress; 1407 } 1408 else 1409 { 1410 if (link->alias_addr.s_addr == 0) 1411 return aliasAddress; 1412 else 1413 return link->alias_addr; 1414 } 1415 } 1416 1417 1418 /* External routines for getting or changing link data 1419 (external to alias_db.c, but internal to alias*.c) 1420 1421 SetFragmentData(), GetFragmentData() 1422 SetFragmentPtr(), GetFragmentPtr() 1423 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1424 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1425 GetOriginalPort(), GetAliasPort() 1426 SetAckModified(), GetAckModified() 1427 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1428 */ 1429 1430 1431 void 1432 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1433 { 1434 link->data.frag_addr = src_addr; 1435 } 1436 1437 1438 void 1439 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1440 { 1441 *src_addr = link->data.frag_addr; 1442 } 1443 1444 1445 void 1446 SetFragmentPtr(struct alias_link *link, char *fptr) 1447 { 1448 link->data.frag_ptr = fptr; 1449 } 1450 1451 1452 void 1453 GetFragmentPtr(struct alias_link *link, char **fptr) 1454 { 1455 *fptr = link->data.frag_ptr; 1456 } 1457 1458 1459 void 1460 SetStateIn(struct alias_link *link, int state) 1461 { 1462 /* TCP input state */ 1463 switch (state) { 1464 case ALIAS_TCP_STATE_DISCONNECTED: 1465 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) { 1466 link->expire_time = TCP_EXPIRE_DEAD; 1467 } else { 1468 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1469 } 1470 link->data.tcp->state.in = state; 1471 break; 1472 case ALIAS_TCP_STATE_CONNECTED: 1473 link->expire_time = TCP_EXPIRE_CONNECTED; 1474 /*FALLTHROUGH*/ 1475 case ALIAS_TCP_STATE_NOT_CONNECTED: 1476 link->data.tcp->state.in = state; 1477 break; 1478 default: 1479 abort(); 1480 } 1481 } 1482 1483 1484 void 1485 SetStateOut(struct alias_link *link, int state) 1486 { 1487 /* TCP output state */ 1488 switch (state) { 1489 case ALIAS_TCP_STATE_DISCONNECTED: 1490 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) { 1491 link->expire_time = TCP_EXPIRE_DEAD; 1492 } else { 1493 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1494 } 1495 link->data.tcp->state.out = state; 1496 break; 1497 case ALIAS_TCP_STATE_CONNECTED: 1498 link->expire_time = TCP_EXPIRE_CONNECTED; 1499 /*FALLTHROUGH*/ 1500 case ALIAS_TCP_STATE_NOT_CONNECTED: 1501 link->data.tcp->state.out = state; 1502 break; 1503 default: 1504 abort(); 1505 } 1506 } 1507 1508 1509 int 1510 GetStateIn(struct alias_link *link) 1511 { 1512 /* TCP input state */ 1513 return link->data.tcp->state.in; 1514 } 1515 1516 1517 int 1518 GetStateOut(struct alias_link *link) 1519 { 1520 /* TCP output state */ 1521 return link->data.tcp->state.out; 1522 } 1523 1524 1525 struct in_addr 1526 GetOriginalAddress(struct alias_link *link) 1527 { 1528 if (link->src_addr.s_addr == 0) 1529 return aliasAddress; 1530 else 1531 return(link->src_addr); 1532 } 1533 1534 1535 struct in_addr 1536 GetDestAddress(struct alias_link *link) 1537 { 1538 return(link->dst_addr); 1539 } 1540 1541 1542 struct in_addr 1543 GetAliasAddress(struct alias_link *link) 1544 { 1545 if (link->alias_addr.s_addr == 0) 1546 return aliasAddress; 1547 else 1548 return link->alias_addr; 1549 } 1550 1551 1552 struct in_addr 1553 GetDefaultAliasAddress() 1554 { 1555 return aliasAddress; 1556 } 1557 1558 1559 void 1560 SetDefaultAliasAddress(struct in_addr alias_addr) 1561 { 1562 aliasAddress = alias_addr; 1563 } 1564 1565 1566 u_short 1567 GetOriginalPort(struct alias_link *link) 1568 { 1569 return(link->src_port); 1570 } 1571 1572 1573 u_short 1574 GetAliasPort(struct alias_link *link) 1575 { 1576 return(link->alias_port); 1577 } 1578 1579 u_short 1580 GetDestPort(struct alias_link *link) 1581 { 1582 return(link->dst_port); 1583 } 1584 1585 void 1586 SetAckModified(struct alias_link *link) 1587 { 1588 /* Indicate that ack numbers have been modified in a TCP connection */ 1589 link->data.tcp->state.ack_modified = 1; 1590 } 1591 1592 1593 struct in_addr 1594 GetProxyAddress(struct alias_link *link) 1595 { 1596 return link->proxy_addr; 1597 } 1598 1599 1600 void 1601 SetProxyAddress(struct alias_link *link, struct in_addr addr) 1602 { 1603 link->proxy_addr = addr; 1604 } 1605 1606 1607 u_short 1608 GetProxyPort(struct alias_link *link) 1609 { 1610 return link->proxy_port; 1611 } 1612 1613 1614 void 1615 SetProxyPort(struct alias_link *link, u_short port) 1616 { 1617 link->proxy_port = port; 1618 } 1619 1620 1621 int 1622 GetAckModified(struct alias_link *link) 1623 { 1624 /* See if ack numbers have been modified */ 1625 return link->data.tcp->state.ack_modified; 1626 } 1627 1628 1629 int 1630 GetDeltaAckIn(struct ip *pip, struct alias_link *link) 1631 { 1632 /* 1633 Find out how much the ack number has been altered for an incoming 1634 TCP packet. To do this, a circular list is ack numbers where the TCP 1635 packet size was altered is searched. 1636 */ 1637 1638 int i; 1639 struct tcphdr *tc; 1640 int delta, ack_diff_min; 1641 u_long ack; 1642 1643 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1644 ack = tc->th_ack; 1645 1646 delta = 0; 1647 ack_diff_min = -1; 1648 for (i=0; i<N_LINK_TCP_DATA; i++) 1649 { 1650 struct ack_data_record x; 1651 1652 x = link->data.tcp->ack[i]; 1653 if (x.active == 1) 1654 { 1655 int ack_diff; 1656 1657 ack_diff = SeqDiff(x.ack_new, ack); 1658 if (ack_diff >= 0) 1659 { 1660 if (ack_diff_min >= 0) 1661 { 1662 if (ack_diff < ack_diff_min) 1663 { 1664 delta = x.delta; 1665 ack_diff_min = ack_diff; 1666 } 1667 } 1668 else 1669 { 1670 delta = x.delta; 1671 ack_diff_min = ack_diff; 1672 } 1673 } 1674 } 1675 } 1676 return (delta); 1677 } 1678 1679 1680 int 1681 GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 1682 { 1683 /* 1684 Find out how much the seq number has been altered for an outgoing 1685 TCP packet. To do this, a circular list is ack numbers where the TCP 1686 packet size was altered is searched. 1687 */ 1688 1689 int i; 1690 struct tcphdr *tc; 1691 int delta, seq_diff_min; 1692 u_long seq; 1693 1694 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1695 seq = tc->th_seq; 1696 1697 delta = 0; 1698 seq_diff_min = -1; 1699 for (i=0; i<N_LINK_TCP_DATA; i++) 1700 { 1701 struct ack_data_record x; 1702 1703 x = link->data.tcp->ack[i]; 1704 if (x.active == 1) 1705 { 1706 int seq_diff; 1707 1708 seq_diff = SeqDiff(x.ack_old, seq); 1709 if (seq_diff >= 0) 1710 { 1711 if (seq_diff_min >= 0) 1712 { 1713 if (seq_diff < seq_diff_min) 1714 { 1715 delta = x.delta; 1716 seq_diff_min = seq_diff; 1717 } 1718 } 1719 else 1720 { 1721 delta = x.delta; 1722 seq_diff_min = seq_diff; 1723 } 1724 } 1725 } 1726 } 1727 return (delta); 1728 } 1729 1730 1731 void 1732 AddSeq(struct ip *pip, struct alias_link *link, int delta) 1733 { 1734 /* 1735 When a TCP packet has been altered in length, save this 1736 information in a circular list. If enough packets have 1737 been altered, then this list will begin to overwrite itself. 1738 */ 1739 1740 struct tcphdr *tc; 1741 struct ack_data_record x; 1742 int hlen, tlen, dlen; 1743 int i; 1744 1745 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 1746 1747 hlen = (pip->ip_hl + tc->th_off) << 2; 1748 tlen = ntohs(pip->ip_len); 1749 dlen = tlen - hlen; 1750 1751 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 1752 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 1753 x.delta = delta; 1754 x.active = 1; 1755 1756 i = link->data.tcp->state.index; 1757 link->data.tcp->ack[i] = x; 1758 1759 i++; 1760 if (i == N_LINK_TCP_DATA) 1761 link->data.tcp->state.index = 0; 1762 else 1763 link->data.tcp->state.index = i; 1764 } 1765 1766 void 1767 SetExpire(struct alias_link *link, int expire) 1768 { 1769 if (expire == 0) 1770 { 1771 link->flags &= ~LINK_PERMANENT; 1772 DeleteLink(link); 1773 } 1774 else if (expire == -1) 1775 { 1776 link->flags |= LINK_PERMANENT; 1777 } 1778 else if (expire > 0) 1779 { 1780 link->expire_time = expire; 1781 } 1782 else 1783 { 1784 fprintf(stderr, "PacketAlias/SetExpire(): "); 1785 fprintf(stderr, "error in expire parameter\n"); 1786 } 1787 } 1788 1789 void 1790 ClearCheckNewLink(void) 1791 { 1792 newDefaultLink = 0; 1793 } 1794 1795 1796 /* Miscellaneous Functions 1797 1798 HouseKeeping() 1799 InitPacketAliasLog() 1800 UninitPacketAliasLog() 1801 */ 1802 1803 /* 1804 Whenever an outgoing or incoming packet is handled, HouseKeeping() 1805 is called to find and remove timed-out aliasing links. Logic exists 1806 to sweep through the entire table and linked list structure 1807 every 60 seconds. 1808 1809 (prototype in alias_local.h) 1810 */ 1811 1812 void 1813 HouseKeeping(void) 1814 { 1815 int i, n, n100; 1816 struct timeval tv; 1817 struct timezone tz; 1818 1819 /* 1820 * Save system time (seconds) in global variable timeStamp for 1821 * use by other functions. This is done so as not to unnecessarily 1822 * waste timeline by making system calls. 1823 */ 1824 gettimeofday(&tv, &tz); 1825 timeStamp = tv.tv_sec; 1826 1827 /* Compute number of spokes (output table link chains) to cover */ 1828 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 1829 n100 *= timeStamp - lastCleanupTime; 1830 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 1831 1832 n = n100/100; 1833 1834 /* Handle different cases */ 1835 if (n > ALIAS_CLEANUP_MAX_SPOKES) 1836 { 1837 n = ALIAS_CLEANUP_MAX_SPOKES; 1838 lastCleanupTime = timeStamp; 1839 houseKeepingResidual = 0; 1840 1841 for (i=0; i<n; i++) 1842 IncrementalCleanup(); 1843 } 1844 else if (n > 0) 1845 { 1846 lastCleanupTime = timeStamp; 1847 houseKeepingResidual = n100 - 100*n; 1848 1849 for (i=0; i<n; i++) 1850 IncrementalCleanup(); 1851 } 1852 else if (n < 0) 1853 { 1854 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 1855 fprintf(stderr, "something unexpected in time values\n"); 1856 lastCleanupTime = timeStamp; 1857 houseKeepingResidual = 0; 1858 } 1859 } 1860 1861 1862 /* Init the log file and enable logging */ 1863 static void 1864 InitPacketAliasLog(void) 1865 { 1866 if ((~packetAliasMode & PKT_ALIAS_LOG) 1867 && (monitorFile = fopen("/var/log/alias.log", "w"))) 1868 { 1869 packetAliasMode |= PKT_ALIAS_LOG; 1870 fprintf(monitorFile, 1871 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 1872 } 1873 } 1874 1875 1876 /* Close the log-file and disable logging. */ 1877 static void 1878 UninitPacketAliasLog(void) 1879 { 1880 if (monitorFile) { 1881 fclose(monitorFile); 1882 monitorFile = NULL; 1883 } 1884 packetAliasMode &= ~PKT_ALIAS_LOG; 1885 } 1886 1887 1888 1889 1890 1891 1892 /* Outside world interfaces 1893 1894 -- "outside world" means other than alias*.c routines -- 1895 1896 PacketAliasRedirectPort() 1897 PacketAliasRedirectAddr() 1898 PacketAliasRedirectDelete() 1899 PacketAliasSetAddress() 1900 PacketAliasInit() 1901 PacketAliasUninit() 1902 PacketAliasSetMode() 1903 1904 (prototypes in alias.h) 1905 */ 1906 1907 /* Redirection from a specific public addr:port to a 1908 a private addr:port */ 1909 struct alias_link * 1910 PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 1911 struct in_addr dst_addr, u_short dst_port, 1912 struct in_addr alias_addr, u_short alias_port, 1913 u_char proto) 1914 { 1915 int link_type; 1916 struct alias_link *link; 1917 1918 switch(proto) 1919 { 1920 case IPPROTO_UDP: 1921 link_type = LINK_UDP; 1922 break; 1923 case IPPROTO_TCP: 1924 link_type = LINK_TCP; 1925 break; 1926 default: 1927 fprintf(stderr, "PacketAliasRedirectPort(): "); 1928 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 1929 return NULL; 1930 } 1931 1932 link = AddLink(src_addr, dst_addr, alias_addr, 1933 src_port, dst_port, alias_port, 1934 link_type); 1935 1936 if (link != NULL) 1937 { 1938 link->flags |= LINK_PERMANENT; 1939 } 1940 else 1941 { 1942 fprintf(stderr, "PacketAliasRedirectPort(): " 1943 "call to AddLink() failed\n"); 1944 } 1945 1946 return link; 1947 } 1948 1949 /* Translate PPTP packets to a machine on the inside 1950 */ 1951 int 1952 PacketAliasPptp(struct in_addr src_addr) 1953 { 1954 1955 pptpAliasAddr = src_addr; /* Address of the inside PPTP machine */ 1956 pptpAliasFlag = 1; 1957 1958 1959 return 1; 1960 } 1961 1962 int GetPptpAlias (struct in_addr* alias_addr) 1963 { 1964 if (pptpAliasFlag) 1965 *alias_addr = pptpAliasAddr; 1966 1967 return pptpAliasFlag; 1968 } 1969 1970 /* Static address translation */ 1971 struct alias_link * 1972 PacketAliasRedirectAddr(struct in_addr src_addr, 1973 struct in_addr alias_addr) 1974 { 1975 struct alias_link *link; 1976 1977 link = AddLink(src_addr, nullAddress, alias_addr, 1978 0, 0, 0, 1979 LINK_ADDR); 1980 1981 if (link != NULL) 1982 { 1983 link->flags |= LINK_PERMANENT; 1984 } 1985 else 1986 { 1987 fprintf(stderr, "PacketAliasRedirectAddr(): " 1988 "call to AddLink() failed\n"); 1989 } 1990 1991 return link; 1992 } 1993 1994 1995 void 1996 PacketAliasRedirectDelete(struct alias_link *link) 1997 { 1998 /* This is a dangerous function to put in the API, 1999 because an invalid pointer can crash the program. */ 2000 2001 deleteAllLinks = 1; 2002 DeleteLink(link); 2003 deleteAllLinks = 0; 2004 } 2005 2006 2007 void 2008 PacketAliasSetAddress(struct in_addr addr) 2009 { 2010 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2011 && aliasAddress.s_addr != addr.s_addr) 2012 CleanupAliasData(); 2013 2014 aliasAddress = addr; 2015 } 2016 2017 2018 void 2019 PacketAliasSetTarget(struct in_addr target_addr) 2020 { 2021 targetAddress = target_addr; 2022 } 2023 2024 2025 void 2026 PacketAliasInit(void) 2027 { 2028 int i; 2029 struct timeval tv; 2030 struct timezone tz; 2031 static int firstCall = 1; 2032 2033 if (firstCall == 1) 2034 { 2035 gettimeofday(&tv, &tz); 2036 timeStamp = tv.tv_sec; 2037 lastCleanupTime = tv.tv_sec; 2038 houseKeepingResidual = 0; 2039 2040 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2041 linkTableOut[i] = NULL; 2042 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2043 linkTableIn[i] = NULL; 2044 2045 atexit(PacketAliasUninit); 2046 firstCall = 0; 2047 } 2048 else 2049 { 2050 deleteAllLinks = 1; 2051 CleanupAliasData(); 2052 deleteAllLinks = 0; 2053 } 2054 2055 aliasAddress.s_addr = 0; 2056 targetAddress.s_addr = 0; 2057 2058 icmpLinkCount = 0; 2059 udpLinkCount = 0; 2060 tcpLinkCount = 0; 2061 fragmentIdLinkCount = 0; 2062 fragmentPtrLinkCount = 0; 2063 sockCount = 0; 2064 2065 cleanupIndex =0; 2066 2067 packetAliasMode = PKT_ALIAS_SAME_PORTS 2068 | PKT_ALIAS_USE_SOCKETS 2069 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2070 2071 pptpAliasFlag = 0; 2072 } 2073 2074 void 2075 PacketAliasUninit(void) { 2076 deleteAllLinks = 1; 2077 CleanupAliasData(); 2078 deleteAllLinks = 0; 2079 UninitPacketAliasLog(); 2080 #ifndef NO_FW_PUNCH 2081 UninitPunchFW(); 2082 #endif 2083 } 2084 2085 2086 /* Change mode for some operations */ 2087 unsigned int 2088 PacketAliasSetMode( 2089 unsigned int flags, /* Which state to bring flags to */ 2090 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2091 probe for flag values) */ 2092 ) 2093 { 2094 /* Enable logging? */ 2095 if (flags & mask & PKT_ALIAS_LOG) 2096 { 2097 InitPacketAliasLog(); /* Do the enable */ 2098 } else 2099 /* _Disable_ logging? */ 2100 if (~flags & mask & PKT_ALIAS_LOG) { 2101 UninitPacketAliasLog(); 2102 } 2103 2104 #ifndef NO_FW_PUNCH 2105 /* Start punching holes in the firewall? */ 2106 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2107 InitPunchFW(); 2108 } else 2109 /* Stop punching holes in the firewall? */ 2110 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2111 UninitPunchFW(); 2112 } 2113 #endif 2114 2115 /* Other flags can be set/cleared without special action */ 2116 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2117 return packetAliasMode; 2118 } 2119 2120 2121 int 2122 PacketAliasCheckNewLink(void) 2123 { 2124 return newDefaultLink; 2125 } 2126 2127 2128 #ifndef NO_FW_PUNCH 2129 2130 /***************** 2131 Code to support firewall punching. This shouldn't really be in this 2132 file, but making variables global is evil too. 2133 ****************/ 2134 2135 /* Firewall include files */ 2136 #include <sys/queue.h> 2137 #include <net/if.h> 2138 #include <netinet/ip_fw.h> 2139 #include <string.h> 2140 #include <err.h> 2141 2142 static void ClearAllFWHoles(void); 2143 2144 static int fireWallBaseNum; /* The first firewall entry free for our use */ 2145 static int fireWallNumNums; /* How many entries can we use? */ 2146 static int fireWallActiveNum; /* Which entry did we last use? */ 2147 static char *fireWallField; /* bool array for entries */ 2148 2149 #define fw_setfield(field, num) \ 2150 do { \ 2151 (field)[num] = 1; \ 2152 } /*lint -save -e717 */ while(0) /*lint -restore */ 2153 #define fw_clrfield(field, num) \ 2154 do { \ 2155 (field)[num] = 0; \ 2156 } /*lint -save -e717 */ while(0) /*lint -restore */ 2157 #define fw_tstfield(field, num) ((field)[num]) 2158 2159 void 2160 PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2161 fireWallBaseNum = base; 2162 fireWallNumNums = num; 2163 } 2164 2165 static void 2166 InitPunchFW(void) { 2167 fireWallField = malloc(fireWallNumNums); 2168 if (fireWallField) { 2169 memset(fireWallField, 0, fireWallNumNums); 2170 if (fireWallFD < 0) { 2171 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2172 } 2173 ClearAllFWHoles(); 2174 fireWallActiveNum = fireWallBaseNum; 2175 } 2176 } 2177 2178 static void 2179 UninitPunchFW(void) { 2180 ClearAllFWHoles(); 2181 if (fireWallFD >= 0) 2182 close(fireWallFD); 2183 fireWallFD = -1; 2184 if (fireWallField) 2185 free(fireWallField); 2186 fireWallField = NULL; 2187 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2188 } 2189 2190 /* Make a certain link go through the firewall */ 2191 void 2192 PunchFWHole(struct alias_link *link) { 2193 int r; /* Result code */ 2194 struct ip_fw rule; /* On-the-fly built rule */ 2195 int fwhole; /* Where to punch hole */ 2196 2197 /* Don't do anything unless we are asked to */ 2198 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2199 fireWallFD < 0 || 2200 link->link_type != LINK_TCP || 2201 !link->data.tcp) 2202 return; 2203 2204 memset(&rule, 0, sizeof rule); 2205 2206 /** Build rule **/ 2207 2208 /* Find empty slot */ 2209 for (fwhole = fireWallActiveNum; 2210 fwhole < fireWallBaseNum + fireWallNumNums && 2211 fw_tstfield(fireWallField, fwhole); 2212 fwhole++) 2213 ; 2214 if (fwhole >= fireWallBaseNum + fireWallNumNums || 2215 fw_tstfield(fireWallField, fwhole)) { 2216 for (fwhole = fireWallBaseNum; 2217 fwhole < fireWallActiveNum && 2218 fw_tstfield(fireWallField, fwhole); 2219 fwhole++) 2220 ; 2221 if (fwhole == fireWallActiveNum) { 2222 /* No rule point empty - we can't punch more holes. */ 2223 fireWallActiveNum = fireWallBaseNum; 2224 fprintf(stderr, "libalias: Unable to create firewall hole!\n"); 2225 return; 2226 } 2227 } 2228 /* Start next search at next position */ 2229 fireWallActiveNum = fwhole+1; 2230 2231 /* Build generic part of the two rules */ 2232 rule.fw_number = fwhole; 2233 rule.fw_nports = 1; /* Number of source ports; dest ports follow */ 2234 rule.fw_flg = IP_FW_F_ACCEPT; 2235 rule.fw_prot = IPPROTO_TCP; 2236 rule.fw_smsk.s_addr = INADDR_BROADCAST; 2237 rule.fw_dmsk.s_addr = INADDR_BROADCAST; 2238 2239 /* Build and apply specific part of the rules */ 2240 rule.fw_src = GetOriginalAddress(link); 2241 rule.fw_dst = GetDestAddress(link); 2242 rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link)); 2243 rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link)); 2244 2245 /* Skip non-bound links - XXX should not be strictly necessary, 2246 but seems to leave hole if not done. Leak of non-bound links? 2247 (Code should be left even if the problem is fixed - it is a 2248 clear optimization) */ 2249 if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) { 2250 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2251 if (r) 2252 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)"); 2253 rule.fw_src = GetDestAddress(link); 2254 rule.fw_dst = GetOriginalAddress(link); 2255 rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link)); 2256 rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link)); 2257 r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule); 2258 if (r) 2259 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)"); 2260 } 2261 /* Indicate hole applied */ 2262 link->data.tcp->fwhole = fwhole; 2263 fw_setfield(fireWallField, fwhole); 2264 } 2265 2266 /* Remove a hole in a firewall associated with a particular alias 2267 link. Calling this too often is harmless. */ 2268 static void 2269 ClearFWHole(struct alias_link *link) { 2270 if (link->link_type == LINK_TCP && link->data.tcp) { 2271 int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */ 2272 struct ip_fw rule; 2273 2274 if (fwhole < 0) 2275 return; 2276 2277 memset(&rule, 0, sizeof rule); 2278 rule.fw_number = fwhole; 2279 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2280 ; 2281 fw_clrfield(fireWallField, fwhole); 2282 link->data.tcp->fwhole = -1; 2283 } 2284 } 2285 2286 /* Clear out the entire range dedicated to firewall holes. */ 2287 static void 2288 ClearAllFWHoles(void) { 2289 struct ip_fw rule; /* On-the-fly built rule */ 2290 int i; 2291 2292 if (fireWallFD < 0) 2293 return; 2294 2295 memset(&rule, 0, sizeof rule); 2296 for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) { 2297 rule.fw_number = i; 2298 while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule)) 2299 ; 2300 } 2301 memset(fireWallField, 0, fireWallNumNums); 2302 } 2303 #endif 2304