package agent import ( "fmt" "net" "net/url" "regexp" "strings" "sultan/pkg/policy" ) // backendHost bestimmt die Adresse, unter der der Ingress die Dienste // dieses Hosts erreicht: explizit gesetzt, sonst die IP des angegebenen // Interfaces (z. B. wt0 für NetBird), sonst die lokale IP, über die der // Server erreicht wird. func backendHost(explicit, iface, serverURL string) (string, error) { if explicit != "" { return explicit, nil } if iface != "" { return interfaceIP(iface) } addr, err := hostPort(serverURL) if err != nil { return "", err } // UDP-"Verbindung" sendet nichts, ermittelt aber die ausgehende Adresse. conn, err := net.Dial("udp", addr) if err != nil { return "", fmt.Errorf("agent: Backend-Adresse ermitteln: %w", err) } defer conn.Close() return conn.LocalAddr().(*net.UDPAddr).IP.String(), nil } func interfaceIP(name string) (string, error) { ifc, err := net.InterfaceByName(name) if err != nil { return "", fmt.Errorf("agent: Interface %s: %w", name, err) } addrs, err := ifc.Addrs() if err != nil { return "", err } var v6 string for _, a := range addrs { ipnet, ok := a.(*net.IPNet) if !ok { continue } if ip4 := ipnet.IP.To4(); ip4 != nil { return ip4.String(), nil } if v6 == "" && !ipnet.IP.IsLinkLocalUnicast() { v6 = ipnet.IP.String() } } if v6 != "" { return v6, nil } return "", fmt.Errorf("agent: Interface %s hat keine nutzbare IP", name) } // hostPort liefert host:port der Server-URL (Default-Port 443). func hostPort(serverURL string) (string, error) { u, err := url.Parse(serverURL) if err != nil || u.Hostname() == "" { return "", fmt.Errorf("agent: Server-URL %q ungültig", serverURL) } if u.Port() == "" { return net.JoinHostPort(u.Hostname(), "443"), nil } return u.Host, nil } var ( nodeIDUnsafe = regexp.MustCompile(`[^a-z0-9_-]+`) nodeIDDashes = regexp.MustCompile(`-{2,}`) nodeIDUnders = regexp.MustCompile(`_{2,}`) ) // DefaultNodeID leitet aus dem Hostnamen eine gültige Knoten-ID ab // (klein, a–z/0–9/-/_, kein "__"). func DefaultNodeID(hostname string) (string, error) { id := nodeIDUnsafe.ReplaceAllString(strings.ToLower(strings.TrimSpace(hostname)), "-") id = nodeIDDashes.ReplaceAllString(id, "-") id = nodeIDUnders.ReplaceAllString(id, "_") id = strings.Trim(id, "-_") if !policy.ValidID(id) { return "", fmt.Errorf("agent: aus Hostname %q lässt sich keine Knoten-ID ableiten – --node-id angeben", hostname) } return id, nil }