From 3ff82c514becd08922fcf9bc9f4870941650932a Mon Sep 17 00:00:00 2001 From: Laslo Hunhold Date: Tue, 3 Apr 2018 00:55:52 +0200 Subject: [PATCH] Clean up request host properly We all agree that the IPv6 address format is a big clusterfuck and only an insane person would've come up with it given the double colons interfere with the way one actually appends a port to a normal IPv4 address. To counteract in this issue, the RFC specifies that one should enclose IPv6-addresses in square brackets to make the disctinction possible, i.e. host: ::1 port: 80 --> [::1]:80 The host field can contain both a port suffix and, of course by the RFC, have the address enclosed in square brackets. Given I personally see this as a "transport enclosure" I'd rather like to see it gone as soon as possible and thus implement this cleanup in the http-header-parser so the output is nice and clean and we don't have to deal with this garbage later on. Thanks to Josuah Demangeon for his wonderful input and his dedication to read the RFCs 3986 and 2732 in such great detail. --- http.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/http.c b/http.c index 12ebde8..9296f83 100644 --- a/http.c +++ b/http.c @@ -95,6 +95,7 @@ decode(char src[PATH_MAX], char dest[PATH_MAX]) int http_get_request(int fd, struct request *r) { + struct in6_addr res; size_t hlen, i, mlen; ssize_t off; char h[HEADER_MAX], *p, *q; @@ -232,6 +233,43 @@ http_get_request(int fd, struct request *r) p = q + (sizeof("\r\n") - 1); } + /* + * clean up host + */ + + p = strrchr(r->field[REQ_HOST], ':'); + q = strrchr(r->field[REQ_HOST], ']'); + + /* strip port suffix but don't interfere with IPv6 bracket notation + * as per RFC 2732 */ + if (p && (!q || p > q)) { + /* port suffix must not be empty */ + if (*(p + 1) == '\0') { + return http_send_status(fd, S_BAD_REQUEST); + } + *p = '\0'; + } + + /* strip the brackets from the IPv6 notation and validate the address */ + if (q) { + /* brackets must be on the outside */ + if (r->field[REQ_HOST][0] != '[' || *(q + 1) != '\0') { + return http_send_status(fd, S_BAD_REQUEST); + } + + /* remove the right bracket */ + *q = '\0'; + p = r->field[REQ_HOST] + 1; + + /* validate the contained IPv6 address */ + if (inet_pton(AF_INET6, p, &res) != 1) { + return http_send_status(fd, S_BAD_REQUEST); + } + + /* copy it into the host field */ + memmove(r->field[REQ_HOST], p, q - p + 1); + } + return 0; }