trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jpe...@apache.org
Subject git commit: TS-2169: SSL statistics
Date Tue, 04 Mar 2014 01:28:37 GMT
Repository: trafficserver
Updated Branches:
  refs/heads/master 3b3461edf -> 983e22bc8


TS-2169: SSL statistics

Add SSL event and cipher statistics.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/983e22bc
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/983e22bc
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/983e22bc

Branch: refs/heads/master
Commit: 983e22bc83c7036f585efba539a49e7e57e69ef9
Parents: 3b3461e
Author: Ron Barber <rbarber@yahoo-inc.com>
Authored: Mon Mar 3 17:20:43 2014 -0800
Committer: James Peach <jpeach@apache.org>
Committed: Mon Mar 3 17:25:52 2014 -0800

----------------------------------------------------------------------
 CHANGES                                    |   3 +
 doc/reference/commands/traffic_line.en.rst | 134 ++++++++++++
 iocore/net/P_SSLCertLookup.h               |   3 +
 iocore/net/P_SSLUtils.h                    |  56 ++++-
 iocore/net/SSLCertLookup.cc                |  14 ++
 iocore/net/SSLNetProcessor.cc              |   3 +
 iocore/net/SSLNetVConnection.cc            |  19 +-
 iocore/net/SSLUtils.cc                     | 279 +++++++++++++++++++++++-
 8 files changed, 496 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/983e22bc/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index c1b35dc..3a83537 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 5.0.0
 
+  *) [TS-2169] Add SSL statistics
+   Author: Ron Barber <rbarber@yahoo-inc.com>
+
   *) [TS-2607] Fix TS_USE_HWLOC #define in build process
 
   *) [TS-2595] DNS lookup failed with multiple search domains. 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/983e22bc/doc/reference/commands/traffic_line.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/commands/traffic_line.en.rst b/doc/reference/commands/traffic_line.en.rst
index aed8830..54eef3e 100644
--- a/doc/reference/commands/traffic_line.en.rst
+++ b/doc/reference/commands/traffic_line.en.rst
@@ -792,6 +792,140 @@ The :option:`traffic_line -r` option accepts the following variable
names::
     proxy.process.cache.volume_0.hdr_marshal_bytes
     proxy.process.cache.volume_0.gc_bytes_evacuated
     proxy.process.cache.volume_0.gc_frags_evacuated
