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