/*****************************************************************************/
/*
                               ProxyMaint.c

See PROXYCACHE.C for commentary.  This module implements both the ROUTINE and
REACTIVE purge maintenance for the proxy file cache.  See PROXYCACHE.C module
for information on cache management strategy.


VERSION HISTORY
---------------
20-MAR-2021  MGD  reduced to a shadow of its former self (caching obsolete)
28-APR-2018  MGD  refactor Admin..() AST delivery
18-JAN-2010  JPP  bugfix; ProxyMaintInit() use v10orPrev10() for scan spec
19-AUG-2007  MGD  use PercentOf() to avoid divide-by-zero exceptions
12-APR-2005  MGD  ProxyMaintSupervisor() return if caching not enabled
04-SEP-2004  MGD  PROXYCACHE.C v9.0.0 cache file header date/time usage 
30-APR-2004  MGD  use QIO to erase cache file (save a few cycles)
13-JAN-2004  MGD  DECC 6.2 objected to '$DESCRIPTOR(name,ptr->string)'
11-JUN-2003  MGD  bugfix; ProxyMaintDeviceStats() volume count (set) handling
11-MAY-2003  MGD  proxy unknown request fields
29-APR-2003  MGD  add proxy cache device error count statistics
02-APR-2003  MGD  maintain 'ProxyXForwardedFor',
                  modify for 'ProxyForwarded'
20-FEB-2003  MGD  ProxytMaintSupervisor() used instead of timers,
                  background purge (set with '[ProxyCacheRoutineHourOfDay] 24')
03-JUN-2002  MGD  bugfix; ensure sys$search() RMS channel is released
15-MAY-2002  MGD  proxy gateway statistics
11-APR-2002  MGD  make a reactive purge initially more agressive,
                  bugfix; switch return not break with next reactive scan
04-APR-2002  MGD  add command-line and menu STOP to cache scans,
                  update admin and monitor status string with scan progress,
                  bugfix; command-line cache maintenance reporting
02-FEB-2002  MGD  rework POSTed query due to request body processing changes
22-SEP-2001  MGD  InstanceLock/UnLock() to control access to cache
04-AUG-2001  MGD  support module WATCHing
07-MAY-2001  MGD  monitor global section accounting changes
05-APR-2001  MGD  add boolean to prevent ProxyMaintCacheLock() lock status
                  block overwriting if multiple scans intiated from Admin Menu
20-DEC-2000  MGD  routine proxy maintainence optionally disabled/external
13-SEP-2000  MGD  ProxyMaintReport() call refined to optionally provide
                  host name cache entries
08-JUL-2000  MGD  add VMS locking around cache scan (for clusters)
04-MAR-2000  MGD  use FaolToBuffer(), et.al.
03-JAN-2000  MGD  no changes required for ODS-5 compliance ... it's not
                  (see note in PROXYCACHE.C)
30-DEC-1999  MGD  change $GETDVI() to $GETDVIW() (potential bugfix)
04-DEC-1999  MGD  rework startup cache device and report details
22-OCT-1999  MGD  inaccessable cache device non-fatal during startup
20-JUN-1999  MGD  allow for cache devices >9GB in space calculations,
                  some refinement to statistics report
19-AUG-1998  MGD  initial development (recommenced DEC 1998)
*/
/*****************************************************************************/

#ifdef WASD_VMS_V7
#undef _VMS__V6__SOURCE
#define _VMS__V6__SOURCE
#undef __VMS_VER
#define __VMS_VER 70000000
#undef __CRTL_VER
#define __CRTL_VER 70000000
#endif

/* standard C header files */
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

/* VMS related header files */
#include <atrdef.h>
#include <descrip.h>
#include <dvidef.h>
#include <fibdef.h>
#include <iodef.h>
#include <lkidef.h>
#include <lckdef.h>
#include <prvdef.h>
#include <rmsdef.h>
#include <ssdef.h>
#include <stsdef.h>

/* application-related header files */
#include "wasd.h"

#define WASD_MODULE "PROXYMAINT"