+    proxy.process.ssl.user_agent_other_errors
+    proxy.process.ssl.user_agent_expired_cert
+    proxy.process.ssl.user_agent_revoked_cert
+    proxy.process.ssl.user_agent_unknown_cert
+    proxy.process.ssl.user_agent_cert_verify_failed
+    proxy.process.ssl.user_agent_bad_cert
+    proxy.process.ssl.user_agent_decryption_failed
+    proxy.process.ssl.user_agent_wrong_version
+    proxy.process.ssl.user_agent_unknown_ca
+    proxy.process.ssl.origin_server_other_errors
+    proxy.process.ssl.origin_server_expired_cert
+    proxy.process.ssl.origin_server_revoked_cert
+    proxy.process.ssl.origin_server_unknown_cert
+    proxy.process.ssl.origin_server_cert_verify_failed
+    proxy.process.ssl.origin_server_bad_cert
+    proxy.process.ssl.origin_server_decryption_failed
+    proxy.process.ssl.origin_server_wrong_version
+    proxy.process.ssl.origin_server_unknown_ca
+    proxy.process.ssl.user_agent_sessions
+    proxy.process.ssl.user_agent_session_hit
+    proxy.process.ssl.user_agent_session_miss
+    proxy.process.ssl.user_agent_session_timeout
+    proxy.process.ssl.cipher.user_agent.{cipherName}
+
+Statistics Descriptions
+=======================
+
+proxy.process.ssl.user_agent_other_errors
+  Total number of *other* ssl client connection errors (counts ssl
+  errors that are not captured in other user agent stats below)
+
+proxy.process.ssl.user_agent_expired_cert
+  Total number of ssl client connection failures where the cert was
+  expired.
+
+proxy.process.ssl.user_agent_revoked_cert
+  Total number of ssl client connection failures where the cert was
+  revoked.
+
+proxy.process.ssl.user_agent_unknown_cert
+  Total number of ssl client connection failures related to the cert,
+  but specific error was unknown.
+
+proxy.process.ssl.user_agent_cert_verify_failed
+  Total number of ssl client connection failures where cert verification
+  failed.
+
+proxy.process.ssl.user_agent_bad_cert
+  Total number of ssl client connection failures where the cert is bad.
+
+proxy.process.ssl.user_agent_decryption_failed
+  Total number of ssl client connection decryption failures (during
+  negotiation).
+
+proxy.process.ssl.user_agent_wrong_version
+  Total number of ssl client connections that provided an invalid protocol
+  version.
+
+proxy.process.ssl.user_agent_unknown_ca
+  Total number of ssl client connection that failed due to unknown ca.
+
+proxy.process.ssl.origin_server_other_errors
+  Total number of *other* ssl origin server connection errors (counts ssl
+  errors that are not captured in other origin server stats below).
+
+proxy.process.ssl.origin_server_expired_cert
+  Total number of ssl origin server connection failures where the cert
+  was expired.
+
+proxy.process.ssl.origin_server_revoked_cert
+  Total number of ssl origin server connection failures where the cert
+  was revoked.
+
+proxy.process.ssl.origin_server_unknown_cert
+  Total number of ssl origin server connection failures related to the
+  cert where specific error was unknown.
+
+proxy.process.ssl.origin_server_cert_verify_failed
+  Total number of ssl origin server connection failures where cert
+  verification failed.
+
+proxy.process.ssl.origin_server_bad_cert
+  Total number of ssl origin server connection failures where the cert
+  is bad.
+
+proxy.process.ssl.origin_server_decryption_failed
+  Total number of ssl origin server connection decryption failures
+  (during negotiation).
+
+proxy.process.ssl.origin_server_wrong_version
+  Total number of ssl origin server connections that provided an invalid
+  protocol version.
+
+proxy.process.ssl.origin_server_unknown_ca
+  Total number of ssl origin server connection that failed due to
+  unknown ca.
+
+proxy.process.ssl.user_agent_sessions
+  Total number of ssl/tls sessions created.
+
+proxy.process.ssl.user_agent_session_hit
+  Total number of session hits.  A previous session was reused which
+  resulted in an abbreviated ssl client negotiation.
+
+proxy.process.ssl.user_agent_session_miss
+  Total number of session misses.  The ssl client provided a session id
+  that was not found in cache and, therefore, could not be used.
+
+proxy.process.ssl.user_agent_session_timeout
+  Total number of session timeouts.  The ssl client provided a session, but
+  it could not be used because it was past the session timeout.
+
+proxy.process.ssl.cipher.user_agent.{cipherName}
+  Total number of ssl client connections that used cipherName.  The list of
+  cipher stats is dynamic and depends upon the installed ciphers and the
+  cipher configuration of ats (proxy.config.ssl.server.cipher_suite).
+  Some common cipher stats are:
+    proxy.process.ssl.cipher.user_agent.ECDHE-RSA-RC4-SHA
+    proxy.process.ssl.cipher.user_agent.ECDHE-RSA-AES128-SHA256
+    proxy.process.ssl.cipher.user_agent.ECDHE-RSA-AES128-GCM-SHA256
+    proxy.process.ssl.cipher.user_agent.ECDHE-RSA-AES128-SHA
+    proxy.process.ssl.cipher.user_agent.RC4-SHA
+    proxy.process.ssl.cipher.user_agent.RC4-MD5
+    proxy.process.ssl.cipher.user_agent.AES128-GCM-SHA256
+    proxy.process.ssl.cipher.user_agent.AES128-SHA
+  There are two ways to get the list of cipher stats:
+  1.  Run ATS with debug logging and show ssl diags:
+      CONFIG proxy.config.diags.debug.enabled INT 1
+      CONFIG proxy.config.diags.debug.tags STRING ssl.*
+      View output of traffic.out looking for lines like:
+         (ssl) Registering ssl cipher stat 'proxy.process.ssl.cipher.user_agent.ECDHE-RSA-AES256-GCM-SHA384'
+  2.  Run this (asks openssl to tell us) to get a list of all possible ciphers
+    on the system (not all may be available as stats):
+         openssl ciphers | sed 's/\([^:]\+\)/proxy.process.ssl.cipher.user_agent.\1/g; s/:/\n/g'
 
 Examples
 ========

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/983e22bc/iocore/net/P_SSLCertLookup.h
----------------------------------------------------------------------
diff --git a/iocore/net/P_SSLCertLookup.h b/iocore/net/P_SSLCertLookup.h
index dced909..f2328ef 100644
--- a/iocore/net/P_SSLCertLookup.h
+++ b/iocore/net/P_SSLCertLookup.h
@@ -43,6 +43,9 @@ struct SSLCertLookup : public ConfigInfo
   // Return the last-resort default TLS context if there is no name or address match.
   SSL_CTX * defaultContext() const { return ssl_default; }
 
