forked from hswaw/hscloud
66 lines
2.2 KiB
Go
66 lines
2.2 KiB
Go
package mirko
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// parsePort parses a string as a port number from 1 to 65535.
|
|
func parsePort(s string) (uint16, error) {
|
|
port, err := strconv.ParseUint(s, 10, 16)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("could not parse port %q: %v", s, err)
|
|
}
|
|
if port < 1 || port > 65535 {
|
|
return 0, fmt.Errorf("port %d out of range", port)
|
|
}
|
|
return uint16(port), nil
|
|
}
|
|
|
|
// GetHTTPRemoteClient returns the IP address and source port of the client
|
|
// initiating the given HTTP request. This will either interpret the remote
|
|
// side of the HTTP connection if not running within a cluster, or the source
|
|
// IP/port as reported by the cluster reverse proxy (nginx-ingress-controller).
|
|
// An error will be returned if the request is unparseable for this data. In
|
|
// this case, the caller should assume that the environment is misconfigured,
|
|
// and that the client source cannot be deduced.
|
|
func GetHTTPRemoteClient(r *http.Request) (net.IP, uint16, error) {
|
|
if KubernetesClient() == nil {
|
|
// We're not running inside a cluster (we're probably running on a dev
|
|
// machine), so just return whatever net/http says.
|
|
|
|
host, portStr, err := net.SplitHostPort(r.RemoteAddr)
|
|
if err != nil {
|
|
return nil, 0, fmt.Errorf("could not split hostport: %v", err)
|
|
}
|
|
ip := net.ParseIP(host)
|
|
if ip == nil {
|
|
return nil, 0, fmt.Errorf("could not parse host %q to IP address", host)
|
|
}
|
|
port, err := parsePort(portStr)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
return ip, uint16(port), nil
|
|
}
|
|
|
|
// We are running in a cluster, so we can expect Hscloud-* headers.
|
|
// These are configured in the nginx-ingress-controller, //cluster/kube/lib/nginx.libsonnet.
|
|
nsip := strings.TrimSpace(r.Header.Get("Hscloud-Nic-Source-IP"))
|
|
nsport := strings.TrimSpace(r.Header.Get("Hscloud-Nic-Source-Port"))
|
|
if nsip == "" || nsport == "" {
|
|
return nil, 0, fmt.Errorf("Hscloud-Nic-* headers not set")
|
|
}
|
|
ip := net.ParseIP(nsip)
|
|
if ip == nil {
|
|
return nil, 0, fmt.Errorf("Invalid Hscloud-Nix-Source-IP %q", nsip)
|
|
}
|
|
port, err := parsePort(nsport)
|
|
if err != nil {
|
|
return nil, 0, fmt.Errorf("Invalid Hscloud-Nix-Source-Port: %v", err)
|
|
}
|
|
return ip, port, nil
|
|
}
|