ip.go

58 lines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
package router

import (
	"net"
	"net/http"
	"strings"
	"sync"
	"time"
)

// ClientIP extracts the client IP from a request, respecting X-Forwarded-For.
func ClientIP(r *http.Request) string {
	if fwd := r.Header.Get("X-Forwarded-For"); fwd != "" {
		if i := strings.IndexByte(fwd, ','); i > 0 {
			return strings.TrimSpace(fwd[:i])
		}
		return fwd
	}
	return r.RemoteAddr
}

func stripPort(host string) string {
	if h, _, err := net.SplitHostPort(host); err == nil {
		return h
	}
	return host
}

// --- Server IP detection ---

var (
	serverIPOnce sync.Once
	serverIPVal  string
)

// ServerIP returns this server's public IP (cached after first call).
func ServerIP() string {
	serverIPOnce.Do(func() {
		client := &http.Client{Timeout: 3 * time.Second}
		for _, url := range []string{
			"http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address",
			"https://ifconfig.me",
		} {
			resp, err := client.Get(url)
			if err != nil {
				continue
			}
			body := make([]byte, 64)
			n, _ := resp.Body.Read(body)
			resp.Body.Close()
			if ip := strings.TrimSpace(string(body[:n])); ip != "" {
				serverIPVal = ip
				return
			}
		}
	})
	return serverIPVal
}