+  unsigned count() const;
+  SSL_CTX * get(unsigned i) const;
+
   SSLCertLookup();
   virtual ~SSLCertLookup();
 };

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/983e22bc/iocore/net/P_SSLUtils.h
----------------------------------------------------------------------
diff --git a/iocore/net/P_SSLUtils.h b/iocore/net/P_SSLUtils.h
index 1dd46d4..7297eac 100644
--- a/iocore/net/P_SSLUtils.h
+++ b/iocore/net/P_SSLUtils.h
@@ -35,6 +35,51 @@
 
 struct SSLConfigParams;
 struct SSLCertLookup;
+class SSLNetVConnection;
+struct RecRawStatBlock;
+
+enum SSL_Stats
+{
+  ssl_origin_server_expired_cert_stat,
+  ssl_user_agent_expired_cert_stat,
+  ssl_origin_server_revoked_cert_stat,
+  ssl_user_agent_revoked_cert_stat,
+  ssl_origin_server_unknown_cert_stat,
+  ssl_user_agent_unknown_cert_stat,
+  ssl_origin_server_cert_verify_failed_stat,
+  ssl_user_agent_cert_verify_failed_stat,
+  ssl_origin_server_bad_cert_stat,
+  ssl_user_agent_bad_cert_stat,
+  ssl_origin_server_decryption_failed_stat,
+  ssl_user_agent_decryption_failed_stat,
+  ssl_origin_server_wrong_version_stat,
+  ssl_user_agent_wrong_version_stat,
+  ssl_origin_server_other_errors_stat,
+  ssl_user_agent_other_errors_stat,
+  ssl_origin_server_unknown_ca_stat,
+  ssl_user_agent_unknown_ca_stat,
+  ssl_user_agent_sessions_stat,
+  ssl_user_agent_session_hit_stat,
+  ssl_user_agent_session_miss_stat,
+  ssl_user_agent_session_timeout_stat,
+
+  ssl_cipher_stats_start = 100,
+  ssl_cipher_stats_end = 300,
+
+  Ssl_Stat_Count
+};
+
+extern RecRawStatBlock *ssl_rsb;
+
+/* Stats should only be accessed using these macros */
+#define SSL_INCREMENT_DYN_STAT(x) RecIncrRawStat(ssl_rsb, NULL, (int) x, 1)
+#define SSL_DECREMENT_DYN_STAT(x) RecIncrRawStat(ssl_rsb, NULL, (int) x, -1)
+#define SSL_SET_COUNT_DYN_STAT(x,count) RecSetRawStatCount(ssl_rsb, x, count)
+#define SSL_CLEAR_DYN_STAT(x) \
+  do { \
+    RecSetRawStatSum(ssl_rsb, (x), 0); \
+    RecSetRawStatCount(ssl_rsb, (x), 0); \
+  } while (0);
 
 // Create a default SSL server context.
 SSL_CTX * SSLDefaultServerContext();