/********************/
/* external storage */
/********************/

extern BOOL  ProxyServingEnabled,
             ProxyUnknownRequestFields;

extern int  EfnWait,
            EfnNoWait,
            HttpdTickSecond,
            OpcomMessages,
            ProxyConnectPersistMax,
            ProxyConnectPersistSeconds,
            ProxyConnectTimeoutSeconds,
            ProxyForwardedBy,
            ProxyHostLookupRetryCount,
            ProxyNetConnectCount,
            ProxyVerifyRecordMax,
            ProxyXForwardedFor;

extern int  ToLowerCase[],
            ToUpperCase[];

extern char  ErrorSanityCheck[],
             ServerHostPort[];

extern unsigned short HttpdTime7[];

extern ACCOUNTING_STRUCT  *AccountingPtr;
extern CONFIG_STRUCT  Config;
extern MSG_STRUCT  Msgs;
extern PROXY_ACCOUNTING_STRUCT  *ProxyAccountingPtr;
extern PROXYVERIFY_GBLSEC  *ProxyVerifyGblSecPtr;
extern WATCH_STRUCT  Watch;

/*****************************************************************************/
/*
Return a report and control menu related proxy serving.
*/ 

ProxyMaintReport (REQUEST_STRUCT *rqptr)

{
   int  status;

   /*********/
   /* begin */
   /*********/

   if (WATCHMOD (rqptr, WATCH_MOD_PROXY))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_PROXY, "ProxyMaintReport()");

   AdminPageTitle (rqptr, "Proxy Report");

   status = ProxyMaintStatsReport (rqptr);
   if (VMSnok (status))
   {
      rqptr->rqResponse.ErrorTextPtr = "ProxyMaintStatisticsReport()";
      ErrorVmsStatus (rqptr, status, FI_LI);
      AdminEnd (rqptr);
      return;
   }

   status = ProxyMaintFunctionReport (rqptr);
   if (VMSnok (status))
   {
      rqptr->rqResponse.ErrorTextPtr = "ProxyMaintFunctionReport()";
      ErrorVmsStatus (rqptr, status, FI_LI);
      AdminEnd (rqptr);
      return;
   }

   rqptr->rqResponse.PreExpired = PRE_EXPIRE_ADMIN;
   ResponseHeader200 (rqptr, "text/html", &rqptr->NetWriteBufferDsc);

   AdminEnd (rqptr);
}

/*****************************************************************************/
/*
Return a report on proxy serving.
*/ 

int ProxyMaintStatsReport (REQUEST_STRUCT *rqptr)

