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