@@ -45,15 +90,20 @@ SSL_CTX * SSLInitClientContext(const SSLConfigParams * param);
 // Initialize the SSL library.
 void SSLInitializeLibrary();
 
+// Initialize SSL statistics.
+void SSLInitializeStatistics();
+
 // Release SSL_CTX and the associated data
 void SSLReleaseContext(SSL_CTX* ctx);
 
 // Log an SSL error.
-#define SSLError(fmt, ...) SSLDiagnostic(DiagsMakeLocation(), false, fmt, ##__VA_ARGS__)
+#define SSLError(fmt, ...) SSLDiagnostic(DiagsMakeLocation(), false, NULL, fmt, ##__VA_ARGS__)
+#define SSLErrorVC(vc,fmt, ...) SSLDiagnostic(DiagsMakeLocation(), false, vc, fmt, ##__VA_ARGS__)
 // Log a SSL diagnostic using the "ssl" diagnostic tag.
-#define SSLDebug(fmt, ...) SSLDiagnostic(DiagsMakeLocation(), true, fmt, ##__VA_ARGS__)
+#define SSLDebug(fmt, ...) SSLDiagnostic(DiagsMakeLocation(), true, NULL, fmt, ##__VA_ARGS__)
+#define SSLDebugVC(vc,fmt, ...) SSLDiagnostic(DiagsMakeLocation(), true, vc, fmt, ##__VA_ARGS__)
 
-void SSLDiagnostic(const SrcLoc& loc, bool debug, const char * fmt, ...) TS_PRINTFLIKE(3,
4);
+void SSLDiagnostic(const SrcLoc& loc, bool debug, SSLNetVConnection * vc, const char
* fmt, ...) TS_PRINTFLIKE(4, 5);
 
 // Return a static string name for a SSL_ERROR constant.
 const char * SSLErrorName(int ssl_error);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/983e22bc/iocore/net/SSLCertLookup.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLCertLookup.cc b/iocore/net/SSLCertLookup.cc
index df77418..2d8bf54 100644
--- a/iocore/net/SSLCertLookup.cc
+++ b/iocore/net/SSLCertLookup.cc
@@ -75,6 +75,8 @@ struct SSLContextStorage
 
   bool insert(SSL_CTX * ctx, const char * name);
   SSL_CTX * lookup(const char * name) const;
+  unsigned count() const { return this->references.count(); }
+  SSL_CTX * get(unsigned i) const { return this->references[i]; }
 
 private:
   struct SSLEntry
@@ -141,6 +143,18 @@ SSLCertLookup::insert(SSL_CTX * ctx, const IpEndpoint& address)
   return this->ssl_storage->insert(ctx, key.get());
 }
 
+unsigned
+SSLCertLookup::count() const
+{
+  return ssl_storage->count();
+}
+
+SSL_CTX *
+SSLCertLookup::get(unsigned i) const
+{
+  return ssl_storage->get(i);
+}
+
 struct ats_wildcard_matcher
 {
   ats_wildcard_matcher() {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/983e22bc/iocore/net/SSLNetProcessor.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLNetProcessor.cc b/iocore/net/SSLNetProcessor.cc
index 25b4204..094eeaf 100644
--- a/iocore/net/SSLNetProcessor.cc
+++ b/iocore/net/SSLNetProcessor.cc
@@ -69,6 +69,9 @@ SSLNetProcessor::start(int number_of_ssl_threads, size_t stacksize)
     return -1;
   }
 
+  // Initialize SSL statistics. This depends on an initial set of certificates being loaded
above.
+  SSLInitializeStatistics();
+
   SSLNetProcessor::ET_SSL = eventProcessor.spawn_event_threads(number_of_ssl_threads, "ET_SSL",
stacksize);
   return UnixNetProcessor::start(0, stacksize);
 }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/983e22bc/iocore/net/SSLNetVConnection.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc
