{
switch (c->err_code) {
case CO_ER_NONE: return "Success";
+ case CO_ER_PRX_EMPTY: return "Connection closed while waiting for PROXY protocol header";
+ case CO_ER_PRX_ABORT: return "Connection error while waiting for PROXY protocol header";
case CO_ER_PRX_TIMEOUT: return "Timeout while waiting for PROXY protocol header";
+ case CO_ER_PRX_TRUNCATED: return "Truncated PROXY protocol header received";
+ case CO_ER_PRX_NOT_HDR: return "Received something which does not look like a PROXY protocol header";
+ case CO_ER_PRX_BAD_HDR: return "Received an invalid PROXY protocol header";
+ case CO_ER_PRX_BAD_PROTO: return "Received an unhandled protocol in the PROXY protocol header";
case CO_ER_SSL_TIMEOUT: return "Timeout during SSL handshake";
}
return NULL;
/* possible connection error codes */
enum {
CO_ER_NONE, /* no error */
+ CO_ER_PRX_EMPTY, /* nothing received in PROXY protocol header */
+ CO_ER_PRX_ABORT, /* client abort during PROXY protocol header */
CO_ER_PRX_TIMEOUT, /* timeout while waiting for a PROXY header */
+ CO_ER_PRX_TRUNCATED, /* truncated PROXY protocol header */
+ CO_ER_PRX_NOT_HDR, /* not a PROXY protocol header */
+ CO_ER_PRX_BAD_HDR, /* bad PROXY protocol header */
+ CO_ER_PRX_BAD_PROTO, /* unsupported protocol in PROXY header */
+
CO_ER_SSL_TIMEOUT, /* timeout during SSL handshake */
};
conn_sock_poll_recv(conn);
return 0;
}
- goto fail;
+ goto recv_abort;
}
} while (0);
+ if (!trash.len) {
+ /* client shutdown */
+ conn->err_code = CO_ER_PRX_EMPTY;
+ goto fail;
+ }
+
if (trash.len < 6)
goto missing;
end = trash.str + trash.len;
/* Decode a possible proxy request, fail early if it does not match */
- if (strncmp(line, "PROXY ", 6) != 0)
+ if (strncmp(line, "PROXY ", 6) != 0) {
+ conn->err_code = CO_ER_PRX_NOT_HDR;
goto fail;
+ }
line += 6;
if (trash.len < 18) /* shortest possible line */
if (line == end)
goto missing;
if (*line++ != ' ')
- goto fail;
+ goto bad_header;
dst3 = inetaddr_host_lim_ret(line, end, &line);
if (line == end)
goto missing;
if (*line++ != ' ')
- goto fail;
+ goto bad_header;
sport = read_uint((const char **)&line, end);
if (line == end)
goto missing;
if (*line++ != ' ')
- goto fail;
+ goto bad_header;
dport = read_uint((const char **)&line, end);
if (line > end - 2)
goto missing;
if (*line++ != '\r')
- goto fail;
+ goto bad_header;
if (*line++ != '\n')
- goto fail;
+ goto bad_header;
/* update the session's addresses and mark them set */
((struct sockaddr_in *)&conn->addr.from)->sin_family = AF_INET;
*line = 0;
line++;
if (*line++ != '\n')
- goto fail;
+ goto bad_header;
break;
}
}
if (!dst_s || !sport_s || !dport_s)
- goto fail;
+ goto bad_header;
sport = read_uint((const char **)&sport_s,dport_s - 1);
if (*sport_s != 0)
- goto fail;
+ goto bad_header;
dport = read_uint((const char **)&dport_s,line - 2);
if (*dport_s != 0)
- goto fail;
+ goto bad_header;
if (inet_pton(AF_INET6, src_s, (void *)&src3) != 1)
- goto fail;
+ goto bad_header;
if (inet_pton(AF_INET6, dst_s, (void *)&dst3) != 1)
- goto fail;
+ goto bad_header;
/* update the session's addresses and mark them set */
((struct sockaddr_in6 *)&conn->addr.from)->sin6_family = AF_INET6;
conn->flags |= CO_FL_ADDR_FROM_SET | CO_FL_ADDR_TO_SET;
}
else {
+ /* The protocol does not match something known (TCP4/TCP6) */
+ conn->err_code = CO_ER_PRX_BAD_PROTO;
goto fail;
}
if (len2 < 0 && errno == EINTR)
continue;
if (len2 != trash.len)
- goto fail;
+ goto recv_abort;
} while (0);
conn->flags &= ~flag;
* we have not read anything. Otherwise we need to fail because we won't
* be able to poll anymore.
*/
+ conn->err_code = CO_ER_PRX_TRUNCATED;
+ goto fail;
+
+ bad_header:
+ /* This is not a valid proxy protocol header */
+ conn->err_code = CO_ER_PRX_BAD_HDR;
+ goto fail;
+
+ recv_abort:
+ conn->err_code = CO_ER_PRX_ABORT;
+ goto fail;
+
fail:
conn_sock_stop_both(conn);
conn->flags |= CO_FL_ERROR;