Re: httpd: multiple addresses for one server
On Thu, Jan 01, 2015 at 11:54:46PM -0500, Geoff Steckel wrote: Is there any way todo the equivalent of: server an.example.com listen on 192.168.2.99 listen on 2001.fefe.1.1::99 ?? It appears that the code in parse.y explicitly forbids this and the data structures for a server don't *seem* to have more than one slot for an address. Is there another way to achieve this effect? From one comment in the checkins, it looks like server an.example.com listen on 192.168.2.99 . server an.example.com listen on 2001.fefe.1.1::99 would work. Duplicating the entire server description is difficult to maintain. Is someone planning to work in this area soon? thanks Geoff Steckel I used include directives to avoid duplications (see previous reply) but the following diff allows to add aliases and multiple listen statements. Reyk Index: config.c === RCS file: /cvs/src/usr.sbin/httpd/config.c,v retrieving revision 1.26 diff -u -p -u -p -r1.26 config.c --- config.c21 Dec 2014 00:54:49 - 1.26 +++ config.c3 Jan 2015 13:33:25 - @@ -174,7 +174,9 @@ config_setserver(struct httpd *env, stru if ((what CONFIG_SERVERS) == 0 || id == privsep_process) continue; - DPRINTF(%s: sending server \%s[%u]\ to %s fd %d, __func__, + DPRINTF(%s: sending %s \%s[%u]\ to %s fd %d, __func__, + (srv-srv_conf.flags SRVFLAG_LOCATION) ? + location : server, srv-srv_conf.name, srv-srv_conf.id, ps-ps_title[id], srv-srv_s); Index: httpd.conf.5 === RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v retrieving revision 1.40 diff -u -p -u -p -r1.40 httpd.conf.5 --- httpd.conf.528 Dec 2014 13:53:23 - 1.40 +++ httpd.conf.53 Jan 2015 13:33:25 - @@ -135,6 +135,10 @@ must have a .Ar name and include one or more lines of the following syntax: .Bl -tag -width Ds +.It Ic alias Ar name +Specify an additional alias +.Ar name +for this server. .It Ic connection Ar option Set the specified options and limits for HTTP connections. Valid options are: @@ -180,6 +184,7 @@ and defaults to .Pa /run/slowcgi.sock . .It Ic listen on Ar address Oo Ic tls Oc Ic port Ar number Set the listen address and port. +This statement can be specified multiple times. .It Ic location Ar path Brq ... Specify server configuration rules for a specific location. The @@ -391,6 +396,13 @@ If the same address is repeated multiple statement, the server will be matched based on the requested host name. .Bd -literal -offset indent +server www.example.com { + alias example.com + listen on * port 80 + listen on * tls port 443 + root /htdocs/www.example.com +} + server www.a.example.com { listen on 203.0.113.1 port 80 root /htdocs/www.a.example.com Index: parse.y === RCS file: /cvs/src/usr.sbin/httpd/parse.y,v retrieving revision 1.46 diff -u -p -u -p -r1.46 parse.y --- parse.y 21 Dec 2014 00:54:49 - 1.46 +++ parse.y 3 Jan 2015 13:33:26 - @@ -106,6 +106,8 @@ int host_if(const char *, struct addre int host(const char *, struct addresslist *, int, struct portrange *, const char *, int); voidhost_free(struct addresslist *); +struct server *server_inherit(struct server *, const char *, + struct server_config *); int getservice(char *); int is_if_in_group(const char *, const char *); @@ -125,10 +127,10 @@ typedef struct { %} -%token ACCESS AUTO BACKLOG BODY BUFFER CERTIFICATE CHROOT CIPHERS COMMON +%token ACCESS ALIAS AUTO BACKLOG BODY BUFFER CERTIFICATE CHROOT CIPHERS COMMON %token COMBINED CONNECTION DIRECTORY ERR FCGI INDEX IP KEY LISTEN LOCATION %token LOG LOGDIR MAXIMUM NO NODELAY ON PORT PREFORK REQUEST REQUESTS ROOT -%token SACK SERVER SOCKET STYLE SYSLOG TCP TIMEOUT TLS TYPES +%token SACK SERVER SOCKET STYLE SYSLOG TCP TIMEOUT TLS TYPES %token ERROR INCLUDE %token v.string STRING %token v.number NUMBER @@ -247,8 +249,14 @@ server : SERVER STRING { srv_conf = srv-srv_conf; SPLAY_INIT(srv-srv_clients); + TAILQ_INIT(srv-srv_hosts); + + TAILQ_INSERT_TAIL(srv-srv_hosts, srv_conf, entry); } '{' optnl serveropts_l '}'{ - struct server *s = NULL; + struct server *s = NULL, *sn; + struct server_config*a, *b; + + srv_conf = srv-srv_conf; TAILQ_FOREACH(s, conf-sc_servers, srv_entry) { if
Re: httpd: multiple addresses for one server
On Sat, Jan 03, 2015 at 04:40:19PM +0100, Christopher Zimmermann wrote: Hi, On Sat, 3 Jan 2015 14:42:18 +0100 Reyk Floeter r...@openbsd.org wrote: On Thu, Jan 01, 2015 at 11:54:46PM -0500, Geoff Steckel wrote: Is there any way todo the equivalent of: server an.example.com listen on 192.168.2.99 listen on 2001.fefe.1.1::99 I used include directives to avoid duplications (see previous reply) but the following diff allows to add aliases and multiple listen statements. Reyk As I understand your diff you will duplicate the entire struct server_config for each combination of hostname (alias), listen address and location section. Correct. Isn't this overkill? No, it is just a few K per server block that is allocated once on startup. How many aliases do you have? My tests show that memory usage is not the problem but that there's indeed a problem with the pre-opened file descriptors for servers; something that is not necessary with aliases. A simple fix will follow. To me it seems like server_config is serving too much purposes here. A clean design should split up the struct server_config into one struct for connection settings, which will contain a TAILQ of hostnames, a TAILQ of listen addresses and a TAILQ of structs with location settings: A clean design should ... One could argue that a clean design wouldn't try to add too many layers of indirection that add code complexity and kill some of the flexibility that we have with the current implementation. I might split up struct server_config at some point, when it is really needed, but it is not the right time. TAILQ_HEAD(hostnames, char*); struct server_config { charlocation[NAME_MAX]; charroot[MAXPATHLEN]; [...] } TAILQ_HEAD(server_configs, server_config); struct serverhost { struct sockaddr_storages*srv_ss; char*tls_cert; int tcpbufsize; [... other connection settings ...] struct hostnames*srv_names; struct server_configs *srv_confs; } For now you could simply loop over a TAILQ of hostnames in server_privinit() and add an inner LOOP in server_response() searching for the hostname/aliases. Which makes the implementation more complicated, especially the reload and privsep code, adds additional loops to save a few bytes of memory. Don't get me wrong - I do care about memory usage - but this is not per connection - it is persistent during runtime. Reyk
Re: httpd: multiple addresses for one server
Hi, On Sat, 3 Jan 2015 14:42:18 +0100 Reyk Floeter r...@openbsd.org wrote: On Thu, Jan 01, 2015 at 11:54:46PM -0500, Geoff Steckel wrote: Is there any way todo the equivalent of: server an.example.com listen on 192.168.2.99 listen on 2001.fefe.1.1::99 I used include directives to avoid duplications (see previous reply) but the following diff allows to add aliases and multiple listen statements. Reyk As I understand your diff you will duplicate the entire struct server_config for each combination of hostname (alias), listen address and location section. Isn't this overkill? To me it seems like server_config is serving too much purposes here. A clean design should split up the struct server_config into one struct for connection settings, which will contain a TAILQ of hostnames, a TAILQ of listen addresses and a TAILQ of structs with location settings: TAILQ_HEAD(hostnames, char*); struct server_config { charlocation[NAME_MAX]; charroot[MAXPATHLEN]; [...] } TAILQ_HEAD(server_configs, server_config); struct serverhost { struct sockaddr_storages*srv_ss; char*tls_cert; int tcpbufsize; [... other connection settings ...] struct hostnames*srv_names; struct server_configs *srv_confs; } For now you could simply loop over a TAILQ of hostnames in server_privinit() and add an inner LOOP in server_response() searching for the hostname/aliases. Christopher -- http://gmerlin.de OpenPGP: http://gmerlin.de/christopher.pub F190 D013 8F01 AA53 E080 3F3C F17F B0A1 D44E 4FEE
Re: httpd: multiple addresses for one server
On Sat, Jan 03, 2015 at 05:19:16PM +0100, Reyk Floeter wrote: My tests show that memory usage is not the problem but that there's indeed a problem with the pre-opened file descriptors for servers; something that is not necessary with aliases. A simple fix will follow. Here is a fix for the previous: in the parent, only open a socket once per unique listen statement. This allows to specify many aliases and listen statements. Reyk Index: config.c === RCS file: /cvs/src/usr.sbin/httpd/config.c,v retrieving revision 1.27 diff -u -p -u -p -r1.27 config.c --- config.c3 Jan 2015 15:49:18 - 1.27 +++ config.c3 Jan 2015 19:32:00 - @@ -200,7 +200,9 @@ config_setserver(struct httpd *env, stru n = -1; proc_range(ps, id, n, m); for (n = 0; n m; n++) { - if ((fd = dup(srv-srv_s)) == -1) + if (srv-srv_s == -1) + fd = -1; + else if ((fd = dup(srv-srv_s)) == -1) return (-1); proc_composev_imsg(ps, id, n, IMSG_CFG_SERVER, fd, iov, c); @@ -211,9 +213,6 @@ config_setserver(struct httpd *env, stru } } - close(srv-srv_s); - srv-srv_s = -1; - return (0); } @@ -356,8 +355,12 @@ config_getserver(struct httpd *env, stru if ((srv = server_byaddr((struct sockaddr *) srv_conf.ss, srv_conf.port)) != NULL) { /* Add host to existing listening server */ - if (imsg-fd != -1) - close(imsg-fd); + if (imsg-fd != -1) { + if (srv-srv_s == -1) + srv-srv_s = imsg-fd; + else + close(imsg-fd); + } return (config_getserver_config(env, srv, imsg)); } Index: parse.y === RCS file: /cvs/src/usr.sbin/httpd/parse.y,v retrieving revision 1.48 diff -u -p -u -p -r1.48 parse.y --- parse.y 3 Jan 2015 16:20:31 - 1.48 +++ parse.y 3 Jan 2015 19:32:01 - @@ -226,6 +226,7 @@ server : SERVER STRING { strlcpy(s-srv_conf.errorlog, HTTPD_ERROR_LOG, sizeof(s-srv_conf.errorlog)); s-srv_conf.id = ++last_server_id; + s-srv_s = -1; s-srv_conf.timeout.tv_sec = SERVER_TIMEOUT; s-srv_conf.maxrequests = SERVER_MAXREQUESTS; s-srv_conf.maxrequestbody = SERVER_MAXREQUESTBODY; @@ -493,6 +494,7 @@ serveroptsl : LISTEN ON STRING opttls po /* A location entry uses the parent id */ s-srv_conf.id = srv-srv_conf.id; s-srv_conf.flags = SRVFLAG_LOCATION; + s-srv_s = -1; memcpy(s-srv_conf.ss, srv-srv_conf.ss, sizeof(s-srv_conf.ss)); s-srv_conf.port = srv-srv_conf.port; @@ -1742,6 +1744,8 @@ server_inherit(struct server *src, const fatal(out of memory); dst-srv_conf.id = ++last_server_id; + dst-srv_s = -1; + if (last_server_id == INT_MAX) { yyerror(too many servers defined); serverconfig_free(dst-srv_conf); @@ -1806,6 +1810,7 @@ server_inherit(struct server *src, const sizeof(dstl-srv_conf.ss)); dstl-srv_conf.port = addr-port; dstl-srv_conf.prefixlen = addr-prefixlen; + dstl-srv_s = -1; DPRINTF(adding location \%s\ for \%s[%u]\, dstl-srv_conf.location, Index: server.c === RCS file: /cvs/src/usr.sbin/httpd/server.c,v retrieving revision 1.49 diff -u -p -u -p -r1.49 server.c --- server.c21 Dec 2014 00:54:49 - 1.49 +++ server.c3 Jan 2015 19:32:01 - @@ -101,11 +101,27 @@ server_shutdown(void) int server_privinit(struct server *srv) { + struct server *s; + if (srv-srv_conf.flags SRVFLAG_LOCATION) return (0); log_debug(%s: adding server %s, __func__, srv-srv_conf.name); + /* +* There's no need to open a new socket if a server with the +* same address already exists. +*/ + TAILQ_FOREACH(s, env-sc_servers, srv_entry) { + if (s != srv s-srv_s != -1 + s-srv_conf.port == srv-srv_conf.port + sockaddr_cmp((struct sockaddr *)s-srv_conf.ss, + (struct sockaddr *)srv-srv_conf.ss, +