index 9ddc8e9..dfcef4d 100644
--- a/iocore/net/SSLNetVConnection.cc
+++ b/iocore/net/SSLNetVConnection.cc
@@ -75,10 +75,9 @@ do_SSL_write(SSL * ssl, void *buf, int size)
 
 
 static int
-ssl_read_from_net(UnixNetVConnection * vc, EThread * lthread, int64_t &ret)
+ssl_read_from_net(SSLNetVConnection * sslvc, EThread * lthread, int64_t &ret)
 {
-  NetState *s = &vc->read;
-  SSLNetVConnection *sslvc = (SSLNetVConnection *) vc;
+  NetState *s = &sslvc->read;
   MIOBufferAccessor & buf = s->vio.buffer;
   IOBufferBlock *b = buf.writer()->first_write_block();
   int event = SSL_READ_ERROR_NONE;
@@ -132,7 +131,7 @@ ssl_read_from_net(UnixNetVConnection * vc, EThread * lthread, int64_t
&ret)
           // not EOF
           event = SSL_READ_ERROR;
           ret = errno;
-          SSLError("[SSL_NetVConnection::ssl_read_from_net] SSL_ERROR_SYSCALL, underlying
IO error: %s", strerror(errno));
+          SSLErrorVC(sslvc, "[SSL_NetVConnection::ssl_read_from_net] SSL_ERROR_SYSCALL, underlying
IO error: %s", strerror(errno));
         } else {
           // then EOF observed, treat it as EOS
           event = SSL_READ_EOS;
@@ -147,7 +146,7 @@ ssl_read_from_net(UnixNetVConnection * vc, EThread * lthread, int64_t
&ret)
       default:
         event = SSL_READ_ERROR;
         ret = errno;
-        SSLError("[SSL_NetVConnection::ssl_read_from_net]");
+        SSLErrorVC(sslvc, "[SSL_NetVConnection::ssl_read_from_net]");
         break;
       }                         // switch
       break;
@@ -158,7 +157,7 @@ ssl_read_from_net(UnixNetVConnection * vc, EThread * lthread, int64_t
&ret)
     Debug("ssl", "[SSL_NetVConnection::ssl_read_from_net] bytes_read=%" PRId64, bytes_read);
     buf.writer()->fill(bytes_read);
     s->vio.ndone += bytes_read;
-    vc->netActivity(lthread);
+    sslvc->netActivity(lthread);
 
     ret = bytes_read;
 
@@ -430,7 +429,7 @@ SSLNetVConnection::load_buffer_and_write(int64_t towrite, int64_t &wattempted,
i
     default:
       r = -errno;
       Debug("ssl", "SSL_write-SSL_ERROR_SSL");
-      SSLError("SSL_write");
+      SSLErrorVC(this, "SSL_write");
       break;
     }
     return (r);
@@ -495,7 +494,7 @@ SSLNetVConnection::sslStartHandShake(int event, int &err)
       this->ssl = make_ssl_connection(lookup->defaultContext(), this);
       if (this->ssl == NULL) {
         Debug("ssl", "SSLNetVConnection::sslServerHandShakeEvent, ssl create failed");
-        SSLError("SSL_StartHandShake");
+        SSLErrorVC(this, "SSL_StartHandShake");
         return EVENT_ERROR;
       }
     }
@@ -523,7 +522,7 @@ SSLNetVConnection::sslServerHandShakeEvent(int &err)
   ssl_error = SSL_get_error(ssl, ret);
   if (ssl_error != SSL_ERROR_NONE) {
     err = errno;
-    SSLDebug("SSL handshake error: %s (%d), errno=%d", SSLErrorName(ssl_error), ssl_error,
err);
+    SSLDebugVC(this,"SSL handshake error: %s (%d), errno=%d", SSLErrorName(ssl_error), ssl_error,
err);
   }
 
   switch (ssl_error) {
@@ -660,7 +659,7 @@ SSLNetVConnection::sslClientHandShakeEvent(int &err)
   case SSL_ERROR_SSL:
   default:
     err = errno;
-    SSLError("sslClientHandShakeEvent");
+    SSLErrorVC(this, "sslClientHandShakeEvent");
     return EVENT_ERROR;
     break;
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/983e22bc/iocore/net/SSLUtils.cc
----------------------------------------------------------------------
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index 32cdd25..b96823e 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -25,6 +25,7 @@
 #include "P_Net.h"
 #include "ink_cap.h"
 
+#include <string>
 #include <openssl/err.h>
 #include <openssl/bio.h>
 #include <openssl/pem.h>
@@ -110,6 +111,9 @@ static int ssl_session_ticket_index = 0;
 static pthread_mutex_t *mutex_buf = NULL;
 static bool open_ssl_initialized = false;
 
+RecRawStatBlock *ssl_rsb = NULL;
+static InkHashTable *ssl_cipher_name_table = NULL;
+
 struct ats_file_bio
 {
   ats_file_bio(const char * path, const char * mode)
@@ -488,6 +492,37 @@ ssl_private_key_validate_exec(const char *cmdLine)
   return bReturn;
 }
 
+static int
+SSLRecRawStatSyncCount(const char *name, RecDataT data_type, RecData *data, RecRawStatBlock
*rsb, int id)
+{
+  // Grab all the stats we want from OpenSSL and set the stats. This function only needs
to be called by one of the
+  // involved stats, all others *must* call RecRawStatSyncSum.
+  SSLCertificateConfig::scoped_config certLookup;
+
+  int64_t sessions = 0;
+  int64_t hits = 0;
+  int64_t misses = 0;
+  int64_t timeouts = 0;
+
+  if (certLookup) {
+    const unsigned ctxCount = certLookup->count();
+    for (size_t i = 0; i < ctxCount; i++) {
+      SSL_CTX * ctx = certLookup->get(i);
+
+      sessions += SSL_CTX_sess_accept_good(ctx);
+      hits += SSL_CTX_sess_hits(ctx);
+      misses += SSL_CTX_sess_misses(ctx);
+      timeouts += SSL_CTX_sess_timeouts(ctx);
+    }
+  }
+
+  SSL_SET_COUNT_DYN_STAT(ssl_user_agent_sessions_stat, sessions);
+  SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_hit_stat, hits);
+  SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_miss_stat, misses);
+  SSL_SET_COUNT_DYN_STAT(ssl_user_agent_session_timeout_stat, timeouts);
+  return RecRawStatSyncCount(name, data_type, data, rsb, id);
+}
+
 void
 SSLInitializeLibrary()
 {
@@ -517,7 +552,224 @@ SSLInitializeLibrary()
 }
 
 void
