strictUntrustedClientIp iterates through the list of client IP headers, parses them from right-to-left, and returns the first valid IP address that is untrusted. If no valid IP address is found, then the direct remote address is returned.
(r *http.Request, headers []string, trusted []netip.Prefix, clientIP string)
| 1133 | // that is untrusted. If no valid IP address is found, then the direct |
| 1134 | // remote address is returned. |
| 1135 | func strictUntrustedClientIp(r *http.Request, headers []string, trusted []netip.Prefix, clientIP string) string { |
| 1136 | for _, headerName := range headers { |
| 1137 | parts := strings.Split(strings.Join(r.Header.Values(headerName), ","), ",") |
| 1138 | |
| 1139 | for _, part := range slices.Backward(parts) { |
| 1140 | // Some proxies may retain the port number, so split if possible |
| 1141 | host, _, err := net.SplitHostPort(part) |
| 1142 | if err != nil { |
| 1143 | host = part |
| 1144 | } |
| 1145 | |
| 1146 | // Remove any zone identifier from the IP address |
| 1147 | host, _, _ = strings.Cut(strings.TrimSpace(host), "%") |
| 1148 | |
| 1149 | // Parse the IP address |
| 1150 | ipAddr, err := netip.ParseAddr(host) |
| 1151 | if err != nil { |
| 1152 | continue |
| 1153 | } |
| 1154 | if !isTrustedClientIP(ipAddr, trusted) { |
| 1155 | return ipAddr.String() |
| 1156 | } |
| 1157 | } |
| 1158 | } |
| 1159 | |
| 1160 | return clientIP |
| 1161 | } |
| 1162 | |
| 1163 | // cloneURL makes a copy of r.URL and returns a |
| 1164 | // new value that doesn't reference the original. |
no test coverage detected