119*/ 120 121 122/* System include files */ 123#include <errno.h> 124#include <stdlib.h> 125#include <stdio.h> 126#include <unistd.h> 127 128#include <sys/queue.h> 129#include <sys/socket.h> 130#include <sys/time.h> 131#include <sys/types.h> 132 133/* BSD network include files */ 134#include <netinet/in_systm.h> 135#include <netinet/in.h> 136#include <netinet/ip.h> 137#include <netinet/tcp.h> 138#include <arpa/inet.h> 139 140#include "alias.h" 141#include "alias_local.h" 142 143 144 145/* 146 Constants (note: constants are also defined 147 near relevant functions or structs) 148*/ 149 150/* Sizes of input and output link tables */ 151#define LINK_TABLE_OUT_SIZE 101 152#define LINK_TABLE_IN_SIZE 4001 153 154/* Parameters used for cleanup of expired links */ 155#define ALIAS_CLEANUP_INTERVAL_SECS 60 156#define ALIAS_CLEANUP_MAX_SPOKES 30 157 158/* Timeouts (in seconds) for different link types */ 159#define ICMP_EXPIRE_TIME 60 160#define UDP_EXPIRE_TIME 60 161#define PPTP_EXPIRE_TIME 60 162#define PROTO_EXPIRE_TIME 60 163#define FRAGMENT_ID_EXPIRE_TIME 10 164#define FRAGMENT_PTR_EXPIRE_TIME 30 165 166/* TCP link expire time for different cases */ 167/* When the link has been used and closed - minimal grace time to 168 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 169#ifndef TCP_EXPIRE_DEAD 170# define TCP_EXPIRE_DEAD 10 171#endif 172 173/* When the link has been used and closed on one side - the other side 174 is allowed to still send data */ 175#ifndef TCP_EXPIRE_SINGLEDEAD 176# define TCP_EXPIRE_SINGLEDEAD 90 177#endif 178 179/* When the link isn't yet up */ 180#ifndef TCP_EXPIRE_INITIAL 181# define TCP_EXPIRE_INITIAL 300 182#endif 183 184/* When the link is up */ 185#ifndef TCP_EXPIRE_CONNECTED 186# define TCP_EXPIRE_CONNECTED 86400 187#endif 188 189 190/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 191 These constants can be anything except zero, which indicates an 192 unknown port number. */ 193 194#define NO_DEST_PORT 1 195#define NO_SRC_PORT 1 196 197 198 199/* Data Structures 200 201 The fundamental data structure used in this program is 202 "struct alias_link". Whenever a TCP connection is made, 203 a UDP datagram is sent out, or an ICMP echo request is made, 204 a link record is made (if it has not already been created). 205 The link record is identified by the source address/port 206 and the destination address/port. In the case of an ICMP 207 echo request, the source port is treated as being equivalent 208 with the 16-bit ID number of the ICMP packet. 209 210 The link record also can store some auxiliary data. For 211 TCP connections that have had sequence and acknowledgment 212 modifications, data space is available to track these changes. 213 A state field is used to keep track in changes to the TCP 214 connection state. ID numbers of fragments can also be 215 stored in the auxiliary space. Pointers to unresolved 216 fragments can also be stored. 217 218 The link records support two independent chainings. Lookup 219 tables for input and out tables hold the initial pointers 220 the link chains. On input, the lookup table indexes on alias 221 port and link type. On output, the lookup table indexes on 222 source address, destination address, source port, destination 223 port and link type. 224*/ 225 226struct ack_data_record /* used to save changes to ACK/sequence numbers */ 227{ 228 u_long ack_old; 229 u_long ack_new; 230 int delta; 231 int active; 232}; 233 234struct tcp_state /* Information about TCP connection */ 235{ 236 int in; /* State for outside -> inside */ 237 int out; /* State for inside -> outside */ 238 int index; /* Index to ACK data array */ 239 int ack_modified; /* Indicates whether ACK and sequence numbers */ 240 /* been modified */ 241}; 242 243#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes 244 saved for a modified TCP stream */ 245struct tcp_dat 246{ 247 struct tcp_state state; 248 struct ack_data_record ack[N_LINK_TCP_DATA]; 249 int fwhole; /* Which firewall record is used for this hole? */ 250}; 251 252struct server /* LSNAT server pool (circular list) */ 253{ 254 struct in_addr addr; 255 u_short port; 256 struct server *next; 257}; 258 259struct alias_link /* Main data structure */ 260{ 261 struct in_addr src_addr; /* Address and port information */ 262 struct in_addr dst_addr; 263 struct in_addr alias_addr; 264 struct in_addr proxy_addr; 265 u_short src_port; 266 u_short dst_port; 267 u_short alias_port; 268 u_short proxy_port; 269 struct server *server; 270 271 int link_type; /* Type of link: TCP, UDP, ICMP, proto, frag */ 272 273/* values for link_type */ 274#define LINK_ICMP IPPROTO_ICMP 275#define LINK_UDP IPPROTO_UDP 276#define LINK_TCP IPPROTO_TCP 277#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 278#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 279#define LINK_ADDR (IPPROTO_MAX + 3) 280#define LINK_PPTP (IPPROTO_MAX + 4) 281 282 int flags; /* indicates special characteristics */ 283 284/* flag bits */ 285#define LINK_UNKNOWN_DEST_PORT 0x01 286#define LINK_UNKNOWN_DEST_ADDR 0x02 287#define LINK_PERMANENT 0x04 288#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 289#define LINK_UNFIREWALLED 0x08 290#define LINK_LAST_LINE_CRLF_TERMED 0x10 291 292 int timestamp; /* Time link was last accessed */ 293 int expire_time; /* Expire time for link */ 294 295 int sockfd; /* socket descriptor */ 296 297 LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for */ 298 LIST_ENTRY(alias_link) list_in; /* input and output lookup tables */ 299 300 union /* Auxiliary data */ 301 { 302 char *frag_ptr; 303 struct in_addr frag_addr; 304 struct tcp_dat *tcp; 305 } data; 306}; 307 308 309 310 311 312/* Global Variables 313 314 The global variables listed here are only accessed from 315 within alias_db.c and so are prefixed with the static 316 designation. 317*/ 318 319int packetAliasMode; /* Mode flags */ 320 /* - documented in alias.h */ 321 322static struct in_addr aliasAddress; /* Address written onto source */ 323 /* field of IP packet. */ 324 325static struct in_addr targetAddress; /* IP address incoming packets */ 326 /* are sent to if no aliasing */ 327 /* link already exists */ 328 329static struct in_addr nullAddress; /* Used as a dummy parameter for */ 330 /* some function calls */ 331static LIST_HEAD(, alias_link) 332linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ 333 /* chains of link records. Each */ 334static LIST_HEAD(, alias_link) /* link record is doubly indexed */ 335linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ 336 /* tables. */ 337 338static int icmpLinkCount; /* Link statistics */ 339static int udpLinkCount; 340static int tcpLinkCount; 341static int pptpLinkCount; 342static int protoLinkCount; 343static int fragmentIdLinkCount; 344static int fragmentPtrLinkCount; 345static int sockCount; 346 347static int cleanupIndex; /* Index to chain of link table */ 348 /* being inspected for old links */ 349 350static int timeStamp; /* System time in seconds for */ 351 /* current packet */ 352 353static int lastCleanupTime; /* Last time IncrementalCleanup() */ 354 /* was called */ 355 356static int houseKeepingResidual; /* used by HouseKeeping() */ 357 358static int deleteAllLinks; /* If equal to zero, DeleteLink() */ 359 /* will not remove permanent links */ 360 361static FILE *monitorFile; /* File descriptor for link */ 362 /* statistics monitoring file */ 363 364static int newDefaultLink; /* Indicates if a new aliasing */ 365 /* link has been created after a */ 366 /* call to PacketAliasIn/Out(). */ 367 368#ifndef NO_FW_PUNCH 369static int fireWallFD = -1; /* File descriptor to be able to */ 370 /* control firewall. Opened by */ 371 /* PacketAliasSetMode on first */ 372 /* setting the PKT_ALIAS_PUNCH_FW */ 373 /* flag. */ 374#endif 375 376 377 378 379 380 381 382/* Internal utility routines (used only in alias_db.c) 383 384Lookup table starting points: 385 StartPointIn() -- link table initial search point for 386 incoming packets 387 StartPointOut() -- link table initial search point for 388 outgoing packets 389 390Miscellaneous: 391 SeqDiff() -- difference between two TCP sequences 392 ShowAliasStats() -- send alias statistics to a monitor file 393*/ 394 395 396/* Local prototypes */ 397static u_int StartPointIn(struct in_addr, u_short, int); 398 399static u_int StartPointOut(struct in_addr, struct in_addr, 400 u_short, u_short, int); 401 402static int SeqDiff(u_long, u_long); 403 404static void ShowAliasStats(void); 405 406#ifndef NO_FW_PUNCH 407/* Firewall control */ 408static void InitPunchFW(void); 409static void UninitPunchFW(void); 410static void ClearFWHole(struct alias_link *link); 411#endif 412 413/* Log file control */ 414static void InitPacketAliasLog(void); 415static void UninitPacketAliasLog(void); 416 417static u_int 418StartPointIn(struct in_addr alias_addr, 419 u_short alias_port, 420 int link_type) 421{ 422 u_int n; 423 424 n = alias_addr.s_addr; 425 n += alias_port; 426 n += link_type; 427 return(n % LINK_TABLE_IN_SIZE); 428} 429 430 431static u_int 432StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 433 u_short src_port, u_short dst_port, int link_type) 434{ 435 u_int n; 436 437 n = src_addr.s_addr; 438 n += dst_addr.s_addr; 439 n += src_port; 440 n += dst_port; 441 n += link_type; 442 443 return(n % LINK_TABLE_OUT_SIZE); 444} 445 446 447static int 448SeqDiff(u_long x, u_long y) 449{ 450/* Return the difference between two TCP sequence numbers */ 451 452/* 453 This function is encapsulated in case there are any unusual 454 arithmetic conditions that need to be considered. 455*/ 456 457 return (ntohl(y) - ntohl(x)); 458} 459 460 461static void 462ShowAliasStats(void) 463{ 464/* Used for debugging */ 465 466 if (monitorFile) 467 { 468 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", 469 icmpLinkCount, 470 udpLinkCount, 471 tcpLinkCount, 472 pptpLinkCount, 473 protoLinkCount, 474 fragmentIdLinkCount, 475 fragmentPtrLinkCount); 476 477 fprintf(monitorFile, " / tot=%d (sock=%d)\n", 478 icmpLinkCount + udpLinkCount 479 + tcpLinkCount 480 + pptpLinkCount 481 + protoLinkCount 482 + fragmentIdLinkCount 483 + fragmentPtrLinkCount, 484 sockCount); 485 486 fflush(monitorFile); 487 } 488} 489 490 491 492 493 494/* Internal routines for finding, deleting and adding links 495 496Port Allocation: 497 GetNewPort() -- find and reserve new alias port number 498 GetSocket() -- try to allocate a socket for a given port 499 500Link creation and deletion: 501 CleanupAliasData() - remove all link chains from lookup table 502 IncrementalCleanup() - look for stale links in a single chain 503 DeleteLink() - remove link 504 AddLink() - add link 505 ReLink() - change link 506 507Link search: 508 FindLinkOut() - find link for outgoing packets 509 FindLinkIn() - find link for incoming packets 510 511Port search: 512 FindNewPortGroup() - find an available group of ports 513*/ 514 515/* Local prototypes */ 516static int GetNewPort(struct alias_link *, int); 517 518static u_short GetSocket(u_short, int *, int); 519 520static void CleanupAliasData(void); 521 522static void IncrementalCleanup(void); 523 524static void DeleteLink(struct alias_link *); 525 526static struct alias_link * 527AddLink(struct in_addr, struct in_addr, struct in_addr, 528 u_short, u_short, int, int); 529 530static struct alias_link * 531ReLink(struct alias_link *, 532 struct in_addr, struct in_addr, struct in_addr, 533 u_short, u_short, int, int); 534 535static struct alias_link * 536FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int); 537 538static struct alias_link * 539FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); 540 541 542#define ALIAS_PORT_BASE 0x08000 543#define ALIAS_PORT_MASK 0x07fff 544#define ALIAS_PORT_MASK_EVEN 0x07ffe 545#define GET_NEW_PORT_MAX_ATTEMPTS 20 546 547#define GET_ALIAS_PORT -1 548#define GET_ALIAS_ID GET_ALIAS_PORT 549 550#define FIND_EVEN_ALIAS_BASE 1 551 552/* GetNewPort() allocates port numbers. Note that if a port number 553 is already in use, that does not mean that it cannot be used by 554 another link concurrently. This is because GetNewPort() looks for 555 unused triplets: (dest addr, dest port, alias port). */ 556 557static int 558GetNewPort(struct alias_link *link, int alias_port_param) 559{ 560 int i; 561 int max_trials; 562 u_short port_sys; 563 u_short port_net; 564 565/* 566 Description of alias_port_param for GetNewPort(). When 567 this parameter is zero or positive, it precisely specifies 568 the port number. GetNewPort() will return this number 569 without check that it is in use. 570 571 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly 572 selected port number. 573*/ 574 575 if (alias_port_param == GET_ALIAS_PORT) 576 { 577 /* 578 * The aliasing port is automatically selected 579 * by one of two methods below: 580 */ 581 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 582 583 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) 584 { 585 /* 586 * When the PKT_ALIAS_SAME_PORTS option is 587 * chosen, the first try will be the 588 * actual source port. If this is already 589 * in use, the remainder of the trials 590 * will be random. 591 */ 592 port_net = link->src_port; 593 port_sys = ntohs(port_net); 594 } 595 else 596 { 597 /* First trial and all subsequent are random. */ 598 port_sys = random() & ALIAS_PORT_MASK; 599 port_sys += ALIAS_PORT_BASE; 600 port_net = htons(port_sys); 601 } 602 } 603 else if (alias_port_param >= 0 && alias_port_param < 0x10000) 604 { 605 link->alias_port = (u_short) alias_port_param; 606 return(0); 607 } 608 else 609 { 610#ifdef DEBUG 611 fprintf(stderr, "PacketAlias/GetNewPort(): "); 612 fprintf(stderr, "input parameter error\n"); 613#endif 614 return(-1); 615 } 616 617 618/* Port number search */ 619 for (i=0; i<max_trials; i++) 620 { 621 int go_ahead; 622 struct alias_link *search_result; 623 624 search_result = FindLinkIn(link->dst_addr, link->alias_addr, 625 link->dst_port, port_net, 626 link->link_type, 0); 627 628 if (search_result == NULL) 629 go_ahead = 1; 630 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) 631 && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 632 go_ahead = 1; 633 else 634 go_ahead = 0; 635 636 if (go_ahead) 637 { 638 if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS) 639 && (link->flags & LINK_PARTIALLY_SPECIFIED) 640 && ((link->link_type == LINK_TCP) || 641 (link->link_type == LINK_UDP))) 642 { 643 if (GetSocket(port_net, &link->sockfd, link->link_type)) 644 { 645 link->alias_port = port_net; 646 return(0); 647 } 648 } 649 else 650 { 651 link->alias_port = port_net; 652 return(0); 653 } 654 } 655 656 port_sys = random() & ALIAS_PORT_MASK; 657 port_sys += ALIAS_PORT_BASE; 658 port_net = htons(port_sys); 659 } 660 661#ifdef DEBUG 662 fprintf(stderr, "PacketAlias/GetnewPort(): "); 663 fprintf(stderr, "could not find free port\n"); 664#endif 665 666 return(-1); 667} 668 669 670static u_short 671GetSocket(u_short port_net, int *sockfd, int link_type) 672{ 673 int err; 674 int sock; 675 struct sockaddr_in sock_addr; 676 677 if (link_type == LINK_TCP) 678 sock = socket(AF_INET, SOCK_STREAM, 0); 679 else if (link_type == LINK_UDP) 680 sock = socket(AF_INET, SOCK_DGRAM, 0); 681 else 682 { 683#ifdef DEBUG 684 fprintf(stderr, "PacketAlias/GetSocket(): "); 685 fprintf(stderr, "incorrect link type\n"); 686#endif 687 return(0); 688 } 689 690 if (sock < 0) 691 { 692#ifdef DEBUG 693 fprintf(stderr, "PacketAlias/GetSocket(): "); 694 fprintf(stderr, "socket() error %d\n", *sockfd); 695#endif 696 return(0); 697 } 698 699 sock_addr.sin_family = AF_INET; 700 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 701 sock_addr.sin_port = port_net; 702 703 err = bind(sock, 704 (struct sockaddr *) &sock_addr, 705 sizeof(sock_addr)); 706 if (err == 0) 707 { 708 sockCount++; 709 *sockfd = sock; 710 return(1); 711 } 712 else 713 { 714 close(sock); 715 return(0); 716 } 717} 718 719 720/* FindNewPortGroup() returns a base port number for an available 721 range of contiguous port numbers. Note that if a port number 722 is already in use, that does not mean that it cannot be used by 723 another link concurrently. This is because FindNewPortGroup() 724 looks for unused triplets: (dest addr, dest port, alias port). */ 725 726int 727FindNewPortGroup(struct in_addr dst_addr, 728 struct in_addr alias_addr, 729 u_short src_port, 730 u_short dst_port, 731 u_short port_count, 732 u_char proto, 733 u_char align) 734{ 735 int i, j; 736 int max_trials; 737 u_short port_sys; 738 int link_type; 739 740 /* 741 * Get link_type from protocol 742 */ 743 744 switch (proto) 745 { 746 case IPPROTO_UDP: 747 link_type = LINK_UDP; 748 break; 749 case IPPROTO_TCP: 750 link_type = LINK_TCP; 751 break; 752 default: 753 return (0); 754 break; 755 } 756 757 /* 758 * The aliasing port is automatically selected 759 * by one of two methods below: 760 */ 761 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 762 763 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) { 764 /* 765 * When the ALIAS_SAME_PORTS option is 766 * chosen, the first try will be the 767 * actual source port. If this is already 768 * in use, the remainder of the trials 769 * will be random. 770 */ 771 port_sys = ntohs(src_port); 772 773 } else { 774 775 /* First trial and all subsequent are random. */ 776 if (align == FIND_EVEN_ALIAS_BASE) 777 port_sys = random() & ALIAS_PORT_MASK_EVEN; 778 else 779 port_sys = random() & ALIAS_PORT_MASK; 780 781 port_sys += ALIAS_PORT_BASE; 782 } 783 784/* Port number search */ 785 for (i = 0; i < max_trials; i++) { 786 787 struct alias_link *search_result; 788 789 for (j = 0; j < port_count; j++) 790 if (0 != (search_result = FindLinkIn(dst_addr, alias_addr, 791 dst_port, htons(port_sys + j), 792 link_type, 0))) 793 break; 794 795 /* Found a good range, return base */ 796 if (j == port_count) 797 return (htons(port_sys)); 798 799 /* Find a new base to try */ 800 if (align == FIND_EVEN_ALIAS_BASE) 801 port_sys = random() & ALIAS_PORT_MASK_EVEN; 802 else 803 port_sys = random() & ALIAS_PORT_MASK; 804 805 port_sys += ALIAS_PORT_BASE; 806 } 807 808#ifdef DEBUG 809 fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 810 fprintf(stderr, "could not find free port(s)\n"); 811#endif 812 813 return(0); 814} 815 816static void 817CleanupAliasData(void) 818{ 819 struct alias_link *link; 820 int i, icount; 821 822 icount = 0; 823 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 824 { 825 link = LIST_FIRST(&linkTableOut[i]); 826 while (link != NULL) 827 { 828 struct alias_link *link_next; 829 link_next = LIST_NEXT(link, list_out); 830 icount++; 831 DeleteLink(link); 832 link = link_next; 833 } 834 } 835 836 cleanupIndex =0; 837} 838 839 840static void 841IncrementalCleanup(void) 842{ 843 int icount; 844 struct alias_link *link; 845 846 icount = 0; 847 link = LIST_FIRST(&linkTableOut[cleanupIndex++]); 848 while (link != NULL) 849 { 850 int idelta; 851 struct alias_link *link_next; 852 853 link_next = LIST_NEXT(link, list_out); 854 idelta = timeStamp - link->timestamp; 855 switch (link->link_type) 856 { 857 case LINK_TCP: 858 if (idelta > link->expire_time) 859 { 860 struct tcp_dat *tcp_aux; 861 862 tcp_aux = link->data.tcp; 863 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 864 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) 865 { 866 DeleteLink(link); 867 icount++; 868 } 869 } 870 break; 871 default: 872 if (idelta > link->expire_time) 873 { 874 DeleteLink(link); 875 icount++; 876 } 877 break; 878 } 879 link = link_next; 880 } 881 882 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 883 cleanupIndex = 0; 884} 885 886static void 887DeleteLink(struct alias_link *link) 888{ 889 890/* Don't do anything if the link is marked permanent */ 891 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 892 return; 893 894#ifndef NO_FW_PUNCH 895/* Delete associated firewall hole, if any */ 896 ClearFWHole(link); 897#endif 898 899/* Free memory allocated for LSNAT server pool */ 900 if (link->server != NULL) { 901 struct server *head, *curr, *next; 902 903 head = curr = link->server; 904 do { 905 next = curr->next; 906 free(curr); 907 } while ((curr = next) != head); 908 } 909 910/* Adjust output table pointers */ 911 LIST_REMOVE(link, list_out); 912 913/* Adjust input table pointers */ 914 LIST_REMOVE(link, list_in); 915 916/* Close socket, if one has been allocated */ 917 if (link->sockfd != -1) 918 { 919 sockCount--; 920 close(link->sockfd); 921 } 922 923/* Link-type dependent cleanup */ 924 switch(link->link_type) 925 { 926 case LINK_ICMP: 927 icmpLinkCount--; 928 break; 929 case LINK_UDP: 930 udpLinkCount--; 931 break; 932 case LINK_TCP: 933 tcpLinkCount--;
| 119*/ 120 121 122/* System include files */ 123#include <errno.h> 124#include <stdlib.h> 125#include <stdio.h> 126#include <unistd.h> 127 128#include <sys/queue.h> 129#include <sys/socket.h> 130#include <sys/time.h> 131#include <sys/types.h> 132 133/* BSD network include files */ 134#include <netinet/in_systm.h> 135#include <netinet/in.h> 136#include <netinet/ip.h> 137#include <netinet/tcp.h> 138#include <arpa/inet.h> 139 140#include "alias.h" 141#include "alias_local.h" 142 143 144 145/* 146 Constants (note: constants are also defined 147 near relevant functions or structs) 148*/ 149 150/* Sizes of input and output link tables */ 151#define LINK_TABLE_OUT_SIZE 101 152#define LINK_TABLE_IN_SIZE 4001 153 154/* Parameters used for cleanup of expired links */ 155#define ALIAS_CLEANUP_INTERVAL_SECS 60 156#define ALIAS_CLEANUP_MAX_SPOKES 30 157 158/* Timeouts (in seconds) for different link types */ 159#define ICMP_EXPIRE_TIME 60 160#define UDP_EXPIRE_TIME 60 161#define PPTP_EXPIRE_TIME 60 162#define PROTO_EXPIRE_TIME 60 163#define FRAGMENT_ID_EXPIRE_TIME 10 164#define FRAGMENT_PTR_EXPIRE_TIME 30 165 166/* TCP link expire time for different cases */ 167/* When the link has been used and closed - minimal grace time to 168 allow ACKs and potential re-connect in FTP (XXX - is this allowed?) */ 169#ifndef TCP_EXPIRE_DEAD 170# define TCP_EXPIRE_DEAD 10 171#endif 172 173/* When the link has been used and closed on one side - the other side 174 is allowed to still send data */ 175#ifndef TCP_EXPIRE_SINGLEDEAD 176# define TCP_EXPIRE_SINGLEDEAD 90 177#endif 178 179/* When the link isn't yet up */ 180#ifndef TCP_EXPIRE_INITIAL 181# define TCP_EXPIRE_INITIAL 300 182#endif 183 184/* When the link is up */ 185#ifndef TCP_EXPIRE_CONNECTED 186# define TCP_EXPIRE_CONNECTED 86400 187#endif 188 189 190/* Dummy port number codes used for FindLinkIn/Out() and AddLink(). 191 These constants can be anything except zero, which indicates an 192 unknown port number. */ 193 194#define NO_DEST_PORT 1 195#define NO_SRC_PORT 1 196 197 198 199/* Data Structures 200 201 The fundamental data structure used in this program is 202 "struct alias_link". Whenever a TCP connection is made, 203 a UDP datagram is sent out, or an ICMP echo request is made, 204 a link record is made (if it has not already been created). 205 The link record is identified by the source address/port 206 and the destination address/port. In the case of an ICMP 207 echo request, the source port is treated as being equivalent 208 with the 16-bit ID number of the ICMP packet. 209 210 The link record also can store some auxiliary data. For 211 TCP connections that have had sequence and acknowledgment 212 modifications, data space is available to track these changes. 213 A state field is used to keep track in changes to the TCP 214 connection state. ID numbers of fragments can also be 215 stored in the auxiliary space. Pointers to unresolved 216 fragments can also be stored. 217 218 The link records support two independent chainings. Lookup 219 tables for input and out tables hold the initial pointers 220 the link chains. On input, the lookup table indexes on alias 221 port and link type. On output, the lookup table indexes on 222 source address, destination address, source port, destination 223 port and link type. 224*/ 225 226struct ack_data_record /* used to save changes to ACK/sequence numbers */ 227{ 228 u_long ack_old; 229 u_long ack_new; 230 int delta; 231 int active; 232}; 233 234struct tcp_state /* Information about TCP connection */ 235{ 236 int in; /* State for outside -> inside */ 237 int out; /* State for inside -> outside */ 238 int index; /* Index to ACK data array */ 239 int ack_modified; /* Indicates whether ACK and sequence numbers */ 240 /* been modified */ 241}; 242 243#define N_LINK_TCP_DATA 3 /* Number of distinct ACK number changes 244 saved for a modified TCP stream */ 245struct tcp_dat 246{ 247 struct tcp_state state; 248 struct ack_data_record ack[N_LINK_TCP_DATA]; 249 int fwhole; /* Which firewall record is used for this hole? */ 250}; 251 252struct server /* LSNAT server pool (circular list) */ 253{ 254 struct in_addr addr; 255 u_short port; 256 struct server *next; 257}; 258 259struct alias_link /* Main data structure */ 260{ 261 struct in_addr src_addr; /* Address and port information */ 262 struct in_addr dst_addr; 263 struct in_addr alias_addr; 264 struct in_addr proxy_addr; 265 u_short src_port; 266 u_short dst_port; 267 u_short alias_port; 268 u_short proxy_port; 269 struct server *server; 270 271 int link_type; /* Type of link: TCP, UDP, ICMP, proto, frag */ 272 273/* values for link_type */ 274#define LINK_ICMP IPPROTO_ICMP 275#define LINK_UDP IPPROTO_UDP 276#define LINK_TCP IPPROTO_TCP 277#define LINK_FRAGMENT_ID (IPPROTO_MAX + 1) 278#define LINK_FRAGMENT_PTR (IPPROTO_MAX + 2) 279#define LINK_ADDR (IPPROTO_MAX + 3) 280#define LINK_PPTP (IPPROTO_MAX + 4) 281 282 int flags; /* indicates special characteristics */ 283 284/* flag bits */ 285#define LINK_UNKNOWN_DEST_PORT 0x01 286#define LINK_UNKNOWN_DEST_ADDR 0x02 287#define LINK_PERMANENT 0x04 288#define LINK_PARTIALLY_SPECIFIED 0x03 /* logical-or of first two bits */ 289#define LINK_UNFIREWALLED 0x08 290#define LINK_LAST_LINE_CRLF_TERMED 0x10 291 292 int timestamp; /* Time link was last accessed */ 293 int expire_time; /* Expire time for link */ 294 295 int sockfd; /* socket descriptor */ 296 297 LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for */ 298 LIST_ENTRY(alias_link) list_in; /* input and output lookup tables */ 299 300 union /* Auxiliary data */ 301 { 302 char *frag_ptr; 303 struct in_addr frag_addr; 304 struct tcp_dat *tcp; 305 } data; 306}; 307 308 309 310 311 312/* Global Variables 313 314 The global variables listed here are only accessed from 315 within alias_db.c and so are prefixed with the static 316 designation. 317*/ 318 319int packetAliasMode; /* Mode flags */ 320 /* - documented in alias.h */ 321 322static struct in_addr aliasAddress; /* Address written onto source */ 323 /* field of IP packet. */ 324 325static struct in_addr targetAddress; /* IP address incoming packets */ 326 /* are sent to if no aliasing */ 327 /* link already exists */ 328 329static struct in_addr nullAddress; /* Used as a dummy parameter for */ 330 /* some function calls */ 331static LIST_HEAD(, alias_link) 332linkTableOut[LINK_TABLE_OUT_SIZE]; /* Lookup table of pointers to */ 333 /* chains of link records. Each */ 334static LIST_HEAD(, alias_link) /* link record is doubly indexed */ 335linkTableIn[LINK_TABLE_IN_SIZE]; /* into input and output lookup */ 336 /* tables. */ 337 338static int icmpLinkCount; /* Link statistics */ 339static int udpLinkCount; 340static int tcpLinkCount; 341static int pptpLinkCount; 342static int protoLinkCount; 343static int fragmentIdLinkCount; 344static int fragmentPtrLinkCount; 345static int sockCount; 346 347static int cleanupIndex; /* Index to chain of link table */ 348 /* being inspected for old links */ 349 350static int timeStamp; /* System time in seconds for */ 351 /* current packet */ 352 353static int lastCleanupTime; /* Last time IncrementalCleanup() */ 354 /* was called */ 355 356static int houseKeepingResidual; /* used by HouseKeeping() */ 357 358static int deleteAllLinks; /* If equal to zero, DeleteLink() */ 359 /* will not remove permanent links */ 360 361static FILE *monitorFile; /* File descriptor for link */ 362 /* statistics monitoring file */ 363 364static int newDefaultLink; /* Indicates if a new aliasing */ 365 /* link has been created after a */ 366 /* call to PacketAliasIn/Out(). */ 367 368#ifndef NO_FW_PUNCH 369static int fireWallFD = -1; /* File descriptor to be able to */ 370 /* control firewall. Opened by */ 371 /* PacketAliasSetMode on first */ 372 /* setting the PKT_ALIAS_PUNCH_FW */ 373 /* flag. */ 374#endif 375 376 377 378 379 380 381 382/* Internal utility routines (used only in alias_db.c) 383 384Lookup table starting points: 385 StartPointIn() -- link table initial search point for 386 incoming packets 387 StartPointOut() -- link table initial search point for 388 outgoing packets 389 390Miscellaneous: 391 SeqDiff() -- difference between two TCP sequences 392 ShowAliasStats() -- send alias statistics to a monitor file 393*/ 394 395 396/* Local prototypes */ 397static u_int StartPointIn(struct in_addr, u_short, int); 398 399static u_int StartPointOut(struct in_addr, struct in_addr, 400 u_short, u_short, int); 401 402static int SeqDiff(u_long, u_long); 403 404static void ShowAliasStats(void); 405 406#ifndef NO_FW_PUNCH 407/* Firewall control */ 408static void InitPunchFW(void); 409static void UninitPunchFW(void); 410static void ClearFWHole(struct alias_link *link); 411#endif 412 413/* Log file control */ 414static void InitPacketAliasLog(void); 415static void UninitPacketAliasLog(void); 416 417static u_int 418StartPointIn(struct in_addr alias_addr, 419 u_short alias_port, 420 int link_type) 421{ 422 u_int n; 423 424 n = alias_addr.s_addr; 425 n += alias_port; 426 n += link_type; 427 return(n % LINK_TABLE_IN_SIZE); 428} 429 430 431static u_int 432StartPointOut(struct in_addr src_addr, struct in_addr dst_addr, 433 u_short src_port, u_short dst_port, int link_type) 434{ 435 u_int n; 436 437 n = src_addr.s_addr; 438 n += dst_addr.s_addr; 439 n += src_port; 440 n += dst_port; 441 n += link_type; 442 443 return(n % LINK_TABLE_OUT_SIZE); 444} 445 446 447static int 448SeqDiff(u_long x, u_long y) 449{ 450/* Return the difference between two TCP sequence numbers */ 451 452/* 453 This function is encapsulated in case there are any unusual 454 arithmetic conditions that need to be considered. 455*/ 456 457 return (ntohl(y) - ntohl(x)); 458} 459 460 461static void 462ShowAliasStats(void) 463{ 464/* Used for debugging */ 465 466 if (monitorFile) 467 { 468 fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d", 469 icmpLinkCount, 470 udpLinkCount, 471 tcpLinkCount, 472 pptpLinkCount, 473 protoLinkCount, 474 fragmentIdLinkCount, 475 fragmentPtrLinkCount); 476 477 fprintf(monitorFile, " / tot=%d (sock=%d)\n", 478 icmpLinkCount + udpLinkCount 479 + tcpLinkCount 480 + pptpLinkCount 481 + protoLinkCount 482 + fragmentIdLinkCount 483 + fragmentPtrLinkCount, 484 sockCount); 485 486 fflush(monitorFile); 487 } 488} 489 490 491 492 493 494/* Internal routines for finding, deleting and adding links 495 496Port Allocation: 497 GetNewPort() -- find and reserve new alias port number 498 GetSocket() -- try to allocate a socket for a given port 499 500Link creation and deletion: 501 CleanupAliasData() - remove all link chains from lookup table 502 IncrementalCleanup() - look for stale links in a single chain 503 DeleteLink() - remove link 504 AddLink() - add link 505 ReLink() - change link 506 507Link search: 508 FindLinkOut() - find link for outgoing packets 509 FindLinkIn() - find link for incoming packets 510 511Port search: 512 FindNewPortGroup() - find an available group of ports 513*/ 514 515/* Local prototypes */ 516static int GetNewPort(struct alias_link *, int); 517 518static u_short GetSocket(u_short, int *, int); 519 520static void CleanupAliasData(void); 521 522static void IncrementalCleanup(void); 523 524static void DeleteLink(struct alias_link *); 525 526static struct alias_link * 527AddLink(struct in_addr, struct in_addr, struct in_addr, 528 u_short, u_short, int, int); 529 530static struct alias_link * 531ReLink(struct alias_link *, 532 struct in_addr, struct in_addr, struct in_addr, 533 u_short, u_short, int, int); 534 535static struct alias_link * 536FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int); 537 538static struct alias_link * 539FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int); 540 541 542#define ALIAS_PORT_BASE 0x08000 543#define ALIAS_PORT_MASK 0x07fff 544#define ALIAS_PORT_MASK_EVEN 0x07ffe 545#define GET_NEW_PORT_MAX_ATTEMPTS 20 546 547#define GET_ALIAS_PORT -1 548#define GET_ALIAS_ID GET_ALIAS_PORT 549 550#define FIND_EVEN_ALIAS_BASE 1 551 552/* GetNewPort() allocates port numbers. Note that if a port number 553 is already in use, that does not mean that it cannot be used by 554 another link concurrently. This is because GetNewPort() looks for 555 unused triplets: (dest addr, dest port, alias port). */ 556 557static int 558GetNewPort(struct alias_link *link, int alias_port_param) 559{ 560 int i; 561 int max_trials; 562 u_short port_sys; 563 u_short port_net; 564 565/* 566 Description of alias_port_param for GetNewPort(). When 567 this parameter is zero or positive, it precisely specifies 568 the port number. GetNewPort() will return this number 569 without check that it is in use. 570 571 When this parameter is GET_ALIAS_PORT, it indicates to get a randomly 572 selected port number. 573*/ 574 575 if (alias_port_param == GET_ALIAS_PORT) 576 { 577 /* 578 * The aliasing port is automatically selected 579 * by one of two methods below: 580 */ 581 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 582 583 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) 584 { 585 /* 586 * When the PKT_ALIAS_SAME_PORTS option is 587 * chosen, the first try will be the 588 * actual source port. If this is already 589 * in use, the remainder of the trials 590 * will be random. 591 */ 592 port_net = link->src_port; 593 port_sys = ntohs(port_net); 594 } 595 else 596 { 597 /* First trial and all subsequent are random. */ 598 port_sys = random() & ALIAS_PORT_MASK; 599 port_sys += ALIAS_PORT_BASE; 600 port_net = htons(port_sys); 601 } 602 } 603 else if (alias_port_param >= 0 && alias_port_param < 0x10000) 604 { 605 link->alias_port = (u_short) alias_port_param; 606 return(0); 607 } 608 else 609 { 610#ifdef DEBUG 611 fprintf(stderr, "PacketAlias/GetNewPort(): "); 612 fprintf(stderr, "input parameter error\n"); 613#endif 614 return(-1); 615 } 616 617 618/* Port number search */ 619 for (i=0; i<max_trials; i++) 620 { 621 int go_ahead; 622 struct alias_link *search_result; 623 624 search_result = FindLinkIn(link->dst_addr, link->alias_addr, 625 link->dst_port, port_net, 626 link->link_type, 0); 627 628 if (search_result == NULL) 629 go_ahead = 1; 630 else if (!(link->flags & LINK_PARTIALLY_SPECIFIED) 631 && (search_result->flags & LINK_PARTIALLY_SPECIFIED)) 632 go_ahead = 1; 633 else 634 go_ahead = 0; 635 636 if (go_ahead) 637 { 638 if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS) 639 && (link->flags & LINK_PARTIALLY_SPECIFIED) 640 && ((link->link_type == LINK_TCP) || 641 (link->link_type == LINK_UDP))) 642 { 643 if (GetSocket(port_net, &link->sockfd, link->link_type)) 644 { 645 link->alias_port = port_net; 646 return(0); 647 } 648 } 649 else 650 { 651 link->alias_port = port_net; 652 return(0); 653 } 654 } 655 656 port_sys = random() & ALIAS_PORT_MASK; 657 port_sys += ALIAS_PORT_BASE; 658 port_net = htons(port_sys); 659 } 660 661#ifdef DEBUG 662 fprintf(stderr, "PacketAlias/GetnewPort(): "); 663 fprintf(stderr, "could not find free port\n"); 664#endif 665 666 return(-1); 667} 668 669 670static u_short 671GetSocket(u_short port_net, int *sockfd, int link_type) 672{ 673 int err; 674 int sock; 675 struct sockaddr_in sock_addr; 676 677 if (link_type == LINK_TCP) 678 sock = socket(AF_INET, SOCK_STREAM, 0); 679 else if (link_type == LINK_UDP) 680 sock = socket(AF_INET, SOCK_DGRAM, 0); 681 else 682 { 683#ifdef DEBUG 684 fprintf(stderr, "PacketAlias/GetSocket(): "); 685 fprintf(stderr, "incorrect link type\n"); 686#endif 687 return(0); 688 } 689 690 if (sock < 0) 691 { 692#ifdef DEBUG 693 fprintf(stderr, "PacketAlias/GetSocket(): "); 694 fprintf(stderr, "socket() error %d\n", *sockfd); 695#endif 696 return(0); 697 } 698 699 sock_addr.sin_family = AF_INET; 700 sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 701 sock_addr.sin_port = port_net; 702 703 err = bind(sock, 704 (struct sockaddr *) &sock_addr, 705 sizeof(sock_addr)); 706 if (err == 0) 707 { 708 sockCount++; 709 *sockfd = sock; 710 return(1); 711 } 712 else 713 { 714 close(sock); 715 return(0); 716 } 717} 718 719 720/* FindNewPortGroup() returns a base port number for an available 721 range of contiguous port numbers. Note that if a port number 722 is already in use, that does not mean that it cannot be used by 723 another link concurrently. This is because FindNewPortGroup() 724 looks for unused triplets: (dest addr, dest port, alias port). */ 725 726int 727FindNewPortGroup(struct in_addr dst_addr, 728 struct in_addr alias_addr, 729 u_short src_port, 730 u_short dst_port, 731 u_short port_count, 732 u_char proto, 733 u_char align) 734{ 735 int i, j; 736 int max_trials; 737 u_short port_sys; 738 int link_type; 739 740 /* 741 * Get link_type from protocol 742 */ 743 744 switch (proto) 745 { 746 case IPPROTO_UDP: 747 link_type = LINK_UDP; 748 break; 749 case IPPROTO_TCP: 750 link_type = LINK_TCP; 751 break; 752 default: 753 return (0); 754 break; 755 } 756 757 /* 758 * The aliasing port is automatically selected 759 * by one of two methods below: 760 */ 761 max_trials = GET_NEW_PORT_MAX_ATTEMPTS; 762 763 if (packetAliasMode & PKT_ALIAS_SAME_PORTS) { 764 /* 765 * When the ALIAS_SAME_PORTS option is 766 * chosen, the first try will be the 767 * actual source port. If this is already 768 * in use, the remainder of the trials 769 * will be random. 770 */ 771 port_sys = ntohs(src_port); 772 773 } else { 774 775 /* First trial and all subsequent are random. */ 776 if (align == FIND_EVEN_ALIAS_BASE) 777 port_sys = random() & ALIAS_PORT_MASK_EVEN; 778 else 779 port_sys = random() & ALIAS_PORT_MASK; 780 781 port_sys += ALIAS_PORT_BASE; 782 } 783 784/* Port number search */ 785 for (i = 0; i < max_trials; i++) { 786 787 struct alias_link *search_result; 788 789 for (j = 0; j < port_count; j++) 790 if (0 != (search_result = FindLinkIn(dst_addr, alias_addr, 791 dst_port, htons(port_sys + j), 792 link_type, 0))) 793 break; 794 795 /* Found a good range, return base */ 796 if (j == port_count) 797 return (htons(port_sys)); 798 799 /* Find a new base to try */ 800 if (align == FIND_EVEN_ALIAS_BASE) 801 port_sys = random() & ALIAS_PORT_MASK_EVEN; 802 else 803 port_sys = random() & ALIAS_PORT_MASK; 804 805 port_sys += ALIAS_PORT_BASE; 806 } 807 808#ifdef DEBUG 809 fprintf(stderr, "PacketAlias/FindNewPortGroup(): "); 810 fprintf(stderr, "could not find free port(s)\n"); 811#endif 812 813 return(0); 814} 815 816static void 817CleanupAliasData(void) 818{ 819 struct alias_link *link; 820 int i, icount; 821 822 icount = 0; 823 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 824 { 825 link = LIST_FIRST(&linkTableOut[i]); 826 while (link != NULL) 827 { 828 struct alias_link *link_next; 829 link_next = LIST_NEXT(link, list_out); 830 icount++; 831 DeleteLink(link); 832 link = link_next; 833 } 834 } 835 836 cleanupIndex =0; 837} 838 839 840static void 841IncrementalCleanup(void) 842{ 843 int icount; 844 struct alias_link *link; 845 846 icount = 0; 847 link = LIST_FIRST(&linkTableOut[cleanupIndex++]); 848 while (link != NULL) 849 { 850 int idelta; 851 struct alias_link *link_next; 852 853 link_next = LIST_NEXT(link, list_out); 854 idelta = timeStamp - link->timestamp; 855 switch (link->link_type) 856 { 857 case LINK_TCP: 858 if (idelta > link->expire_time) 859 { 860 struct tcp_dat *tcp_aux; 861 862 tcp_aux = link->data.tcp; 863 if (tcp_aux->state.in != ALIAS_TCP_STATE_CONNECTED 864 || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED) 865 { 866 DeleteLink(link); 867 icount++; 868 } 869 } 870 break; 871 default: 872 if (idelta > link->expire_time) 873 { 874 DeleteLink(link); 875 icount++; 876 } 877 break; 878 } 879 link = link_next; 880 } 881 882 if (cleanupIndex == LINK_TABLE_OUT_SIZE) 883 cleanupIndex = 0; 884} 885 886static void 887DeleteLink(struct alias_link *link) 888{ 889 890/* Don't do anything if the link is marked permanent */ 891 if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT) 892 return; 893 894#ifndef NO_FW_PUNCH 895/* Delete associated firewall hole, if any */ 896 ClearFWHole(link); 897#endif 898 899/* Free memory allocated for LSNAT server pool */ 900 if (link->server != NULL) { 901 struct server *head, *curr, *next; 902 903 head = curr = link->server; 904 do { 905 next = curr->next; 906 free(curr); 907 } while ((curr = next) != head); 908 } 909 910/* Adjust output table pointers */ 911 LIST_REMOVE(link, list_out); 912 913/* Adjust input table pointers */ 914 LIST_REMOVE(link, list_in); 915 916/* Close socket, if one has been allocated */ 917 if (link->sockfd != -1) 918 { 919 sockCount--; 920 close(link->sockfd); 921 } 922 923/* Link-type dependent cleanup */ 924 switch(link->link_type) 925 { 926 case LINK_ICMP: 927 icmpLinkCount--; 928 break; 929 case LINK_UDP: 930 udpLinkCount--; 931 break; 932 case LINK_TCP: 933 tcpLinkCount--;
|
1131 old_link->data.tcp->fwhole > 0) { 1132 PunchFWHole(new_link); 1133 } 1134#endif 1135 DeleteLink(old_link); 1136 return new_link; 1137} 1138 1139static struct alias_link * 1140_FindLinkOut(struct in_addr src_addr, 1141 struct in_addr dst_addr, 1142 u_short src_port, 1143 u_short dst_port, 1144 int link_type, 1145 int replace_partial_links) 1146{ 1147 u_int i; 1148 struct alias_link *link; 1149 1150 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1151 LIST_FOREACH(link, &linkTableOut[i], list_out) 1152 { 1153 if (link->src_addr.s_addr == src_addr.s_addr 1154 && link->server == NULL 1155 && link->dst_addr.s_addr == dst_addr.s_addr 1156 && link->dst_port == dst_port 1157 && link->src_port == src_port 1158 && link->link_type == link_type) 1159 { 1160 link->timestamp = timeStamp; 1161 break; 1162 } 1163 } 1164 1165/* Search for partially specified links. */ 1166 if (link == NULL && replace_partial_links) 1167 { 1168 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) 1169 { 1170 link = _FindLinkOut(src_addr, dst_addr, src_port, 0, 1171 link_type, 0); 1172 if (link == NULL) 1173 link = _FindLinkOut(src_addr, nullAddress, src_port, 1174 dst_port, link_type, 0); 1175 } 1176 if (link == NULL && 1177 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) 1178 { 1179 link = _FindLinkOut(src_addr, nullAddress, src_port, 0, 1180 link_type, 0); 1181 } 1182 if (link != NULL) 1183 { 1184 link = ReLink(link, 1185 src_addr, dst_addr, link->alias_addr, 1186 src_port, dst_port, link->alias_port, 1187 link_type); 1188 } 1189 } 1190 1191 return(link); 1192} 1193 1194static struct alias_link * 1195FindLinkOut(struct in_addr src_addr, 1196 struct in_addr dst_addr, 1197 u_short src_port, 1198 u_short dst_port, 1199 int link_type, 1200 int replace_partial_links) 1201{ 1202 struct alias_link *link; 1203 1204 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port, 1205 link_type, replace_partial_links); 1206 1207 if (link == NULL) 1208 { 1209 /* The following allows permanent links to be 1210 specified as using the default source address 1211 (i.e. device interface address) without knowing 1212 in advance what that address is. */ 1213 if (aliasAddress.s_addr != 0 && 1214 src_addr.s_addr == aliasAddress.s_addr) 1215 { 1216 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port, 1217 link_type, replace_partial_links); 1218 } 1219 } 1220 1221 return(link); 1222} 1223 1224 1225static struct alias_link * 1226_FindLinkIn(struct in_addr dst_addr, 1227 struct in_addr alias_addr, 1228 u_short dst_port, 1229 u_short alias_port, 1230 int link_type, 1231 int replace_partial_links) 1232{ 1233 int flags_in; 1234 u_int start_point; 1235 struct alias_link *link; 1236 struct alias_link *link_fully_specified; 1237 struct alias_link *link_unknown_all; 1238 struct alias_link *link_unknown_dst_addr; 1239 struct alias_link *link_unknown_dst_port; 1240 1241/* Initialize pointers */ 1242 link_fully_specified = NULL; 1243 link_unknown_all = NULL; 1244 link_unknown_dst_addr = NULL; 1245 link_unknown_dst_port = NULL; 1246 1247/* If either the dest addr or port is unknown, the search 1248 loop will have to know about this. */ 1249 1250 flags_in = 0; 1251 if (dst_addr.s_addr == INADDR_ANY) 1252 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1253 if (dst_port == 0) 1254 flags_in |= LINK_UNKNOWN_DEST_PORT; 1255 1256/* Search loop */ 1257 start_point = StartPointIn(alias_addr, alias_port, link_type); 1258 LIST_FOREACH(link, &linkTableIn[start_point], list_in) 1259 { 1260 int flags; 1261 1262 flags = flags_in | link->flags; 1263 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1264 { 1265 if (link->alias_addr.s_addr == alias_addr.s_addr 1266 && link->alias_port == alias_port 1267 && link->dst_addr.s_addr == dst_addr.s_addr 1268 && link->dst_port == dst_port 1269 && link->link_type == link_type) 1270 { 1271 link_fully_specified = link; 1272 break; 1273 } 1274 } 1275 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1276 && (flags & LINK_UNKNOWN_DEST_PORT)) 1277 { 1278 if (link->alias_addr.s_addr == alias_addr.s_addr 1279 && link->alias_port == alias_port 1280 && link->link_type == link_type) 1281 { 1282 if (link_unknown_all == NULL) 1283 link_unknown_all = link; 1284 } 1285 } 1286 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1287 { 1288 if (link->alias_addr.s_addr == alias_addr.s_addr 1289 && link->alias_port == alias_port 1290 && link->link_type == link_type 1291 && link->dst_port == dst_port) 1292 { 1293 if (link_unknown_dst_addr == NULL) 1294 link_unknown_dst_addr = link; 1295 } 1296 } 1297 else if (flags & LINK_UNKNOWN_DEST_PORT) 1298 { 1299 if (link->alias_addr.s_addr == alias_addr.s_addr 1300 && link->alias_port == alias_port 1301 && link->link_type == link_type 1302 && link->dst_addr.s_addr == dst_addr.s_addr) 1303 { 1304 if (link_unknown_dst_port == NULL) 1305 link_unknown_dst_port = link; 1306 } 1307 } 1308 } 1309 1310 1311 1312 if (link_fully_specified != NULL) 1313 { 1314 link_fully_specified->timestamp = timeStamp; 1315 link = link_fully_specified; 1316 } 1317 else if (link_unknown_dst_port != NULL) 1318 link = link_unknown_dst_port; 1319 else if (link_unknown_dst_addr != NULL) 1320 link = link_unknown_dst_addr; 1321 else if (link_unknown_all != NULL) 1322 link = link_unknown_all; 1323 else 1324 return (NULL); 1325 1326 if (replace_partial_links && 1327 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) 1328 { 1329 struct in_addr src_addr; 1330 u_short src_port; 1331 1332 if (link->server != NULL) { /* LSNAT link */ 1333 src_addr = link->server->addr; 1334 src_port = link->server->port; 1335 link->server = link->server->next; 1336 } else { 1337 src_addr = link->src_addr; 1338 src_port = link->src_port; 1339 } 1340 1341 link = ReLink(link, 1342 src_addr, dst_addr, alias_addr, 1343 src_port, dst_port, alias_port, 1344 link_type); 1345 } 1346 1347 return (link); 1348} 1349 1350static struct alias_link * 1351FindLinkIn(struct in_addr dst_addr, 1352 struct in_addr alias_addr, 1353 u_short dst_port, 1354 u_short alias_port, 1355 int link_type, 1356 int replace_partial_links) 1357{ 1358 struct alias_link *link; 1359 1360 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, 1361 link_type, replace_partial_links); 1362 1363 if (link == NULL) 1364 { 1365 /* The following allows permanent links to be 1366 specified as using the default aliasing address 1367 (i.e. device interface address) without knowing 1368 in advance what that address is. */ 1369 if (aliasAddress.s_addr != 0 && 1370 alias_addr.s_addr == aliasAddress.s_addr) 1371 { 1372 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port, 1373 link_type, replace_partial_links); 1374 } 1375 } 1376 1377 return(link); 1378} 1379 1380 1381 1382 1383/* External routines for finding/adding links 1384 1385-- "external" means outside alias_db.c, but within alias*.c -- 1386 1387 FindIcmpIn(), FindIcmpOut() 1388 FindFragmentIn1(), FindFragmentIn2() 1389 AddFragmentPtrLink(), FindFragmentPtr() 1390 FindProtoIn(), FindProtoOut() 1391 FindUdpTcpIn(), FindUdpTcpOut() 1392 FindPptpIn(), FindPptpOut() 1393 FindOriginalAddress(), FindAliasAddress() 1394 1395(prototypes in alias_local.h) 1396*/ 1397 1398 1399struct alias_link * 1400FindIcmpIn(struct in_addr dst_addr, 1401 struct in_addr alias_addr, 1402 u_short id_alias) 1403{ 1404 struct alias_link *link; 1405 1406 link = FindLinkIn(dst_addr, alias_addr, 1407 NO_DEST_PORT, id_alias, 1408 LINK_ICMP, 0); 1409 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1410 { 1411 struct in_addr target_addr; 1412 1413 target_addr = FindOriginalAddress(alias_addr); 1414 link = AddLink(target_addr, dst_addr, alias_addr, 1415 id_alias, NO_DEST_PORT, id_alias, 1416 LINK_ICMP); 1417 } 1418 1419 return (link); 1420} 1421 1422 1423struct alias_link * 1424FindIcmpOut(struct in_addr src_addr, 1425 struct in_addr dst_addr, 1426 u_short id) 1427{ 1428 struct alias_link * link; 1429 1430 link = FindLinkOut(src_addr, dst_addr, 1431 id, NO_DEST_PORT, 1432 LINK_ICMP, 0); 1433 if (link == NULL) 1434 { 1435 struct in_addr alias_addr; 1436 1437 alias_addr = FindAliasAddress(src_addr); 1438 link = AddLink(src_addr, dst_addr, alias_addr, 1439 id, NO_DEST_PORT, GET_ALIAS_ID, 1440 LINK_ICMP); 1441 } 1442 1443 return(link); 1444} 1445 1446 1447struct alias_link * 1448FindFragmentIn1(struct in_addr dst_addr, 1449 struct in_addr alias_addr, 1450 u_short ip_id) 1451{ 1452 struct alias_link *link; 1453 1454 link = FindLinkIn(dst_addr, alias_addr, 1455 NO_DEST_PORT, ip_id, 1456 LINK_FRAGMENT_ID, 0); 1457 1458 if (link == NULL) 1459 { 1460 link = AddLink(nullAddress, dst_addr, alias_addr, 1461 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1462 LINK_FRAGMENT_ID); 1463 } 1464 1465 return(link); 1466} 1467 1468 1469struct alias_link * 1470FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1471 struct in_addr alias_addr, /* is not found. */ 1472 u_short ip_id) 1473{ 1474 return FindLinkIn(dst_addr, alias_addr, 1475 NO_DEST_PORT, ip_id, 1476 LINK_FRAGMENT_ID, 0); 1477} 1478 1479 1480struct alias_link * 1481AddFragmentPtrLink(struct in_addr dst_addr, 1482 u_short ip_id) 1483{ 1484 return AddLink(nullAddress, dst_addr, nullAddress, 1485 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1486 LINK_FRAGMENT_PTR); 1487} 1488 1489 1490struct alias_link * 1491FindFragmentPtr(struct in_addr dst_addr, 1492 u_short ip_id) 1493{ 1494 return FindLinkIn(dst_addr, nullAddress, 1495 NO_DEST_PORT, ip_id, 1496 LINK_FRAGMENT_PTR, 0); 1497} 1498 1499 1500struct alias_link * 1501FindProtoIn(struct in_addr dst_addr, 1502 struct in_addr alias_addr, 1503 u_char proto) 1504{ 1505 struct alias_link *link; 1506 1507 link = FindLinkIn(dst_addr, alias_addr, 1508 NO_DEST_PORT, 0, 1509 proto, 1); 1510 1511 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1512 { 1513 struct in_addr target_addr; 1514 1515 target_addr = FindOriginalAddress(alias_addr); 1516 link = AddLink(target_addr, dst_addr, alias_addr, 1517 NO_SRC_PORT, NO_DEST_PORT, 0, 1518 proto); 1519 } 1520 1521 return (link); 1522} 1523 1524 1525struct alias_link * 1526FindProtoOut(struct in_addr src_addr, 1527 struct in_addr dst_addr, 1528 u_char proto) 1529{ 1530 struct alias_link *link; 1531 1532 link = FindLinkOut(src_addr, dst_addr, 1533 NO_SRC_PORT, NO_DEST_PORT, 1534 proto, 1); 1535 1536 if (link == NULL) 1537 { 1538 struct in_addr alias_addr; 1539 1540 alias_addr = FindAliasAddress(src_addr); 1541 link = AddLink(src_addr, dst_addr, alias_addr, 1542 NO_SRC_PORT, NO_DEST_PORT, 0, 1543 proto); 1544 } 1545 1546 return (link); 1547} 1548 1549 1550struct alias_link * 1551FindUdpTcpIn(struct in_addr dst_addr, 1552 struct in_addr alias_addr, 1553 u_short dst_port, 1554 u_short alias_port, 1555 u_char proto) 1556{ 1557 int link_type; 1558 struct alias_link *link; 1559 1560 switch (proto) 1561 { 1562 case IPPROTO_UDP: 1563 link_type = LINK_UDP; 1564 break; 1565 case IPPROTO_TCP: 1566 link_type = LINK_TCP; 1567 break; 1568 default: 1569 return NULL; 1570 break; 1571 } 1572 1573 link = FindLinkIn(dst_addr, alias_addr, 1574 dst_port, alias_port, 1575 link_type, 1); 1576 1577 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING) 1578 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY) 1579 && link == NULL) 1580 { 1581 struct in_addr target_addr; 1582 1583 target_addr = FindOriginalAddress(alias_addr); 1584 link = AddLink(target_addr, dst_addr, alias_addr, 1585 alias_port, dst_port, alias_port, 1586 link_type); 1587 } 1588 1589 return(link); 1590} 1591 1592 1593struct alias_link * 1594FindUdpTcpOut(struct in_addr src_addr, 1595 struct in_addr dst_addr, 1596 u_short src_port, 1597 u_short dst_port, 1598 u_char proto) 1599{ 1600 int link_type; 1601 struct alias_link *link; 1602 1603 switch (proto) 1604 { 1605 case IPPROTO_UDP: 1606 link_type = LINK_UDP; 1607 break; 1608 case IPPROTO_TCP: 1609 link_type = LINK_TCP; 1610 break; 1611 default: 1612 return NULL; 1613 break; 1614 } 1615 1616 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, 1); 1617 1618 if (link == NULL) 1619 { 1620 struct in_addr alias_addr; 1621 1622 alias_addr = FindAliasAddress(src_addr); 1623 link = AddLink(src_addr, dst_addr, alias_addr, 1624 src_port, dst_port, GET_ALIAS_PORT, 1625 link_type); 1626 } 1627 1628 return(link); 1629} 1630 1631 1632struct alias_link * 1633FindPptpIn(struct in_addr dst_addr, 1634 struct in_addr alias_addr, 1635 u_short call_id) 1636{ 1637 struct alias_link *link; 1638 1639 link = FindLinkIn(dst_addr, alias_addr, 1640 NO_DEST_PORT, call_id, 1641 LINK_PPTP, 1); 1642 1643 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1644 { 1645 struct in_addr target_addr; 1646 1647 target_addr = FindOriginalAddress(alias_addr); 1648 link = AddLink(target_addr, dst_addr, alias_addr, 1649 call_id, NO_DEST_PORT, call_id, 1650 LINK_PPTP); 1651 } 1652 1653 return(link); 1654} 1655 1656 1657struct alias_link * 1658FindPptpOut(struct in_addr src_addr, 1659 struct in_addr dst_addr, 1660 u_short call_id) 1661{ 1662 struct alias_link *link; 1663 1664 link = FindLinkOut(src_addr, dst_addr, 1665 call_id, NO_DEST_PORT, 1666 LINK_PPTP, 1); 1667 1668 if (link == NULL) 1669 { 1670 struct in_addr alias_addr; 1671 1672 alias_addr = FindAliasAddress(src_addr); 1673 link = AddLink(src_addr, dst_addr, alias_addr, 1674 call_id, NO_DEST_PORT, GET_ALIAS_PORT, 1675 LINK_PPTP); 1676 } 1677 1678 return(link); 1679} 1680 1681 1682struct alias_link * 1683QueryUdpTcpIn(struct in_addr dst_addr, 1684 struct in_addr alias_addr, 1685 u_short dst_port, 1686 u_short alias_port, 1687 u_char proto) 1688{ 1689 int link_type; 1690 struct alias_link *link; 1691 1692 switch (proto) 1693 { 1694 case IPPROTO_UDP: 1695 link_type = LINK_UDP; 1696 break; 1697 case IPPROTO_TCP: 1698 link_type = LINK_TCP; 1699 break; 1700 default: 1701 return NULL; 1702 break; 1703 } 1704 1705 link = FindLinkIn(dst_addr, alias_addr, 1706 dst_port, alias_port, 1707 link_type, 0); 1708 1709 return(link); 1710} 1711 1712 1713struct alias_link * 1714QueryUdpTcpOut(struct in_addr src_addr, 1715 struct in_addr dst_addr, 1716 u_short src_port, 1717 u_short dst_port, 1718 u_char proto) 1719{ 1720 int link_type; 1721 struct alias_link *link; 1722 1723 switch (proto) 1724 { 1725 case IPPROTO_UDP: 1726 link_type = LINK_UDP; 1727 break; 1728 case IPPROTO_TCP: 1729 link_type = LINK_TCP; 1730 break; 1731 default: 1732 return NULL; 1733 break; 1734 } 1735 1736 link = FindLinkOut(src_addr, dst_addr, 1737 src_port, dst_port, 1738 link_type, 0); 1739 1740 return(link); 1741} 1742 1743 1744struct alias_link * 1745FindRtspOut(struct in_addr src_addr, 1746 struct in_addr dst_addr, 1747 u_short src_port, 1748 u_short alias_port, 1749 u_char proto) 1750{ 1751 int link_type; 1752 struct alias_link *link; 1753 1754 switch (proto) 1755 { 1756 case IPPROTO_UDP: 1757 link_type = LINK_UDP; 1758 break; 1759 case IPPROTO_TCP: 1760 link_type = LINK_TCP; 1761 break; 1762 default: 1763 return NULL; 1764 break; 1765 } 1766 1767 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1); 1768 1769 if (link == NULL) 1770 { 1771 struct in_addr alias_addr; 1772 1773 alias_addr = FindAliasAddress(src_addr); 1774 link = AddLink(src_addr, dst_addr, alias_addr, 1775 src_port, 0, alias_port, 1776 link_type); 1777 } 1778 1779 return(link); 1780} 1781 1782 1783struct in_addr 1784FindOriginalAddress(struct in_addr alias_addr) 1785{ 1786 struct alias_link *link; 1787 1788 link = FindLinkIn(nullAddress, alias_addr, 1789 0, 0, LINK_ADDR, 0); 1790 if (link == NULL) 1791 { 1792 newDefaultLink = 1; 1793 if (targetAddress.s_addr == INADDR_ANY) 1794 return alias_addr; 1795 else if (targetAddress.s_addr == INADDR_NONE) 1796 return aliasAddress; 1797 else 1798 return targetAddress; 1799 } 1800 else 1801 { 1802 if (link->server != NULL) { /* LSNAT link */ 1803 struct in_addr src_addr; 1804 1805 src_addr = link->server->addr; 1806 link->server = link->server->next; 1807 return (src_addr); 1808 } else if (link->src_addr.s_addr == INADDR_ANY) 1809 return aliasAddress; 1810 else 1811 return link->src_addr; 1812 } 1813} 1814 1815 1816struct in_addr 1817FindAliasAddress(struct in_addr original_addr) 1818{ 1819 struct alias_link *link; 1820 1821 link = FindLinkOut(original_addr, nullAddress, 1822 0, 0, LINK_ADDR, 0); 1823 if (link == NULL) 1824 { 1825 return aliasAddress; 1826 } 1827 else 1828 { 1829 if (link->alias_addr.s_addr == INADDR_ANY) 1830 return aliasAddress; 1831 else 1832 return link->alias_addr; 1833 } 1834} 1835 1836 1837/* External routines for getting or changing link data 1838 (external to alias_db.c, but internal to alias*.c) 1839 1840 SetFragmentData(), GetFragmentData() 1841 SetFragmentPtr(), GetFragmentPtr() 1842 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1843 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1844 GetOriginalPort(), GetAliasPort() 1845 SetAckModified(), GetAckModified() 1846 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1847 SetLastLineCrlfTermed(), GetLastLineCrlfTermed() 1848*/ 1849 1850 1851void 1852SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1853{ 1854 link->data.frag_addr = src_addr; 1855} 1856 1857 1858void 1859GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1860{ 1861 *src_addr = link->data.frag_addr; 1862} 1863 1864 1865void 1866SetFragmentPtr(struct alias_link *link, char *fptr) 1867{ 1868 link->data.frag_ptr = fptr; 1869} 1870 1871 1872void 1873GetFragmentPtr(struct alias_link *link, char **fptr) 1874{ 1875 *fptr = link->data.frag_ptr; 1876} 1877 1878 1879void 1880SetStateIn(struct alias_link *link, int state) 1881{ 1882 /* TCP input state */ 1883 switch (state) { 1884 case ALIAS_TCP_STATE_DISCONNECTED: 1885 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1886 link->expire_time = TCP_EXPIRE_DEAD; 1887 else 1888 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1889 break; 1890 case ALIAS_TCP_STATE_CONNECTED: 1891 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1892 link->expire_time = TCP_EXPIRE_CONNECTED; 1893 break; 1894 default: 1895 abort(); 1896 } 1897 link->data.tcp->state.in = state; 1898} 1899 1900 1901void 1902SetStateOut(struct alias_link *link, int state) 1903{ 1904 /* TCP output state */ 1905 switch (state) { 1906 case ALIAS_TCP_STATE_DISCONNECTED: 1907 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1908 link->expire_time = TCP_EXPIRE_DEAD; 1909 else 1910 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1911 break; 1912 case ALIAS_TCP_STATE_CONNECTED: 1913 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1914 link->expire_time = TCP_EXPIRE_CONNECTED; 1915 break; 1916 default: 1917 abort(); 1918 } 1919 link->data.tcp->state.out = state; 1920} 1921 1922 1923int 1924GetStateIn(struct alias_link *link) 1925{ 1926 /* TCP input state */ 1927 return link->data.tcp->state.in; 1928} 1929 1930 1931int 1932GetStateOut(struct alias_link *link) 1933{ 1934 /* TCP output state */ 1935 return link->data.tcp->state.out; 1936} 1937 1938 1939struct in_addr 1940GetOriginalAddress(struct alias_link *link) 1941{ 1942 if (link->src_addr.s_addr == INADDR_ANY) 1943 return aliasAddress; 1944 else 1945 return(link->src_addr); 1946} 1947 1948 1949struct in_addr 1950GetDestAddress(struct alias_link *link) 1951{ 1952 return(link->dst_addr); 1953} 1954 1955 1956struct in_addr 1957GetAliasAddress(struct alias_link *link) 1958{ 1959 if (link->alias_addr.s_addr == INADDR_ANY) 1960 return aliasAddress; 1961 else 1962 return link->alias_addr; 1963} 1964 1965 1966struct in_addr 1967GetDefaultAliasAddress() 1968{ 1969 return aliasAddress; 1970} 1971 1972 1973void 1974SetDefaultAliasAddress(struct in_addr alias_addr) 1975{ 1976 aliasAddress = alias_addr; 1977} 1978 1979 1980u_short 1981GetOriginalPort(struct alias_link *link) 1982{ 1983 return(link->src_port); 1984} 1985 1986 1987u_short 1988GetAliasPort(struct alias_link *link) 1989{ 1990 return(link->alias_port); 1991} 1992 1993#ifndef NO_FW_PUNCH 1994static u_short 1995GetDestPort(struct alias_link *link) 1996{ 1997 return(link->dst_port); 1998} 1999#endif 2000 2001void 2002SetAckModified(struct alias_link *link) 2003{ 2004/* Indicate that ACK numbers have been modified in a TCP connection */ 2005 link->data.tcp->state.ack_modified = 1; 2006} 2007 2008 2009struct in_addr 2010GetProxyAddress(struct alias_link *link) 2011{ 2012 return link->proxy_addr; 2013} 2014 2015 2016void 2017SetProxyAddress(struct alias_link *link, struct in_addr addr) 2018{ 2019 link->proxy_addr = addr; 2020} 2021 2022 2023u_short 2024GetProxyPort(struct alias_link *link) 2025{ 2026 return link->proxy_port; 2027} 2028 2029 2030void 2031SetProxyPort(struct alias_link *link, u_short port) 2032{ 2033 link->proxy_port = port; 2034} 2035 2036 2037int 2038GetAckModified(struct alias_link *link) 2039{ 2040/* See if ACK numbers have been modified */ 2041 return link->data.tcp->state.ack_modified; 2042} 2043 2044 2045int 2046GetDeltaAckIn(struct ip *pip, struct alias_link *link) 2047{ 2048/* 2049Find out how much the ACK number has been altered for an incoming 2050TCP packet. To do this, a circular list of ACK numbers where the TCP 2051packet size was altered is searched. 2052*/ 2053 2054 int i; 2055 struct tcphdr *tc; 2056 int delta, ack_diff_min; 2057 u_long ack; 2058 2059 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2060 ack = tc->th_ack; 2061 2062 delta = 0; 2063 ack_diff_min = -1; 2064 for (i=0; i<N_LINK_TCP_DATA; i++) 2065 { 2066 struct ack_data_record x; 2067 2068 x = link->data.tcp->ack[i]; 2069 if (x.active == 1) 2070 { 2071 int ack_diff; 2072 2073 ack_diff = SeqDiff(x.ack_new, ack); 2074 if (ack_diff >= 0) 2075 { 2076 if (ack_diff_min >= 0) 2077 { 2078 if (ack_diff < ack_diff_min) 2079 { 2080 delta = x.delta; 2081 ack_diff_min = ack_diff; 2082 } 2083 } 2084 else 2085 { 2086 delta = x.delta; 2087 ack_diff_min = ack_diff; 2088 } 2089 } 2090 } 2091 } 2092 return (delta); 2093} 2094 2095 2096int 2097GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 2098{ 2099/* 2100Find out how much the sequence number has been altered for an outgoing 2101TCP packet. To do this, a circular list of ACK numbers where the TCP 2102packet size was altered is searched. 2103*/ 2104 2105 int i; 2106 struct tcphdr *tc; 2107 int delta, seq_diff_min; 2108 u_long seq; 2109 2110 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2111 seq = tc->th_seq; 2112 2113 delta = 0; 2114 seq_diff_min = -1; 2115 for (i=0; i<N_LINK_TCP_DATA; i++) 2116 { 2117 struct ack_data_record x; 2118 2119 x = link->data.tcp->ack[i]; 2120 if (x.active == 1) 2121 { 2122 int seq_diff; 2123 2124 seq_diff = SeqDiff(x.ack_old, seq); 2125 if (seq_diff >= 0) 2126 { 2127 if (seq_diff_min >= 0) 2128 { 2129 if (seq_diff < seq_diff_min) 2130 { 2131 delta = x.delta; 2132 seq_diff_min = seq_diff; 2133 } 2134 } 2135 else 2136 { 2137 delta = x.delta; 2138 seq_diff_min = seq_diff; 2139 } 2140 } 2141 } 2142 } 2143 return (delta); 2144} 2145 2146 2147void 2148AddSeq(struct ip *pip, struct alias_link *link, int delta) 2149{ 2150/* 2151When a TCP packet has been altered in length, save this 2152information in a circular list. If enough packets have 2153been altered, then this list will begin to overwrite itself. 2154*/ 2155 2156 struct tcphdr *tc; 2157 struct ack_data_record x; 2158 int hlen, tlen, dlen; 2159 int i; 2160 2161 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2162 2163 hlen = (pip->ip_hl + tc->th_off) << 2; 2164 tlen = ntohs(pip->ip_len); 2165 dlen = tlen - hlen; 2166 2167 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 2168 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 2169 x.delta = delta; 2170 x.active = 1; 2171 2172 i = link->data.tcp->state.index; 2173 link->data.tcp->ack[i] = x; 2174 2175 i++; 2176 if (i == N_LINK_TCP_DATA) 2177 link->data.tcp->state.index = 0; 2178 else 2179 link->data.tcp->state.index = i; 2180} 2181 2182void 2183SetExpire(struct alias_link *link, int expire) 2184{ 2185 if (expire == 0) 2186 { 2187 link->flags &= ~LINK_PERMANENT; 2188 DeleteLink(link); 2189 } 2190 else if (expire == -1) 2191 { 2192 link->flags |= LINK_PERMANENT; 2193 } 2194 else if (expire > 0) 2195 { 2196 link->expire_time = expire; 2197 } 2198 else 2199 { 2200#ifdef DEBUG 2201 fprintf(stderr, "PacketAlias/SetExpire(): "); 2202 fprintf(stderr, "error in expire parameter\n"); 2203#endif 2204 } 2205} 2206 2207void 2208ClearCheckNewLink(void) 2209{ 2210 newDefaultLink = 0; 2211} 2212 2213void 2214SetLastLineCrlfTermed(struct alias_link *link, int yes) 2215{ 2216 2217 if (yes) 2218 link->flags |= LINK_LAST_LINE_CRLF_TERMED; 2219 else 2220 link->flags &= ~LINK_LAST_LINE_CRLF_TERMED; 2221} 2222 2223int 2224GetLastLineCrlfTermed(struct alias_link *link) 2225{ 2226 2227 return (link->flags & LINK_LAST_LINE_CRLF_TERMED); 2228} 2229 2230 2231/* Miscellaneous Functions 2232 2233 HouseKeeping() 2234 InitPacketAliasLog() 2235 UninitPacketAliasLog() 2236*/ 2237 2238/* 2239 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2240 is called to find and remove timed-out aliasing links. Logic exists 2241 to sweep through the entire table and linked list structure 2242 every 60 seconds. 2243 2244 (prototype in alias_local.h) 2245*/ 2246 2247void 2248HouseKeeping(void) 2249{ 2250 int i, n, n100; 2251 struct timeval tv; 2252 struct timezone tz; 2253 2254 /* 2255 * Save system time (seconds) in global variable timeStamp for 2256 * use by other functions. This is done so as not to unnecessarily 2257 * waste timeline by making system calls. 2258 */ 2259 gettimeofday(&tv, &tz); 2260 timeStamp = tv.tv_sec; 2261 2262 /* Compute number of spokes (output table link chains) to cover */ 2263 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 2264 n100 *= timeStamp - lastCleanupTime; 2265 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 2266 2267 n = n100/100; 2268 2269 /* Handle different cases */ 2270 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2271 { 2272 n = ALIAS_CLEANUP_MAX_SPOKES; 2273 lastCleanupTime = timeStamp; 2274 houseKeepingResidual = 0; 2275 2276 for (i=0; i<n; i++) 2277 IncrementalCleanup(); 2278 } 2279 else if (n > 0) 2280 { 2281 lastCleanupTime = timeStamp; 2282 houseKeepingResidual = n100 - 100*n; 2283 2284 for (i=0; i<n; i++) 2285 IncrementalCleanup(); 2286 } 2287 else if (n < 0) 2288 { 2289#ifdef DEBUG 2290 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2291 fprintf(stderr, "something unexpected in time values\n"); 2292#endif 2293 lastCleanupTime = timeStamp; 2294 houseKeepingResidual = 0; 2295 } 2296} 2297 2298 2299/* Init the log file and enable logging */ 2300static void 2301InitPacketAliasLog(void) 2302{ 2303 if ((~packetAliasMode & PKT_ALIAS_LOG) 2304 && (monitorFile = fopen("/var/log/alias.log", "w"))) 2305 { 2306 packetAliasMode |= PKT_ALIAS_LOG; 2307 fprintf(monitorFile, 2308 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2309 } 2310} 2311 2312 2313/* Close the log-file and disable logging. */ 2314static void 2315UninitPacketAliasLog(void) 2316{ 2317 if (monitorFile) { 2318 fclose(monitorFile); 2319 monitorFile = NULL; 2320 } 2321 packetAliasMode &= ~PKT_ALIAS_LOG; 2322} 2323 2324 2325 2326 2327 2328 2329/* Outside world interfaces 2330 2331-- "outside world" means other than alias*.c routines -- 2332 2333 PacketAliasRedirectPort() 2334 PacketAliasAddServer() 2335 PacketAliasRedirectProto() 2336 PacketAliasRedirectAddr() 2337 PacketAliasRedirectDelete() 2338 PacketAliasSetAddress() 2339 PacketAliasInit() 2340 PacketAliasUninit() 2341 PacketAliasSetMode() 2342 2343(prototypes in alias.h) 2344*/ 2345 2346/* Redirection from a specific public addr:port to a 2347 private addr:port */ 2348struct alias_link * 2349PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 2350 struct in_addr dst_addr, u_short dst_port, 2351 struct in_addr alias_addr, u_short alias_port, 2352 u_char proto) 2353{ 2354 int link_type; 2355 struct alias_link *link; 2356 2357 switch(proto) 2358 { 2359 case IPPROTO_UDP: 2360 link_type = LINK_UDP; 2361 break; 2362 case IPPROTO_TCP: 2363 link_type = LINK_TCP; 2364 break; 2365 default: 2366#ifdef DEBUG 2367 fprintf(stderr, "PacketAliasRedirectPort(): "); 2368 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2369#endif 2370 return NULL; 2371 } 2372 2373 link = AddLink(src_addr, dst_addr, alias_addr, 2374 src_port, dst_port, alias_port, 2375 link_type); 2376 2377 if (link != NULL) 2378 { 2379 link->flags |= LINK_PERMANENT; 2380 } 2381#ifdef DEBUG 2382 else 2383 { 2384 fprintf(stderr, "PacketAliasRedirectPort(): " 2385 "call to AddLink() failed\n"); 2386 } 2387#endif 2388 2389 return link; 2390} 2391 2392/* Add server to the pool of servers */ 2393int 2394PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) 2395{ 2396 struct server *server; 2397 2398 server = malloc(sizeof(struct server)); 2399 2400 if (server != NULL) { 2401 struct server *head; 2402 2403 server->addr = addr; 2404 server->port = port; 2405 2406 head = link->server; 2407 if (head == NULL) 2408 server->next = server; 2409 else { 2410 struct server *s; 2411 2412 for (s = head; s->next != head; s = s->next); 2413 s->next = server; 2414 server->next = head; 2415 } 2416 link->server = server; 2417 return (0); 2418 } else 2419 return (-1); 2420} 2421 2422/* Redirect packets of a given IP protocol from a specific 2423 public address to a private address */ 2424struct alias_link * 2425PacketAliasRedirectProto(struct in_addr src_addr, 2426 struct in_addr dst_addr, 2427 struct in_addr alias_addr, 2428 u_char proto) 2429{ 2430 struct alias_link *link; 2431 2432 link = AddLink(src_addr, dst_addr, alias_addr, 2433 NO_SRC_PORT, NO_DEST_PORT, 0, 2434 proto); 2435 2436 if (link != NULL) 2437 { 2438 link->flags |= LINK_PERMANENT; 2439 } 2440#ifdef DEBUG 2441 else 2442 { 2443 fprintf(stderr, "PacketAliasRedirectProto(): " 2444 "call to AddLink() failed\n"); 2445 } 2446#endif 2447 2448 return link; 2449} 2450 2451/* Static address translation */ 2452struct alias_link * 2453PacketAliasRedirectAddr(struct in_addr src_addr, 2454 struct in_addr alias_addr) 2455{ 2456 struct alias_link *link; 2457 2458 link = AddLink(src_addr, nullAddress, alias_addr, 2459 0, 0, 0, 2460 LINK_ADDR); 2461 2462 if (link != NULL) 2463 { 2464 link->flags |= LINK_PERMANENT; 2465 } 2466#ifdef DEBUG 2467 else 2468 { 2469 fprintf(stderr, "PacketAliasRedirectAddr(): " 2470 "call to AddLink() failed\n"); 2471 } 2472#endif 2473 2474 return link; 2475} 2476 2477 2478void 2479PacketAliasRedirectDelete(struct alias_link *link) 2480{ 2481/* This is a dangerous function to put in the API, 2482 because an invalid pointer can crash the program. */ 2483 2484 deleteAllLinks = 1; 2485 DeleteLink(link); 2486 deleteAllLinks = 0; 2487} 2488 2489 2490void 2491PacketAliasSetAddress(struct in_addr addr) 2492{ 2493 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2494 && aliasAddress.s_addr != addr.s_addr) 2495 CleanupAliasData(); 2496 2497 aliasAddress = addr; 2498} 2499 2500 2501void 2502PacketAliasSetTarget(struct in_addr target_addr) 2503{ 2504 targetAddress = target_addr; 2505} 2506 2507 2508void 2509PacketAliasInit(void) 2510{ 2511 int i; 2512 struct timeval tv; 2513 struct timezone tz; 2514 static int firstCall = 1; 2515 2516 if (firstCall == 1) 2517 { 2518 gettimeofday(&tv, &tz); 2519 timeStamp = tv.tv_sec; 2520 lastCleanupTime = tv.tv_sec; 2521 houseKeepingResidual = 0; 2522 2523 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2524 LIST_INIT(&linkTableOut[i]); 2525 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2526 LIST_INIT(&linkTableIn[i]); 2527 2528 atexit(PacketAliasUninit); 2529 firstCall = 0; 2530 } 2531 else 2532 { 2533 deleteAllLinks = 1; 2534 CleanupAliasData(); 2535 deleteAllLinks = 0; 2536 } 2537 2538 aliasAddress.s_addr = INADDR_ANY; 2539 targetAddress.s_addr = INADDR_ANY; 2540 2541 icmpLinkCount = 0; 2542 udpLinkCount = 0; 2543 tcpLinkCount = 0; 2544 pptpLinkCount = 0; 2545 protoLinkCount = 0; 2546 fragmentIdLinkCount = 0; 2547 fragmentPtrLinkCount = 0; 2548 sockCount = 0; 2549 2550 cleanupIndex =0; 2551 2552 packetAliasMode = PKT_ALIAS_SAME_PORTS 2553 | PKT_ALIAS_USE_SOCKETS 2554 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2555} 2556 2557void 2558PacketAliasUninit(void) { 2559 deleteAllLinks = 1; 2560 CleanupAliasData(); 2561 deleteAllLinks = 0; 2562 UninitPacketAliasLog(); 2563#ifndef NO_FW_PUNCH 2564 UninitPunchFW(); 2565#endif 2566} 2567 2568 2569/* Change mode for some operations */ 2570unsigned int 2571PacketAliasSetMode( 2572 unsigned int flags, /* Which state to bring flags to */ 2573 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2574 probe for flag values) */ 2575) 2576{ 2577/* Enable logging? */ 2578 if (flags & mask & PKT_ALIAS_LOG) 2579 { 2580 InitPacketAliasLog(); /* Do the enable */ 2581 } else 2582/* _Disable_ logging? */ 2583 if (~flags & mask & PKT_ALIAS_LOG) { 2584 UninitPacketAliasLog(); 2585 } 2586 2587#ifndef NO_FW_PUNCH 2588/* Start punching holes in the firewall? */ 2589 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2590 InitPunchFW(); 2591 } else 2592/* Stop punching holes in the firewall? */ 2593 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2594 UninitPunchFW(); 2595 } 2596#endif 2597 2598/* Other flags can be set/cleared without special action */ 2599 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2600 return packetAliasMode; 2601} 2602 2603 2604int 2605PacketAliasCheckNewLink(void) 2606{ 2607 return newDefaultLink; 2608} 2609 2610 2611#ifndef NO_FW_PUNCH 2612 2613/***************** 2614 Code to support firewall punching. This shouldn't really be in this 2615 file, but making variables global is evil too. 2616 ****************/ 2617 2618/* Firewall include files */ 2619#include <net/if.h> 2620#include <netinet/ip_fw.h> 2621#include <string.h> 2622#include <err.h> 2623 2624static void ClearAllFWHoles(void); 2625 2626static int fireWallBaseNum; /* The first firewall entry free for our use */ 2627static int fireWallNumNums; /* How many entries can we use? */ 2628static int fireWallActiveNum; /* Which entry did we last use? */ 2629static char *fireWallField; /* bool array for entries */ 2630 2631#define fw_setfield(field, num) \ 2632do { \ 2633 (field)[(num) - fireWallBaseNum] = 1; \ 2634} /*lint -save -e717 */ while(0) /*lint -restore */ 2635#define fw_clrfield(field, num) \ 2636do { \ 2637 (field)[(num) - fireWallBaseNum] = 0; \ 2638} /*lint -save -e717 */ while(0) /*lint -restore */ 2639#define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum]) 2640 2641void 2642PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2643 fireWallBaseNum = base; 2644 fireWallNumNums = num; 2645} 2646 2647static void 2648InitPunchFW(void) { 2649 fireWallField = malloc(fireWallNumNums); 2650 if (fireWallField) { 2651 memset(fireWallField, 0, fireWallNumNums); 2652 if (fireWallFD < 0) { 2653 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2654 } 2655 ClearAllFWHoles(); 2656 fireWallActiveNum = fireWallBaseNum; 2657 } 2658} 2659 2660static void 2661UninitPunchFW(void) { 2662 ClearAllFWHoles(); 2663 if (fireWallFD >= 0) 2664 close(fireWallFD); 2665 fireWallFD = -1; 2666 if (fireWallField) 2667 free(fireWallField); 2668 fireWallField = NULL; 2669 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2670} 2671 2672/* Make a certain link go through the firewall */ 2673void 2674PunchFWHole(struct alias_link *link) { 2675 int r; /* Result code */ 2676 struct ip_fw rule; /* On-the-fly built rule */ 2677 int fwhole; /* Where to punch hole */ 2678 2679/* Don't do anything unless we are asked to */ 2680 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2681 fireWallFD < 0 ||
| 1131 old_link->data.tcp->fwhole > 0) { 1132 PunchFWHole(new_link); 1133 } 1134#endif 1135 DeleteLink(old_link); 1136 return new_link; 1137} 1138 1139static struct alias_link * 1140_FindLinkOut(struct in_addr src_addr, 1141 struct in_addr dst_addr, 1142 u_short src_port, 1143 u_short dst_port, 1144 int link_type, 1145 int replace_partial_links) 1146{ 1147 u_int i; 1148 struct alias_link *link; 1149 1150 i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type); 1151 LIST_FOREACH(link, &linkTableOut[i], list_out) 1152 { 1153 if (link->src_addr.s_addr == src_addr.s_addr 1154 && link->server == NULL 1155 && link->dst_addr.s_addr == dst_addr.s_addr 1156 && link->dst_port == dst_port 1157 && link->src_port == src_port 1158 && link->link_type == link_type) 1159 { 1160 link->timestamp = timeStamp; 1161 break; 1162 } 1163 } 1164 1165/* Search for partially specified links. */ 1166 if (link == NULL && replace_partial_links) 1167 { 1168 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) 1169 { 1170 link = _FindLinkOut(src_addr, dst_addr, src_port, 0, 1171 link_type, 0); 1172 if (link == NULL) 1173 link = _FindLinkOut(src_addr, nullAddress, src_port, 1174 dst_port, link_type, 0); 1175 } 1176 if (link == NULL && 1177 (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) 1178 { 1179 link = _FindLinkOut(src_addr, nullAddress, src_port, 0, 1180 link_type, 0); 1181 } 1182 if (link != NULL) 1183 { 1184 link = ReLink(link, 1185 src_addr, dst_addr, link->alias_addr, 1186 src_port, dst_port, link->alias_port, 1187 link_type); 1188 } 1189 } 1190 1191 return(link); 1192} 1193 1194static struct alias_link * 1195FindLinkOut(struct in_addr src_addr, 1196 struct in_addr dst_addr, 1197 u_short src_port, 1198 u_short dst_port, 1199 int link_type, 1200 int replace_partial_links) 1201{ 1202 struct alias_link *link; 1203 1204 link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port, 1205 link_type, replace_partial_links); 1206 1207 if (link == NULL) 1208 { 1209 /* The following allows permanent links to be 1210 specified as using the default source address 1211 (i.e. device interface address) without knowing 1212 in advance what that address is. */ 1213 if (aliasAddress.s_addr != 0 && 1214 src_addr.s_addr == aliasAddress.s_addr) 1215 { 1216 link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port, 1217 link_type, replace_partial_links); 1218 } 1219 } 1220 1221 return(link); 1222} 1223 1224 1225static struct alias_link * 1226_FindLinkIn(struct in_addr dst_addr, 1227 struct in_addr alias_addr, 1228 u_short dst_port, 1229 u_short alias_port, 1230 int link_type, 1231 int replace_partial_links) 1232{ 1233 int flags_in; 1234 u_int start_point; 1235 struct alias_link *link; 1236 struct alias_link *link_fully_specified; 1237 struct alias_link *link_unknown_all; 1238 struct alias_link *link_unknown_dst_addr; 1239 struct alias_link *link_unknown_dst_port; 1240 1241/* Initialize pointers */ 1242 link_fully_specified = NULL; 1243 link_unknown_all = NULL; 1244 link_unknown_dst_addr = NULL; 1245 link_unknown_dst_port = NULL; 1246 1247/* If either the dest addr or port is unknown, the search 1248 loop will have to know about this. */ 1249 1250 flags_in = 0; 1251 if (dst_addr.s_addr == INADDR_ANY) 1252 flags_in |= LINK_UNKNOWN_DEST_ADDR; 1253 if (dst_port == 0) 1254 flags_in |= LINK_UNKNOWN_DEST_PORT; 1255 1256/* Search loop */ 1257 start_point = StartPointIn(alias_addr, alias_port, link_type); 1258 LIST_FOREACH(link, &linkTableIn[start_point], list_in) 1259 { 1260 int flags; 1261 1262 flags = flags_in | link->flags; 1263 if (!(flags & LINK_PARTIALLY_SPECIFIED)) 1264 { 1265 if (link->alias_addr.s_addr == alias_addr.s_addr 1266 && link->alias_port == alias_port 1267 && link->dst_addr.s_addr == dst_addr.s_addr 1268 && link->dst_port == dst_port 1269 && link->link_type == link_type) 1270 { 1271 link_fully_specified = link; 1272 break; 1273 } 1274 } 1275 else if ((flags & LINK_UNKNOWN_DEST_ADDR) 1276 && (flags & LINK_UNKNOWN_DEST_PORT)) 1277 { 1278 if (link->alias_addr.s_addr == alias_addr.s_addr 1279 && link->alias_port == alias_port 1280 && link->link_type == link_type) 1281 { 1282 if (link_unknown_all == NULL) 1283 link_unknown_all = link; 1284 } 1285 } 1286 else if (flags & LINK_UNKNOWN_DEST_ADDR) 1287 { 1288 if (link->alias_addr.s_addr == alias_addr.s_addr 1289 && link->alias_port == alias_port 1290 && link->link_type == link_type 1291 && link->dst_port == dst_port) 1292 { 1293 if (link_unknown_dst_addr == NULL) 1294 link_unknown_dst_addr = link; 1295 } 1296 } 1297 else if (flags & LINK_UNKNOWN_DEST_PORT) 1298 { 1299 if (link->alias_addr.s_addr == alias_addr.s_addr 1300 && link->alias_port == alias_port 1301 && link->link_type == link_type 1302 && link->dst_addr.s_addr == dst_addr.s_addr) 1303 { 1304 if (link_unknown_dst_port == NULL) 1305 link_unknown_dst_port = link; 1306 } 1307 } 1308 } 1309 1310 1311 1312 if (link_fully_specified != NULL) 1313 { 1314 link_fully_specified->timestamp = timeStamp; 1315 link = link_fully_specified; 1316 } 1317 else if (link_unknown_dst_port != NULL) 1318 link = link_unknown_dst_port; 1319 else if (link_unknown_dst_addr != NULL) 1320 link = link_unknown_dst_addr; 1321 else if (link_unknown_all != NULL) 1322 link = link_unknown_all; 1323 else 1324 return (NULL); 1325 1326 if (replace_partial_links && 1327 (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) 1328 { 1329 struct in_addr src_addr; 1330 u_short src_port; 1331 1332 if (link->server != NULL) { /* LSNAT link */ 1333 src_addr = link->server->addr; 1334 src_port = link->server->port; 1335 link->server = link->server->next; 1336 } else { 1337 src_addr = link->src_addr; 1338 src_port = link->src_port; 1339 } 1340 1341 link = ReLink(link, 1342 src_addr, dst_addr, alias_addr, 1343 src_port, dst_port, alias_port, 1344 link_type); 1345 } 1346 1347 return (link); 1348} 1349 1350static struct alias_link * 1351FindLinkIn(struct in_addr dst_addr, 1352 struct in_addr alias_addr, 1353 u_short dst_port, 1354 u_short alias_port, 1355 int link_type, 1356 int replace_partial_links) 1357{ 1358 struct alias_link *link; 1359 1360 link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port, 1361 link_type, replace_partial_links); 1362 1363 if (link == NULL) 1364 { 1365 /* The following allows permanent links to be 1366 specified as using the default aliasing address 1367 (i.e. device interface address) without knowing 1368 in advance what that address is. */ 1369 if (aliasAddress.s_addr != 0 && 1370 alias_addr.s_addr == aliasAddress.s_addr) 1371 { 1372 link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port, 1373 link_type, replace_partial_links); 1374 } 1375 } 1376 1377 return(link); 1378} 1379 1380 1381 1382 1383/* External routines for finding/adding links 1384 1385-- "external" means outside alias_db.c, but within alias*.c -- 1386 1387 FindIcmpIn(), FindIcmpOut() 1388 FindFragmentIn1(), FindFragmentIn2() 1389 AddFragmentPtrLink(), FindFragmentPtr() 1390 FindProtoIn(), FindProtoOut() 1391 FindUdpTcpIn(), FindUdpTcpOut() 1392 FindPptpIn(), FindPptpOut() 1393 FindOriginalAddress(), FindAliasAddress() 1394 1395(prototypes in alias_local.h) 1396*/ 1397 1398 1399struct alias_link * 1400FindIcmpIn(struct in_addr dst_addr, 1401 struct in_addr alias_addr, 1402 u_short id_alias) 1403{ 1404 struct alias_link *link; 1405 1406 link = FindLinkIn(dst_addr, alias_addr, 1407 NO_DEST_PORT, id_alias, 1408 LINK_ICMP, 0); 1409 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1410 { 1411 struct in_addr target_addr; 1412 1413 target_addr = FindOriginalAddress(alias_addr); 1414 link = AddLink(target_addr, dst_addr, alias_addr, 1415 id_alias, NO_DEST_PORT, id_alias, 1416 LINK_ICMP); 1417 } 1418 1419 return (link); 1420} 1421 1422 1423struct alias_link * 1424FindIcmpOut(struct in_addr src_addr, 1425 struct in_addr dst_addr, 1426 u_short id) 1427{ 1428 struct alias_link * link; 1429 1430 link = FindLinkOut(src_addr, dst_addr, 1431 id, NO_DEST_PORT, 1432 LINK_ICMP, 0); 1433 if (link == NULL) 1434 { 1435 struct in_addr alias_addr; 1436 1437 alias_addr = FindAliasAddress(src_addr); 1438 link = AddLink(src_addr, dst_addr, alias_addr, 1439 id, NO_DEST_PORT, GET_ALIAS_ID, 1440 LINK_ICMP); 1441 } 1442 1443 return(link); 1444} 1445 1446 1447struct alias_link * 1448FindFragmentIn1(struct in_addr dst_addr, 1449 struct in_addr alias_addr, 1450 u_short ip_id) 1451{ 1452 struct alias_link *link; 1453 1454 link = FindLinkIn(dst_addr, alias_addr, 1455 NO_DEST_PORT, ip_id, 1456 LINK_FRAGMENT_ID, 0); 1457 1458 if (link == NULL) 1459 { 1460 link = AddLink(nullAddress, dst_addr, alias_addr, 1461 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1462 LINK_FRAGMENT_ID); 1463 } 1464 1465 return(link); 1466} 1467 1468 1469struct alias_link * 1470FindFragmentIn2(struct in_addr dst_addr, /* Doesn't add a link if one */ 1471 struct in_addr alias_addr, /* is not found. */ 1472 u_short ip_id) 1473{ 1474 return FindLinkIn(dst_addr, alias_addr, 1475 NO_DEST_PORT, ip_id, 1476 LINK_FRAGMENT_ID, 0); 1477} 1478 1479 1480struct alias_link * 1481AddFragmentPtrLink(struct in_addr dst_addr, 1482 u_short ip_id) 1483{ 1484 return AddLink(nullAddress, dst_addr, nullAddress, 1485 NO_SRC_PORT, NO_DEST_PORT, ip_id, 1486 LINK_FRAGMENT_PTR); 1487} 1488 1489 1490struct alias_link * 1491FindFragmentPtr(struct in_addr dst_addr, 1492 u_short ip_id) 1493{ 1494 return FindLinkIn(dst_addr, nullAddress, 1495 NO_DEST_PORT, ip_id, 1496 LINK_FRAGMENT_PTR, 0); 1497} 1498 1499 1500struct alias_link * 1501FindProtoIn(struct in_addr dst_addr, 1502 struct in_addr alias_addr, 1503 u_char proto) 1504{ 1505 struct alias_link *link; 1506 1507 link = FindLinkIn(dst_addr, alias_addr, 1508 NO_DEST_PORT, 0, 1509 proto, 1); 1510 1511 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1512 { 1513 struct in_addr target_addr; 1514 1515 target_addr = FindOriginalAddress(alias_addr); 1516 link = AddLink(target_addr, dst_addr, alias_addr, 1517 NO_SRC_PORT, NO_DEST_PORT, 0, 1518 proto); 1519 } 1520 1521 return (link); 1522} 1523 1524 1525struct alias_link * 1526FindProtoOut(struct in_addr src_addr, 1527 struct in_addr dst_addr, 1528 u_char proto) 1529{ 1530 struct alias_link *link; 1531 1532 link = FindLinkOut(src_addr, dst_addr, 1533 NO_SRC_PORT, NO_DEST_PORT, 1534 proto, 1); 1535 1536 if (link == NULL) 1537 { 1538 struct in_addr alias_addr; 1539 1540 alias_addr = FindAliasAddress(src_addr); 1541 link = AddLink(src_addr, dst_addr, alias_addr, 1542 NO_SRC_PORT, NO_DEST_PORT, 0, 1543 proto); 1544 } 1545 1546 return (link); 1547} 1548 1549 1550struct alias_link * 1551FindUdpTcpIn(struct in_addr dst_addr, 1552 struct in_addr alias_addr, 1553 u_short dst_port, 1554 u_short alias_port, 1555 u_char proto) 1556{ 1557 int link_type; 1558 struct alias_link *link; 1559 1560 switch (proto) 1561 { 1562 case IPPROTO_UDP: 1563 link_type = LINK_UDP; 1564 break; 1565 case IPPROTO_TCP: 1566 link_type = LINK_TCP; 1567 break; 1568 default: 1569 return NULL; 1570 break; 1571 } 1572 1573 link = FindLinkIn(dst_addr, alias_addr, 1574 dst_port, alias_port, 1575 link_type, 1); 1576 1577 if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING) 1578 && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY) 1579 && link == NULL) 1580 { 1581 struct in_addr target_addr; 1582 1583 target_addr = FindOriginalAddress(alias_addr); 1584 link = AddLink(target_addr, dst_addr, alias_addr, 1585 alias_port, dst_port, alias_port, 1586 link_type); 1587 } 1588 1589 return(link); 1590} 1591 1592 1593struct alias_link * 1594FindUdpTcpOut(struct in_addr src_addr, 1595 struct in_addr dst_addr, 1596 u_short src_port, 1597 u_short dst_port, 1598 u_char proto) 1599{ 1600 int link_type; 1601 struct alias_link *link; 1602 1603 switch (proto) 1604 { 1605 case IPPROTO_UDP: 1606 link_type = LINK_UDP; 1607 break; 1608 case IPPROTO_TCP: 1609 link_type = LINK_TCP; 1610 break; 1611 default: 1612 return NULL; 1613 break; 1614 } 1615 1616 link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, 1); 1617 1618 if (link == NULL) 1619 { 1620 struct in_addr alias_addr; 1621 1622 alias_addr = FindAliasAddress(src_addr); 1623 link = AddLink(src_addr, dst_addr, alias_addr, 1624 src_port, dst_port, GET_ALIAS_PORT, 1625 link_type); 1626 } 1627 1628 return(link); 1629} 1630 1631 1632struct alias_link * 1633FindPptpIn(struct in_addr dst_addr, 1634 struct in_addr alias_addr, 1635 u_short call_id) 1636{ 1637 struct alias_link *link; 1638 1639 link = FindLinkIn(dst_addr, alias_addr, 1640 NO_DEST_PORT, call_id, 1641 LINK_PPTP, 1); 1642 1643 if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING)) 1644 { 1645 struct in_addr target_addr; 1646 1647 target_addr = FindOriginalAddress(alias_addr); 1648 link = AddLink(target_addr, dst_addr, alias_addr, 1649 call_id, NO_DEST_PORT, call_id, 1650 LINK_PPTP); 1651 } 1652 1653 return(link); 1654} 1655 1656 1657struct alias_link * 1658FindPptpOut(struct in_addr src_addr, 1659 struct in_addr dst_addr, 1660 u_short call_id) 1661{ 1662 struct alias_link *link; 1663 1664 link = FindLinkOut(src_addr, dst_addr, 1665 call_id, NO_DEST_PORT, 1666 LINK_PPTP, 1); 1667 1668 if (link == NULL) 1669 { 1670 struct in_addr alias_addr; 1671 1672 alias_addr = FindAliasAddress(src_addr); 1673 link = AddLink(src_addr, dst_addr, alias_addr, 1674 call_id, NO_DEST_PORT, GET_ALIAS_PORT, 1675 LINK_PPTP); 1676 } 1677 1678 return(link); 1679} 1680 1681 1682struct alias_link * 1683QueryUdpTcpIn(struct in_addr dst_addr, 1684 struct in_addr alias_addr, 1685 u_short dst_port, 1686 u_short alias_port, 1687 u_char proto) 1688{ 1689 int link_type; 1690 struct alias_link *link; 1691 1692 switch (proto) 1693 { 1694 case IPPROTO_UDP: 1695 link_type = LINK_UDP; 1696 break; 1697 case IPPROTO_TCP: 1698 link_type = LINK_TCP; 1699 break; 1700 default: 1701 return NULL; 1702 break; 1703 } 1704 1705 link = FindLinkIn(dst_addr, alias_addr, 1706 dst_port, alias_port, 1707 link_type, 0); 1708 1709 return(link); 1710} 1711 1712 1713struct alias_link * 1714QueryUdpTcpOut(struct in_addr src_addr, 1715 struct in_addr dst_addr, 1716 u_short src_port, 1717 u_short dst_port, 1718 u_char proto) 1719{ 1720 int link_type; 1721 struct alias_link *link; 1722 1723 switch (proto) 1724 { 1725 case IPPROTO_UDP: 1726 link_type = LINK_UDP; 1727 break; 1728 case IPPROTO_TCP: 1729 link_type = LINK_TCP; 1730 break; 1731 default: 1732 return NULL; 1733 break; 1734 } 1735 1736 link = FindLinkOut(src_addr, dst_addr, 1737 src_port, dst_port, 1738 link_type, 0); 1739 1740 return(link); 1741} 1742 1743 1744struct alias_link * 1745FindRtspOut(struct in_addr src_addr, 1746 struct in_addr dst_addr, 1747 u_short src_port, 1748 u_short alias_port, 1749 u_char proto) 1750{ 1751 int link_type; 1752 struct alias_link *link; 1753 1754 switch (proto) 1755 { 1756 case IPPROTO_UDP: 1757 link_type = LINK_UDP; 1758 break; 1759 case IPPROTO_TCP: 1760 link_type = LINK_TCP; 1761 break; 1762 default: 1763 return NULL; 1764 break; 1765 } 1766 1767 link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1); 1768 1769 if (link == NULL) 1770 { 1771 struct in_addr alias_addr; 1772 1773 alias_addr = FindAliasAddress(src_addr); 1774 link = AddLink(src_addr, dst_addr, alias_addr, 1775 src_port, 0, alias_port, 1776 link_type); 1777 } 1778 1779 return(link); 1780} 1781 1782 1783struct in_addr 1784FindOriginalAddress(struct in_addr alias_addr) 1785{ 1786 struct alias_link *link; 1787 1788 link = FindLinkIn(nullAddress, alias_addr, 1789 0, 0, LINK_ADDR, 0); 1790 if (link == NULL) 1791 { 1792 newDefaultLink = 1; 1793 if (targetAddress.s_addr == INADDR_ANY) 1794 return alias_addr; 1795 else if (targetAddress.s_addr == INADDR_NONE) 1796 return aliasAddress; 1797 else 1798 return targetAddress; 1799 } 1800 else 1801 { 1802 if (link->server != NULL) { /* LSNAT link */ 1803 struct in_addr src_addr; 1804 1805 src_addr = link->server->addr; 1806 link->server = link->server->next; 1807 return (src_addr); 1808 } else if (link->src_addr.s_addr == INADDR_ANY) 1809 return aliasAddress; 1810 else 1811 return link->src_addr; 1812 } 1813} 1814 1815 1816struct in_addr 1817FindAliasAddress(struct in_addr original_addr) 1818{ 1819 struct alias_link *link; 1820 1821 link = FindLinkOut(original_addr, nullAddress, 1822 0, 0, LINK_ADDR, 0); 1823 if (link == NULL) 1824 { 1825 return aliasAddress; 1826 } 1827 else 1828 { 1829 if (link->alias_addr.s_addr == INADDR_ANY) 1830 return aliasAddress; 1831 else 1832 return link->alias_addr; 1833 } 1834} 1835 1836 1837/* External routines for getting or changing link data 1838 (external to alias_db.c, but internal to alias*.c) 1839 1840 SetFragmentData(), GetFragmentData() 1841 SetFragmentPtr(), GetFragmentPtr() 1842 SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut() 1843 GetOriginalAddress(), GetDestAddress(), GetAliasAddress() 1844 GetOriginalPort(), GetAliasPort() 1845 SetAckModified(), GetAckModified() 1846 GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq() 1847 SetLastLineCrlfTermed(), GetLastLineCrlfTermed() 1848*/ 1849 1850 1851void 1852SetFragmentAddr(struct alias_link *link, struct in_addr src_addr) 1853{ 1854 link->data.frag_addr = src_addr; 1855} 1856 1857 1858void 1859GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr) 1860{ 1861 *src_addr = link->data.frag_addr; 1862} 1863 1864 1865void 1866SetFragmentPtr(struct alias_link *link, char *fptr) 1867{ 1868 link->data.frag_ptr = fptr; 1869} 1870 1871 1872void 1873GetFragmentPtr(struct alias_link *link, char **fptr) 1874{ 1875 *fptr = link->data.frag_ptr; 1876} 1877 1878 1879void 1880SetStateIn(struct alias_link *link, int state) 1881{ 1882 /* TCP input state */ 1883 switch (state) { 1884 case ALIAS_TCP_STATE_DISCONNECTED: 1885 if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) 1886 link->expire_time = TCP_EXPIRE_DEAD; 1887 else 1888 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1889 break; 1890 case ALIAS_TCP_STATE_CONNECTED: 1891 if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED) 1892 link->expire_time = TCP_EXPIRE_CONNECTED; 1893 break; 1894 default: 1895 abort(); 1896 } 1897 link->data.tcp->state.in = state; 1898} 1899 1900 1901void 1902SetStateOut(struct alias_link *link, int state) 1903{ 1904 /* TCP output state */ 1905 switch (state) { 1906 case ALIAS_TCP_STATE_DISCONNECTED: 1907 if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) 1908 link->expire_time = TCP_EXPIRE_DEAD; 1909 else 1910 link->expire_time = TCP_EXPIRE_SINGLEDEAD; 1911 break; 1912 case ALIAS_TCP_STATE_CONNECTED: 1913 if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED) 1914 link->expire_time = TCP_EXPIRE_CONNECTED; 1915 break; 1916 default: 1917 abort(); 1918 } 1919 link->data.tcp->state.out = state; 1920} 1921 1922 1923int 1924GetStateIn(struct alias_link *link) 1925{ 1926 /* TCP input state */ 1927 return link->data.tcp->state.in; 1928} 1929 1930 1931int 1932GetStateOut(struct alias_link *link) 1933{ 1934 /* TCP output state */ 1935 return link->data.tcp->state.out; 1936} 1937 1938 1939struct in_addr 1940GetOriginalAddress(struct alias_link *link) 1941{ 1942 if (link->src_addr.s_addr == INADDR_ANY) 1943 return aliasAddress; 1944 else 1945 return(link->src_addr); 1946} 1947 1948 1949struct in_addr 1950GetDestAddress(struct alias_link *link) 1951{ 1952 return(link->dst_addr); 1953} 1954 1955 1956struct in_addr 1957GetAliasAddress(struct alias_link *link) 1958{ 1959 if (link->alias_addr.s_addr == INADDR_ANY) 1960 return aliasAddress; 1961 else 1962 return link->alias_addr; 1963} 1964 1965 1966struct in_addr 1967GetDefaultAliasAddress() 1968{ 1969 return aliasAddress; 1970} 1971 1972 1973void 1974SetDefaultAliasAddress(struct in_addr alias_addr) 1975{ 1976 aliasAddress = alias_addr; 1977} 1978 1979 1980u_short 1981GetOriginalPort(struct alias_link *link) 1982{ 1983 return(link->src_port); 1984} 1985 1986 1987u_short 1988GetAliasPort(struct alias_link *link) 1989{ 1990 return(link->alias_port); 1991} 1992 1993#ifndef NO_FW_PUNCH 1994static u_short 1995GetDestPort(struct alias_link *link) 1996{ 1997 return(link->dst_port); 1998} 1999#endif 2000 2001void 2002SetAckModified(struct alias_link *link) 2003{ 2004/* Indicate that ACK numbers have been modified in a TCP connection */ 2005 link->data.tcp->state.ack_modified = 1; 2006} 2007 2008 2009struct in_addr 2010GetProxyAddress(struct alias_link *link) 2011{ 2012 return link->proxy_addr; 2013} 2014 2015 2016void 2017SetProxyAddress(struct alias_link *link, struct in_addr addr) 2018{ 2019 link->proxy_addr = addr; 2020} 2021 2022 2023u_short 2024GetProxyPort(struct alias_link *link) 2025{ 2026 return link->proxy_port; 2027} 2028 2029 2030void 2031SetProxyPort(struct alias_link *link, u_short port) 2032{ 2033 link->proxy_port = port; 2034} 2035 2036 2037int 2038GetAckModified(struct alias_link *link) 2039{ 2040/* See if ACK numbers have been modified */ 2041 return link->data.tcp->state.ack_modified; 2042} 2043 2044 2045int 2046GetDeltaAckIn(struct ip *pip, struct alias_link *link) 2047{ 2048/* 2049Find out how much the ACK number has been altered for an incoming 2050TCP packet. To do this, a circular list of ACK numbers where the TCP 2051packet size was altered is searched. 2052*/ 2053 2054 int i; 2055 struct tcphdr *tc; 2056 int delta, ack_diff_min; 2057 u_long ack; 2058 2059 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2060 ack = tc->th_ack; 2061 2062 delta = 0; 2063 ack_diff_min = -1; 2064 for (i=0; i<N_LINK_TCP_DATA; i++) 2065 { 2066 struct ack_data_record x; 2067 2068 x = link->data.tcp->ack[i]; 2069 if (x.active == 1) 2070 { 2071 int ack_diff; 2072 2073 ack_diff = SeqDiff(x.ack_new, ack); 2074 if (ack_diff >= 0) 2075 { 2076 if (ack_diff_min >= 0) 2077 { 2078 if (ack_diff < ack_diff_min) 2079 { 2080 delta = x.delta; 2081 ack_diff_min = ack_diff; 2082 } 2083 } 2084 else 2085 { 2086 delta = x.delta; 2087 ack_diff_min = ack_diff; 2088 } 2089 } 2090 } 2091 } 2092 return (delta); 2093} 2094 2095 2096int 2097GetDeltaSeqOut(struct ip *pip, struct alias_link *link) 2098{ 2099/* 2100Find out how much the sequence number has been altered for an outgoing 2101TCP packet. To do this, a circular list of ACK numbers where the TCP 2102packet size was altered is searched. 2103*/ 2104 2105 int i; 2106 struct tcphdr *tc; 2107 int delta, seq_diff_min; 2108 u_long seq; 2109 2110 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2111 seq = tc->th_seq; 2112 2113 delta = 0; 2114 seq_diff_min = -1; 2115 for (i=0; i<N_LINK_TCP_DATA; i++) 2116 { 2117 struct ack_data_record x; 2118 2119 x = link->data.tcp->ack[i]; 2120 if (x.active == 1) 2121 { 2122 int seq_diff; 2123 2124 seq_diff = SeqDiff(x.ack_old, seq); 2125 if (seq_diff >= 0) 2126 { 2127 if (seq_diff_min >= 0) 2128 { 2129 if (seq_diff < seq_diff_min) 2130 { 2131 delta = x.delta; 2132 seq_diff_min = seq_diff; 2133 } 2134 } 2135 else 2136 { 2137 delta = x.delta; 2138 seq_diff_min = seq_diff; 2139 } 2140 } 2141 } 2142 } 2143 return (delta); 2144} 2145 2146 2147void 2148AddSeq(struct ip *pip, struct alias_link *link, int delta) 2149{ 2150/* 2151When a TCP packet has been altered in length, save this 2152information in a circular list. If enough packets have 2153been altered, then this list will begin to overwrite itself. 2154*/ 2155 2156 struct tcphdr *tc; 2157 struct ack_data_record x; 2158 int hlen, tlen, dlen; 2159 int i; 2160 2161 tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2)); 2162 2163 hlen = (pip->ip_hl + tc->th_off) << 2; 2164 tlen = ntohs(pip->ip_len); 2165 dlen = tlen - hlen; 2166 2167 x.ack_old = htonl(ntohl(tc->th_seq) + dlen); 2168 x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta); 2169 x.delta = delta; 2170 x.active = 1; 2171 2172 i = link->data.tcp->state.index; 2173 link->data.tcp->ack[i] = x; 2174 2175 i++; 2176 if (i == N_LINK_TCP_DATA) 2177 link->data.tcp->state.index = 0; 2178 else 2179 link->data.tcp->state.index = i; 2180} 2181 2182void 2183SetExpire(struct alias_link *link, int expire) 2184{ 2185 if (expire == 0) 2186 { 2187 link->flags &= ~LINK_PERMANENT; 2188 DeleteLink(link); 2189 } 2190 else if (expire == -1) 2191 { 2192 link->flags |= LINK_PERMANENT; 2193 } 2194 else if (expire > 0) 2195 { 2196 link->expire_time = expire; 2197 } 2198 else 2199 { 2200#ifdef DEBUG 2201 fprintf(stderr, "PacketAlias/SetExpire(): "); 2202 fprintf(stderr, "error in expire parameter\n"); 2203#endif 2204 } 2205} 2206 2207void 2208ClearCheckNewLink(void) 2209{ 2210 newDefaultLink = 0; 2211} 2212 2213void 2214SetLastLineCrlfTermed(struct alias_link *link, int yes) 2215{ 2216 2217 if (yes) 2218 link->flags |= LINK_LAST_LINE_CRLF_TERMED; 2219 else 2220 link->flags &= ~LINK_LAST_LINE_CRLF_TERMED; 2221} 2222 2223int 2224GetLastLineCrlfTermed(struct alias_link *link) 2225{ 2226 2227 return (link->flags & LINK_LAST_LINE_CRLF_TERMED); 2228} 2229 2230 2231/* Miscellaneous Functions 2232 2233 HouseKeeping() 2234 InitPacketAliasLog() 2235 UninitPacketAliasLog() 2236*/ 2237 2238/* 2239 Whenever an outgoing or incoming packet is handled, HouseKeeping() 2240 is called to find and remove timed-out aliasing links. Logic exists 2241 to sweep through the entire table and linked list structure 2242 every 60 seconds. 2243 2244 (prototype in alias_local.h) 2245*/ 2246 2247void 2248HouseKeeping(void) 2249{ 2250 int i, n, n100; 2251 struct timeval tv; 2252 struct timezone tz; 2253 2254 /* 2255 * Save system time (seconds) in global variable timeStamp for 2256 * use by other functions. This is done so as not to unnecessarily 2257 * waste timeline by making system calls. 2258 */ 2259 gettimeofday(&tv, &tz); 2260 timeStamp = tv.tv_sec; 2261 2262 /* Compute number of spokes (output table link chains) to cover */ 2263 n100 = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual; 2264 n100 *= timeStamp - lastCleanupTime; 2265 n100 /= ALIAS_CLEANUP_INTERVAL_SECS; 2266 2267 n = n100/100; 2268 2269 /* Handle different cases */ 2270 if (n > ALIAS_CLEANUP_MAX_SPOKES) 2271 { 2272 n = ALIAS_CLEANUP_MAX_SPOKES; 2273 lastCleanupTime = timeStamp; 2274 houseKeepingResidual = 0; 2275 2276 for (i=0; i<n; i++) 2277 IncrementalCleanup(); 2278 } 2279 else if (n > 0) 2280 { 2281 lastCleanupTime = timeStamp; 2282 houseKeepingResidual = n100 - 100*n; 2283 2284 for (i=0; i<n; i++) 2285 IncrementalCleanup(); 2286 } 2287 else if (n < 0) 2288 { 2289#ifdef DEBUG 2290 fprintf(stderr, "PacketAlias/HouseKeeping(): "); 2291 fprintf(stderr, "something unexpected in time values\n"); 2292#endif 2293 lastCleanupTime = timeStamp; 2294 houseKeepingResidual = 0; 2295 } 2296} 2297 2298 2299/* Init the log file and enable logging */ 2300static void 2301InitPacketAliasLog(void) 2302{ 2303 if ((~packetAliasMode & PKT_ALIAS_LOG) 2304 && (monitorFile = fopen("/var/log/alias.log", "w"))) 2305 { 2306 packetAliasMode |= PKT_ALIAS_LOG; 2307 fprintf(monitorFile, 2308 "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n"); 2309 } 2310} 2311 2312 2313/* Close the log-file and disable logging. */ 2314static void 2315UninitPacketAliasLog(void) 2316{ 2317 if (monitorFile) { 2318 fclose(monitorFile); 2319 monitorFile = NULL; 2320 } 2321 packetAliasMode &= ~PKT_ALIAS_LOG; 2322} 2323 2324 2325 2326 2327 2328 2329/* Outside world interfaces 2330 2331-- "outside world" means other than alias*.c routines -- 2332 2333 PacketAliasRedirectPort() 2334 PacketAliasAddServer() 2335 PacketAliasRedirectProto() 2336 PacketAliasRedirectAddr() 2337 PacketAliasRedirectDelete() 2338 PacketAliasSetAddress() 2339 PacketAliasInit() 2340 PacketAliasUninit() 2341 PacketAliasSetMode() 2342 2343(prototypes in alias.h) 2344*/ 2345 2346/* Redirection from a specific public addr:port to a 2347 private addr:port */ 2348struct alias_link * 2349PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, 2350 struct in_addr dst_addr, u_short dst_port, 2351 struct in_addr alias_addr, u_short alias_port, 2352 u_char proto) 2353{ 2354 int link_type; 2355 struct alias_link *link; 2356 2357 switch(proto) 2358 { 2359 case IPPROTO_UDP: 2360 link_type = LINK_UDP; 2361 break; 2362 case IPPROTO_TCP: 2363 link_type = LINK_TCP; 2364 break; 2365 default: 2366#ifdef DEBUG 2367 fprintf(stderr, "PacketAliasRedirectPort(): "); 2368 fprintf(stderr, "only TCP and UDP protocols allowed\n"); 2369#endif 2370 return NULL; 2371 } 2372 2373 link = AddLink(src_addr, dst_addr, alias_addr, 2374 src_port, dst_port, alias_port, 2375 link_type); 2376 2377 if (link != NULL) 2378 { 2379 link->flags |= LINK_PERMANENT; 2380 } 2381#ifdef DEBUG 2382 else 2383 { 2384 fprintf(stderr, "PacketAliasRedirectPort(): " 2385 "call to AddLink() failed\n"); 2386 } 2387#endif 2388 2389 return link; 2390} 2391 2392/* Add server to the pool of servers */ 2393int 2394PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) 2395{ 2396 struct server *server; 2397 2398 server = malloc(sizeof(struct server)); 2399 2400 if (server != NULL) { 2401 struct server *head; 2402 2403 server->addr = addr; 2404 server->port = port; 2405 2406 head = link->server; 2407 if (head == NULL) 2408 server->next = server; 2409 else { 2410 struct server *s; 2411 2412 for (s = head; s->next != head; s = s->next); 2413 s->next = server; 2414 server->next = head; 2415 } 2416 link->server = server; 2417 return (0); 2418 } else 2419 return (-1); 2420} 2421 2422/* Redirect packets of a given IP protocol from a specific 2423 public address to a private address */ 2424struct alias_link * 2425PacketAliasRedirectProto(struct in_addr src_addr, 2426 struct in_addr dst_addr, 2427 struct in_addr alias_addr, 2428 u_char proto) 2429{ 2430 struct alias_link *link; 2431 2432 link = AddLink(src_addr, dst_addr, alias_addr, 2433 NO_SRC_PORT, NO_DEST_PORT, 0, 2434 proto); 2435 2436 if (link != NULL) 2437 { 2438 link->flags |= LINK_PERMANENT; 2439 } 2440#ifdef DEBUG 2441 else 2442 { 2443 fprintf(stderr, "PacketAliasRedirectProto(): " 2444 "call to AddLink() failed\n"); 2445 } 2446#endif 2447 2448 return link; 2449} 2450 2451/* Static address translation */ 2452struct alias_link * 2453PacketAliasRedirectAddr(struct in_addr src_addr, 2454 struct in_addr alias_addr) 2455{ 2456 struct alias_link *link; 2457 2458 link = AddLink(src_addr, nullAddress, alias_addr, 2459 0, 0, 0, 2460 LINK_ADDR); 2461 2462 if (link != NULL) 2463 { 2464 link->flags |= LINK_PERMANENT; 2465 } 2466#ifdef DEBUG 2467 else 2468 { 2469 fprintf(stderr, "PacketAliasRedirectAddr(): " 2470 "call to AddLink() failed\n"); 2471 } 2472#endif 2473 2474 return link; 2475} 2476 2477 2478void 2479PacketAliasRedirectDelete(struct alias_link *link) 2480{ 2481/* This is a dangerous function to put in the API, 2482 because an invalid pointer can crash the program. */ 2483 2484 deleteAllLinks = 1; 2485 DeleteLink(link); 2486 deleteAllLinks = 0; 2487} 2488 2489 2490void 2491PacketAliasSetAddress(struct in_addr addr) 2492{ 2493 if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE 2494 && aliasAddress.s_addr != addr.s_addr) 2495 CleanupAliasData(); 2496 2497 aliasAddress = addr; 2498} 2499 2500 2501void 2502PacketAliasSetTarget(struct in_addr target_addr) 2503{ 2504 targetAddress = target_addr; 2505} 2506 2507 2508void 2509PacketAliasInit(void) 2510{ 2511 int i; 2512 struct timeval tv; 2513 struct timezone tz; 2514 static int firstCall = 1; 2515 2516 if (firstCall == 1) 2517 { 2518 gettimeofday(&tv, &tz); 2519 timeStamp = tv.tv_sec; 2520 lastCleanupTime = tv.tv_sec; 2521 houseKeepingResidual = 0; 2522 2523 for (i=0; i<LINK_TABLE_OUT_SIZE; i++) 2524 LIST_INIT(&linkTableOut[i]); 2525 for (i=0; i<LINK_TABLE_IN_SIZE; i++) 2526 LIST_INIT(&linkTableIn[i]); 2527 2528 atexit(PacketAliasUninit); 2529 firstCall = 0; 2530 } 2531 else 2532 { 2533 deleteAllLinks = 1; 2534 CleanupAliasData(); 2535 deleteAllLinks = 0; 2536 } 2537 2538 aliasAddress.s_addr = INADDR_ANY; 2539 targetAddress.s_addr = INADDR_ANY; 2540 2541 icmpLinkCount = 0; 2542 udpLinkCount = 0; 2543 tcpLinkCount = 0; 2544 pptpLinkCount = 0; 2545 protoLinkCount = 0; 2546 fragmentIdLinkCount = 0; 2547 fragmentPtrLinkCount = 0; 2548 sockCount = 0; 2549 2550 cleanupIndex =0; 2551 2552 packetAliasMode = PKT_ALIAS_SAME_PORTS 2553 | PKT_ALIAS_USE_SOCKETS 2554 | PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2555} 2556 2557void 2558PacketAliasUninit(void) { 2559 deleteAllLinks = 1; 2560 CleanupAliasData(); 2561 deleteAllLinks = 0; 2562 UninitPacketAliasLog(); 2563#ifndef NO_FW_PUNCH 2564 UninitPunchFW(); 2565#endif 2566} 2567 2568 2569/* Change mode for some operations */ 2570unsigned int 2571PacketAliasSetMode( 2572 unsigned int flags, /* Which state to bring flags to */ 2573 unsigned int mask /* Mask of which flags to affect (use 0 to do a 2574 probe for flag values) */ 2575) 2576{ 2577/* Enable logging? */ 2578 if (flags & mask & PKT_ALIAS_LOG) 2579 { 2580 InitPacketAliasLog(); /* Do the enable */ 2581 } else 2582/* _Disable_ logging? */ 2583 if (~flags & mask & PKT_ALIAS_LOG) { 2584 UninitPacketAliasLog(); 2585 } 2586 2587#ifndef NO_FW_PUNCH 2588/* Start punching holes in the firewall? */ 2589 if (flags & mask & PKT_ALIAS_PUNCH_FW) { 2590 InitPunchFW(); 2591 } else 2592/* Stop punching holes in the firewall? */ 2593 if (~flags & mask & PKT_ALIAS_PUNCH_FW) { 2594 UninitPunchFW(); 2595 } 2596#endif 2597 2598/* Other flags can be set/cleared without special action */ 2599 packetAliasMode = (flags & mask) | (packetAliasMode & ~mask); 2600 return packetAliasMode; 2601} 2602 2603 2604int 2605PacketAliasCheckNewLink(void) 2606{ 2607 return newDefaultLink; 2608} 2609 2610 2611#ifndef NO_FW_PUNCH 2612 2613/***************** 2614 Code to support firewall punching. This shouldn't really be in this 2615 file, but making variables global is evil too. 2616 ****************/ 2617 2618/* Firewall include files */ 2619#include <net/if.h> 2620#include <netinet/ip_fw.h> 2621#include <string.h> 2622#include <err.h> 2623 2624static void ClearAllFWHoles(void); 2625 2626static int fireWallBaseNum; /* The first firewall entry free for our use */ 2627static int fireWallNumNums; /* How many entries can we use? */ 2628static int fireWallActiveNum; /* Which entry did we last use? */ 2629static char *fireWallField; /* bool array for entries */ 2630 2631#define fw_setfield(field, num) \ 2632do { \ 2633 (field)[(num) - fireWallBaseNum] = 1; \ 2634} /*lint -save -e717 */ while(0) /*lint -restore */ 2635#define fw_clrfield(field, num) \ 2636do { \ 2637 (field)[(num) - fireWallBaseNum] = 0; \ 2638} /*lint -save -e717 */ while(0) /*lint -restore */ 2639#define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum]) 2640 2641void 2642PacketAliasSetFWBase(unsigned int base, unsigned int num) { 2643 fireWallBaseNum = base; 2644 fireWallNumNums = num; 2645} 2646 2647static void 2648InitPunchFW(void) { 2649 fireWallField = malloc(fireWallNumNums); 2650 if (fireWallField) { 2651 memset(fireWallField, 0, fireWallNumNums); 2652 if (fireWallFD < 0) { 2653 fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2654 } 2655 ClearAllFWHoles(); 2656 fireWallActiveNum = fireWallBaseNum; 2657 } 2658} 2659 2660static void 2661UninitPunchFW(void) { 2662 ClearAllFWHoles(); 2663 if (fireWallFD >= 0) 2664 close(fireWallFD); 2665 fireWallFD = -1; 2666 if (fireWallField) 2667 free(fireWallField); 2668 fireWallField = NULL; 2669 packetAliasMode &= ~PKT_ALIAS_PUNCH_FW; 2670} 2671 2672/* Make a certain link go through the firewall */ 2673void 2674PunchFWHole(struct alias_link *link) { 2675 int r; /* Result code */ 2676 struct ip_fw rule; /* On-the-fly built rule */ 2677 int fwhole; /* Where to punch hole */ 2678 2679/* Don't do anything unless we are asked to */ 2680 if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) || 2681 fireWallFD < 0 ||
|