diff --git a/doc/configuration.txt b/doc/configuration.txt index b2a3df97a..aef9b4522 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -18757,7 +18757,11 @@ hdr_ip([[,]]) : ip (deprecated) This extracts the last occurrence of header in an HTTP request, converts it to an IPv4 or IPv6 address and returns this address. When used with ACLs, all occurrences are checked, and if is omitted, every value - of every header is checked. + of every header is checked. The parser strictly adheres to the format + described in RFC7239, with the extension that IPv4 addresses may optionally + be followed by a colon (':') and a valid decimal port number (0 to 65535), + which will be silently dropped. All other forms will not match and will + cause the address to be ignored. The parameter is processed as with req.hdr(). diff --git a/src/http_fetch.c b/src/http_fetch.c index 3d627a926..a4169452f 100644 --- a/src/http_fetch.c +++ b/src/http_fetch.c @@ -988,19 +988,30 @@ static int smp_fetch_hdr_val(const struct arg *args, struct sample *smp, const c /* Fetch an HTTP header's IP value. takes a mandatory argument of type string * and an optional one of type int to designate a specific occurrence. - * It returns an IPv4 or IPv6 address. + * It returns an IPv4 or IPv6 address. Addresses surrounded by invalid chars + * are rejected. However IPv4 addresses may be followed with a colon and a + * valid port number. */ static int smp_fetch_hdr_ip(const struct arg *args, struct sample *smp, const char *kw, void *private) { - int ret; struct buffer *temp = get_trash_chunk(); + int ret, len; + int port; while ((ret = smp_fetch_hdr(args, smp, kw, private)) > 0) { if (smp->data.u.str.data < temp->size - 1) { memcpy(temp->area, smp->data.u.str.area, smp->data.u.str.data); temp->area[smp->data.u.str.data] = '\0'; - if (url2ipv4((char *) temp->area, &smp->data.u.ipv4)) { + len = url2ipv4((char *) temp->area, &smp->data.u.ipv4); + if (len == smp->data.u.str.data) { + /* plain IPv4 address */ + smp->data.type = SMP_T_IPV4; + break; + } else if (len > 0 && temp->area[len] == ':' && + strl2irc(temp->area + len + 1, smp->data.u.str.data - len - 1, &port) == 0 && + port >= 0 && port <= 65535) { + /* IPv4 address suffixed with ':' followed by a valid port number */ smp->data.type = SMP_T_IPV4; break; } else if (inet_pton(AF_INET6, temp->area, &smp->data.u.ipv6)) {