From a9f475fb88860f40489f8d5f78826b2491c85b2e Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 29 Mar 2013 22:06:33 +0900 Subject: [PATCH] spdycat, shrpx: TLS SNI enhancements shrpx: * Added an option to set the TLS SNI extension between shrpx and the origin on the command line spdycat: * If the user set an explicit host header ( using --headers ) use that name for the TLS SNI extension. * Added the handshake completion time to the verbose output * The gettimeofday call in get_time was using the incorrect structure ( I believe ) * In update_html_parser it was submitting the request regardless of the return value of add_request. Patch from Stephen Ludin --- src/shrpx.cc | 12 +++++++++++- src/shrpx_config.cc | 3 +++ src/shrpx_config.h | 2 ++ src/shrpx_spdy_session.cc | 12 ++++++++++-- src/spdycat.cc | 27 +++++++++++++++++++++++---- src/spdylay_ssl.cc | 2 +- 6 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/shrpx.cc b/src/shrpx.cc index 749a5216..a750ad84 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -520,7 +520,10 @@ void print_help(std::ostream& out) << " key file. Shrpx will choose certificates\n" << " based on the hostname indicated by client\n" << " using TLS SNI extension. This option can be\n" - << " used multiple times.\n" + << " --backend-tls-sni-field=\n" + << " Explicitly set the content of the TLS SNI\n" + << " extension. This will default to the backend\n" + << " HOST name.\n" << "\n" << " SPDY:\n" << " -c, --spdy-max-concurrent-streams=\n" @@ -659,6 +662,7 @@ int main(int argc, char **argv) {"backend-spdy-proto", required_argument, &flag, 28}, {"frontend-spdy-no-tls", no_argument, &flag, 29}, {"frontend-spdy-proto", required_argument, &flag, 30}, + {"backend-tls-sni-field", required_argument, &flag, 31}, {0, 0, 0, 0 } }; int option_index = 0; @@ -838,6 +842,12 @@ int main(int argc, char **argv) cmdcfgs.push_back(std::make_pair(SHRPX_OPT_FRONTEND_SPDY_PROTO, optarg)); break; + case 31: + // --backend-tls-sni-field + cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND_TLS_SNI_FIELD, + optarg)); + break; + default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 97efebb1..d0d43064 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -79,6 +79,7 @@ const char SHRPX_OPT_FRONTEND_SPDY_NO_TLS[] = "frontend-spdy-no-tls"; const char SHRPX_OPT_FRONTEND_SPDY_PROTO[] = "frontend-spdy-proto"; const char SHRPX_OPT_BACKEND_SPDY_NO_TLS[] = "backend-spdy-no-tls"; const char SHRPX_OPT_BACKEND_SPDY_PROTO[] = "backend-spdy-proto"; +const char SHRPX_OPT_BACKEND_TLS_SNI_FIELD[] = "backend-tls-sni-field"; const char SHRPX_OPT_PID_FILE[] = "pid-file"; const char SHRPX_OPT_USER[] = "user"; const char SHRPX_OPT_SYSLOG[] = "syslog"; @@ -300,6 +301,8 @@ int parse_config(const char *opt, const char *optarg) } else { mod_config()->spdy_downstream_version = version; } + } else if(util::strieq(opt, SHRPX_OPT_BACKEND_TLS_SNI_FIELD)) { + set_config_str(&mod_config()->backend_tls_sni_name, optarg); } else if(util::strieq(opt, SHRPX_OPT_PID_FILE)) { set_config_str(&mod_config()->pid_file, optarg); } else if(util::strieq(opt, SHRPX_OPT_USER)) { diff --git a/src/shrpx_config.h b/src/shrpx_config.h index b63d6e0c..5fb67ae2 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -84,6 +84,7 @@ extern const char SHRPX_OPT_CACERT[]; extern const char SHRPX_OPT_BACKEND_IPV4[]; extern const char SHRPX_OPT_BACKEND_IPV6[]; extern const char SHRPX_OPT_BACKEND_HTTP_PROXY_URI[]; +extern const char SHRPX_OPT_BACKEND_TLS_SNI_FIELD[]; union sockaddr_union { sockaddr sa; @@ -134,6 +135,7 @@ struct Config { uint16_t spdy_upstream_version; bool spdy_downstream_no_tls; uint16_t spdy_downstream_version; + char *backend_tls_sni_name; char *pid_file; uid_t uid; gid_t gid; diff --git a/src/shrpx_spdy_session.cc b/src/shrpx_spdy_session.cc index c9c6b937..ae029239 100644 --- a/src/shrpx_spdy_session.cc +++ b/src/shrpx_spdy_session.cc @@ -402,11 +402,19 @@ int SpdySession::initiate_connection() return -1; } - if(!ssl::numeric_host(get_config()->downstream_host)) { + const char *sni_name = 0; + if ( get_config()->backend_tls_sni_name ) { + sni_name = get_config()->backend_tls_sni_name; + } + else { + sni_name = get_config()->downstream_host; + } + + if(!ssl::numeric_host(sni_name)) { // TLS extensions: SNI. There is no documentation about the return // code for this function (actually this is macro wrapping SSL_ctrl // at the time of this writing). - SSL_set_tlsext_host_name(ssl_, get_config()->downstream_host); + SSL_set_tlsext_host_name(ssl_, sni_name); } // If state_ == PROXY_CONNECTED, we has connected to the proxy // using fd_ and tunnel has been established. diff --git a/src/spdycat.cc b/src/spdycat.cc index 13e2eac8..6d324bb6 100644 --- a/src/spdycat.cc +++ b/src/spdycat.cc @@ -396,9 +396,10 @@ void update_html_parser(SpdySession *spdySession, Request *req, fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_HOST) && porteq(uri.c_str(), u, req->uri.c_str(), req->u)) { // No POST data for assets - spdySession->add_request(uri, u, 0, 0, req->level+1); - submit_request(*spdySession->sc, spdySession->hostport, config.headers, - spdySession->reqvec.back()); + if ( spdySession->add_request(uri, u, 0, 0, req->level+1) ) { + submit_request(*spdySession->sc, spdySession->hostport, config.headers, + spdySession->reqvec.back()); + } } } req->html_parser->clear_links(); @@ -721,7 +722,20 @@ int communicate(const std::string& host, uint16_t port, result = -1; goto fin; } - if (!SSL_set_tlsext_host_name(ssl, host.c_str())) { + + // If the user overrode the host header, use that value for the + // SNI extension + const char *host_string = 0; + std::map::const_iterator i = + config.headers.find( "Host" ); + if ( i != config.headers.end() ) { + host_string = (*i).second.c_str(); + } + else { + host_string = host.c_str(); + } + + if (!SSL_set_tlsext_host_name(ssl, host_string)) { std::cerr << ERR_error_string(ERR_get_error(), 0) << std::endl; result = -1; goto fin; @@ -739,6 +753,11 @@ int communicate(const std::string& host, uint16_t port, } } + if ( config.verbose ) { + print_timer(); + std::cout << " Handshake complete" << std::endl; + } + spdySession.record_handshake_time(); spdy_version = spdylay_npn_get_version( reinterpret_cast(next_proto.c_str()), diff --git a/src/spdylay_ssl.cc b/src/spdylay_ssl.cc index 11f55c1e..2b131a91 100644 --- a/src/spdylay_ssl.cc +++ b/src/spdylay_ssl.cc @@ -916,7 +916,7 @@ int get_time(timeval *tv) tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec/1000; #else // !HAVE_CLOCK_GETTIME - rv = gettimeofday(&base_tv, 0); + rv = gettimeofday(tv, 0); #endif // !HAVE_CLOCK_GETTIME return rv; }