-SSLDiagnostic(const SrcLoc& loc, bool debug, const char * fmt, ...)
+SSLInitializeStatistics()
+{
+  SSL_CTX *               ctx;
+  SSL *                   ssl;
+  STACK_OF(SSL_CIPHER) *  ciphers;
+
+  // Allocate SSL statistics block.
+  ssl_rsb = RecAllocateRawStatBlock((int) Ssl_Stat_Count);
+  ink_assert(ssl_rsb != NULL);
+
+  // SSL client errors.
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_other_errors",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_other_errors_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_expired_cert",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_expired_cert_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_revoked_cert",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_revoked_cert_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_unknown_cert",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_unknown_cert_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_cert_verify_failed",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_cert_verify_failed_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_bad_cert",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_bad_cert_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_decryption_failed",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_decryption_failed_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_wrong_version",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_wrong_version_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_unknown_ca",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_user_agent_unknown_ca_stat,
+                     RecRawStatSyncSum);
+
+  // Polled SSL context statistics.
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_sessions",
+                     RECD_INT, RECP_NON_PERSISTENT, (int) ssl_user_agent_sessions_stat,
+                     SSLRecRawStatSyncCount); //<- only use this fn once
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_hit",
+                     RECD_INT, RECP_NON_PERSISTENT, (int) ssl_user_agent_session_hit_stat,
+                     RecRawStatSyncCount);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_miss",
+                     RECD_INT, RECP_NON_PERSISTENT, (int) ssl_user_agent_session_miss_stat,
+                     RecRawStatSyncCount);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.user_agent_session_timeout",
+                     RECD_INT, RECP_NON_PERSISTENT, (int) ssl_user_agent_session_timeout_stat,
+                     RecRawStatSyncCount);
+
+  // SSL server errors.
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_other_errors",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_other_errors_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_expired_cert",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_expired_cert_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_revoked_cert",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_revoked_cert_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_unknown_cert",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_unknown_cert_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_cert_verify_failed",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_cert_verify_failed_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_bad_cert",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_bad_cert_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_decryption_failed",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_decryption_failed_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_wrong_version",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_wrong_version_stat,
+                     RecRawStatSyncSum);
+  RecRegisterRawStat(ssl_rsb, RECT_PROCESS, "proxy.process.ssl.origin_server_unknown_ca",
+                     RECD_INT, RECP_PERSISTENT, (int) ssl_origin_server_unknown_ca_stat,
+                     RecRawStatSyncSum);
+
+  // Get and register the SSL cipher stats. Note that we are using the default SSL context
to obtain
+  // the cipher list. This means that the set of ciphers is fixed by the build configuration
and not
+  // filtered by proxy.config.ssl.server.cipher_suite. This keeps the set of cipher suites
stable across
+  // configuration reloads and works for the case where we honor the client cipher preference.
+
+  // initialize stat name->index hash table
+  ssl_cipher_name_table = ink_hash_table_create(InkHashTableKeyType_Word);
+
+  ctx = SSLDefaultServerContext();
+  ssl = SSL_new(ctx);
+  ciphers = SSL_get_ciphers(ssl);
+
+  for (int index = 0; index < sk_SSL_CIPHER_num(ciphers); index++) {
+    SSL_CIPHER * cipher = sk_SSL_CIPHER_value(ciphers, index);
+    const char * cipherName = SSL_CIPHER_get_name(cipher);
+    std::string  statName = "proxy.process.ssl.cipher.user_agent." + std::string(cipherName);
+
+    // If room in allocated space ...
+    if ((ssl_cipher_stats_start + index) > ssl_cipher_stats_end) {
+      // Too many ciphers, increase ssl_cipher_stats_end.
+      SSLError("too many ciphers to register metric '%s', increase SSL_Stats::ssl_cipher_stats_end",
+               statName.c_str());
+      continue;
+    }
+
+    // If not already registered ...
+    if (!ink_hash_table_isbound(ssl_cipher_name_table, cipherName)) {
+      ink_hash_table_insert(ssl_cipher_name_table, cipherName, (void *)(intptr_t) (ssl_cipher_stats_start
+ index));
+      // Register as non-persistent since the order/index is dependent upon configuration.
+      RecRegisterRawStat(ssl_rsb, RECT_PROCESS, statName.c_str(),
+                         RECD_INT, RECP_NON_PERSISTENT, (int) ssl_cipher_stats_start + index,
+                         RecRawStatSyncSum);
+      SSL_CLEAR_DYN_STAT((int) ssl_cipher_stats_start + index);
+      Debug("ssl", "registering SSL cipher metric '%s'", statName.c_str());
+    }
+  }
+
+  SSL_free(ssl);
+  SSL_CTX_free(ctx);
+}
+
+// return true if we have a stat for the error
+static bool
+increment_ssl_client_error(unsigned long err)
+{
+  // we only look for LIB_SSL errors atm
+  if (ERR_LIB_SSL != ERR_GET_LIB(err)) {
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_other_errors_stat);
+    return false;
+  }
+
+  // error was in LIB_SSL, now just switch on REASON
+  // (we ignore FUNCTION with the prejudice that we don't care what function
+  // the error came from, hope that's ok?)
+  switch (ERR_GET_REASON(err)) {
+  case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_expired_cert_stat);
+    break;
+  case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_revoked_cert_stat);
+    break;
+  case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_unknown_cert_stat);
+    break;
+  case SSL_R_CERTIFICATE_VERIFY_FAILED:
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_cert_verify_failed_stat);
+    break;
+  case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_bad_cert_stat);
+    break;
+  case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED:
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_decryption_failed_stat);
+    break;
+  case SSL_R_WRONG_VERSION_NUMBER:
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_wrong_version_stat);
+    break;
+  case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_unknown_ca_stat);
+    break;
+  default:
+    SSL_INCREMENT_DYN_STAT(ssl_user_agent_other_errors_stat);
+    return false;
+  }
+
+  return true;
+}
+
+// return true if we have a stat for the error
+
+static bool
+increment_ssl_server_error(unsigned long err)
+{
+  // we only look for LIB_SSL errors atm
+  if (ERR_LIB_SSL != ERR_GET_LIB(err)) {
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_other_errors_stat);
+    return false;
+  }
+
+  // error was in LIB_SSL, now just switch on REASON
+  // (we ignore FUNCTION with the prejudice that we don't care what function
+  // the error came from, hope that's ok?)
+  switch (ERR_GET_REASON(err)) {
+  case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_expired_cert_stat);
+    break;
+  case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_revoked_cert_stat);
+    break;
+  case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_unknown_cert_stat);
+    break;
+  case SSL_R_CERTIFICATE_VERIFY_FAILED:
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_cert_verify_failed_stat);
+    break;
+  case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_bad_cert_stat);
+    break;
+  case SSL_R_TLSV1_ALERT_DECRYPTION_FAILED:
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_decryption_failed_stat);
+    break;
+  case SSL_R_WRONG_VERSION_NUMBER:
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_wrong_version_stat);
+    break;
+  case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_unknown_ca_stat);
+    break;
+  default:
+    SSL_INCREMENT_DYN_STAT(ssl_origin_server_other_errors_stat);
+    return false;
+  }
+
+  return true;
+}
+
+void
+SSLDiagnostic(const SrcLoc& loc, bool debug, SSLNetVConnection * vc, const char * fmt,
...)
 {
   unsigned long l;
   char buf[256];
@@ -540,6 +792,17 @@ SSLDiagnostic(const SrcLoc& loc, bool debug, const char * fmt, ...)
           "SSL::%lu:%s:%s:%d%s%s", es, ERR_error_string(l, buf), file, line,
           (flags & ERR_TXT_STRING) ? ":" : "", (flags & ERR_TXT_STRING) ? data :
"");
     }
