Files
br ca6cdcca63 software steht so weit.
jetzt build + docker build und testen
2026-10-02 13:25:34 +02:00

95 lines
2.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}