You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
2.9 KiB
96 lines
2.9 KiB
package app |
|
|
|
import ( |
|
"net/http" |
|
"strings" |
|
|
|
"lol.mleku.dev/log" |
|
) |
|
|
|
// GetRemoteFromReq retrieves the originating IP address of the client from |
|
// an HTTP request, considering standard and non-standard proxy headers. |
|
// |
|
// # Parameters |
|
// |
|
// - r: The HTTP request object containing details of the client and |
|
// routing information. |
|
// |
|
// # Return Values |
|
// |
|
// - rr: A string value representing the IP address of the originating |
|
// remote client. |
|
// |
|
// # Expected behaviour |
|
// |
|
// The function first checks for the standardized "Forwarded" header (RFC 7239) |
|
// to identify the original client IP. If that isn't available, it falls back to |
|
// the "X-Forwarded-For" header. If both headers are absent, it defaults to |
|
// using the request's RemoteAddr. |
|
// |
|
// For the "Forwarded" header, it extracts the client IP from the "for" |
|
// parameter. For the "X-Forwarded-For" header, if it contains one IP, it |
|
// returns that. If it contains two IPs, it returns the second. |
|
func GetRemoteFromReq(r *http.Request) (rr string) { |
|
// First check for the standardized Forwarded header (RFC 7239) |
|
forwarded := r.Header.Get("Forwarded") |
|
if forwarded != "" { |
|
// Parse the Forwarded header which can contain multiple parameters |
|
// |
|
// Format: |
|
// |
|
// Forwarded: by=<identifier>;for=<identifier>;host=<host>;proto=<http|https> |
|
parts := strings.Split(forwarded, ";") |
|
for _, part := range parts { |
|
part = strings.TrimSpace(part) |
|
if strings.HasPrefix(part, "for=") { |
|
// Extract the client IP from the "for" parameter |
|
forValue := strings.TrimPrefix(part, "for=") |
|
// Remove quotes if present |
|
forValue = strings.Trim(forValue, "\"") |
|
// Handle IPv6 addresses which are enclosed in square brackets |
|
forValue = strings.Trim(forValue, "[]") |
|
return forValue |
|
} |
|
} |
|
} |
|
// If the Forwarded header is not available or doesn't contain "for" |
|
// parameter, fall back to X-Forwarded-For |
|
rem := r.Header.Get("X-Forwarded-For") |
|
if rem == "" { |
|
rr = r.RemoteAddr |
|
} else { |
|
splitted := strings.Split(rem, " ") |
|
if len(splitted) == 1 { |
|
rr = splitted[0] |
|
} |
|
if len(splitted) == 2 { |
|
rr = splitted[1] |
|
} |
|
} |
|
return |
|
} |
|
|
|
// LogProxyInfo logs comprehensive proxy information for debugging |
|
func LogProxyInfo(r *http.Request, prefix string) { |
|
proxyHeaders := map[string]string{ |
|
"X-Forwarded-For": r.Header.Get("X-Forwarded-For"), |
|
"X-Real-IP": r.Header.Get("X-Real-IP"), |
|
"X-Forwarded-Proto": r.Header.Get("X-Forwarded-Proto"), |
|
"X-Forwarded-Host": r.Header.Get("X-Forwarded-Host"), |
|
"X-Forwarded-Port": r.Header.Get("X-Forwarded-Port"), |
|
"Forwarded": r.Header.Get("Forwarded"), |
|
"Host": r.Header.Get("Host"), |
|
"User-Agent": r.Header.Get("User-Agent"), |
|
} |
|
|
|
var info []string |
|
for header, value := range proxyHeaders { |
|
if value != "" { |
|
info = append(info, header+":"+value) |
|
} |
|
} |
|
|
|
if len(info) > 0 { |
|
log.T.F("%s proxy info: %s", prefix, strings.Join(info, " ")) |
|
} |
|
}
|
|
|