{
   static char  ResponseFao [] =
"<p><table class=\"ctgry\">\n\
<tr><th class=\"ctttl\">Statistics!AZ</th></tr>\n\
<tr><td>\n\
<table class=\"rghtrght\">\n\
<tr><td>\n\
\
<table cellpadding=\"0\" cellspacing=\"5\" border=\"0\">\n\
<tr><th class=\"sbttl\">Proxy&nbsp;Total</th></tr>\n\
<tr><th>Requests:</th><td>!&L</td></tr>\n\
<tr><th>Bytes:</th><td colspan=\"2\" align=\"left\">!&,@UQ</td></tr>\n\
<tr><th>IPv4:</th><td>!&L</td><td>(!UL%)</td></tr>\n\
<tr><th>IPv6:</th><td>!&L</td><td>(!UL%)</td></tr>\n\
</table>\n\
\
</td><td style=\"padding-left:1em;\">\n\
\
<table cellpadding=\"0\" cellspacing=\"5\" border=\"0\">\n\
<tr><th class=\"sbttl\">SOCKS5</th></tr>\n\
<tr><th>Total:</th><td>!&L</td></tr>\n\
<tr><th>Success:</th><td>!&L</td></tr>\n\
<tr><th>Fail:</th><td>!&L</td></tr>\n\
</table>\n\
\
</td><td>\n\
\
<table cellpadding=\"0\" cellspacing=\"5\" border=\"0\">\n\
<tr><th class=\"sbttl\">Host&nbsp;Resolution</th></tr>\n\
<tr><th>Literal:</th><td>!&L</td></tr>\n\
<tr><th>DNS:</th><td>!&L</td><td>(!UL%)</td></tr>\n\
<tr><th>Cache:</th><td>!&L</td></tr>\n\
<tr><th>Error:</th><td>!&L</td></tr>\n\
</table>\n\
\
</td></tr>\n\
</table>\n\
</td></tr>\n\
</table>\n";

   int  status,
        ConnectCountNetwork,
        PercentBytesNetwork,
        PercentCountIpv4,
        PercentCountIpv6,
        PercentCountNetwork,
        PercentDnsName,
        TotalCount;
   int64  BytesRaw64,
          BytesRawRx64,
          BytesRawTx64,
          BytesTotal64;
   unsigned short  Length;
   unsigned long  FaoVector [64];
   unsigned long  *vecptr;
   char  Buffer [2048];
   $DESCRIPTOR (BufferDsc, Buffer);

   /*********/
   /* begin */
   /*********/

   if (WATCHMOD (rqptr, WATCH_MOD_PROXY))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_PROXY, "ProxyMaintStatsReport()");

   InstanceMutexLock (INSTANCE_MUTEX_HTTPD);

   /*********/
   /* bytes */
   /*********/

   BytesRaw64 = ProxyAccountingPtr->BytesRawRx64 +
                ProxyAccountingPtr->BytesRawTx64;

   PercentBytesNetwork = PercentOf64 (&BytesRaw64, &BytesTotal64);

   /*********************/
   /* counts percentage */
   /*********************/

   ConnectCountNetwork = ProxyAccountingPtr->ConnectIpv4Count +
                         ProxyAccountingPtr->ConnectIpv6Count;
   PercentCountIpv4 = PercentOf32 (&ProxyAccountingPtr->ConnectIpv4Count,
                                   &ConnectCountNetwork);
   PercentCountIpv6 = PercentOf32 (&ProxyAccountingPtr->ConnectIpv6Count,
                                   &ConnectCountNetwork);

   /* get these values because of the locking requirements */
   BytesRawRx64 = ProxyAccountingPtr->BytesRawRx64;
   BytesRawTx64 = ProxyAccountingPtr->BytesRawTx64;

   TotalCount = AccountingPtr->LookupDnsNameCount +
                AccountingPtr->LookupCacheNameCount;
   if (TotalCount)
      PercentDnsName = AccountingPtr->LookupDnsNameCount * 100 / TotalCount;
   else
      PercentDnsName = 0;

   /***********/
   /* display */
   /***********/

   vecptr = FaoVector;

   if (ProxyServingEnabled)
      *vecptr++ = "";
   else
      *vecptr++ = "<span style=\"color:#ff0000\"> ... DISABLED</span>";

   *vecptr++ = AccountingPtr->DoProxyCount;
   *vecptr++ = &BytesRaw64;
   *vecptr++ = ProxyAccountingPtr->ConnectIpv4Count;
   *vecptr++ = PercentCountIpv4;
   *vecptr++ = ProxyAccountingPtr->ConnectIpv6Count;
   *vecptr++ = PercentCountIpv6;

   *vecptr++ = ProxyAccountingPtr->Socks5Count;
   *vecptr++ = ProxyAccountingPtr->Socks5SuccessCount;
   *vecptr++ = ProxyAccountingPtr->Socks5FailCount;

   *vecptr++ = AccountingPtr->LookupLiteralCount;
   *vecptr++ = AccountingPtr->LookupDnsNameCount;
   *vecptr++ = PercentDnsName;
   *vecptr++ = AccountingPtr->LookupCacheNameCount;
   *vecptr++ = AccountingPtr->LookupDnsNameErrorCount;

   InstanceMutexUnLock (INSTANCE_MUTEX_HTTPD);

   *vecptr++ = AdminRefresh (rqptr);

   status = FaolToNet (rqptr, ResponseFao, &FaoVector);
   if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI);

   return (status);
}

