Commit d03fe336 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp Committed by Dridi Boukelmoune

Rewrite the proxy TLV wandering code, hoping coverity can make

better sense of it now.
parent 18c9e0c2
......@@ -42,6 +42,13 @@
#include "vsa.h"
#include "vtcp.h"
struct vpx_tlv {
unsigned magic;
#define VPX_TLV_MAGIC 0xdeb9a4a5
unsigned len;
char tlv[1];
};
/**********************************************************************
* PROXY 1 protocol
*/
......@@ -156,17 +163,6 @@ vpx_proto1(const struct worker *wrk, const struct req *req)
* PROXY 2 protocol
*/
struct pp2_tlv {
uint8_t type;
uint8_t length_hi;
uint8_t length_lo;
}__attribute__((packed));
struct pp2_tlv_ssl {
uint8_t client;
uint32_t verify;
}__attribute__((packed));
static const char vpx2_sig[] = {
'\r', '\n', '\r', '\n', '\0', '\r', '\n',
'Q', 'U', 'I', 'T', '\n',
......@@ -248,60 +244,85 @@ static uint32_t crc32c(const uint8_t *buf, int len)
return (crc ^ 0xffffffff);
}
struct vpx_tlv_iter {
uint8_t t;
void *p;
uint16_t l;
const char *e;
unsigned char *_p;
uint16_t _l;
};
static void
vpx_tlv_iter0(struct vpx_tlv_iter *vpi, void *p, unsigned l)
{
AN(p);
assert(l < 65536);
memset(vpi, 0, sizeof *vpi);
vpi->_p = p;
vpi->_l = l;
}
static int
vpx_tlv_itern(struct vpx_tlv_iter *vpi)
{
if (vpi->_l == 0 || vpi->e != NULL)
return (0);
if (vpi->_l < 3) {
vpi->e = "Dribble bytes";
return (0);
}
vpi->t = *vpi->_p;
vpi->l = vbe16dec(vpi->_p + 1);
if (vpi->l + 3 > vpi->_l) {
vpi->e = "Length Error";
return (0);
}
vpi->p = vpi->_p + 3;
vpi->_p += 3 + vpi->l;
vpi->_l -= 3 + vpi->l;
return (1);
}
#define VPX_TLV_FOREACH(ptr, len, itv) \
for(vpx_tlv_iter0(itv, ptr, len); vpx_tlv_itern(itv);)
int
VPX_tlv(const struct req *req, int tlv, void **dst, int *len)
VPX_tlv(const struct req *req, int typ, void **dst, int *len)
{
uintptr_t *p;
uint16_t *tlv_len_p;
uint16_t l;
char *d;
int ssltlv = 0;
struct vpx_tlv *tlv;
struct vpx_tlv_iter vpi[1], vpi2[1];
uintptr_t *up;
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
CHECK_OBJ_NOTNULL(req->sp, SESS_MAGIC);
AN(dst);
AN(len);
*dst = NULL;
*len = 0;
if (SES_Get_xport_priv(req->sp, &p) != 0) {
*dst = NULL;
if (SES_Get_proxy_tlv(req->sp, &up) != 0 || *up == 0)
return (-1);
}
tlv_len_p = (void *)(*p);
l = *tlv_len_p;
d = (char *)(tlv_len_p + 1);
CAST_OBJ_NOTNULL(tlv, (void*)(*up), VPX_TLV_MAGIC);
if (tlv > PP2_TYPE_SSL && tlv <= PP2_SUBTYPE_SSL_MAX) {
ssltlv = tlv;
tlv = PP2_TYPE_SSL;
}
while (l > sizeof(struct pp2_tlv)) {
uint16_t v_len = vbe16dec(d + 1);
if (d[0] == tlv) {
if (ssltlv) {
char *sd;
int sl;
sd = d + sizeof(struct pp2_tlv) +
sizeof(struct pp2_tlv_ssl);
sl = l - sizeof(struct pp2_tlv) -
sizeof(struct pp2_tlv_ssl);
while (sl > sizeof(struct pp2_tlv)) {
uint16_t subv_len = vbe16dec(sd + 1);
if (sd[0] == ssltlv) {
*dst = sd + 3;
*len = subv_len;
return (0);
}
sd += (subv_len + 3);
sl -= (subv_len + 3);
}
} else {
*dst = d + 3;
*len = v_len;
VPX_TLV_FOREACH(tlv->tlv, tlv->len, vpi) {
if (vpi->t == typ) {
*dst = vpi->p;
*len = vpi->l;
return (0);
}
if (vpi->t != PP2_TYPE_SSL)
continue;
VPX_TLV_FOREACH((char*)vpi->p + 5, vpi->l - 5, vpi2) {
if (vpi2->t == typ) {
*dst = vpi2->p;
*len = vpi2->l;
return (0);
}
}
d += (v_len + 3);
l -= (v_len + 3);
}
*dst = NULL;
return (-1);
}
......@@ -310,7 +331,6 @@ vpx_proto2(const struct worker *wrk, struct req *req)
{
int l, hdr_len;
uintptr_t *up;
uint16_t *tlv_len_p;
uint16_t tlv_len;
const uint8_t *p;
char *d, *tlv_start;
......@@ -322,6 +342,8 @@ vpx_proto2(const struct worker *wrk, struct req *req)
char pa[VTCP_PORTBUFSIZE];
char hb[VTCP_ADDRBUFSIZE];
char pb[VTCP_PORTBUFSIZE];
struct vpx_tlv_iter vpi[1], vpi2[1];
struct vpx_tlv *tlv;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
......@@ -374,27 +396,6 @@ vpx_proto2(const struct worker *wrk, struct req *req)
}
l -= 12;
d += 12;
break;
case 0x21:
/* IPv6|TCP */
pfam = AF_INET6;
if (l < 36) {
VSL(SLT_ProxyGarbage, req->sp->vxid,
"PROXY2: Ignoring short IPv6 addresses (%d)", l);
return (0);
}
l -= 36;
d += 36;
break;
default:
/* Ignore proxy header */
VSL(SLT_ProxyGarbage, req->sp->vxid,
"PROXY2: Ignoring unsupported protocol (0x%02x)", p[13]);
return (0);
}
switch (pfam) {
case AF_INET:
memset(&sin4, 0, sizeof sin4);
sin4.sin_family = pfam;
......@@ -411,7 +412,16 @@ vpx_proto2(const struct worker *wrk, struct req *req)
SES_Reserve_client_addr(req->sp, &sa);
AN(VSA_Build(sa, &sin4, sizeof sin4));
break;
case AF_INET6:
case 0x21:
/* IPv6|TCP */
pfam = AF_INET6;
if (l < 36) {
VSL(SLT_ProxyGarbage, req->sp->vxid,
"PROXY2: Ignoring short IPv6 addresses (%d)", l);
return (0);
}
l -= 36;
d += 36;
memset(&sin6, 0, sizeof sin6);
sin6.sin6_family = pfam;
......@@ -429,7 +439,10 @@ vpx_proto2(const struct worker *wrk, struct req *req)
AN(VSA_Build(sa, &sin6, sizeof sin6));
break;
default:
WRONG("Wrong pfam");
/* Ignore proxy header */
VSL(SLT_ProxyGarbage, req->sp->vxid,
"PROXY2: Ignoring unsupported protocol (0x%02x)", p[13]);
return (0);
}
AN(sa);
......@@ -442,62 +455,36 @@ vpx_proto2(const struct worker *wrk, struct req *req)
tlv_start = d;
tlv_len = l;
while (l > sizeof(struct pp2_tlv)) {
int el = vbe16dec(d + 1) + 3;
if (el > l) {
VSL(SLT_ProxyGarbage, req->sp->vxid,
"PROXY2: Ignoring TLV");
return (0);
}
switch (d[0]) {
case PP2_TYPE_CRC32C:
{
uint32_t n_crc32c = vbe32dec(d+3);
*(d+3) = 0; *(d+4) = 0; *(d+5) = 0; *(d+6) = 0;
VPX_TLV_FOREACH(d, l, vpi) {
if (vpi->t == PP2_TYPE_SSL) {
VPX_TLV_FOREACH((char*)vpi->p + 5, vpi->l - 5, vpi2) {
}
vpi->e = vpi2->e;
} else if (vpi->t == PP2_TYPE_CRC32C) {
uint32_t n_crc32c = vbe32dec(vpi->p);
vbe32enc(vpi->p, 0);
if (crc32c(p, hdr_len) != n_crc32c) {
VSL(SLT_ProxyGarbage, req->sp->vxid,
"PROXY2: CRC error");
return (-1);
}
break;
}
case PP2_TYPE_SSL:
{
const char *sd;
int sl;
sd = d + sizeof(struct pp2_tlv) +
sizeof(struct pp2_tlv_ssl);
sl = l - sizeof(struct pp2_tlv) -
sizeof(struct pp2_tlv_ssl);
while (sl > sizeof(struct pp2_tlv)) {
int esl = vbe16dec(sd + 1) + 3;
if (esl > sl) {
VSL(SLT_ProxyGarbage, req->sp->vxid,
"PROXY2: Ignoring SSL TLV");
return (0);
}
sd += esl;
sl -= esl;
}
break;
}
}
d += el;
l -= el;
}
if (l) {
VSL(SLT_ProxyGarbage, req->sp->vxid,
"PROXY2: header length mismatch");
return (0);
if (vpi->e != NULL) {
VSL(SLT_ProxyGarbage, req->sp->vxid, "PROXY2: TLV %s", vpi->e);
return (-1);
}
if (tlv_len && WS_Reserve(req->sp->ws, 2 + tlv_len)) {
tlv_len_p = (void *)req->sp->ws->f;
*tlv_len_p = tlv_len;
memcpy(req->sp->ws->f + 2, tlv_start, tlv_len);
WS_Release(req->sp->ws, 2 + tlv_len);
SES_Reserve_xport_priv(req->sp, &up);
*up = (uintptr_t)tlv_len_p;
tlv = WS_Alloc(req->sp->ws, sizeof *tlv + tlv_len);
if (tlv == NULL) {
VSL(SLT_ProxyGarbage, req->sp->vxid,
"PROXY2: TLV overflows WS");
return (-1);
}
INIT_OBJ(tlv, VPX_TLV_MAGIC);
tlv->len = tlv_len;
memcpy(tlv->tlv, tlv_start, tlv_len);
SES_Reserve_proxy_tlv(req->sp, &up);
*up = (uintptr_t)tlv;
return (0);
}
......
......@@ -31,16 +31,31 @@ varnish v1 -proto "PROXY" -vcl+backend {
}
} -start
logexpect l1 -v v1 -g raw {
expect * 1000 Begin "sess 0 PROXY"
expect * 1000 Proxy "2 217.70.181.33 60822 95.142.168.34 443"
expect * 1000 Link "req 1001 rxreq"
} -start
client c1 {
# PROXY2 with CRC32C TLV
sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a 21 11 00 65"
sendhex "d9 46 b5 21 5f 8e a8 22 ed 96 01 bb 03 00 04 95"
sendhex "03 ee 75 01 00 02 68 32 02 00 0a 68 6f 63 64 65"
sendhex "74 2e 6e 65 74 20 00 3d 01 00 00 00 00 21 00 07"
sendhex "54 4c 53 76 31 2e 33 25 00 05 45 43 32 35 36 24"
sendhex "00 0a 52 53 41 2d 53 48 41 32 35 36 23 00 16 41"
sendhex "45 41 44 2d 41 45 53 31 32 38 2d 47 43 4d 2d 53"
sendhex "48 41 32 35 36"
sendhex {
0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a
21 11 00 65
d9 46 b5 21
5f 8e a8 22
ed 96
01 bb
03 00 04 95 03 ee 75
01 00 02 68 32
02 00 0a 68 6f 63 64 65 74 2e 6e 65 74
20 00 3d
01 00 00 00 00
21 00 07 54 4c 53 76 31 2e 33
25 00 05 45 43 32 35 36
24 00 0a 52 53 41 2d 53 48 41 32 35 36
23 00 16 41 45 41 44 2d 41 45 53 31 32 38 2d 47 43 4d 2d 53 48 41 32 35 36
}
txreq
rxresp
expect resp.status == 200
......@@ -57,16 +72,136 @@ client c1 {
expect resp.http.cn == ""
} -run
varnish v1 -vsl_catchup
logexpect l1 -wait
logexpect l1 -v v1 -g raw {
expect * 1003 Begin "sess 0 PROXY"
expect * 1003 ProxyGarbage "PROXY2: CRC error"
} -start
client c1 {
# PROXY2 with CRC32C TLV and bad checksum
sendhex {
0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a
21 11 00 65
d9 46 b5 21
5f 8e a8 22
ed 96
01 bb
03 00 04 95 03 ee 74
01 00 02 68 32
02 00 0a 68 6f 63 64 65 74 2e 6e 65 74
20 00 3d
01 00 00 00 00
21 00 07 54 4c 53 76 31 2e 33
25 00 05 45 43 32 35 36
24 00 0a 52 53 41 2d 53 48 41 32 35 36
23 00 16 41 45 41 44 2d 41 45 53 31 32 38 2d 47 43 4d 2d 53 48 41 32 35 36
}
txreq
expect_close
} -run
varnish v1 -vsl_catchup
logexpect l1 -wait
logexpect l1 -v v1 -g raw {
expect * 1004 Begin "sess 0 PROXY"
expect * 1004 ProxyGarbage "PROXY2: TLV Dribble bytes"
} -start
client c1 {
# PROXY2 with CRC32C TLV and bad checksum
sendhex {
0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a
21 11 00 67
d9 46 b5 21
5f 8e a8 22
ed 96
01 bb
ff 00 04 95 03 ee 74
01 00 02 68 32
02 00 0a 68 6f 63 64 65 74 2e 6e 65 74
20 00 3d
01 00 00 00 00
21 00 07 54 4c 53 76 31 2e 33
25 00 05 45 43 32 35 36
24 00 0a 52 53 41 2d 53 48 41 32 35 36
23 00 16 41 45 41 44 2d 41 45 53 31 32 38 2d 47 43 4d 2d 53 48 41 32 35 36
ff ff
}
txreq
expect_close
} -run
varnish v1 -vsl_catchup
logexpect l1 -wait
logexpect l1 -v v1 -g raw {
expect * 1005 Begin "sess 0 PROXY"
expect * 1005 ProxyGarbage "PROXY2: TLV Length Error"
} -start
client c1 {
# PROXY2 with CRC32C TLV and bad checksum
sendhex {
0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a
21 11 00 60
d9 46 b5 21
5f 8e a8 22
ed 96
01 bb
ff 00 04 95 03 ee 74
01 00 02 68 32
02 00 0a 68 6f 63 64 65 74 2e 6e 65 74
20 00 3d
01 00 00 00 00
21 00 07 54 4c 53 76 31 2e 33
25 00 05 45 43 32 35 36
24 00 0a 52 53 41 2d 53 48 41 32 35 36
23 00 16 41 45 41 44 2d 41 45 53 31 32 38 2d 47 43 4d 2d 53 48 41 32 35 36
}
txreq
expect_close
} -run
varnish v1 -vsl_catchup
logexpect l1 -wait
logexpect l1 -v v1 -g raw {
expect * 1006 Begin "sess 0 PROXY"
expect * 1006 ProxyGarbage "PROXY2: TLV Length Error"
} -start
client c1 {
# PROXY2 with CRC32C TLV and bad checksum
sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a 21 11 00 65"
sendhex "d9 46 b5 21 5f 8e a8 22 ed 96 01 bb 03 00 04 95"
sendhex "03 ee 75 01 00 02 68 32 02 00 0a 68 6f 63 64 65"
sendhex "74 2e 6e 65 74 20 00 3d 01 00 00 00 00 21 00 07"
sendhex "54 4c 53 76 31 2e 33 25 00 05 45 43 32 35 36 24"
sendhex "00 0a 52 53 41 2d 53 48 41 32 35 36 23 00 16 41"
sendhex "45 41 44 2d 41 45 53 31 32 38 2d 47 43 4d 2d 53"
sendhex "48 41 32 35 35"
sendhex {
0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a
21 11 00 65
d9 46 b5 21
5f 8e a8 22
ed 96
01 bb
ff 00 04 95 03 ee 74
01 00 02 68 32
02 00 0a 68 6f 63 64 65 74 2e 6e 65 74
20 00 3c
01 00 00 00 00
21 00 07 54 4c 53 76 31 2e 33
25 00 05 45 43 32 35 36
24 00 0a 52 53 41 2d 53 48 41 32 35 36
23 00 16 41 45 41 44 2d 41 45 53 31 32 38 2d 47 43 4d 2d 53 48 41 32 35 36
}
txreq
expect_close
} -run
varnish v1 -vsl_catchup
logexpect l1 -wait
......@@ -39,7 +39,7 @@ SESS_ATTR(CLIENT_ADDR, client_addr, struct suckaddr, vsa_suckaddr_len)
SESS_ATTR(SERVER_ADDR, server_addr, struct suckaddr, vsa_suckaddr_len)
SESS_ATTR(CLIENT_IP, client_ip, char, -1)
SESS_ATTR(CLIENT_PORT, client_port, char, -1)
SESS_ATTR(XPORT_PRIV, xport_priv, uintptr_t, sizeof(uintptr_t))
SESS_ATTR(PROXY_TLV, proxy_tlv, uintptr_t, sizeof(uintptr_t))
SESS_ATTR(PROTO_PRIV, proto_priv, uintptr_t, sizeof(uintptr_t))
#undef SESS_ATTR
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment