Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d7a489f58 |
@@ -215,11 +215,12 @@ has its forwarded headers ignored, and the direct peer is logged and
|
||||
rate-limited instead. From a direct peer inside the set, the client address is
|
||||
the right-most `X-Forwarded-For` entry that is not in the set: each proxy
|
||||
appends the address it took the request from, so the entries further left were
|
||||
written by the client and are not used. If the search from the right finds only
|
||||
addresses in the set, or meets an entry that is not an IP address, the direct
|
||||
peer is used. `X-Real-IP` is read only when `X-Forwarded-For` is missing or
|
||||
empty. The container image does not use this default; see
|
||||
[Deployment](#deployment).
|
||||
written by the client and are not used. An entry written as an address with a
|
||||
port, such as `198.51.100.7:5000` or `[2001:db8::1]:443`, is read as that
|
||||
address. If the search from the right finds only addresses in the set, or meets
|
||||
an entry that is not an address at all, such as `unknown`, the direct peer is
|
||||
used. `X-Real-IP` is read only when `X-Forwarded-For` is missing or empty. The
|
||||
container image does not use this default; see [Deployment](#deployment).
|
||||
|
||||
A variable set to a value the server cannot use, such as `PORT=abc`,
|
||||
`DEBUG=maybe` or a `BIND_ADDRESS` that is not an IP address, stops it from
|
||||
|
||||
@@ -26,13 +26,15 @@ Run `make frontend-viewport-test` in CI as its own step; it is not part of
|
||||
([#144](https://git.eeqj.de/sneak/netwatch/issues/144)). It took the left-most
|
||||
entry, which the client writes itself behind a proxy that appends to the
|
||||
header, so a client could choose the address the rate limit counts and the
|
||||
request log records. With only trusted addresses in the header, or an entry
|
||||
that is not an IP address met on the way, the direct peer is used. `X-Real-IP`
|
||||
is read only without `X-Forwarded-For`, and every `X-Forwarded-For` header
|
||||
line is read, not only the first. The image's nginx, and the
|
||||
`TRUSTED_PROXIES=127.0.0.1/32` it starts the backend with, are unchanged. Unit
|
||||
tests resolve the address from chains ending in an untrusted address, in
|
||||
trusted ones, of only trusted ones, and split over two header lines
|
||||
request log records. An entry written as an address with a port is read as
|
||||
that address. With only trusted addresses in the header, or an entry that is
|
||||
not an address at all (such as `unknown`) met on the way, the direct peer is
|
||||
used. `X-Real-IP` is read only without `X-Forwarded-For`, and every
|
||||
`X-Forwarded-For` header line is read, not only the first. The image's nginx,
|
||||
and the `TRUSTED_PROXIES=127.0.0.1/32` it starts the backend with, are
|
||||
unchanged. Unit tests resolve the address from chains ending in an untrusted
|
||||
address, in trusted ones, of only trusted ones, with ports, with an entry that
|
||||
is not an address, and split over two header lines
|
||||
- 2026-10-18: after an interval change, the summary's Reachable slot reads
|
||||
`--/--` in white, as at page load, until the second round since the change
|
||||
ends ([#140](https://git.eeqj.de/sneak/netwatch/issues/140)). It used to read
|
||||
|
||||
@@ -139,10 +139,12 @@ func ipFromHostPort(hostPort string) string {
|
||||
// request from, so the entries on the right are written by the
|
||||
// trusted proxies and those further left by the client. The
|
||||
// client's address is therefore the right-most entry that is not
|
||||
// a trusted proxy. When every entry is a trusted proxy, or the
|
||||
// walk from the right meets an entry that is not an address, the
|
||||
// peer is used. X-Real-IP is read only when there is no
|
||||
// X-Forwarded-For entry at all.
|
||||
// a trusted proxy. An entry written as an address with a port is
|
||||
// read as that address, both for the trust check and as the
|
||||
// result. When every entry is a trusted proxy, or the walk from
|
||||
// the right meets an entry that is not an address at all (such as
|
||||
// "unknown"), the peer is used. X-Real-IP is read only when there
|
||||
// is no X-Forwarded-For entry at all.
|
||||
func clientIP(
|
||||
remoteAddr string,
|
||||
header http.Header,
|
||||
@@ -180,7 +182,10 @@ func clientIP(
|
||||
// forwardedFor returns the entries of X-Forwarded-For in order,
|
||||
// leaving out blank ones. A proxy may add its entry as a header
|
||||
// line of its own rather than append it to the line the client
|
||||
// sent, so every line is read, not only the first.
|
||||
// sent, so every line is read, not only the first. Some proxies
|
||||
// write an entry as an address with a port, such as
|
||||
// 198.51.100.7:5000 or [2001:db8::1]:443; the port is removed so
|
||||
// that the entry is read as its address.
|
||||
func forwardedFor(header http.Header) []string {
|
||||
value := strings.Join(header.Values("X-Forwarded-For"), ",")
|
||||
|
||||
@@ -189,7 +194,7 @@ func forwardedFor(header http.Header) []string {
|
||||
for part := range strings.SplitSeq(value, ",") {
|
||||
entry := strings.TrimSpace(part)
|
||||
if entry != "" {
|
||||
entries = append(entries, entry)
|
||||
entries = append(entries, ipFromHostPort(entry))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,9 +106,27 @@ func clientIPCases() []clientIPCase {
|
||||
want: loopbackIP,
|
||||
},
|
||||
{
|
||||
name: "entry that is not an address uses peer",
|
||||
name: "entry with a port is read as its address",
|
||||
remoteAddr: loopbackPeer,
|
||||
xff: "203.0.113.9, 198.51.100.7:5000",
|
||||
want: "198.51.100.7",
|
||||
},
|
||||
{
|
||||
name: "ipv6 entry with a port is read as its address",
|
||||
remoteAddr: loopbackPeer,
|
||||
xff: "203.0.113.9, [2001:db8::1]:443",
|
||||
want: "2001:db8::1",
|
||||
},
|
||||
{
|
||||
name: "trusted proxy entry with a port is skipped",
|
||||
remoteAddr: loopbackPeer,
|
||||
xff: "203.0.113.9, 10.0.0.5:5000",
|
||||
want: "203.0.113.9",
|
||||
},
|
||||
{
|
||||
name: "entry that is not an address uses peer",
|
||||
remoteAddr: loopbackPeer,
|
||||
xff: "203.0.113.9, unknown",
|
||||
want: loopbackIP,
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user