diff --git a/README b/README index bfd27a5..aa9f8ef 100644 --- a/README +++ b/README @@ -155,11 +155,12 @@ IPv6 ---- Since version > 0.91 lophttpd also supports IPv6, by simply using "-6" -command-line switch. The default bind goes to "::0" then, so -if you want to bind to a specific IPv6 address, you have to -add -I switch *after* -6. You can either run IPv4 or IPv6 in once -instance, not both. But you can run two lophttpd's: one with IPv4 -and one with IPv6 if needed. +command-line switch. The default bind goes to "::" unless +given -l local bind address. +You can either run IPv4 or IPv6 in one instance, not both. But you can run +two lophttpd's: one with IPv4 and one with IPv6 if needed. +Frontend reverse proxy also supports IPv6, both on the frontend and +the backend side. You can even mix IPv4 and IPv6 backend nodes. Proxies diff --git a/config.cc b/config.cc index 1a05c47..1acaf41 100644 --- a/config.cc +++ b/config.cc @@ -21,7 +21,7 @@ namespace httpd_config string user = "wwwrun", logfile = "/var/log/lophttpd", log_provider = "file"; uid_t user_uid = 99, user_gid = 99; string host = "0.0.0.0", port = "80"; - int cores = 1, af = AF_INET; + int cores = 1; // on multicore there is only one master int master = 1; @@ -58,7 +58,6 @@ int parse(const string &cfile) struct addrinfo *ai = NULL, hints; memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_INET; while (fgets(buf, sizeof(buf), f)) { ptr = buf; while (*ptr == ' ' || *ptr == '\t') @@ -73,14 +72,16 @@ int parse(const string &cfile) string opath = ""; backend b; - strtok(ptr, " \t\n#"); + + // No '#' token in 'map' allowed due to port specifier + strtok(ptr, " \t"); opath = ptr; - ptr = strtok(NULL, " \t\n#"); + ptr = strtok(NULL, " \t\n"); memset(host, 0, sizeof(host)); memset(path, 0, sizeof(path)); - if (strchr(ptr + 5, ':')) { - if (sscanf(ptr, "http://%255[^:]:%hu/%255c", host, &b.port, path) == 0) { + if (strchr(ptr + 5, '#')) { + if (sscanf(ptr, "http://%255[^#]#%hu/%255c", host, &b.port, path) == 0) { err = "rproxy_config::parse::sscanf: invalid 'map' config."; return -1; } diff --git a/config.h b/config.h index 72eddb0..d789458 100644 --- a/config.h +++ b/config.h @@ -18,7 +18,7 @@ namespace httpd_config extern std::string user, logfile, log_provider; extern uid_t user_uid, user_gid; extern std::string host, port; - extern int cores, master, af; + extern int cores, master; extern uint16_t mss; extern uint32_t max_connections; extern uint32_t ncache; diff --git a/frontend-main.cc b/frontend-main.cc index 5df465d..2a518dc 100644 --- a/frontend-main.cc +++ b/frontend-main.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Sebastian Krahmer. + * Copyright (C) 2012-2013 Sebastian Krahmer. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -117,7 +117,7 @@ int main(int argc, char **argv) return -1; } - if (proxy->init(rproxy_config::host, rproxy_config::port, AF_INET) < 0) { + if (proxy->init(rproxy_config::host, rproxy_config::port) < 0) { proxy->log(proxy->why()); exit(-1); } diff --git a/lonely.cc b/lonely.cc index b39c238..596fa17 100644 --- a/lonely.cc +++ b/lonely.cc @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -147,29 +148,44 @@ const char *lonely::why() template -int lonely::init(const string &host, const string &port, int a) +int lonely::init(const string &host, const string &port) { struct timeval tv; + int r = 0; gettimeofday(&tv, NULL); cur_time = tv.tv_sec; cur_usec = tv.tv_usec; - af = a; + addrinfo hints, *ai = NULL; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + + if ((r = getaddrinfo(host.c_str(), port.c_str(), &hints, &ai)) != 0) { + err = "lonely::init:: getaddrinfo: "; + err += gai_strerror(r); + return -1; + } + + af = ai->ai_family; int sock_fd = socket(af, SOCK_STREAM, 0); if (sock_fd < 0) { + freeaddrinfo(ai); err = "lonely::init::socket:"; err += strerror(errno); return -1; } // bind & listen - if (bind_local(sock_fd, host, port, 1, af) < 0) { + if (bind_local(sock_fd, ai->ai_addr, ai->ai_addrlen, 1) < 0) { + freeaddrinfo(ai); err = ns_socket::why(); return -1; } + freeaddrinfo(ai); + socklen_t olen = sizeof(so_sndbuf); getsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &so_sndbuf, &olen); diff --git a/lonely.h b/lonely.h index 2feb76b..704ab57 100644 --- a/lonely.h +++ b/lonely.h @@ -129,7 +129,7 @@ class lonely { virtual ~lonely() { delete [] pfds; delete logger; } - int init(const std::string &, const std::string &, int a = AF_INET); + int init(const std::string &, const std::string &); int open_log(const std::string &, const std::string &, int core); diff --git a/main.cc b/main.cc index a3fbe1e..dd36b4e 100644 --- a/main.cc +++ b/main.cc @@ -170,8 +170,8 @@ int main(int argc, char **argv) while ((c = getopt(argc, argv, "iHhR:p:l:L:u:n:S:I:6B:qU:rEQN:C:K:e:s:")) != -1) { switch (c) { case '6': - httpd_config::host = "::0"; - httpd_config::af = AF_INET6; + if (httpd_config::host == "0.0.0.0") + httpd_config::host = "::"; break; case 'i': httpd_config::gen_index = 1; @@ -290,7 +290,7 @@ int main(int argc, char **argv) } } - if (httpd->init(httpd_config::host, httpd_config::port, httpd_config::af) < 0) { + if (httpd->init(httpd_config::host, httpd_config::port) < 0) { cerr<why()<from_ip = from; fd2peer[afd]->fd = afd; diff --git a/sample.conf b/sample.conf index f938905..358b326 100644 --- a/sample.conf +++ b/sample.conf @@ -21,19 +21,23 @@ logprovider file # # -# :port specifier is not required for port 80 +# #port specifier is not required for port 80 # # The URI must match what a potential "Location:" redirect reply from one of # the backends also would contain as URI (without sub paths) # and it must be resolvable by DNS if its not an IP address. Otherwise redirects # do not work. # -map /foo http://127.0.0.1:8080/ +# '#' comments in the same line as the 'map' command are not allowed as it would +# clash with port specifier +# + +map /foo http://127.0.0.1#8080/ # multiple assignments for the same /path are possile # (load balancing) -map /foo http://127.0.0.2:8080/ +map /foo http://127.0.0.2#8080/ #... # The path component is always required, even if its just / diff --git a/socket.cc b/socket.cc index f9174c9..418f97d 100644 --- a/socket.cc +++ b/socket.cc @@ -87,33 +87,17 @@ int reuse(int sock) } -int bind_local(int sock, const string &host, const string &port, bool do_listen, int af) +int bind_local(int sock, const struct sockaddr *s, socklen_t slen, bool do_listen) { - struct addrinfo *ai = NULL, hints; - int r; - - memset(&hints, 0, sizeof(hints)); - - hints.ai_family = af; - hints.ai_socktype = SOCK_STREAM; - - if ((r = getaddrinfo(host.c_str(), port.c_str(), &hints, &ai)) < 0) { - error = "ns_socket::bind_local::getaddrinfo:"; - error += gai_strerror(r); - return -1; - } - if (reuse(sock) < 0) return -1; - if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { + if (bind(sock, s, slen) < 0) { error = "ns_socket::bind_local::bind: "; error += strerror(errno); return -1; } - freeaddrinfo(ai); - if (do_listen) { if (listen(sock, 100000) < 0) { if (listen(sock, 10000) < 0) { @@ -130,22 +114,32 @@ int bind_local(int sock, const string &host, const string &port, bool do_listen, } -int bind_local(int sock, u_int16_t port, bool do_listen, int tries) +int bind_local(int sock, uint16_t port, int af, bool do_listen, int tries) { - struct sockaddr_in saddr; + sockaddr_in sin4; + sockaddr_in6 sin6; + sockaddr *sin = (sockaddr *)&sin4; + socklen_t slen = sizeof(sin4); + + if (af == AF_INET6) { + sin = (sockaddr *)&sin6; + slen = sizeof(sin6); + } + // XXX: static since connect will ne non-blocking, thus bind() will never fail static int i = 0; - memset(&saddr, 0, sizeof(saddr)); + memset(&sin4, 0, sizeof(sin4)); + memset(&sin6, 0, sizeof(sin6)); - saddr.sin_family = AF_INET; + sin4.sin_family = sin6.sin6_family = af; if (reuse(sock) < 0) return -1; for (; i < tries; ++i) { - saddr.sin_port = htons(port + i); - if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr)) < 0 && + sin4.sin_port = sin6.sin6_port = htons(port + i); + if (bind(sock, sin, slen) < 0 && (errno != EADDRINUSE || i == tries - 1)) { error = "ns_socket::bind_local::bind: "; error += strerror(errno); @@ -180,7 +174,7 @@ int tcp_connect_nb(const struct addrinfo &ai, uint16_t local_port) //int one = 1; //setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one ,sizeof(one)); if (local_port > 0) { - if (bind_local(sock, local_port, 0, 1000) < 0) + if (bind_local(sock, local_port, ai.ai_family, 0, 1000) < 0) return -1; } diff --git a/socket.h b/socket.h index 364d081..f1be509 100644 --- a/socket.h +++ b/socket.h @@ -49,9 +49,9 @@ int reuse(int sock); int dstaddr(int sock, sockaddr_in *dst); -int bind_local(int sock, const std::string &h, const std::string &p, bool do_listen, int af = AF_INET); +int bind_local(int sock, const sockaddr *, socklen_t, bool do_listen); -int bind_local(int sock, u_int16_t port, bool do_listen, int tries); +int bind_local(int sock, uint16_t port, bool do_listen, int tries); int tcp_connect_nb(const struct addrinfo &, uint16_t);