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