1
0
mirror of https://github.com/moparisthebest/spdylay synced 2024-08-13 17:03:54 -04:00
spdylay/src/shrpx.cc
Raul Gutierrez Segales cbf8ccf7d1 [shrpx] read private key's passwd from a file
This avoids the need to provide the password for your
private key interactively.

It can be used via --private-key-passwd-file or private-key-passwd-file
in the given config file. The first line in the file
(without \n) will be treated as the passwd. There isn't
any validation and all lines after the first one (if any)
are ignored.

The security model behind this is a bit simplistic so I
am open to better ideas. Basically your password file
should be root:root (700) and you *should* drop root
and run as an unprivileged user.

If the file exists and a line can be read then a callback
will be set for the SSL ctxt and it'll feed the passwd
when the private key is read (if password is needed).

If the file exists with the wrong permisions it'll be
logged and ignored.
2012-12-03 21:55:32 -08:00

829 lines
27 KiB
C++

/*
* Spdylay - SPDY Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "shrpx.h"
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netdb.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <getopt.h>
#include <syslog.h>
#include <limits>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <event2/listener.h>
#include <spdylay/spdylay.h>
#include "shrpx_config.h"
#include "shrpx_listen_handler.h"
#include "shrpx_ssl.h"
namespace shrpx {
namespace {
void ssl_acceptcb(evconnlistener *listener, int fd,
sockaddr *addr, int addrlen, void *arg)
{
ListenHandler *handler = reinterpret_cast<ListenHandler*>(arg);
handler->accept_connection(fd, addr, addrlen);
}
} // namespace
namespace {
bool is_ipv6_numeric_addr(const char *host)
{
uint8_t dst[16];
return inet_pton(AF_INET6, host, dst) == 1;
}
} // namespace
namespace {
int cache_downstream_host_address()
{
addrinfo hints;
int rv;
char service[10];
snprintf(service, sizeof(service), "%u", get_config()->downstream_port);
memset(&hints, 0, sizeof(addrinfo));
if(get_config()->backend_ipv4) {
hints.ai_family = AF_INET;
} else if(get_config()->backend_ipv6) {
hints.ai_family = AF_INET6;
} else {
hints.ai_family = AF_UNSPEC;
}
hints.ai_socktype = SOCK_STREAM;
#ifdef AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG;
#endif // AI_ADDRCONFIG
addrinfo *res;
rv = getaddrinfo(get_config()->downstream_host, service, &hints, &res);
if(rv != 0) {
LOG(FATAL) << "Unable to get downstream address: " << gai_strerror(rv);
DIE();
}
char host[NI_MAXHOST];
rv = getnameinfo(res->ai_addr, res->ai_addrlen, host, sizeof(host),
0, 0, NI_NUMERICHOST);
if(rv == 0) {
LOG(INFO) << "Using first returned address for downstream "
<< host
<< ", port "
<< get_config()->downstream_port;
} else {
LOG(FATAL) << gai_strerror(rv);
DIE();
}
memcpy(&mod_config()->downstream_addr, res->ai_addr, res->ai_addrlen);
mod_config()->downstream_addrlen = res->ai_addrlen;
freeaddrinfo(res);
return 0;
}
} // namespace
namespace {
void evlistener_errorcb(evconnlistener *listener, void *ptr)
{
LOG(ERROR) << "Accepting incoming connection failed";
}
} // namespace
namespace {
evconnlistener* create_evlistener(ListenHandler *handler, int family)
{
// TODO Listen both IPv4 and IPv6
addrinfo hints;
int fd = -1;
int r;
char service[10];
snprintf(service, sizeof(service), "%u", get_config()->port);
memset(&hints, 0, sizeof(addrinfo));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
#ifdef AI_ADDRCONFIG
hints.ai_flags |= AI_ADDRCONFIG;
#endif // AI_ADDRCONFIG
addrinfo *res, *rp;
r = getaddrinfo(get_config()->host, service, &hints, &res);
if(r != 0) {
LOG(INFO) << "Unable to get address for " << get_config()->host << ": "
<< gai_strerror(r);
return NULL;
}
for(rp = res; rp; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(fd == -1) {
continue;
}
int val = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
static_cast<socklen_t>(sizeof(val))) == -1) {
close(fd);
continue;
}
evutil_make_socket_nonblocking(fd);
#ifdef IPV6_V6ONLY
if(family == AF_INET6) {
if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
static_cast<socklen_t>(sizeof(val))) == -1) {
close(fd);
continue;
}
}
#endif // IPV6_V6ONLY
if(bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) {
break;
}
close(fd);
}
if(rp) {
char host[NI_MAXHOST];
r = getnameinfo(rp->ai_addr, rp->ai_addrlen, host, sizeof(host),
0, 0, NI_NUMERICHOST);
if(r == 0) {
LOG(INFO) << "Listening on " << host << ", port " << get_config()->port;
} else {
LOG(FATAL) << gai_strerror(r);
DIE();
}
}
freeaddrinfo(res);
if(rp == 0) {
if(ENABLE_LOG) {
LOG(INFO) << "Listening " << (family == AF_INET ? "IPv4" : "IPv6")
<< " socket failed";
}
return 0;
}
evconnlistener *evlistener = evconnlistener_new
(handler->get_evbase(),
ssl_acceptcb,
handler,
LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
get_config()->backlog,
fd);
evconnlistener_set_error_cb(evlistener, evlistener_errorcb);
return evlistener;
}
} // namespace
namespace {
void drop_privileges()
{
if(getuid() == 0 && get_config()->uid != 0) {
if(setgid(get_config()->gid) != 0) {
LOG(FATAL) << "Could not change gid: " << strerror(errno);
exit(EXIT_FAILURE);
}
if(setuid(get_config()->uid) != 0) {
LOG(FATAL) << "Could not change uid: " << strerror(errno);
exit(EXIT_FAILURE);
}
if(setuid(0) != -1) {
LOG(FATAL) << "Still have root privileges?";
exit(EXIT_FAILURE);
}
}
}
} // namespace
namespace {
int event_loop()
{
event_base *evbase = event_base_new();
ListenHandler *listener_handler = new ListenHandler(evbase);
if(get_config()->daemon) {
if(daemon(0, 0) == -1) {
LOG(FATAL) << "Failed to daemonize: " << strerror(errno);
exit(EXIT_FAILURE);
}
}
// ListenHandler loads private key. After that, we drop the root
// privileges if needed.
drop_privileges();
evconnlistener *evlistener6, *evlistener4;
evlistener6 = create_evlistener(listener_handler, AF_INET6);
evlistener4 = create_evlistener(listener_handler, AF_INET);
if(!evlistener6 && !evlistener4) {
LOG(FATAL) << "Failed to listen on address "
<< get_config()->host << ", port " << get_config()->port;
exit(EXIT_FAILURE);
}
if(get_config()->num_worker > 1) {
listener_handler->create_worker_thread(get_config()->num_worker);
} else if(get_config()->client_mode) {
listener_handler->create_spdy_session();
}
if(ENABLE_LOG) {
LOG(INFO) << "Entering event loop";
}
event_base_loop(evbase, 0);
if(evlistener4) {
evconnlistener_free(evlistener4);
}
if(evlistener6) {
evconnlistener_free(evlistener6);
}
return 0;
}
} // namespace
namespace {
void save_pid()
{
std::ofstream out(get_config()->pid_file, std::ios::binary);
out << getpid() << "\n";
out.close();
if(!out) {
LOG(ERROR) << "Could not save PID to file " << get_config()->pid_file;
exit(EXIT_FAILURE);
}
}
} // namespace
namespace {
// Returns true if regular file or symbolic link |path| exists.
bool conf_exists(const char *path)
{
struct stat buf;
int rv = stat(path, &buf);
return rv == 0 && (buf.st_mode & (S_IFREG | S_IFLNK));
}
} // namespace
namespace {
void fill_default_config()
{
memset(mod_config(), 0, sizeof(*mod_config()));
mod_config()->verbose = false;
mod_config()->daemon = false;
mod_config()->verify_client = false;
mod_config()->server_name = "shrpx spdylay/"SPDYLAY_VERSION;
set_config_str(&mod_config()->host, "0.0.0.0");
mod_config()->port = 3000;
mod_config()->private_key_file = 0;
mod_config()->private_key_passwd = 0;
mod_config()->cert_file = 0;
// Read timeout for SPDY upstream connection
mod_config()->spdy_upstream_read_timeout.tv_sec = 180;
mod_config()->spdy_upstream_read_timeout.tv_usec = 0;
// Read timeout for non-SPDY upstream connection
mod_config()->upstream_read_timeout.tv_sec = 180;
mod_config()->upstream_read_timeout.tv_usec = 0;
// Write timeout for SPDY/non-SPDY upstream connection
mod_config()->upstream_write_timeout.tv_sec = 60;
mod_config()->upstream_write_timeout.tv_usec = 0;
// Read/Write timeouts for downstream connection
mod_config()->downstream_read_timeout.tv_sec = 900;
mod_config()->downstream_read_timeout.tv_usec = 0;
mod_config()->downstream_write_timeout.tv_sec = 60;
mod_config()->downstream_write_timeout.tv_usec = 0;
// Timeout for pooled (idle) connections
mod_config()->downstream_idle_read_timeout.tv_sec = 60;
// window bits for SPDY upstream/downstream connection. 2**16 =
// 64KiB, which is SPDY/3 default.
mod_config()->spdy_upstream_window_bits = 16;
mod_config()->spdy_downstream_window_bits = 16;
set_config_str(&mod_config()->downstream_host, "127.0.0.1");
mod_config()->downstream_port = 80;
mod_config()->downstream_hostport = 0;
mod_config()->downstream_addrlen = 0;
mod_config()->num_worker = 1;
mod_config()->spdy_max_concurrent_streams =
SPDYLAY_INITIAL_MAX_CONCURRENT_STREAMS;
mod_config()->add_x_forwarded_for = false;
mod_config()->accesslog = false;
set_config_str(&mod_config()->conf_path, "/etc/shrpx/shrpx.conf");
mod_config()->syslog = false;
mod_config()->syslog_facility = LOG_DAEMON;
mod_config()->use_syslog = false;
// Default accept() backlog
mod_config()->backlog = 256;
mod_config()->ciphers = 0;
mod_config()->spdy_proxy = false;
mod_config()->client_proxy = false;
mod_config()->client = false;
mod_config()->client_mode = false;
mod_config()->insecure = false;
mod_config()->cacert = 0;
mod_config()->pid_file = 0;
mod_config()->uid = 0;
mod_config()->gid = 0;
mod_config()->backend_ipv4 = false;
mod_config()->backend_ipv6 = false;
}
} // namespace
namespace {
void print_version(std::ostream& out)
{
out << get_config()->server_name << std::endl;
}
} // namespace
namespace {
void print_usage(std::ostream& out)
{
out << "Usage: shrpx [-Dh] [-s|--client|-p] [-b <HOST,PORT>]\n"
<< " [-f <HOST,PORT>] [-n <CORES>] [-c <NUM>] [-L <LEVEL>]\n"
<< " [OPTIONS...] [<PRIVATE_KEY> <CERT>]\n"
<< "\n"
<< "A reverse proxy for SPDY/HTTPS.\n"
<< std::endl;
}
} // namespace
namespace {
void print_help(std::ostream& out)
{
print_usage(out);
out << "Positional arguments:\n"
<< " <PRIVATE_KEY> Set path to server's private key. Required\n"
<< " unless either -p or --client is specified.\n"
<< " <CERT> Set path to server's certificate. Required\n"
<< " unless either -p or --client is specified.\n"
<< "\n"
<< "OPTIONS:\n"
<< "\n"
<< " Connections:\n"
<< " -b, --backend=<HOST,PORT>\n"
<< " Set backend host and port.\n"
<< " Default: '"
<< get_config()->downstream_host << ","
<< get_config()->downstream_port << "'\n"
<< " -f, --frontend=<HOST,PORT>\n"
<< " Set frontend host and port.\n"
<< " Default: '"
<< get_config()->host << "," << get_config()->port << "'\n"
<< " --backlog=<NUM> Set listen backlog size.\n"
<< " Default: "
<< get_config()->backlog << "\n"
<< " --backend-ipv4 Resolve backend hostname to IPv4 address\n"
<< " only.\n"
<< " --backend-ipv6 Resolve backend hostname to IPv6 address\n"
<< " only.\n"
<< "\n"
<< " Performance:\n"
<< " -n, --workers=<CORES>\n"
<< " Set the number of worker threads.\n"
<< " Default: "
<< get_config()->num_worker << "\n"
<< "\n"
<< " Timeout:\n"
<< " --frontend-spdy-read-timeout=<SEC>\n"
<< " Specify read timeout for SPDY frontend\n"
<< " connection. Default: "
<< get_config()->spdy_upstream_read_timeout.tv_sec << "\n"
<< " --frontend-read-timeout=<SEC>\n"
<< " Specify read timeout for non-SPDY frontend\n"
<< " connection. Default: "
<< get_config()->upstream_read_timeout.tv_sec << "\n"
<< " --frontend-write-timeout=<SEC>\n"
<< " Specify write timeout for both SPDY and\n"
<< " non-SPDY frontends.\n"
<< " connection. Default: "
<< get_config()->upstream_write_timeout.tv_sec << "\n"
<< " --backend-read-timeout=<SEC>\n"
<< " Specify read timeout for backend connection.\n"
<< " Default: "
<< get_config()->downstream_read_timeout.tv_sec << "\n"
<< " --backend-write-timeout=<SEC>\n"
<< " Specify write timeout for backend\n"
<< " connection. Default: "
<< get_config()->downstream_write_timeout.tv_sec << "\n"
<< " --backend-keep-alive-timeout=<SEC>\n"
<< " Specify keep-alive timeout for backend\n"
<< " connection. Default: "
<< get_config()->downstream_idle_read_timeout.tv_sec << "\n"
<< "\n"
<< " SSL/TLS:\n"
<< " --ciphers=<SUITE> Set allowed cipher list. The format of the\n"
<< " string is described in OpenSSL ciphers(1).\n"
<< " -k, --insecure When used with -p or --client, don't verify\n"
<< " backend server's certificate.\n"
<< " --cacert=<PATH> When used with -p or --client, set path to\n"
<< " trusted CA certificate file.\n"
<< " The file must be in PEM format. It can\n"
<< " contain multiple certificates. If the\n"
<< " linked OpenSSL is configured to load system\n"
<< " wide certificates, they are loaded\n"
<< " at startup regardless of this option.\n"
<< " --private-key-passwd-file=<FILEPATH>\n"
<< " Path to file that contains password for the\n"
<< " server's private key. If none is given and\n"
<< " the private key is password protected it'll\n"
<< " be requested interactively."
<< "\n"
<< " SPDY:\n"
<< " -c, --spdy-max-concurrent-streams=<NUM>\n"
<< " Set the maximum number of the concurrent\n"
<< " streams in one SPDY session.\n"
<< " Default: "
<< get_config()->spdy_max_concurrent_streams << "\n"
<< " --frontend-spdy-window-bits=<N>\n"
<< " Sets the initial window size of SPDY\n"
<< " frontend connection to 2**<N>.\n"
<< " Default: "
<< get_config()->spdy_upstream_window_bits << "\n"
<< " --backend-spdy-window-bits=<N>\n"
<< " Sets the initial window size of SPDY\n"
<< " backend connection to 2**<N>.\n"
<< " Default: "
<< get_config()->spdy_downstream_window_bits << "\n"
<< "\n"
<< " Mode:\n"
<< " -s, --spdy-proxy Enable secure SPDY proxy mode.\n"
<< " --client Instead of accepting SPDY/HTTPS connection,\n"
<< " accept HTTP connection and communicate with\n"
<< " backend server in SPDY. To use shrpx as\n"
<< " a forward proxy, use -p option instead.\n"
<< " -p, --client-proxy Like --client option, but it also requires\n"
<< " the request path from frontend must be\n"
<< " an absolute URI, suitable for use as a\n"
<< " forward proxy."
<< "\n"
<< " Logging:\n"
<< " -L, --log-level=<LEVEL>\n"
<< " Set the severity level of log output.\n"
<< " INFO, WARNING, ERROR and FATAL.\n"
<< " Default: WARNING\n"
<< " --accesslog Print simple accesslog to stderr.\n"
<< " --syslog Send log messages to syslog.\n"
<< " --syslog-facility=<FACILITY>\n"
<< " Set syslog facility.\n"
<< " Default: "
<< str_syslog_facility(get_config()->syslog_facility) << "\n"
<< "\n"
<< " Misc:\n"
<< " --add-x-forwarded-for\n"
<< " Append X-Forwarded-For header field to the\n"
<< " downstream request.\n"
<< " -D, --daemon Run in a background. If -D is used, the\n"
<< " current working directory is changed to '/'.\n"
<< " --pid-file=<PATH> Set path to save PID of this program.\n"
<< " --user=<USER> Run this program as USER. This option is\n"
<< " intended to be used to drop root privileges.\n"
<< " --conf=<PATH> Load configuration from PATH.\n"
<< " Default: "
<< get_config()->conf_path << "\n"
<< " -v, --version Print version and exit.\n"
<< " -h, --help Print this help and exit.\n"
<< std::endl;
}
} // namespace
int main(int argc, char **argv)
{
Log::set_severity_level(WARNING);
create_config();
fill_default_config();
std::vector<std::pair<const char*, const char*> > cmdcfgs;
while(1) {
int flag;
static option long_options[] = {
{"daemon", no_argument, 0, 'D' },
{"log-level", required_argument, 0, 'L' },
{"backend", required_argument, 0, 'b' },
{"spdy-max-concurrent-streams", required_argument, 0, 'c' },
{"frontend", required_argument, 0, 'f' },
{"help", no_argument, 0, 'h' },
{"insecure", no_argument, 0, 'k' },
{"workers", required_argument, 0, 'n' },
{"client-proxy", no_argument, 0, 'p' },
{"spdy-proxy", no_argument, 0, 's' },
{"version", no_argument, 0, 'v' },
{"add-x-forwarded-for", no_argument, &flag, 1 },
{"frontend-spdy-read-timeout", required_argument, &flag, 2 },
{"frontend-read-timeout", required_argument, &flag, 3 },
{"frontend-write-timeout", required_argument, &flag, 4 },
{"backend-read-timeout", required_argument, &flag, 5 },
{"backend-write-timeout", required_argument, &flag, 6 },
{"accesslog", no_argument, &flag, 7 },
{"backend-keep-alive-timeout", required_argument, &flag, 8 },
{"frontend-spdy-window-bits", required_argument, &flag, 9 },
{"pid-file", required_argument, &flag, 10 },
{"user", required_argument, &flag, 11 },
{"conf", required_argument, &flag, 12 },
{"syslog", no_argument, &flag, 13 },
{"syslog-facility", required_argument, &flag, 14 },
{"backlog", required_argument, &flag, 15 },
{"ciphers", required_argument, &flag, 16 },
{"client", no_argument, &flag, 17 },
{"backend-spdy-window-bits", required_argument, &flag, 18 },
{"cacert", required_argument, &flag, 19 },
{"backend-ipv4", no_argument, &flag, 20 },
{"backend-ipv6", no_argument, &flag, 21 },
{"private-key-passwd-file", required_argument, &flag, 22},
{0, 0, 0, 0 }
};
int option_index = 0;
int c = getopt_long(argc, argv, "DL:b:c:f:hkn:psv", long_options,
&option_index);
if(c == -1) {
break;
}
switch(c) {
case 'D':
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_DAEMON, "yes"));
break;
case 'L':
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_LOG_LEVEL, optarg));
break;
case 'b':
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND, optarg));
break;
case 'c':
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_SPDY_MAX_CONCURRENT_STREAMS,
optarg));
break;
case 'f':
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_FRONTEND, optarg));
break;
case 'h':
print_help(std::cout);
exit(EXIT_SUCCESS);
case 'k':
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_INSECURE, "yes"));
break;
case 'n':
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_WORKERS, optarg));
break;
case 'p':
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CLIENT_PROXY, "yes"));
break;
case 's':
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_SPDY_PROXY, "yes"));
break;
case 'v':
print_version(std::cout);
exit(EXIT_SUCCESS);
case '?':
exit(EXIT_FAILURE);
case 0:
switch(flag) {
case 1:
// --add-x-forwarded-for
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_ADD_X_FORWARDED_FOR,
"yes"));
break;
case 2:
// --frontend-spdy-read-timeout
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_FRONTEND_SPDY_READ_TIMEOUT,
optarg));
break;
case 3:
// --frontend-read-timeout
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_FRONTEND_READ_TIMEOUT,
optarg));
break;
case 4:
// --frontend-write-timeout
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_FRONTEND_WRITE_TIMEOUT,
optarg));
break;
case 5:
// --backend-read-timeout
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND_READ_TIMEOUT,
optarg));
break;
case 6:
// --backend-write-timeout
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND_WRITE_TIMEOUT,
optarg));
break;
case 7:
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_ACCESSLOG, "yes"));
break;
case 8:
// --backend-keep-alive-timeout
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND_KEEP_ALIVE_TIMEOUT,
optarg));
break;
case 9:
// --frontend-spdy-window-bits
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_FRONTEND_SPDY_WINDOW_BITS,
optarg));
break;
case 10:
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_PID_FILE, optarg));
break;
case 11:
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_USER, optarg));
break;
case 12:
// --conf
set_config_str(&mod_config()->conf_path, optarg);
break;
case 13:
// --syslog
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_SYSLOG, "yes"));
break;
case 14:
// --syslog-facility
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_SYSLOG_FACILITY, optarg));
break;
case 15:
// --backlog
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKLOG, optarg));
break;
case 16:
// --ciphers
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CIPHERS, optarg));
break;
case 17:
// --client
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CLIENT, "yes"));
break;
case 18:
// --backend-spdy-window-bits
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND_SPDY_WINDOW_BITS,
optarg));
break;
case 19:
// --cacert
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CACERT, optarg));
break;
case 20:
// --backend-ipv4
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND_IPV4, "yes"));
break;
case 21:
// --backend-ipv6
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND_IPV6, "yes"));
break;
case 22:
// --private-key-passwd-file
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE,
optarg));
break;
default:
break;
}
break;
default:
break;
}
}
if(conf_exists(get_config()->conf_path)) {
if(load_config(get_config()->conf_path) == -1) {
LOG(FATAL) << "Failed to load configuration from "
<< get_config()->conf_path;
exit(EXIT_FAILURE);
}
}
if(argc - optind >= 2) {
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_PRIVATE_KEY_FILE,
argv[optind++]));
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_CERTIFICATE_FILE,
argv[optind++]));
}
for(size_t i = 0, len = cmdcfgs.size(); i < len; ++i) {
if(parse_config(cmdcfgs[i].first, cmdcfgs[i].second) == -1) {
LOG(FATAL) << "Failed to parse command-line argument.";
exit(EXIT_FAILURE);
}
}
if(get_config()->backend_ipv4 && get_config()->backend_ipv6) {
LOG(FATAL) << "--backend-ipv4 and --backend-ipv6 cannot be used at the "
<< "same time.";
exit(EXIT_FAILURE);
}
int mode = get_config()->spdy_proxy |
(get_config()->client_proxy << 1) | (get_config()->client << 2);
if(mode != 0 && mode != 1 && mode != 2 && mode != 4) {
LOG(FATAL) << "--spdy-proxy, --client-proxy and --client cannot be used "
<< "at the same time.";
exit(EXIT_FAILURE);
}
if(get_config()->client || get_config()->client_proxy) {
mod_config()->client_mode = true;
}
if(!get_config()->client_mode) {
if(!get_config()->private_key_file || !get_config()->cert_file) {
print_usage(std::cerr);
LOG(FATAL) << "Too few arguments";
exit(EXIT_FAILURE);
}
}
char hostport[NI_MAXHOST+16];
bool downstream_ipv6_addr =
is_ipv6_numeric_addr(get_config()->downstream_host);
if(get_config()->downstream_port == 80) {
snprintf(hostport, sizeof(hostport), "%s%s%s",
downstream_ipv6_addr ? "[" : "",
get_config()->downstream_host,
downstream_ipv6_addr ? "]" : "");
} else {
snprintf(hostport, sizeof(hostport), "%s%s%s:%u",
downstream_ipv6_addr ? "[" : "",
get_config()->downstream_host,
downstream_ipv6_addr ? "]" : "",
get_config()->downstream_port);
}
set_config_str(&mod_config()->downstream_hostport, hostport);
if(cache_downstream_host_address() == -1) {
exit(EXIT_FAILURE);
}
if(get_config()->syslog) {
openlog("shrpx", LOG_NDELAY | LOG_NOWAIT | LOG_PID,
get_config()->syslog_facility);
mod_config()->use_syslog = true;
}
if(get_config()->pid_file) {
save_pid();
}
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, 0);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
ssl::setup_ssl_lock();
event_loop();
ssl::teardown_ssl_lock();
return 0;
}
} // namespace shrpx
int main(int argc, char **argv)
{
return shrpx::main(argc, argv);
}