/*****************************************************************************/
/*
Return a report on proxy special functionality.
*/ 

int ProxyMaintFunctionReport (REQUEST_STRUCT *rqptr)

{
   static char  ResponseFao [] =
"<p><table class=\"ctgry\">\n\
<tr><th class=\"ctttl\">Function!AZ</th></tr>\n\
<tr><td>\n\
<table class=\"rghtlft\">\n\
<tr><td>\n\
\
<table class=\"rghtlft\">\n\
<tr><th class=\"sbttl tacnt\" colspan=\"4\">Gateway</th></tr>\n\
<tr><th class=\"tacnt\">Out&nbsp;\\&nbsp;In:</th>\
<th class=\"talft\">HTTP</th>\
<th class=\"talft\">HTTPS</th>\
</tr>\n\
<tr>\
<th>HTTP</th>\
<td>!&L</td>\
<td>!&L</td>\
</tr>\n\
<tr>\
<th>HTTPS</th>\
<td>!&L</td>\
<td>!&L</td>\
</tr>\n\
\
<tr><th class=\"tacnt\">Out&nbsp;\\&nbsp;In:</th>\
<th class=\"talft\">IPv4</th>\
<th class=\"talft\">IPv6</th>\
</tr>\n\
<tr>\
<th>IPv4</th>\
<td>!&L</td>\
<td>!&L</td>\
</tr>\n\
<tr>\
<th>IPv6</th>\
<td>!&L</td>\
<td>!&L</td>\
</tr>\n\
</table>\n\
</td>\
\
<td colspan=\"3\">\n\
<table class=\"rghtlft\">\n\
<tr><th class=\"sbttl tacnt\" colspan=\"7\">Tunnel</th></tr>\n\
<tr><th class=\"tacnt\">Out&nbsp;\\&nbsp;In:</th>\
<th class=\"talft\">CONNECT</th>\
<th class=\"talft\">Firewall</th>\
<th class=\"talft\">Raw</th>\
</tr>\n\
<tr>\
<th>CONNECT</th>\
<td>!&L</td>\
<td>!&L</td>\
<td>!&L</td>\
</tr>\n\
<tr>\
<th>HTTP</th>\
<td>!&L</td>\
<td>!&L</td>\
<td>!&L</td>\
</tr>\n\
<tr>\
<th>HTTPS</th>\
<td>!&L</td>\
<td>!&L</td>\
<td>!&L</td>\
</tr>\n\
<tr>\
<th>Raw</th>\
<td>!&L</td>\
<td>!&L</td>\
<td>!&L</td>\
</tr>\n\
<tr><td></td></tr>\n\
<tr><th>Current:</th><td>!&L&nbsp;&nbsp;\
<a class=\"abttn bttn400!AZ\" href=\"!AZ\">Report</a>\n\
</td></tr>\n\
</table>\n\
</td>\n\
\
</tr>\n\
\
<tr><td></td></tr>\n\
\
\
<tr><td>\n\
<table class=\"rghtrght\">\n\
<tr><th class=\"sbttl tacnt\" colspan=\"4\">Verify</th></tr>\n\
<tr><th>Max:</th><td>!&L</td>\n\
<th>Full:</th><td>!&L</td></tr>\n\
<tr><th>Current:</th><td>!&L</td>\n\
<th>200:</th><td>!&L</td></tr>\n\
<tr><th>Set:</th><td>!&L</td>\n\
<th>403:</th><td>!&L</td></tr>\n\
<tr><th>Find:</th><td>!&L</td>\n\
<th>404:</th><td>!&L</td></tr>\n\
</table>\n\
</td>\n\
\
<td>\n\
<table class=\"rghtrght\">\n\
<tr><th class=\"sbttl tacnt\" colspan=\"4\">Rework</th></tr>\n\
<tr><th>Count:</th><td>!&L</td></tr>\n\
<tr><th>No&nbsp;Type:</th><td>!&L</td></tr>\n\
<tr><th>Search:</th><td>!&L</td></tr>\n\
<tr><th>Replace:</th><td>!&L</td></tr>\n\
<tr><th>Too&nbsp;Big:</th><td>!&L</td></tr>\n\
</table>\n\
\
</td></tr>\n\
</table>\n\
</td></tr>\n\
</table>\n";

   int  in, out, status;
   unsigned short  Length;
   unsigned long  FaoVector [64];
   unsigned long  *vecptr;
   char  Buffer [2048];
   $DESCRIPTOR (BufferDsc, Buffer);

   /*********/
   /* begin */
   /*********/

   if (WATCHMOD (rqptr, WATCH_MOD_PROXY))
      WatchThis (WATCHITM(rqptr), WATCH_MOD_PROXY,
                 "ProxyMaintFunctionReport()");

   InstanceMutexLock (INSTANCE_MUTEX_HTTPD);

   vecptr = FaoVector;

   if (ProxyServingEnabled)
      *vecptr++ = "";
   else
      *vecptr++ = "<span style=\"color:#ff0000\"> ... DISABLED</span>";

   /* [http=0,https=1][http=0,https=1] */
   *vecptr++ = ProxyAccountingPtr->GatewaySchemeCount[0][0];
   *vecptr++ = ProxyAccountingPtr->GatewaySchemeCount[1][0];
   *vecptr++ = ProxyAccountingPtr->GatewaySchemeCount[0][1];
   *vecptr++ = ProxyAccountingPtr->GatewaySchemeCount[1][1];

   /* [ipv4=0,ipv6=1][ipv4=0,ipv6=1] */
   *vecptr++ = ProxyAccountingPtr->GatewayIpvCount[0][0];
   *vecptr++ = ProxyAccountingPtr->GatewayIpvCount[1][0];
   *vecptr++ = ProxyAccountingPtr->GatewayIpvCount[0][1];
   *vecptr++ = ProxyAccountingPtr->GatewayIpvCount[1][1];

   for (out = 0; out < TUNNEL_COUNT_MAX; out++)
   {
      if (out+1 == PROXY_TUNNEL_FIREWALL) continue;
      for (in = 0; in < TUNNEL_COUNT_MAX; in++)
      {
         if (in+1 == PROXY_TUNNEL_HTTP || in+1 == PROXY_TUNNEL_HTTPS) continue;
         *vecptr++ = ProxyAccountingPtr->TunnelCount[in][out];
      }
   }

   *vecptr++ = ProxyAccountingPtr->TunnelCurrent;

   if (SysTrnLnm ("WASD_TUNNEL"))
      *vecptr++ = "";
   else
      *vecptr++ = " dbttn";
   *vecptr++ = ADMIN_REPORT_PROXY_TUNNEL;

   *vecptr++ = ProxyVerifyRecordMax;
   *vecptr++ = ProxyAccountingPtr->VerifyFullCount;
   *vecptr++ = ProxyAccountingPtr->VerifyCurrentCount;
   *vecptr++ = ProxyAccountingPtr->Verify200Count;
   *vecptr++ = ProxyAccountingPtr->VerifySetRecordCount;
   *vecptr++ = ProxyAccountingPtr->Verify403Count;
   *vecptr++ = ProxyAccountingPtr->VerifyFindRecordCount;
   *vecptr++ = ProxyAccountingPtr->Verify404Count;

   *vecptr++ = ProxyAccountingPtr->ReworkCount;
   *vecptr++ = ProxyAccountingPtr->ReworkNoType;
   *vecptr++ = ProxyAccountingPtr->ReworkReplaceSearch;
   *vecptr++ = ProxyAccountingPtr->ReworkReplaceCount;
   *vecptr++ = ProxyAccountingPtr->ReworkTooBig;

   InstanceMutexUnLock (INSTANCE_MUTEX_HTTPD);

   status = FaolToNet (rqptr, ResponseFao, &FaoVector);
   if (VMSnok (status)) ErrorNoticed (rqptr, status, NULL, FI_LI);

   return (status);
}

/****************************************************************************/
