commit - 37df23d183de23b74f8a026977b8210dc22701a6
commit + 509d0509a50883a6f8407b63774f40dd1e41dadf
blob - 3f563ed2aba7598f4c4da31068d0ece6d23cb7a9
blob + 82097604764fbbc218ab0d4a03cbd130ac9d8376
--- config.c
+++ config.c
TAILQ_INIT(&conf->fcgi);
TAILQ_INIT(&conf->hosts);
TAILQ_INIT(&conf->pkis);
+ TAILQ_INIT(&conf->addrs);
- conf->port = 1965;
- conf->ipv6 = 0;
conf->protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
init_mime(&conf->mime);
conf->use_privsep_crypto = 1;
#endif
- conf->sock4 = -1;
- conf->sock6 = -1;
-
return conf;
}
struct envlist *e, *te;
struct alist *a, *ta;
struct pki *pki, *tpki;
+ struct address *addr, *taddr;
int use_privsep_crypto;
ps = conf->ps;
use_privsep_crypto = conf->use_privsep_crypto;
- if (conf->sock4 != -1) {
- event_del(&conf->evsock4);
- close(conf->sock4);
- }
-
- if (conf->sock6 != -1) {
- event_del(&conf->evsock6);
- close(conf->sock6);
- }
-
free_mime(&conf->mime);
TAILQ_FOREACH_SAFE(f, &conf->fcgi, fcgi, tf) {
TAILQ_REMOVE(&conf->fcgi, f, fcgi);
free(h->key);
free(h->ocsp);
+ TAILQ_FOREACH_SAFE(addr, &h->addrs, addrs, taddr) {
+ TAILQ_REMOVE(&h->addrs, addr, addrs);
+ free(addr);
+ }
+
TAILQ_FOREACH_SAFE(l, &h->locations, locations, tl) {
TAILQ_REMOVE(&h->locations, l, locations);
free(pki);
}
+ TAILQ_FOREACH_SAFE(addr, &conf->addrs, addrs, taddr) {
+ TAILQ_REMOVE(&conf->addrs, addr, addrs);
+ if (addr->sock != -1) {
+ close(addr->sock);
+ event_del(&addr->evsock);
+ }
+ free(addr);
+ }
+
memset(conf, 0, sizeof(*conf));
conf->ps = ps;
conf->use_privsep_crypto = use_privsep_crypto;
- conf->sock4 = conf->sock6 = -1;
conf->protos = TLS_PROTOCOL_TLSv1_2 | TLS_PROTOCOL_TLSv1_3;
init_mime(&conf->mime);
TAILQ_INIT(&conf->fcgi);
}
static int
-make_socket(int port, int family)
+config_send_socks(struct conf *conf)
{
- int sock, v;
- struct sockaddr_in addr4;
- struct sockaddr_in6 addr6;
- struct sockaddr *addr;
- socklen_t len;
+ struct privsep *ps = conf->ps;
+ struct address *addr, a;
+ int sock, v;
- switch (family) {
- case AF_INET:
- memset(&addr4, 0, sizeof(addr4));
- addr4.sin_family = family;
- addr4.sin_port = htons(port);
- addr4.sin_addr.s_addr = INADDR_ANY;
- addr = (struct sockaddr*)&addr4;
- len = sizeof(addr4);
- break;
+ TAILQ_FOREACH(addr, &conf->addrs, addrs) {
+ sock = socket(addr->ai_family, addr->ai_socktype,
+ addr->ai_protocol);
+ if (sock == -1)
+ fatal("socket");
- case AF_INET6:
- memset(&addr6, 0, sizeof(addr6));
- addr6.sin6_family = AF_INET6;
- addr6.sin6_port = htons(port);
- addr6.sin6_addr = in6addr_any;
- addr = (struct sockaddr*)&addr6;
- len = sizeof(addr6);
- break;
+ v = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v))
+ == -1)
+ fatal("setsockopt(SO_REUSEADDR)");
- default:
- /* unreachable */
- abort();
- }
+ v = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(v))
+ == -1)
+ fatal("setsockopt(SO_REUSEPORT)");
- if ((sock = socket(family, SOCK_STREAM, 0)) == -1)
- fatal("socket");
+ mark_nonblock(sock);
- v = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)) == -1)
- fatal("setsockopt(SO_REUSEADDR)");
+ if (bind(sock, (struct sockaddr *)&addr->ss, addr->slen)
+ == -1)
+ fatal("bind");
+
+ if (listen(sock, 16) == -1)
+ fatal("listen");
- v = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &v, sizeof(v)) == -1)
- fatal("setsockopt(SO_REUSEPORT)");
+ memcpy(&a, addr, sizeof(a));
+ a.conf = NULL;
+ a.sock = -1;
+ memset(&a.evsock, 0, sizeof(a.evsock));
+ memset(&a.addrs, 0, sizeof(a.addrs));
- mark_nonblock(sock);
-
- if (bind(sock, addr, len) == -1)
- fatal("bind");
-
- if (listen(sock, 16) == -1)
- fatal("listen");
-
- return sock;
-}
-
-static int
-config_send_socks(struct conf *conf)
-{
- struct privsep *ps = conf->ps;
- int sock;
-
- if ((sock = make_socket(conf->port, AF_INET)) == -1)
- return -1;
-
- if (config_send_file(ps, PROC_SERVER, IMSG_RECONF_SOCK4, sock,
- NULL, 0) == -1)
- return -1;
-
- if (!conf->ipv6)
- return 0;
-
- if ((sock = make_socket(conf->port, AF_INET6)) == -1)
- return -1;
-
- if (config_send_file(ps, PROC_SERVER, IMSG_RECONF_SOCK6, sock,
- NULL, 0) == -1)
- return -1;
+ if (config_send_file(ps, PROC_SERVER, IMSG_RECONF_SOCK, sock,
+ &a, sizeof(a)) == -1)
+ return -1;
+ }
return 0;
}
&conf->protos, sizeof(conf->protos)) == -1)
return -1;
- if (proc_compose(ps, PROC_SERVER, IMSG_RECONF_PORT,
- &conf->port, sizeof(conf->port)) == -1)
- return -1;
-
if (proc_flush_imsg(ps, PROC_SERVER, -1) == -1)
return -1;
struct envlist *env;
struct alist *alias;
struct proxy *proxy;
+ struct address *addr;
uint8_t *d;
size_t len, datalen;
memcpy(&conf->protos, imsg->data, datalen);
break;
- case IMSG_RECONF_PORT:
- IMSG_SIZE_CHECK(imsg, &conf->port);
- memcpy(&conf->port, imsg->data, datalen);
- break;
-
- case IMSG_RECONF_SOCK4:
- if (conf->sock4 != -1)
- fatalx("socket ipv4 already recv'd");
+ case IMSG_RECONF_SOCK:
+ addr = xcalloc(1, sizeof(*addr));
+ IMSG_SIZE_CHECK(imsg, addr);
+ memcpy(addr, imsg->data, sizeof(*addr));
if (imsg->fd == -1)
fatalx("missing socket for IMSG_RECONF_SOCK4");
- conf->sock4 = imsg->fd;
- event_set(&conf->evsock4, conf->sock4, EV_READ|EV_PERSIST,
- do_accept, conf);
+ addr->conf = conf;
+ addr->sock = imsg->fd;
+ event_set(&addr->evsock, addr->sock, EV_READ|EV_PERSIST,
+ do_accept, addr);
+ TAILQ_INSERT_HEAD(&conf->addrs, addr, addrs);
break;
- case IMSG_RECONF_SOCK6:
- if (conf->sock6 != -1)
- fatalx("socket ipv6 already recv'd");
- if (imsg->fd == -1)
- fatalx("missing socket for IMSG_RECONF_SOCK6");
- conf->sock6 = imsg->fd;
- event_set(&conf->evsock6, conf->sock6, EV_READ|EV_PERSIST,
- do_accept, conf);
- break;
-
case IMSG_RECONF_FCGI:
IMSG_SIZE_CHECK(imsg, fcgi);
fcgi = xcalloc(1, sizeof(*fcgi));
blob - bf3cae0f550c74887b455a5befa0fdeb4c821dd6
blob + 1d55b4a5dfde4805a1b1e78511e101f7a371ac1c
--- fcgi.c
+++ fcgi.c
struct tm tminfo;
struct envlist *p;
- e = getnameinfo((struct sockaddr*)&c->addr, sizeof(c->addr),
+ e = getnameinfo((struct sockaddr*)&c->raddr, c->raddrlen,
addr, sizeof(addr),
NULL, 0,
NI_NUMERICHOST);
blob - f45d9b2ce431ea1f1af8f847a89e3f8d7bfb9a05
blob + 4978c2cab70a81f1a85fad0ae6cda0cddb76ddc8
--- ge.c
+++ ge.c
serve(struct conf *conf, const char *host, int port, const char *dir)
{
struct addrinfo hints, *res, *res0;
+ struct vhost *vh = TAILQ_FIRST(&conf->hosts);
+ struct address *addr, *acp;
int r, error, saved_errno, sock = -1;
const char *cause = NULL;
char service[32];
+ int any = 0;
+ event_init();
+
r = snprintf(service, sizeof(service), "%d", port);
if (r < 0 || (size_t)r >= sizeof(service))
fatal("snprintf");
if (listen(sock, 5) == -1)
fatal("listen");
- /*
- * for the time being, we're happy as soon as
- * something binds.
- */
- break;
+ any = 1;
+
+ addr = xcalloc(1, sizeof(*addr));
+ addr->ai_flags = res->ai_flags;
+ addr->ai_family = res->ai_family;
+ addr->ai_socktype = res->ai_socktype;
+ addr->ai_protocol = res->ai_protocol;
+ addr->slen = res->ai_addrlen;
+ memcpy(&addr->ss, res->ai_addr, res->ai_addrlen);
+
+ addr->conf = conf;
+ addr->sock = sock;
+ event_set(&addr->evsock, addr->sock, EV_READ|EV_PERSIST,
+ do_accept, addr);
+
+ TAILQ_INSERT_HEAD(&conf->addrs, addr, addrs);
+
+ acp = xcalloc(1, sizeof(*acp));
+ memcpy(acp, addr, sizeof(*acp));
+ acp->sock = -1;
+ memset(&acp->evsock, 0, sizeof(acp->evsock));
+ TAILQ_INSERT_HEAD(&vh->addrs, addr, addrs);
}
- if (sock == -1)
+ if (!any)
fatal("%s", cause);
freeaddrinfo(res0);
- event_init();
-
- /* cheating */
- conf->sock4 = sock;
- event_set(&conf->evsock4, conf->sock4, EV_READ|EV_PERSIST,
- do_accept, conf);
-
server_init(NULL, NULL, NULL);
if (server_configure_done(conf) == -1)
fatalx("server configuration failed");
struct location *loc;
const char *errstr, *certs_dir = NULL, *hostname = "localhost";
char path[PATH_MAX];
- int ch;
+ int ch, port = 1965;
setlocale(LC_CTYPE, "");
usage();
break;
case 'p':
- conf->port = strtonum(optarg, 0, UINT16_MAX, &errstr);
+ port = strtonum(optarg, 0, UINT16_MAX, &errstr);
if (errstr)
fatalx("port number is %s: %s", errstr,
optarg);
/* start the server */
signal(SIGPIPE, SIG_IGN);
setproctitle("%s", loc->dir);
- return serve(conf, hostname, conf->port, loc->dir);
+ return serve(conf, hostname, port, loc->dir);
}
blob - d3e4cb2d0d3f0d855fa6f743a4e11b55ac7a9ea3
blob + b85fd4a1bb6bc4ed3d4c9d671593916e04b71832
--- gmid.c
+++ gmid.c
if (*conf->chroot != '\0')
printf("chroot \"%s\"\n", conf->chroot);
- printf("ipv6 %s\n", conf->ipv6 ? "on" : "off");
/* XXX: defined mimes? */
- printf("port %d\n", conf->port);
printf("prefork %d\n", conf->prefork);
/* XXX: protocols? */
if (*conf->user != '\0')
blob - 644788bcdf6c52441e6cb6ed9a768ff3187332b1
blob + 8947e68a144d2bc7174694d25f5ccd307ba7b198
--- gmid.h
+++ gmid.h
char *iri;
struct iri *parsed;
const char *err;
+};
+
+struct conf;
+TAILQ_HEAD(addrhead, address);
+struct address {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ struct sockaddr_storage ss;
+ socklen_t slen;
+ int16_t port;
+
+ /* used in the server */
+ struct conf *conf;
+ int sock;
+ struct event evsock; /* set if sock != -1 */
+
+ TAILQ_ENTRY(address) addrs;
};
TAILQ_HEAD(fcgihead, fcgi);
TAILQ_ENTRY(vhost) vhosts;
+ struct addrhead addrs;
+
/*
* the first location rule is always '*' and holds the default
* settings for the vhost, then follows the "real" location
struct conf {
struct privsep *ps;
- int port;
- int ipv6;
uint32_t protos;
struct mime mime;
char chroot[PATH_MAX];
int prefork;
int reload;
int use_privsep_crypto;
-
- int sock4;
- struct event evsock4;
- int sock6;
- struct event evsock6;
struct fcgihead fcgi;
struct vhosthead hosts;
struct pkihead pkis;
+ struct addrhead addrs;
};
extern const char *config_path;
struct client {
struct conf *conf;
+ struct address *addr;
uint32_t id;
struct tls *ctx;
char *req;
IMSG_RECONF_START, /* 7 */
IMSG_RECONF_MIME,
IMSG_RECONF_PROTOS,
- IMSG_RECONF_PORT,
- IMSG_RECONF_SOCK4,
- IMSG_RECONF_SOCK6,
+ IMSG_RECONF_SOCK,
IMSG_RECONF_FCGI,
IMSG_RECONF_HOST,
IMSG_RECONF_CERT,
blob - 8ba06d3931c0035ae9d7310680e632944ca4c861
blob + 2f85a660d177ee24bd720b00b0195502c7766fc8
--- parse.y
+++ parse.y
struct conf *conf;
+static const char *default_host = "*";
+static uint16_t default_port = 1965;
+
TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
static struct file {
TAILQ_ENTRY(file) entry;
int fastcgi_conf(const char *, const char *);
void add_param(char *, char *);
int getservice(const char *);
+void listen_on(const char *, const char *);
static struct vhost *host;
static struct location *loc;
%token FASTCGI FOR_HOST
%token INCLUDE INDEX IPV6
%token KEY
-%token LANG LOCATION LOG
+%token LANG LISTEN LOCATION LOG
%token OCSP OFF ON
%token PARAM PORT PREFORK PROTO PROTOCOLS PROXY
%token RELAY_TO REQUIRE RETURN ROOT
yyerror("chroot path too long");
free($2);
}
- | IPV6 bool { conf->ipv6 = $2; }
- | PORT NUM { conf->port = check_port_num($2); }
+ | IPV6 bool {
+ yywarn("option `ipv6' is deprecated,"
+ " please use `listen on'");
+ if ($2)
+ default_host = "*";
+ else
+ default_host = "0.0.0.0";
+ }
+ | PORT NUM {
+ yywarn("option `port' is deprecated,"
+ " please use `listen on'");
+ default_port = $2;
+ }
| PREFORK NUM { conf->prefork = check_prefork_num($2); }
| PROTOCOLS string {
if (tls_config_parse_protocols(&conf->protos, $2) == -1)
host->key_path == NULL)
yyerror("invalid vhost definition: %s",
host->domain);
+ if (TAILQ_EMPTY(&host->addrs)) {
+ char portno[32];
+ int r;
+
+ r = snprintf(portno, sizeof(portno), "%d",
+ default_port);
+ if (r < 0 || (size_t)r >= sizeof(portno))
+ fatal("snprintf");
+
+ yywarn("missing `listen on' in server %s,"
+ " assuming %s port %d", $2, default_host,
+ default_port);
+ listen_on(default_host, portno);
+ }
}
| error '}' { yyerror("bad server directive"); }
;
}
| PARAM string '=' string {
add_param($2, $4);
+ }
+ | LISTEN ON STRING PORT STRING {
+ listen_on($3, $5);
+ free($3);
+ free($5);
+ }
+ | LISTEN ON STRING PORT NUM {
+ char portno[32];
+ int r;
+
+ r = snprintf(portno, sizeof(portno), "%d", $5);
+ if (r < 0 || (size_t)r >= sizeof(portno))
+ fatal("snprintf");
+
+ listen_on($3, portno);
+ free($3);
}
| locopt
;
{"ipv6", IPV6},
{"key", KEY},
{"lang", LANG},
+ {"listen", LISTEN},
{"location", LOCATION},
{"log", LOG},
{"ocsp", OCSP},
{
struct sym *sym, *next;
+ default_host = "*";
+ default_port = 1965;
+
conf = c;
file = pushfile(filename, 0);
}
return ((unsigned short)llval);
+}
+
+static void
+add_to_addr_queue(struct addrhead *a, struct addrinfo *ai)
+{
+ struct address *addr;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+
+ if (ai->ai_addrlen > sizeof(addr->ss))
+ fatalx("ai_addrlen larger than a sockaddr_storage");
+
+ TAILQ_FOREACH(addr, a, addrs) {
+ if (addr->ai_flags == ai->ai_flags &&
+ addr->ai_family == ai->ai_family &&
+ addr->ai_socktype == ai->ai_socktype &&
+ addr->ai_protocol == ai->ai_protocol &&
+ addr->slen == ai->ai_addrlen &&
+ !memcmp(&addr->ss, ai->ai_addr, addr->slen))
+ return;
+ }
+
+ addr = xcalloc(1, sizeof(*addr));
+ addr->ai_flags = ai->ai_flags;
+ addr->ai_family = ai->ai_family;
+ addr->ai_socktype = ai->ai_socktype;
+ addr->ai_protocol = ai->ai_protocol;
+ addr->slen = ai->ai_addrlen;
+ memcpy(&addr->ss, ai->ai_addr, ai->ai_addrlen);
+
+ /* for commodity */
+ switch (addr->ai_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)&addr->ss;
+ addr->port = ntohs(sin->sin_port);
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)&addr->ss;
+ addr->port = ntohs(sin6->sin6_port);
+ break;
+ default:
+ fatalx("unknown socket family %d", addr->ai_family);
+ }
+
+ addr->sock = -1;
+
+ TAILQ_INSERT_HEAD(a, addr, addrs);
}
+
+void
+listen_on(const char *hostname, const char *servname)
+{
+ struct addrinfo hints, *res, *res0;
+ int error;
+
+ if (!strcmp(hostname, "*"))
+ hostname = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ error = getaddrinfo(hostname, servname, &hints, &res0);
+ if (error) {
+ yyerror("listen on \"%s\" port %s: %s", hostname, servname,
+ gai_strerror(errno));
+ return;
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ add_to_addr_queue(&host->addrs, res);
+ add_to_addr_queue(&conf->addrs, res);
+ }
+
+ freeaddrinfo(res0);
+}
blob - c61285b5f3837c4417ff98a79127247733bb8dab
blob + 06cb7a7762eaabf6718673fa06c8ede41211fce2
--- regress/lib.sh
+++ regress/lib.sh
run_test() {
ggflags=
port=10965
- config_common="ipv6 off
-port $port
-"
+ config_common=""
hdr=
body=
dont_check_server_alive=no
cert "$PWD/cert.pem"
key "$PWD/key.pem"
root "$PWD/testdata"
+ listen on localhost port $port
$2
}
EOF
server "localhost.local" {
cert "$PWD/cert.pem"
key "$PWD/key.pem"
+ listen on localhost port $port
proxy {
relay-to localhost port $port
$1
blob - 5ebc33bdd15f4ea9e6c987995d6c00c0eb5ba344
blob + a38e4ba03a75bf901a4ef6e2a48ab9a6e9c64df3
--- regress/tests.sh
+++ regress/tests.sh
test_macro_expansion() {
cat <<EOF > reg.conf
pwd = "$PWD"
-$config_common
server "localhost" {
# the quoting of \$ is for sh
cert \$pwd "/cert.pem"
key \$pwd "/key.pem"
root \$pwd "/testdata"
+ listen on localhost port $port
}
EOF
blob - 05c1d4bf94ed0e278f6b0013480346ad54dd4094
blob + 18e8c91350428e9f2187966fcc6e62397da4a3ca
--- server.c
+++ server.c
static void
fmt_sbuf(const char *fmt, struct client *c, const char *path)
{
- struct conf *conf = c->conf;
size_t i;
char buf[32];
strlcat(c->sbuf, c->iri.query, sizeof(c->sbuf));
break;
case 'P':
- snprintf(buf, sizeof(buf), "%d", conf->port);
+ snprintf(buf, sizeof(buf), "%d", c->addr->port);
strlcat(c->sbuf, buf, sizeof(c->sbuf));
memset(buf, 0, sizeof(buf));
break;
void
do_accept(int sock, short et, void *d)
{
- struct conf *conf = d;
+ struct address *addr = d;
struct client *c;
struct sockaddr_storage raddr;
struct sockaddr *sraddr;
mark_nonblock(fd);
c = xcalloc(1, sizeof(*c));
- c->conf = conf;
+ c->conf = addr->conf;
+ c->addr = addr;
c->id = ++server_client_id;
c->fd = fd;
c->pfd = -1;
int
server_configure_done(struct conf *conf)
{
+ struct address *addr;
+
if (load_default_mime(&conf->mime) == -1)
fatal("can't load default mime");
sort_mime(&conf->mime);
setup_tls(conf);
load_vhosts(conf);
- if (conf->sock4 != -1)
- event_add(&conf->evsock4, NULL);
- if (conf->sock6 != -1)
- event_add(&conf->evsock6, NULL);
+ TAILQ_FOREACH(addr, &conf->addrs, addrs) {
+ if (addr->sock != -1)
+ event_add(&addr->evsock, NULL);
+ }
+
return 0;
}
case IMSG_RECONF_START:
case IMSG_RECONF_MIME:
case IMSG_RECONF_PROTOS:
- case IMSG_RECONF_PORT:
- case IMSG_RECONF_SOCK4:
- case IMSG_RECONF_SOCK6:
+ case IMSG_RECONF_SOCK:
case IMSG_RECONF_FCGI:
case IMSG_RECONF_HOST:
case IMSG_RECONF_CERT:
blob - 43c1f4d86e007ab4d57004d52162954ce91b70d2
blob + bf28329eca544e589bb3ee70ceb7c34d78ae237b
--- utils.c
+++ utils.c
struct vhost *h;
h = xcalloc(1, sizeof(*h));
+ TAILQ_INIT(&h->addrs);
TAILQ_INIT(&h->locations);
TAILQ_INIT(&h->params);
TAILQ_INIT(&h->aliases);