[master] a2682c0 Support Unix domain sockets as -a listen addresses.
Geoff Simmons
geoff at uplex.de
Thu Feb 22 09:23:09 UTC 2018
commit a2682c0951d6d7d441939574d0b7e0a85865119f
Author: Geoff Simmons <geoff at uplex.de>
Date: Fri Feb 16 19:56:43 2018 +0100
Support Unix domain sockets as -a listen addresses.
Also adds the user, group and mode sub-args to -a, to set
permissions on the path created by -a for UDS.
Add the bogo_ip pseudo-VSA, representing IPv4 0.0.0.0:0, to be
exposed in VCL for non-IP addresses.
Also adding the field listen_sock to struct sess: pointer to the
struct listen_sock that was created by the acceptor and lives in
heritage.socks. This makes information like the endpoint name
(named -a arg) and the UDS path available from an sp.
diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index ed5602f..a8aadd1 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -99,6 +99,7 @@ struct poolparam;
struct sess;
struct transport;
struct worker;
+struct listen_sock;
#define DIGEST_LEN 32
@@ -571,6 +572,7 @@ struct sess {
#define SESS_MAGIC 0x2c2f9c5a
uint16_t sattr[SA_LAST];
+ struct listen_sock *listen_sock;
int refcnt;
int fd;
uint32_t vxid;
diff --git a/bin/varnishd/cache/cache_acceptor.c b/bin/varnishd/cache/cache_acceptor.c
index bb1f000..b54c99a 100644
--- a/bin/varnishd/cache/cache_acceptor.c
+++ b/bin/varnishd/cache/cache_acceptor.c
@@ -37,6 +37,8 @@
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include "cache_varnishd.h"
@@ -86,25 +88,26 @@ static struct tcp_opt {
socklen_t sz;
void *ptr;
int need;
+ int iponly;
} tcp_opts[] = {
-#define TCPO(lvl, nam, sz) { lvl, nam, #nam, sizeof(sz), 0, 0},
+#define TCPO(lvl, nam, sz, ip) { lvl, nam, #nam, sizeof(sz), 0, 0, ip},
- TCPO(SOL_SOCKET, SO_LINGER, struct linger)
- TCPO(SOL_SOCKET, SO_KEEPALIVE, int)
- TCPO(IPPROTO_TCP, TCP_NODELAY, int)
+ TCPO(SOL_SOCKET, SO_LINGER, struct linger, 0)
+ TCPO(SOL_SOCKET, SO_KEEPALIVE, int, 0)
+ TCPO(IPPROTO_TCP, TCP_NODELAY, int, 1)
#ifdef SO_SNDTIMEO_WORKS
- TCPO(SOL_SOCKET, SO_SNDTIMEO, struct timeval)
+ TCPO(SOL_SOCKET, SO_SNDTIMEO, struct timeval, 0)
#endif
#ifdef SO_RCVTIMEO_WORKS
- TCPO(SOL_SOCKET, SO_RCVTIMEO, struct timeval)
+ TCPO(SOL_SOCKET, SO_RCVTIMEO, struct timeval, 0)
#endif
#ifdef HAVE_TCP_KEEP
- TCPO(IPPROTO_TCP, TCP_KEEPIDLE, int)
- TCPO(IPPROTO_TCP, TCP_KEEPCNT, int)
- TCPO(IPPROTO_TCP, TCP_KEEPINTVL, int)
+ TCPO(IPPROTO_TCP, TCP_KEEPIDLE, int, 1)
+ TCPO(IPPROTO_TCP, TCP_KEEPCNT, int, 1)
+ TCPO(IPPROTO_TCP, TCP_KEEPINTVL, int, 1)
#endif
#undef TCPO
@@ -218,15 +221,18 @@ vca_tcp_opt_init(void)
}
static void
-vca_tcp_opt_test(int sock)
+vca_tcp_opt_test(struct listen_sock *ls)
{
- int i, n;
+ int i, n, sock;
struct tcp_opt *to;
socklen_t l;
void *ptr;
+ sock = ls->sock;
for (n = 0; n < n_tcp_opts; n++) {
to = &tcp_opts[n];
+ if (to->iponly && ls->uds)
+ continue;
to->need = 1;
ptr = calloc(1, to->sz);
AN(ptr);
@@ -241,13 +247,16 @@ vca_tcp_opt_test(int sock)
}
static void
-vca_tcp_opt_set(int sock, int force)
+vca_tcp_opt_set(struct listen_sock *ls, int force)
{
- int n;
+ int n, sock;
struct tcp_opt *to;
+ sock = ls->sock;
for (n = 0; n < n_tcp_opts; n++) {
to = &tcp_opts[n];
+ if (to->iponly && ls->uds)
+ continue;
if (to->need || force) {
VTCP_Assert(setsockopt(sock,
to->level, to->optname, to->ptr, to->sz));
@@ -304,15 +313,57 @@ vca_pace_good(void)
* Called from assigned worker thread
*/
+static void
+vca_mk_tcp(struct wrk_accept *wa, struct sess *sp, char *laddr, char *lport,
+ char *raddr, char *rport)
+{
+ struct suckaddr *sa;
+ struct sockaddr_storage ss;
+ socklen_t sl;
+
+ SES_Reserve_remote_addr(sp, &sa);
+ AN(VSA_Build(sa, &wa->acceptaddr, wa->acceptaddrlen));
+ sp->sattr[SA_CLIENT_ADDR] = sp->sattr[SA_REMOTE_ADDR];
+
+ VTCP_name(sa, raddr, VTCP_ADDRBUFSIZE, rport, VTCP_PORTBUFSIZE);
+ SES_Set_String_Attr(sp, SA_CLIENT_IP, raddr);
+ SES_Set_String_Attr(sp, SA_CLIENT_PORT, rport);
+
+ sl = sizeof ss;
+ AZ(getsockname(sp->fd, (void*)&ss, &sl));
+ SES_Reserve_local_addr(sp, &sa);
+ AN(VSA_Build(sa, &ss, sl));
+ sp->sattr[SA_SERVER_ADDR] = sp->sattr[SA_LOCAL_ADDR];
+ VTCP_name(sa, laddr, VTCP_ADDRBUFSIZE, lport, VTCP_PORTBUFSIZE);
+}
+
+static void
+vca_mk_uds(struct wrk_accept *wa, struct sess *sp, char *laddr, char *lport,
+ char *raddr, char *rport)
+{
+ struct suckaddr *sa;
+
+ (void) wa;
+ SES_Reserve_remote_addr(sp, &sa);
+ SES_Set_remote_addr(sp, bogo_ip);
+ sp->sattr[SA_CLIENT_ADDR] = sp->sattr[SA_REMOTE_ADDR];
+ sp->sattr[SA_LOCAL_ADDR] = sp->sattr[SA_REMOTE_ADDR];
+ sp->sattr[SA_SERVER_ADDR] = sp->sattr[SA_REMOTE_ADDR];
+ SES_Set_String_Attr(sp, SA_CLIENT_IP, "0.0.0.0");
+ SES_Set_String_Attr(sp, SA_CLIENT_PORT, "0");
+
+ strcpy(laddr, "0.0.0.0");
+ strcpy(raddr, "0.0.0.0");
+ strcpy(lport, "0");
+ strcpy(rport, "0");
+}
+
static void v_matchproto_(task_func_t)
vca_make_session(struct worker *wrk, void *arg)
{
struct sess *sp;
struct req *req;
struct wrk_accept *wa;
- struct sockaddr_storage ss;
- struct suckaddr *sa;
- socklen_t sl;
char laddr[VTCP_ADDRBUFSIZE];
char lport[VTCP_PORTBUFSIZE];
char raddr[VTCP_ADDRBUFSIZE];
@@ -353,24 +404,16 @@ vca_make_session(struct worker *wrk, void *arg)
sp->fd = wa->acceptsock;
wa->acceptsock = -1;
+ sp->listen_sock = wa->acceptlsock;
assert(wa->acceptaddrlen <= vsa_suckaddr_len);
- SES_Reserve_remote_addr(sp, &sa);
- AN(VSA_Build(sa, &wa->acceptaddr, wa->acceptaddrlen));
- sp->sattr[SA_CLIENT_ADDR] = sp->sattr[SA_REMOTE_ADDR];
-
- VTCP_name(sa, raddr, sizeof raddr, rport, sizeof rport);
- SES_Set_String_Attr(sp, SA_CLIENT_IP, raddr);
- SES_Set_String_Attr(sp, SA_CLIENT_PORT, rport);
-
- sl = sizeof ss;
- AZ(getsockname(sp->fd, (void*)&ss, &sl));
- SES_Reserve_local_addr(sp, &sa);
- AN(VSA_Build(sa, &ss, sl));
- sp->sattr[SA_SERVER_ADDR] = sp->sattr[SA_LOCAL_ADDR];
- VTCP_name(sa, laddr, sizeof laddr, lport, sizeof lport);
+ if (wa->acceptlsock->uds)
+ vca_mk_uds(wa, sp, laddr, lport, raddr, rport);
+ else
+ vca_mk_tcp(wa, sp, laddr, lport, raddr, rport);
+ AN(wa->acceptlsock->name);
VSL(SLT_Begin, sp->vxid, "sess 0 %s",
wa->acceptlsock->transport->name);
VSL(SLT_SessOpen, sp->vxid, "%s %s %s %s %s %.6f %d",
@@ -383,10 +426,10 @@ vca_make_session(struct worker *wrk, void *arg)
wrk->stats->sess_conn++;
if (need_test) {
- vca_tcp_opt_test(sp->fd);
+ vca_tcp_opt_test(wa->acceptlsock);
need_test = 0;
}
- vca_tcp_opt_set(sp->fd, 0);
+ vca_tcp_opt_set(wa->acceptlsock, 0);
req = Req_New(wrk, sp);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
@@ -562,7 +605,7 @@ vca_acct(void *arg)
ls->sock, i, strerror(errno));
}
AZ(listen(ls->sock, cache_param->listen_depth));
- vca_tcp_opt_set(ls->sock, 1);
+ vca_tcp_opt_set(ls, 1);
if (cache_param->accept_filter) {
int i;
i = VTCP_filter_http(ls->sock);
@@ -585,7 +628,7 @@ vca_acct(void *arg)
if (ls->sock == -2)
continue; // VCA_Shutdown
assert (ls->sock > 0);
- vca_tcp_opt_set(ls->sock, 1);
+ vca_tcp_opt_set(ls, 1);
}
AZ(pthread_mutex_unlock(&shut_mtx));
}
diff --git a/bin/varnishd/cache/cache_vrt_var.c b/bin/varnishd/cache/cache_vrt_var.c
index ef6da50..2ab2fdb 100644
--- a/bin/varnishd/cache/cache_vrt_var.c
+++ b/bin/varnishd/cache/cache_vrt_var.c
@@ -250,7 +250,6 @@ VRT_r_beresp_uncacheable(VRT_CTX)
const char *
VRT_r_client_identity(VRT_CTX)
{
-
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
if (ctx->req->client_identity != NULL)
diff --git a/bin/varnishd/common/heritage.h b/bin/varnishd/common/heritage.h
index 64131d6..7903cf6 100644
--- a/bin/varnishd/common/heritage.h
+++ b/bin/varnishd/common/heritage.h
@@ -35,6 +35,7 @@ struct suckaddr;
struct listen_sock;
struct transport;
struct VCLS;
+struct uds_perms;
struct listen_sock {
unsigned magic;
@@ -42,10 +43,12 @@ struct listen_sock {
VTAILQ_ENTRY(listen_sock) list;
VTAILQ_ENTRY(listen_sock) arglist;
int sock;
+ int uds;
char *endpoint;
const char *name;
struct suckaddr *addr;
const struct transport *transport;
+ const struct uds_perms *perms;
};
VTAILQ_HEAD(listen_sock_head, listen_sock);
diff --git a/bin/varnishd/mgt/mgt_acceptor.c b/bin/varnishd/mgt/mgt_acceptor.c
index af09013..64dad07 100644
--- a/bin/varnishd/mgt/mgt_acceptor.c
+++ b/bin/varnishd/mgt/mgt_acceptor.c
@@ -33,11 +33,15 @@
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
#include "mgt/mgt.h"
#include "common/heritage.h"
@@ -47,6 +51,7 @@
#include "vsa.h"
#include "vss.h"
#include "vtcp.h"
+#include "vus.h"
struct listen_arg {
unsigned magic;
@@ -56,6 +61,15 @@ struct listen_arg {
const char *name;
VTAILQ_HEAD(,listen_sock) socks;
const struct transport *transport;
+ const struct uds_perms *perms;
+};
+
+struct uds_perms {
+ unsigned magic;
+#define UDS_PERMS_MAGIC 0x84fb5635
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
};
static VTAILQ_HEAD(,listen_arg) listen_args =
@@ -65,18 +79,35 @@ static int
mac_opensocket(struct listen_sock *ls)
{
int fail;
+ struct sockaddr_un uds;
CHECK_OBJ_NOTNULL(ls, LISTEN_SOCK_MAGIC);
if (ls->sock > 0) {
MCH_Fd_Inherit(ls->sock, NULL);
closefd(&ls->sock);
}
- ls->sock = VTCP_bind(ls->addr, NULL);
+ if (!ls->uds)
+ ls->sock = VTCP_bind(ls->addr, NULL);
+ else {
+ uds.sun_family = PF_UNIX;
+ strcpy(uds.sun_path, ls->endpoint);
+ ls->sock = VUS_bind(&uds, NULL);
+ }
fail = errno;
if (ls->sock < 0) {
AN(fail);
return (fail);
}
+ if (ls->perms != NULL) {
+ CHECK_OBJ(ls->perms, UDS_PERMS_MAGIC);
+ assert(ls->uds);
+ errno = 0;
+ if (ls->perms->mode != 0
+ && chmod(ls->endpoint, ls->perms->mode) != 0)
+ return errno;
+ if (chown(ls->endpoint, ls->perms->uid, ls->perms->gid) != 0)
+ return errno;
+ }
MCH_Fd_Inherit(ls->sock, "sock");
return (0);
}
@@ -109,22 +140,12 @@ MAC_reopen_sockets(void)
/*--------------------------------------------------------------------*/
-static int v_matchproto_(vss_resolved_f)
-mac_callback(void *priv, const struct suckaddr *sa)
+static struct listen_sock *
+mk_listen_sock(struct listen_arg *la, const struct suckaddr *sa)
{
- struct listen_arg *la;
struct listen_sock *ls;
- char abuf[VTCP_ADDRBUFSIZE], pbuf[VTCP_PORTBUFSIZE];
- char nbuf[VTCP_ADDRBUFSIZE+VTCP_PORTBUFSIZE+2];
int fail;
- CAST_OBJ_NOTNULL(la, priv, LISTEN_ARG_MAGIC);
-
- VTAILQ_FOREACH(ls, &heritage.socks, list) {
- if (!VSA_Compare(sa, ls->addr))
- ARGV_ERR("-a arguments %s and %s have same address\n",
- ls->endpoint, la->endpoint);
- }
ALLOC_OBJ(ls, LISTEN_SOCK_MAGIC);
AN(ls);
ls->sock = -1;
@@ -134,6 +155,9 @@ mac_callback(void *priv, const struct suckaddr *sa)
AN(ls->endpoint);
ls->name = la->name;
ls->transport = la->transport;
+ ls->perms = la->perms;
+ if (*la->endpoint == '/')
+ ls->uds = 1;
VJ_master(JAIL_MASTER_PRIVPORT);
fail = mac_opensocket(ls);
VJ_master(JAIL_MASTER_LOW);
@@ -144,8 +168,30 @@ mac_callback(void *priv, const struct suckaddr *sa)
if (fail != EAFNOSUPPORT)
ARGV_ERR("Could not get socket %s: %s\n",
la->endpoint, strerror(fail));
- return(0);
+ return(NULL);
}
+ return(ls);
+}
+
+static int v_matchproto_(vss_resolved_f)
+mac_tcp(void *priv, const struct suckaddr *sa)
+{
+ struct listen_arg *la;
+ struct listen_sock *ls;
+ char abuf[VTCP_ADDRBUFSIZE], pbuf[VTCP_PORTBUFSIZE];
+ char nbuf[VTCP_ADDRBUFSIZE+VTCP_PORTBUFSIZE+2];
+
+ CAST_OBJ_NOTNULL(la, priv, LISTEN_ARG_MAGIC);
+
+ VTAILQ_FOREACH(ls, &heritage.socks, list) {
+ if (!ls->uds && !VSA_Compare(sa, ls->addr))
+ ARGV_ERR("-a arguments %s and %s have same address\n",
+ ls->endpoint, la->endpoint);
+ }
+ ls = mk_listen_sock(la, sa);
+ if (ls == NULL)
+ return(0);
+ AZ(ls->uds);
if (VSA_Port(ls->addr) == 0) {
/*
* If the argv port number is zero, we adopt whatever
@@ -164,6 +210,28 @@ mac_callback(void *priv, const struct suckaddr *sa)
return (0);
}
+static int v_matchproto_(vus_resolved_f)
+mac_uds(void *priv, const struct sockaddr_un *uds)
+{
+ struct listen_arg *la;
+ struct listen_sock *ls;
+
+ CAST_OBJ_NOTNULL(la, priv, LISTEN_ARG_MAGIC);
+
+ VTAILQ_FOREACH(ls, &heritage.socks, list) {
+ if (ls->uds && strcmp(uds->sun_path, ls->endpoint) == 0)
+ ARGV_ERR("-a arguments %s and %s have same address\n",
+ ls->endpoint, la->endpoint);
+ }
+ ls = mk_listen_sock(la, bogo_ip);
+ if (ls == NULL)
+ return(0);
+ AN(ls->uds);
+ VTAILQ_INSERT_TAIL(&la->socks, ls, arglist);
+ VTAILQ_INSERT_TAIL(&heritage.socks, ls, list);
+ return (0);
+}
+
void
MAC_Arg(const char *spec)
{
@@ -171,10 +239,14 @@ MAC_Arg(const char *spec)
struct listen_arg *la;
const char *err;
int error;
- const struct transport *xp;
+ const struct transport *xp = NULL;
const char *name;
char name_buf[8];
static unsigned seq = 0;
+ struct passwd *pwd = NULL;
+ struct group *grp = NULL;
+ mode_t mode = 0;
+ struct uds_perms *perms;
av = MGT_NamedArg(spec, &name, "-a");
AN(av);
@@ -192,19 +264,107 @@ MAC_Arg(const char *spec)
}
la->name = name;
- if (av[2] == NULL) {
- xp = XPORT_Find("http");
- } else {
- xp = XPORT_Find(av[2]);
- if (xp == NULL)
- ARGV_ERR("Unknown protocol '%s'\n", av[2]);
- if (av[3] != NULL)
- ARGV_ERR("Too many sub-arguments to -a(%s)\n", av[2]);
+ if (*la->endpoint != '/' && strchr(la->endpoint, '/') != NULL)
+ ARGV_ERR("Unix domain socket addresses must be absolute paths "
+ "in -a (%s)\n", la->endpoint);
+
+ for (int i = 2; av[i] != NULL; i++) {
+ char *eq, *val;
+ int len;
+
+ if ((eq = strchr(av[i], '=')) == NULL) {
+ if (xp != NULL)
+ ARGV_ERR("Too many protocol sub-args in -a "
+ "(%s)\n", av[i]);
+ xp = XPORT_Find(av[i]);
+ if (xp == NULL)
+ ARGV_ERR("Unknown protocol '%s'\n", av[i]);
+ continue;
+ }
+ if (la->endpoint[0] != '/')
+ ARGV_ERR("Invalid sub-arg %s for IP addresses in -a\n",
+ av[i]);
+
+ val = eq + 1;
+ len = eq - av[i];
+ assert(len >= 0);
+ if (len == 0)
+ ARGV_ERR("Invalid sub-arg %s in -a\n", av[i]);
+
+ if (strncmp(av[i], "user", len) == 0) {
+ if (pwd != NULL)
+ ARGV_ERR("Too many user sub-args in -a (%s)\n",
+ av[i]);
+ pwd = getpwnam(val);
+ if (pwd == NULL)
+ ARGV_ERR("Unknown user %s in -a\n", val);
+ continue;
+ }
+
+ if (strncmp(av[i], "group", len) == 0) {
+ if (grp != NULL)
+ ARGV_ERR("Too many group sub-args in -a (%s)\n",
+ av[i]);
+ grp = getgrnam(val);
+ if (grp == NULL)
+ ARGV_ERR("Unknown group %s in -a\n", val);
+ continue;
+ }
+
+ if (strncmp(av[i], "mode", len) == 0) {
+ long m;
+ char *p;
+
+ if (mode != 0)
+ ARGV_ERR("Too many mode sub-args in -a (%s)\n",
+ av[i]);
+ if (*val == '\0')
+ ARGV_ERR("Empty mode sub-arg in -a\n");
+ errno = 0;
+ m = strtol(val, &p, 8);
+ if (*p != '\0')
+ ARGV_ERR("Invalid mode sub-arg %s in -a\n",
+ val);
+ if (errno)
+ ARGV_ERR("Cannot parse mode sub-arg %s in -a: "
+ "%s\n", val, strerror(errno));
+ if (m <= 0 || m > 0777)
+ ARGV_ERR("Mode sub-arg %s out of range in -a\n",
+ val);
+ mode = (mode_t) m;
+ continue;
+ }
+
+ ARGV_ERR("Invalid sub-arg %s in -a\n", av[i]);
}
+
+ if (xp == NULL)
+ xp = XPORT_Find("http");
AN(xp);
la->transport = xp;
- error = VSS_resolver(av[1], "80", mac_callback, la, &err);
+ if (pwd != NULL || grp != NULL || mode != 0) {
+ ALLOC_OBJ(perms, UDS_PERMS_MAGIC);
+ AN(perms);
+ if (pwd != NULL)
+ perms->uid = pwd->pw_uid;
+ else
+ perms->uid = (uid_t) -1;
+ if (grp != NULL)
+ perms->gid = grp->gr_gid;
+ else
+ perms->gid = (gid_t) -1;
+ perms->mode = mode;
+ la->perms = perms;
+ }
+ else
+ AZ(la->perms);
+
+ if (*la->endpoint != '/')
+ error = VSS_resolver(av[1], "80", mac_tcp, la, &err);
+ else
+ error = VUS_resolver(av[1], mac_uds, la, &err);
+
if (VTAILQ_EMPTY(&la->socks) || error)
ARGV_ERR("Got no socket(s) for %s\n", av[1]);
VAV_Free(av);
diff --git a/bin/varnishd/mgt/mgt_main.c b/bin/varnishd/mgt/mgt_main.c
index 8e968ed..275f6fb 100644
--- a/bin/varnishd/mgt/mgt_main.c
+++ b/bin/varnishd/mgt/mgt_main.c
@@ -41,6 +41,7 @@
#include <syslog.h>
#include <unistd.h>
#include <sys/stat.h>
+#include <sys/socket.h>
#include "mgt/mgt.h"
#include "common/heritage.h"
@@ -59,6 +60,7 @@
#include "vsub.h"
#include "vtim.h"
#include "waiter/mgt_waiter.h"
+#include "vsa.h"
struct heritage heritage;
unsigned d_flag = 0;
@@ -564,6 +566,9 @@ main(int argc, char * const *argv)
VJ_Init(j_arg);
+ /* Initialize the bogo-IP VSA */
+ VSA_Init();
+
optind = 1;
optreset = 1;
while ((o = getopt(argc, argv, opt_spec)) != -1) {
diff --git a/bin/varnishtest/tests/b00053.vtc b/bin/varnishtest/tests/b00053.vtc
new file mode 100644
index 0000000..09e3d20
--- /dev/null
+++ b/bin/varnishtest/tests/b00053.vtc
@@ -0,0 +1,34 @@
+varnishtest "Does anything get through Unix domain sockets at all ?"
+
+server s1 {
+ rxreq
+ txresp -body "012345\n"
+} -start
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock" -vcl+backend {
+ sub vcl_backend_response {
+ set beresp.do_stream = false;
+ }
+} -start
+
+varnish v1 -cliok "param.set debug +workspace"
+varnish v1 -cliok "param.set debug +witness"
+
+varnish v1 -expect n_object == 0
+varnish v1 -expect sess_conn == 0
+varnish v1 -expect client_req == 0
+varnish v1 -expect cache_miss == 0
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+} -run
+
+varnish v1 -expect n_object == 1
+varnish v1 -expect sess_conn == 1
+varnish v1 -expect client_req == 1
+varnish v1 -expect cache_miss == 1
+varnish v1 -expect s_sess == 1
+varnish v1 -expect s_resp_bodybytes == 7
+varnish v1 -expect s_resp_hdrbytes == 178
diff --git a/bin/varnishtest/tests/b00054.vtc b/bin/varnishtest/tests/b00054.vtc
new file mode 100644
index 0000000..4850a56
--- /dev/null
+++ b/bin/varnishtest/tests/b00054.vtc
@@ -0,0 +1,18 @@
+varnishtest "Check poll acceptor on a UDS listen address"
+
+server s1 {
+ rxreq
+ txresp -hdr "Connection: close" -body "012345\n"
+} -start
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock -Wpoll" -vcl+backend {} -start
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+ delay .1
+ txreq -url "/"
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/bin/varnishtest/tests/b00055.vtc b/bin/varnishtest/tests/b00055.vtc
new file mode 100644
index 0000000..bb3a36d
--- /dev/null
+++ b/bin/varnishtest/tests/b00055.vtc
@@ -0,0 +1,30 @@
+varnishtest "Check pipelining over a UDS listen address"
+
+server s1 {
+ rxreq
+ expect req.url == "/foo"
+ txresp -body "foo"
+ rxreq
+ expect req.url == "/bar"
+ txresp -body "foobar"
+} -start
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock" -vcl+backend {} -start
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ send "GET /foo HTTP/1.1\n\nGET /bar HTTP/1.1\n\nGET /bar HTTP/1.1\n\n"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 3
+ expect resp.http.x-varnish == "1001"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 6
+ expect resp.http.x-varnish == "1003"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 6
+ expect resp.http.x-varnish == "1005 1004"
+} -run
+
+varnish v1 -expect sess_readahead == 2
diff --git a/bin/varnishtest/tests/b00056.vtc b/bin/varnishtest/tests/b00056.vtc
new file mode 100644
index 0000000..b875f0b
--- /dev/null
+++ b/bin/varnishtest/tests/b00056.vtc
@@ -0,0 +1,36 @@
+varnishtest "Check read-head / partial pipelining over a UDS listen address"
+
+server s1 {
+ rxreq
+ expect req.url == "/foo"
+ txresp -body "foo"
+ rxreq
+ expect req.url == "/bar"
+ txresp -body "foobar"
+} -start
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock" -vcl+backend {}
+
+# NB: The accept_filter param may not exist.
+varnish v1 -cli "param.set accept_filter false"
+varnish v1 -start
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ send "GET /foo HTTP/1.1\r\n\r\nGET "
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 3
+ expect resp.http.x-varnish == "1001"
+ send "/bar HTTP/1.1\n\nGET /bar "
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 6
+ expect resp.http.x-varnish == "1003"
+ send "HTTP/1.1\n\n"
+ rxresp
+ expect resp.status == 200
+ expect resp.bodylen == 6
+ expect resp.http.x-varnish == "1005 1004"
+} -run
+
+varnish v1 -expect sess_readahead == 2
diff --git a/bin/varnishtest/tests/b00057.vtc b/bin/varnishtest/tests/b00057.vtc
new file mode 100644
index 0000000..74c73cc
--- /dev/null
+++ b/bin/varnishtest/tests/b00057.vtc
@@ -0,0 +1,22 @@
+varnishtest "Test orderly connection closure of a UDS listen socket"
+
+
+server s1 {
+ rxreq
+ txresp -nolen -hdr "Transfer-encoding: chunked"
+ delay .2
+ chunkedlen 30000
+ delay .2
+ chunkedlen 100000
+ delay .2
+ chunkedlen 0
+} -start
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock" -vcl+backend { } -start
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ txreq -hdr "Connection: close"
+ delay 3
+ rxresp
+ expect resp.bodylen == 130000
+} -run
diff --git a/bin/varnishtest/tests/b00059.vtc b/bin/varnishtest/tests/b00059.vtc
new file mode 100644
index 0000000..00ce94f
--- /dev/null
+++ b/bin/varnishtest/tests/b00059.vtc
@@ -0,0 +1,52 @@
+varnishtest "Run a lot of transactions through Unix domain sockets"
+
+server s0 {
+ loop 10 {
+ rxreq
+ txresp -body "foo1"
+ }
+ rxreq
+ txresp -hdr "Connection: close" -body "foo1"
+ expect_close
+} -dispatch
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock -Wpoll" -vcl+backend {
+ sub vcl_recv {
+ return (pass);
+ }
+ sub vcl_backend_fetch {
+ set bereq.backend = s0;
+ }
+
+} -start
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ loop 20 {
+ txreq -url /c1
+ rxresp
+ expect resp.bodylen == 4
+ expect resp.status == 200
+ }
+} -start
+
+client c2 -connect "${tmpdir}/v1.sock" {
+ loop 20 {
+ txreq -url /c2
+ rxresp
+ expect resp.bodylen == 4
+ expect resp.status == 200
+ }
+} -start
+
+client c3 -connect "${tmpdir}/v1.sock" {
+ loop 20 {
+ txreq -url /c3
+ rxresp
+ expect resp.bodylen == 4
+ expect resp.status == 200
+ }
+} -start
+
+client c1 -wait
+client c2 -wait
+client c3 -wait
diff --git a/bin/varnishtest/tests/b00060.vtc b/bin/varnishtest/tests/b00060.vtc
new file mode 100644
index 0000000..6ecd156
--- /dev/null
+++ b/bin/varnishtest/tests/b00060.vtc
@@ -0,0 +1,22 @@
+varnishtest "VSL tags affected by the use of UDS addresses"
+
+varnish v1 -arg "-a foo=${tmpdir}/v1.sock" -vcl {
+ backend b { .host = "${bad_ip}"; }
+
+ sub vcl_recv { return(synth(200)); }
+} -start
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ txreq
+ rxresp
+} -run
+
+logexpect l1 -v v1 -d 1 -g session {
+ expect 0 1000 Begin
+ expect 0 = SessOpen "^0.0.0.0 0 foo 0.0.0.0 0"
+} -run
+
+logexpect l2 -v v1 -d 1 -g vxid {
+ expect 0 1001 Begin
+ expect * = ReqStart "^0.0.0.0 0$"
+} -run
diff --git a/bin/varnishtest/tests/c00003.vtc b/bin/varnishtest/tests/c00003.vtc
index eca86dc..9dfb220 100644
--- a/bin/varnishtest/tests/c00003.vtc
+++ b/bin/varnishtest/tests/c00003.vtc
@@ -6,14 +6,108 @@ shell -err -match "have same address|already in use" {
varnishd -d -a 127.0.0.1:38484 -a 127.0.0.1:38484 -b localhost:80
}
+shell -err -match "have same address|already in use" {
+ varnishd -d -a ${tmpdir}/vtc.sock -a ${tmpdir}/vtc.sock -b localhost:80
+}
+
# -a bad protocol specs
-shell -err -expect "Too many sub-arguments" {
+shell -err -expect "Too many protocol sub-args" {
varnishd -a 127.0.0.1:80000,PROXY,FOO -d
}
-shell -err -expect "Too many sub-arguments" {
+shell -err -expect "Too many protocol sub-args" {
varnishd -a 127.0.0.1:80000,HTTP,FOO -d
}
+# -a relative path for a UDS address not permitted
+shell -err -expect "Unix domain socket addresses must be absolute paths" {
+ varnishd -a foo/bar.sock -d
+}
+
+# -a args for UDS permissions not permitted with IP addresses
+shell -err -expect "Invalid sub-arg user=u for IP addresses" {
+ varnishd -a 127.0.0.1:80000,user=u -d
+}
+
+shell -err -expect "Invalid sub-arg group=g for IP addresses" {
+ varnishd -a 127.0.0.1:80000,group=g -d
+}
+
+shell -err -expect "Invalid sub-arg mode=660 for IP addresses" {
+ varnishd -a 127.0.0.1:80000,mode=660 -d
+}
+
+# Illegal mode sub-args
+shell -err -expect "Too many mode sub-args" {
+ varnishd -a ${tmpdir}/vtc.sock,mode=660,mode=600 -d
+}
+
+shell -err -expect "Empty mode sub-arg" {
+ varnishd -a ${tmpdir}/vtc.sock,mode= -d
+}
+
+shell -err -expect "Invalid mode sub-arg 666devilish" {
+ varnishd -a ${tmpdir}/vtc.sock,mode=666devilish -d
+}
+
+shell -err -expect "Invalid mode sub-arg devilish" {
+ varnishd -a ${tmpdir}/vtc.sock,mode=devilish -d
+}
+
+shell -err -expect "Invalid mode sub-arg 999" {
+ varnishd -a ${tmpdir}/vtc.sock,mode=999 -d
+}
+
+shell -err -expect "Cannot parse mode sub-arg 7" {
+ varnishd -a ${tmpdir}/vtc.sock,mode=77777777777777777777777777777777 -d
+}
+
+shell -err -expect "Cannot parse mode sub-arg -7" {
+ varnishd -a ${tmpdir}/vtc.sock,mode=-77777777777777777777777777777777 -d
+}
+
+shell -err -expect "Mode sub-arg 1666 out of range" {
+ varnishd -a ${tmpdir}/vtc.sock,mode=1666 -d
+}
+
+shell -err -expect "Mode sub-arg 0 out of range" {
+ varnishd -a ${tmpdir}/vtc.sock,mode=0 -d
+}
+
+shell -err -expect "Mode sub-arg -1 out of range" {
+ varnishd -a ${tmpdir}/vtc.sock,mode=-1 -d
+}
+
+##
+## user and group sub-args tested in c00086.vtc, where the user and group
+## features are enabled.
+##
+
+# Invalid sub-arg
+shell -err -expect "Invalid sub-arg foo=bar" {
+ varnishd -a ${tmpdir}/vtc.sock,foo=bar -d
+}
+
+# A sub-arg without '=' is interpreted as a protocol name.
+shell -err -expect "Unknown protocol" {
+ varnishd -a ${tmpdir}/vtc.sock,foobar -d
+}
+
+shell -err -expect "Invalid sub-arg userfoo=u" {
+ varnishd -a ${tmpdir}/vtc.sock,userfoo=u -d
+}
+
+shell -err -expect "Invalid sub-arg groupfoo=g" {
+ varnishd -a ${tmpdir}/vtc.sock,groupfoo=g -d
+}
+
+shell -err -expect "Invalid sub-arg modefoo=666" {
+ varnishd -a ${tmpdir}/vtc.sock,modefoo=666 -d
+}
+
+shell -err -expect "Invalid sub-arg =foo" {
+ varnishd -a ${tmpdir}/vtc.sock,=foo -d
+}
+
# This requires non-local binds to be disabled. If you see this fail
# and are on Linux, ensure /proc/net/ipv4/ip_nonlocal_bind is set to 0.
diff --git a/bin/varnishtest/tests/c00086.vtc b/bin/varnishtest/tests/c00086.vtc
new file mode 100644
index 0000000..e149437
--- /dev/null
+++ b/bin/varnishtest/tests/c00086.vtc
@@ -0,0 +1,53 @@
+varnishtest "-a sub-args user, group and mode"
+
+feature user_vcache
+feature group_varnish
+feature root
+
+shell -err -expect "Too many user sub-args" {
+ varnishd -a ${tmpdir}/vtc.sock,user=vcache,user=vcache -d
+}
+
+shell -err -expect "Too many group sub-args" {
+ varnishd -a ${tmpdir}/vtc.sock,group=varnish,group=varnish -d
+}
+
+# Assuming that empty user and group names always fail getpwnam and getgrnam
+shell -err -expect "Unknown user " {
+ varnishd -a ${tmpdir}/vtc.sock,user= -d
+}
+
+shell -err -expect "Unknown group " {
+ varnishd -a ${tmpdir}/vtc.sock,group= -d
+}
+
+server s1 {} -start
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock,user=vcache,group=varnish,mode=660" \
+ -vcl+backend {}
+
+shell -match "rw-rw----.+vcache.+varnish" { ls -l ${tmpdir}/v1.sock }
+
+varnish v2 -arg "-a ${tmpdir}/v2.sock,user=vcache,mode=600" -vcl+backend {}
+
+shell -match "rw-------.+vcache" { ls -l ${tmpdir}/v2.sock }
+
+varnish v3 -arg "-a ${tmpdir}/v3.sock,group=varnish,mode=660" -vcl+backend {}
+
+shell -match "rw---- .+root.+varnish" { ls -l ${tmpdir}/v3.sock }
+
+varnish v4 -arg "-a ${tmpdir}/v4.sock,mode=666" -vcl+backend {}
+
+shell -match "rw-rw-rw-.+root" { ls -l ${tmpdir}/v4.sock }
+
+varnish v5 -arg "-a ${tmpdir}/v5.sock,user=vcache,group=varnish" -vcl+backend {}
+
+shell -match "vcache.+varnish" { ls -l ${tmpdir}/v5.sock }
+
+varnish v6 -arg "-a ${tmpdir}/v6.sock,user=vcache" -vcl+backend {}
+
+shell -match "vcache" { ls -l ${tmpdir}/v6.sock }
+
+varnish v7 -arg "-a ${tmpdir}/v7.sock,group=varnish" -vcl+backend {}
+
+shell -match "root.+varnish" { ls -l ${tmpdir}/v7.sock }
diff --git a/bin/varnishtest/tests/c00087.vtc b/bin/varnishtest/tests/c00087.vtc
new file mode 100644
index 0000000..5f55cdf
--- /dev/null
+++ b/bin/varnishtest/tests/c00087.vtc
@@ -0,0 +1,116 @@
+varnishtest "VCL *.ip vars as bogo-IPs when -a is UDS, and test ACL matches"
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock" -vcl+backend {
+ acl acl1 {
+ "${localhost}";
+ }
+
+ sub vcl_backend_response {
+ set beresp.http.b-client = client.ip;
+ set beresp.http.b-server = server.ip;
+ set beresp.http.b-local = local.ip;
+ set beresp.http.b-remote = remote.ip;
+ set beresp.http.b-compare = local.ip == remote.ip;
+ }
+
+ sub vcl_deliver {
+ set resp.http.c-client = client.ip;
+ set resp.http.c-server = server.ip;
+ set resp.http.c-local = local.ip;
+ set resp.http.c-remote = remote.ip;
+ set resp.http.c-compare = local.ip == remote.ip;
+ set resp.http.client_acl = client.ip ~ acl1;
+ set resp.http.server_acl = server.ip ~ acl1;
+ set resp.http.local_acl = local.ip ~ acl1;
+ set resp.http.remote_acl = remote.ip ~ acl1;
+ }
+} -start
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.c-client == "0.0.0.0"
+ expect resp.http.c-server == "0.0.0.0"
+ expect resp.http.c-local == "0.0.0.0"
+ expect resp.http.c-remote == "0.0.0.0"
+ expect resp.http.c-compare == "true"
+ expect resp.http.b-client == "0.0.0.0"
+ expect resp.http.b-server == "0.0.0.0"
+ expect resp.http.b-local == "0.0.0.0"
+ expect resp.http.b-remote == "0.0.0.0"
+ expect resp.http.b-compare == "true"
+ expect resp.http.client_acl == "false"
+ expect resp.http.server_acl == "false"
+ expect resp.http.local_acl == "false"
+ expect resp.http.remote_acl == "false"
+} -run
+
+logexpect l1 -v v1 -d 1 -g vxid -q "VCL_acl" {
+ expect 0 * Begin req
+ expect * = VCL_acl "^NO_MATCH acl1$"
+ expect * = VCL_acl "^NO_MATCH acl1$"
+ expect * = VCL_acl "^NO_MATCH acl1$"
+ expect * = VCL_acl "^NO_MATCH acl1$"
+ expect * = End
+} -run
+
+varnish v1 -vcl {
+ backend b { .host = "${bad_ip}"; }
+
+ acl acl1 {
+ "0.0.0.0";
+ }
+
+ sub vcl_recv {
+ return(synth(200));
+ }
+
+ sub vcl_synth {
+ set resp.http.client = client.ip ~ acl1;
+ set resp.http.server = server.ip ~ acl1;
+ set resp.http.local = local.ip ~ acl1;
+ set resp.http.remote = remote.ip ~ acl1;
+ }
+}
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ txreq -url "foo"
+ rxresp
+ expect resp.http.client == "true"
+ expect resp.http.server == "true"
+ expect resp.http.local == "true"
+ expect resp.http.remote == "true"
+} -run
+
+varnish v1 -errvcl {.../mask is not numeric.} {
+ backend b { .host = "${bad_ip}"; }
+
+ acl acl1 {
+ "${tmpdir}/v1.sock";
+ }
+}
+
+# client.ip == 0.0.0.0 appears in X-Forwarded-For
+server s1 {
+ rxreq
+ expect req.http.X-Forwarded-For == "0.0.0.0"
+ txresp
+ rxreq
+ expect req.http.X-Forwarded-For == "1.2.3.4, 0.0.0.0"
+ txresp
+} -start
+
+varnish v1 -vcl+backend {}
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ txreq -url /1
+ rxresp
+ txreq -url /2 -hdr "X-forwarded-for: 1.2.3.4"
+ rxresp
+} -run
diff --git a/bin/varnishtest/tests/j00004.vtc b/bin/varnishtest/tests/j00004.vtc
new file mode 100644
index 0000000..a23f7d7
--- /dev/null
+++ b/bin/varnishtest/tests/j00004.vtc
@@ -0,0 +1,42 @@
+varnishtest "Listen at a Unix domain socket while in jail"
+
+feature user_varnish
+feature group_varnish
+feature root
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock" \
+ -jail "-junix,user=varnish,ccgroup=varnish" \
+ -vcl+backend {
+} -start
+
+# Socket is created as management owner before the child goes to jail
+shell -match "root" { ls -l ${tmpdir}/v1.sock }
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
+
+server s1 {
+ rxreq
+ txresp
+} -start
+
+varnish v2 -arg "-a ${tmpdir}/v2.sock,user=varnish,group=varnish,mode=666" \
+ -jail "-junix,user=varnish,ccgroup=varnish" \
+ -vcl+backend {
+} -start
+
+shell -match "rw-rw-rw-.+varnish.+varnish" { ls -l ${tmpdir}/v2.sock }
+
+client c1 -connect "${tmpdir}/v2.sock" {
+ txreq
+ rxresp
+ expect resp.status == 200
+} -run
diff --git a/bin/varnishtest/tests/v00054.vtc b/bin/varnishtest/tests/v00054.vtc
new file mode 100644
index 0000000..a230fb8
--- /dev/null
+++ b/bin/varnishtest/tests/v00054.vtc
@@ -0,0 +1,28 @@
+varnishtest "client.identity is 0.0.0.0 if unset & client addr is UDS"
+
+varnish v1 -arg "-a ${tmpdir}/v1.sock" -vcl {
+ backend b { .host = "${bad_ip}"; }
+
+ sub vcl_recv {
+ if (req.url == "/nobody") {
+ set client.identity = "Samuel B. Nobody";
+ }
+ set req.http.id = client.identity;
+ return(synth(200));
+ }
+
+ sub vcl_synth {
+ set resp.http.id = req.http.id;
+ }
+} -start
+
+client c1 -connect "${tmpdir}/v1.sock" {
+ txreq -url "/nobody"
+ rxresp
+ expect resp.status == 200
+ expect resp.http.id == "Samuel B. Nobody"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.id == "0.0.0.0"
+} -run
diff --git a/bin/varnishtest/vtc_client.c b/bin/varnishtest/vtc_client.c
index 8db014c..ea33c5a 100644
--- a/bin/varnishtest/vtc_client.c
+++ b/bin/varnishtest/vtc_client.c
@@ -179,9 +179,12 @@ client_uds_connect(struct vtclog *vl, const char *path, double tmo,
assert(tmo >= 0);
+ errno = 0;
fd = VUS_resolver(path, uds_open, &tmo, errp);
- if (fd < 0)
+ if (fd < 0) {
+ *errp = strerror(errno);
return fd;
+ }
vtc_log(vl, 3, "connected fd %d to %s", fd, path);
return fd;
}
diff --git a/include/vsa.h b/include/vsa.h
index c28a7e9..70e4e50 100644
--- a/include/vsa.h
+++ b/include/vsa.h
@@ -32,7 +32,9 @@
struct suckaddr;
extern const int vsa_suckaddr_len;
+extern const struct suckaddr *bogo_ip;
+void VSA_Init(void);
int VSA_Sane(const struct suckaddr *);
unsigned VSA_Port(const struct suckaddr *);
int VSA_Compare(const struct suckaddr *, const struct suckaddr *);
diff --git a/lib/libvarnish/vsa.c b/lib/libvarnish/vsa.c
index c2e157b..1fc496f 100644
--- a/lib/libvarnish/vsa.c
+++ b/lib/libvarnish/vsa.c
@@ -36,7 +36,9 @@
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <netinet/in.h>
+#include <netdb.h>
#include "vdef.h"
#include "vas.h"
@@ -175,6 +177,27 @@ struct suckaddr {
const int vsa_suckaddr_len = sizeof(struct suckaddr);
/*
+ * Bogus IPv4 address 0.0.0.0:0 to be used for VCL *.ip variables when the
+ * "real" address is not IP (such as UDS addresses).
+ */
+static struct suckaddr bogo_ip_vsa;
+const struct suckaddr *bogo_ip = &bogo_ip_vsa;
+
+void
+VSA_Init()
+{
+ struct addrinfo hints, *res = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
+ AZ(getaddrinfo("0.0.0.0", "0", &hints, &res));
+ AN(VSA_Build(&bogo_ip_vsa, res->ai_addr, res->ai_addrlen));
+ assert(VSA_Sane(bogo_ip));
+ freeaddrinfo(res);
+}
+
+/*
* This VRT interface is for the VCC generated ACL code, which needs
* to know the address family and a pointer to the actual address.
*/
More information about the varnish-commit
mailing list