]> err.no Git - varnish/commitdiff
Reject backend hostnames that resolve to multiple IPv4 or multiple
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Fri, 11 Jul 2008 10:12:52 +0000 (10:12 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Fri, 11 Jul 2008 10:12:52 +0000 (10:12 +0000)
IPv6 addresses, but accept one of each.

Emit a bytestring representation of the sockaddr we found for each
of these, into the shared object, so we avoid doing a DNS lookup
again in the cacher.

git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@2934 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/include/vrt.h
varnish-cache/lib/libvcl/vcc_backend.c
varnish-cache/lib/libvcl/vcc_compile.h
varnish-cache/lib/libvcl/vcc_fixed_token.c

index 8bf11690002ca2bb7e89a41ab2bcfd4ee510c277..e7290dcbc800d8ef2668f4216c2c68c44cad18a4 100644 (file)
@@ -57,6 +57,10 @@ struct vrt_backend_probe {
 struct vrt_backend {
        char                            *portname;
        char                            *hostname;
+
+       const unsigned char             *ipv4_sockaddr;
+       const unsigned char             *ipv6_sockaddr;
+
        char                            *vcl_name;
        char                            *ident;
        double                          connect_timeout;
index 240f76d7986b0b2ea6e2950e93a33c9ba9b07d9a..7c410bfa3340905958035d440cfcbce91559d6ef 100644 (file)
@@ -88,6 +88,94 @@ CheckHostPort(const char *host, const char *port)
        return (NULL);
 }
 
+/*--------------------------------------------------------------------
+ * Struct sockaddr is not really designed to be a compile time 
+ * initialized data structure, so we encode it as a byte-string
+ * and put it in an official sockaddr when we load the VCL.
+ */
+
+static void
+Emit_Sockaddr(struct tokenlist *tl, const struct token *t_host, const char *port)
+{
+       struct addrinfo *res, *res0, hint;
+       int n4, n6, len, error, retval;
+       const char *emit, *multiple;
+       unsigned char *u;
+       char hbuf[NI_MAXHOST];
+
+       AN(t_host->dec);
+       retval = 0;
+       memset(&hint, 0, sizeof hint);
+       hint.ai_family = PF_UNSPEC;
+       hint.ai_socktype = SOCK_STREAM;
+       error = getaddrinfo(t_host->dec, port, &hint, &res0);
+       AZ(error);
+       n4 = n6 = 0;
+       multiple = NULL;
+       for (res = res0; res; res = res->ai_next) {
+               emit = NULL;
+               if (res->ai_family == PF_INET) {
+                       if (n4++ == 0)
+                               emit = "ipv4_sockaddr";
+                       else 
+                               multiple = "IPv4";
+               } else if (res->ai_family == PF_INET6) {
+                       if (n6++ == 0)
+                               emit = "ipv6_sockaddr";
+                       else
+                               multiple = "IPv6";
+               } else
+                       continue;
+
+               if (multiple != NULL) {
+                       vsb_printf(tl->sb,
+                           "Backend host %.*s: resolves to "
+                           "multiple %s addresses.\n"
+                           "Only one address is allowed.\n"
+                           "Please specify which exact address "
+                           "you want to use, we found these:\n",
+                           PF(t_host), multiple);
+                       for (res = res0; res; res = res->ai_next) {
+                               error = getnameinfo(res->ai_addr,
+                                   res->ai_addrlen, hbuf, sizeof hbuf,
+                                   NULL, 0, NI_NUMERICHOST);
+                               AZ(error);
+                               vsb_printf(tl->sb, "\t%s\n", hbuf);
+                       }
+                       vcc_ErrWhere(tl, t_host);
+                       return;
+               }
+               AN(emit);
+               AN(res->ai_addr);
+               AN(res->ai_addrlen);
+               assert(res->ai_addrlen < 256);
+               Fh(tl, 0, "\nstatic const unsigned char sockaddr%u[%d] = {\n",
+                   tl->nsockaddr, res->ai_addrlen + 1);
+               Fh(tl, 0, "    %3u, /* Length */\n",  res->ai_addrlen);
+               u = (void*)res->ai_addr;
+               for (len = 0; len < res->ai_addrlen; len++) {
+                       if ((len % 8) == 0) 
+                               Fh(tl, 0, "   ");
+                       Fh(tl, 0, " %3u", u[len]);
+                       if (len + 1 < res->ai_addrlen)
+                               Fh(tl, 0, ",");
+                       if ((len % 8) == 7) 
+                               Fh(tl, 0, "\n");
+               }
+               Fh(tl, 0, "\n};\n");
+               Fb(tl, 0, "\t.%s = sockaddr%u,\n", emit, tl->nsockaddr++);
+               retval++;
+       }
+       freeaddrinfo(res0);
+       if (retval == 0) {
+               vsb_printf(tl->sb,
+                   "Backend host '%.*s': resolves to "
+                   "neither IPv4 nor IPv6 addresses.\n",
+                   PF(t_host) );
+               vcc_ErrWhere(tl, t_host);
+       }
+}
+
 /*--------------------------------------------------------------------
  * When a new VCL is loaded, it is likely to contain backend declarations
  * identical to other loaded VCL programs, and we want to reuse the state
@@ -266,7 +354,7 @@ vcc_ParseProbe(struct tokenlist *tl)
                        ExpectErr(tl, CSTR);
                        Fh(tl, 0, "\t\t.request =\n");
                        Fh(tl, 0, "\t\t\t\"GET \" ");
-                       EncToken(tl->fh, tl->t);
+                       EncToken(tl->fb, tl->t);
                        Fh(tl, 0, " \" /HTTP/1.1\\r\\n\"\n");
                        Fh(tl, 0, "\t\t\t\"Connection: close\\r\\n\"\n");
                        Fh(tl, 0, "\t\t\t\"\\r\\n\",\n");
@@ -278,23 +366,19 @@ vcc_ParseProbe(struct tokenlist *tl)
                        Fh(tl, 0, "\t\t.request =\n");
                        while (tl->t->tok == CSTR) {
                                Fh(tl, 0, "\t\t\t");
-                               EncToken(tl->fh, tl->t);
+                               EncToken(tl->fb, tl->t);
                                Fh(tl, 0, " \"\\r\\n\"\n");
                                vcc_NextToken(tl);
                        }
                        Fh(tl, 0, "\t\t\t\"\\r\\n\",\n");
                } else if (vcc_IdIs(t_field, "timeout")) {
                        Fh(tl, 0, "\t\t.timeout = ");
-                       tl->fb = tl->fh;
                        vcc_TimeVal(tl);
-                       tl->fb = NULL;
                        ERRCHK(tl);
                        Fh(tl, 0, ",\n");
                } else if (vcc_IdIs(t_field, "rate")) {
                        Fh(tl, 0, "\t\t.rate = ");
-                       tl->fb = tl->fh;
                        vcc_TimeVal(tl);
-                       tl->fb = NULL;
                        ERRCHK(tl);
                        Fh(tl, 0, ",\n");
                } else {
@@ -339,6 +423,7 @@ vcc_ParseHostDef(struct tokenlist *tl, int *nbh, const struct token *name, const
        struct token *t_port = NULL;
        const char *ep;
        struct fld_spec *fs;
+       struct vsb *vsb;
 
        fs = vcc_FldSpec(tl,
            "!host", "?port", "?connect_timeout", "?probe", NULL);
@@ -347,8 +432,12 @@ vcc_ParseHostDef(struct tokenlist *tl, int *nbh, const struct token *name, const
        ExpectErr(tl, '{');
        vcc_NextToken(tl);
 
+       vsb = vsb_newauto();
+       AN(vsb);
+       tl->fb = vsb;
+
        *nbh = tl->nbackend_host++;
-       Fh(tl, 0, "\nstatic const struct vrt_backend bh_%d = {\n", *nbh);
+       Fb(tl, 0, "\nstatic const struct vrt_backend bh_%d = {\n", *nbh);
 
        /* Check for old syntax */
        if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) {
@@ -383,12 +472,10 @@ vcc_ParseHostDef(struct tokenlist *tl, int *nbh, const struct token *name, const
                        ExpectErr(tl, ';');
                        vcc_NextToken(tl);
                } else if (vcc_IdIs(t_field, "connect_timeout")) {
-                       Fh(tl, 0, "\t.connect_timeout = ");
-                       tl->fb = tl->fh;
+                       Fb(tl, 0, "\t.connect_timeout = ");
                        vcc_TimeVal(tl);
-                       tl->fb = NULL;
                        ERRCHK(tl);
-                       Fh(tl, 0, ",\n");
+                       Fb(tl, 0, ",\n");
                        ExpectErr(tl, ';');
                        vcc_NextToken(tl);
                } else if (vcc_IdIs(t_field, "probe")) {
@@ -412,33 +499,42 @@ vcc_ParseHostDef(struct tokenlist *tl, int *nbh, const struct token *name, const
                vcc_ErrWhere(tl, t_host);
                return;
        }
-       Fh(tl, 0, "\t.hostname = ");
-       EncToken(tl->fh, t_host);
-       Fh(tl, 0, ",\n");
+       Fb(tl, 0, "\t.hostname = ");
+       EncToken(tl->fb, t_host);
+       Fb(tl, 0, ",\n");
 
        /* Check that the portname makes sense */
        if (t_port != NULL) {
-               ep = CheckHostPort(t_host->dec, t_port->dec);
+               ep = CheckHostPort("localhost", t_port->dec);
                if (ep != NULL) {
                        vsb_printf(tl->sb,
                            "Backend port '%.*s': %s\n", PF(t_port), ep);
                        vcc_ErrWhere(tl, t_port);
                        return;
                }
-               Fh(tl, 0, "\t.portname = ");
-               EncToken(tl->fh, t_port);
-               Fh(tl, 0, ",\n");
+               Fb(tl, 0, "\t.portname = ");
+               EncToken(tl->fb, t_port);
+               Fb(tl, 0, ",\n");
+               Emit_Sockaddr(tl, t_host, t_port->dec);
        } else {
-               Fh(tl, 0, "\t.portname = \"80\",\n");
+               Fb(tl, 0, "\t.portname = \"80\",\n");
+               Emit_Sockaddr(tl, t_host, "80");
        }
+       ERRCHK(tl);
 
        ExpectErr(tl, '}');
-       vcc_EmitBeIdent(tl->fh, name, qual, serial, t_first, tl->t);
-       Fh(tl, 0, "\t.vcl_name = \"%.*s", PF(name));
+       vcc_EmitBeIdent(tl->fb, name, qual, serial, t_first, tl->t);
+       Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(name));
        if (serial)
-               Fh(tl, 0, "[%d]", serial);
-       Fh(tl, 0, "\"\n};\n");
+               Fb(tl, 0, "[%d]", serial);
+       Fb(tl, 0, "\"\n};\n");
        vcc_NextToken(tl);
+
+       tl->fb = NULL;
+       vsb_finish(vsb);
+       AZ(vsb_overflowed(vsb));
+       Fh(tl, 0, "%s", vsb_data(vsb));
+       vsb_delete(vsb);
 }
 
 /*--------------------------------------------------------------------
index 4fff65bc6e2317aff265ce3f6a213fc233612b8e..911e511fbbdb3a1e73145fb218072cc674ccada8 100644 (file)
@@ -87,6 +87,7 @@ struct tokenlist {
 
        unsigned                recnt;
        unsigned                nhashcount;
+       unsigned                nsockaddr;
 };
 
 enum var_type {
index accc74f23bc0a9e99b4627c772b4f13822dd0393..905124d110dcee2a16c7e3b70698c0c6fbfeaff3 100644 (file)
@@ -395,6 +395,10 @@ vcl_output_lang_h(struct vsb *sb)
        vsb_cat(sb, "struct vrt_backend {\n");
        vsb_cat(sb, "   char                            *portname;\n");
        vsb_cat(sb, "   char                            *hostname;\n");
+       vsb_cat(sb, "\n");
+       vsb_cat(sb, "   const unsigned char             *ipv4_sockaddr;\n");
+       vsb_cat(sb, "   const unsigned char             *ipv6_sockaddr;\n");
+       vsb_cat(sb, "\n");
        vsb_cat(sb, "   char                            *vcl_name;\n");
        vsb_cat(sb, "   char                            *ident;\n");
        vsb_cat(sb, "   double                          connect_timeout;\n");