diff --git a/net/http/parseforwarded.c b/net/http/parseforwarded.c index 90759ca90..d5aa2b052 100644 --- a/net/http/parseforwarded.c +++ b/net/http/parseforwarded.c @@ -38,17 +38,14 @@ int ParseForwarded(const char *s, size_t n, uint32_t *ip, uint16_t *port) { int c, t; size_t i; + char *r; uint32_t x; if (n == -1) n = s ? strlen(s) : 0; if (n) { - t = x = 0; - i = n; - while (i > 0) { - if (s[--i] & 255 == ',') { - // skip optional space - if (s[++i] & 255 == ' ') ++i; - break; // i points to the start of the address - } + t = x = i = 0; + if ((r = strrchr(s, ','))) { + i = r - s; + if ((s[++i] & 255) == ' ') ++i; // skip optional space } do { c = s[i++] & 255; diff --git a/tool/net/help.txt b/tool/net/help.txt index f5b21d872..123f321dd 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -574,7 +574,8 @@ FUNCTIONS Returns client ip4 address and port, e.g. 0x01020304,31337 would represent 1.2.3.4:31337. This is the same as GetClientAddr except it will use the ip:port from the X-Forwarded-For header, only if - IsPrivateIp or IsLoopbackIp return true. + IsPrivateIp or IsLoopbackIp return true. When multiple addresses + are present in the header, the last/right-most address is used. GetClientAddr() → ip:uint32,port:uint16 Returns client socket ip4 address and port, e.g. 0x01020304,31337 diff --git a/tool/net/redbean.c b/tool/net/redbean.c index a929286f9..45c98eb09 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -818,8 +818,12 @@ static inline void GetRemoteAddr(uint32_t *ip, uint16_t *port) { GetClientAddr(ip, port); if (HasHeader(kHttpXForwardedFor) && (IsPrivateIp(*ip) || IsLoopbackIp(*ip))) { - ParseForwarded(HeaderData(kHttpXForwardedFor), - HeaderLength(kHttpXForwardedFor), ip, port); + if (ParseForwarded(HeaderData(kHttpXForwardedFor), + HeaderLength(kHttpXForwardedFor), + ip, port) == -1) + WARNF("invalid X-Forwarded-For value: %`'.*s", + HeaderLength(kHttpXForwardedFor), + HeaderData(kHttpXForwardedFor)); } }