mirror of
https://github.com/Gouryella/drip.git
synced 2026-02-24 05:10:43 +00:00
- Add Bearer Token authentication, supporting tunnel access control via the --auth-bearer parameter - Refactor large modules into smaller, more focused components to improve code maintainability - Update dependency versions, including golang.org/x/crypto, golang.org/x/net, etc. - Add SilenceUsage and SilenceErrors configuration for all CLI commands - Modify connector configuration structure to support the new authentication method - Update recent change log in README with new feature descriptions BREAKING CHANGE: Authentication via Bearer Token is now supported, requiring the new --auth-bearer parameter
79 lines
1.8 KiB
Go
79 lines
1.8 KiB
Go
package netutil
|
|
|
|
import (
|
|
"net"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
var privateNetworks []*net.IPNet
|
|
|
|
func init() {
|
|
privateCIDRs := []string{
|
|
"127.0.0.0/8",
|
|
"10.0.0.0/8",
|
|
"172.16.0.0/12",
|
|
"192.168.0.0/16",
|
|
"::1/128",
|
|
"fc00::/7",
|
|
"fe80::/10",
|
|
}
|
|
for _, cidr := range privateCIDRs {
|
|
_, ipNet, _ := net.ParseCIDR(cidr)
|
|
privateNetworks = append(privateNetworks, ipNet)
|
|
}
|
|
}
|
|
|
|
// ExtractRemoteIP extracts the IP address from a remote address string (host:port format).
|
|
func ExtractRemoteIP(remoteAddr string) string {
|
|
host, _, err := net.SplitHostPort(remoteAddr)
|
|
if err != nil {
|
|
return remoteAddr
|
|
}
|
|
return host
|
|
}
|
|
|
|
// IsPrivateIP checks if the given IP is a private/loopback address.
|
|
func IsPrivateIP(ip string) bool {
|
|
parsedIP := net.ParseIP(ip)
|
|
if parsedIP == nil {
|
|
return false
|
|
}
|
|
|
|
for _, network := range privateNetworks {
|
|
if network.Contains(parsedIP) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// ExtractClientIP extracts the client IP from the request.
|
|
// It only trusts X-Forwarded-For and X-Real-IP headers when the request
|
|
// comes from a private/loopback network (typical reverse proxy setup).
|
|
func ExtractClientIP(r *http.Request) string {
|
|
// First, get the direct remote address
|
|
remoteIP := ExtractRemoteIP(r.RemoteAddr)
|
|
|
|
// Only trust proxy headers if the request comes from a private network
|
|
if IsPrivateIP(remoteIP) {
|
|
// Check X-Forwarded-For header (may contain multiple IPs)
|
|
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
|
// Take the first IP (original client)
|
|
if idx := strings.Index(xff, ","); idx != -1 {
|
|
return strings.TrimSpace(xff[:idx])
|
|
}
|
|
return strings.TrimSpace(xff)
|
|
}
|
|
|
|
// Check X-Real-IP header
|
|
if xri := r.Header.Get("X-Real-IP"); xri != "" {
|
|
return strings.TrimSpace(xri)
|
|
}
|
|
}
|
|
|
|
// Fall back to remote address
|
|
return remoteIP
|
|
}
|