+
+    // Tally desired stats (only client/server connection stats, not init
+    // issues where vc is NULL)
+    if (vc) {
+      // getSSLClientConnection - true if ats is client (we update server stats)
+      if (vc->getSSLClientConnection()) {
+        increment_ssl_server_error(l); // update server error stats
+      } else {
+        increment_ssl_client_error(l); // update client error stat
+      }
+    }
   }
 
   va_start(ap, fmt);
@@ -900,7 +1163,7 @@ ssl_index_certificate(SSLCertLookup * lookup, SSL_CTX * ctx, const char
* certfi
 
 // This callback function is executed while OpenSSL processes the SSL
 // handshake and does SSL record layer stuff.  It's used to trap
-// client-initiated renegotiations
+// client-initiated renegotiations and update cipher stats
 static void
 ssl_callback_info(const SSL *ssl, int where, int ret)
 {
@@ -916,6 +1179,18 @@ ssl_callback_info(const SSL *ssl, int where, int ret)
       Debug("ssl", "ssl_callback_info trying to renegotiate from the client");
     }
   }
+  if (where & SSL_CB_HANDSHAKE_DONE) {
+    // handshake is complete
+    const SSL_CIPHER * cipher = SSL_get_current_cipher(ssl);
+    if (cipher) {
+      const char * cipherName = SSL_CIPHER_get_name(cipher);
+      // lookup index of stat by name and incr count
+      InkHashTableValue data;
+      if (ink_hash_table_lookup(ssl_cipher_name_table, cipherName, &data)) {
+        SSL_INCREMENT_DYN_STAT((intptr_t)data);
+      }
+    }
+  }
 }
 
 static bool


Mime
View raw message