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.c    21 Dec 2014 00:54:49 -0000      1.26
+++ config.c    3 Jan 2015 13:33:25 -0000
@@ -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.5        28 Dec 2014 13:53:23 -0000      1.40
+++ httpd.conf.5        3 Jan 2015 13:33:25 -0000
@@ -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 -0000      1.46
+++ parse.y     3 Jan 2015 13:33:26 -0000
@@ -106,6 +106,8 @@ int          host_if(const char *, struct addre
 int             host(const char *, struct addresslist *,
                    int, struct portrange *, const char *, int);
 void            host_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 ((s->srv_conf.flags &
@@ -290,6 +298,44 @@ server             : SERVER STRING         {
 
                        TAILQ_INSERT_TAIL(conf->sc_servers, srv, srv_entry);
 
+                       /*
+                        * Add aliases and additional listen addresses as
+                        * individual servers.
+                        */
+                       TAILQ_FOREACH(a, &srv->srv_hosts, entry) {
+                               /* listen address */
+                               if (a->ss.ss_family == AF_UNSPEC)
+                                       continue;
+                               TAILQ_FOREACH(b, &srv->srv_hosts, entry) {
+                                       /* alias name */
+                                       if (*b->name == '\0' ||
+                                           (b == &srv->srv_conf && b == a))
+                                               continue;
+
+                                       if ((sn = server_inherit(srv,
+                                           b->name, a)) == NULL) {
+                                               serverconfig_free(srv_conf);
+                                               free(srv);
+                                               YYABORT;
+                                       }
+
+                                       DPRINTF("adding server \"%s[%u]\"",
+                                           sn->srv_conf.name, sn->srv_conf.id);
+
+                                       TAILQ_INSERT_TAIL(conf->sc_servers,
+                                           sn, srv_entry);
+                               }
+                       }
+
+                       /* Remove temporary aliases */
+                       TAILQ_FOREACH_SAFE(a, &srv->srv_hosts, entry, b) {
+                               TAILQ_REMOVE(&srv->srv_hosts, a, entry);
+                               if (a == &srv->srv_conf)
+                                       continue;
+                               serverconfig_free(a);
+                               free(a);
+                       }
+
                        srv = NULL;
                        srv_conf = NULL;
                }
@@ -302,7 +348,7 @@ serveropts_l        : serveropts_l serveroptsl 
 serveroptsl    : LISTEN ON STRING opttls port {
                        struct addresslist       al;
                        struct address          *h;
-                       struct server           *s;
+                       struct server_config    *s_conf, *alias = NULL;
 
                        if (parentsrv != NULL) {
                                yyerror("listen %s inside location", $3);
@@ -311,11 +357,14 @@ serveroptsl       : LISTEN ON STRING opttls po
                        }
 
                        if (srv->srv_conf.ss.ss_family != AF_UNSPEC) {
-                               yyerror("listen address already specified");
-                               free($3);
-                               YYERROR;
+                               if ((alias = calloc(1,
+                                   sizeof(*alias))) == NULL)
+                                       fatal("out of memory");
+
+                               /* Add as an alias */
+                               s_conf = alias;
                        } else
-                               s = srv;
+                               s_conf = &srv->srv_conf;
                        if ($5.op != PF_OP_EQ) {
                                yyerror("invalid port");
                                free($3);
@@ -330,15 +379,42 @@ serveroptsl       : LISTEN ON STRING opttls po
                        }
                        free($3);
                        h = TAILQ_FIRST(&al);
-                       memcpy(&srv->srv_conf.ss, &h->ss,
-                           sizeof(s->srv_conf.ss));
-                       s->srv_conf.port = h->port.val[0];
-                       s->srv_conf.prefixlen = h->prefixlen;
+                       memcpy(&s_conf->ss, &h->ss, sizeof(s_conf->ss));
+                       s_conf->port = h->port.val[0];
+                       s_conf->prefixlen = h->prefixlen;
                        host_free(&al);
 
                        if ($4) {
-                               s->srv_conf.flags |= SRVFLAG_TLS;
+                               s_conf->flags |= SRVFLAG_TLS;
+                       }
+
+                       if (alias != NULL) {
+                               TAILQ_INSERT_TAIL(&srv->srv_hosts,
+                                   alias, entry);
+                       }
+               }
+               | ALIAS STRING          {
+                       struct server_config    *alias;
+
+                       if (parentsrv != NULL) {
+                               yyerror("alias inside location");
+                               free($2);
+                               YYERROR;
+                       }
+
+                       if ((alias = calloc(1, sizeof(*alias))) == NULL)
+                               fatal("out of memory");
+
+                       if (strlcpy(alias->name, $2, sizeof(alias->name)) >=
+                           sizeof(alias->name)) {
+                               yyerror("server alias truncated");
+                               free($2);
+                               free(alias);
+                               YYERROR;
                        }
+                       free($2);
+
+                       TAILQ_INSERT_TAIL(&srv->srv_hosts, alias, entry);
                }
                | TCP                   {
                        if (parentsrv != NULL) {
@@ -852,6 +928,7 @@ lookup(char *s)
        /* this has to be sorted always */
        static const struct keywords keywords[] = {
                { "access",             ACCESS },
+               { "alias",              ALIAS },
                { "auto",               AUTO },
                { "backlog",            BACKLOG },
                { "body",               BODY },
@@ -1644,6 +1721,99 @@ host_free(struct addresslist *al)
                TAILQ_REMOVE(al, h, entry);
                free(h);
        }
+}
+
+struct server *
+server_inherit(struct server *src, const char *name,
+    struct server_config *addr)
+{
+       struct server   *dst, *s, *dstl;
+
+       if ((dst = calloc(1, sizeof(*dst))) == NULL)
+               fatal("out of memory");
+
+       /* Copy the source server and assign a new Id */
+       memcpy(&dst->srv_conf, &src->srv_conf, sizeof(dst->srv_conf));
+       if ((dst->srv_conf.tls_cert_file =
+           strdup(src->srv_conf.tls_cert_file)) == NULL)
+               fatal("out of memory");
+       if ((dst->srv_conf.tls_key_file =
+           strdup(src->srv_conf.tls_key_file)) == NULL)
+               fatal("out of memory");
+
+       dst->srv_conf.id = ++last_server_id;
+       if (last_server_id == INT_MAX) {
+               yyerror("too many servers defined");
+               free(dst);
+               return (NULL);
+       }
+
+       /* Now set alias and listen address */
+       strlcpy(dst->srv_conf.name, name, sizeof(dst->srv_conf.name));
+       memcpy(&dst->srv_conf.ss, &addr->ss, sizeof(dst->srv_conf.ss));
+       dst->srv_conf.port = addr->port;
+       dst->srv_conf.prefixlen = addr->prefixlen;
+       if (addr->flags & SRVFLAG_TLS)
+               dst->srv_conf.flags |= SRVFLAG_TLS;
+       else
+               dst->srv_conf.flags &= ~SRVFLAG_TLS;
+
+       if (server_tls_load_keypair(dst) == -1) {
+               yyerror("failed to load public/private keys "
+                   "for server %s", dst->srv_conf.name);
+               serverconfig_free(&dst->srv_conf);
+               free(dst);
+               return (NULL);
+       }
+
+       /* Check if the new server already exists */
+       TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
+               if ((s->srv_conf.flags &
+                   SRVFLAG_LOCATION) == 0 &&
+                   strcmp(s->srv_conf.name,
+                   dst->srv_conf.name) == 0 &&
+                   s->srv_conf.port == dst->srv_conf.port &&
+                   sockaddr_cmp(
+                   (struct sockaddr *)&s->srv_conf.ss,
+                   (struct sockaddr *)&dst->srv_conf.ss,
+                   s->srv_conf.prefixlen) == 0)
+                       break;
+       }
+       if (s != NULL) {
+               yyerror("server \"%s\" defined twice",
+                   dst->srv_conf.name);
+               serverconfig_free(&dst->srv_conf);
+               free(dst);
+               return (NULL);
+       }
+
+       /* Copy all the locations of the source server */
+       TAILQ_FOREACH(s, conf->sc_servers, srv_entry) {
+               if (!(s->srv_conf.flags & SRVFLAG_LOCATION &&
+                   s->srv_conf.id == src->srv_conf.id))
+                       continue;
+
+               if ((dstl = calloc(1, sizeof(*dstl))) == NULL)
+                       fatal("out of memory");
+
+               memcpy(&dstl->srv_conf, &s->srv_conf, sizeof(dstl->srv_conf));
+               strlcpy(dstl->srv_conf.name, name, sizeof(dstl->srv_conf.name));
+
+               /* Copy the new Id and listen address */
+               dstl->srv_conf.id = dst->srv_conf.id;
+               memcpy(&dstl->srv_conf.ss, &addr->ss,
+                   sizeof(dstl->srv_conf.ss));
+               dstl->srv_conf.port = addr->port;
+               dstl->srv_conf.prefixlen = addr->prefixlen;
+
+               DPRINTF("adding location \"%s\" for \"%s[%u]\"",
+                   dstl->srv_conf.location,
+                   dstl->srv_conf.name, dstl->srv_conf.id);
+
+               TAILQ_INSERT_TAIL(conf->sc_servers, dstl, srv_entry);
+       }
+
+       return (dst);
 }
 
 int

Reply via email to