Files
IdP/apps/ldap-auth/dns.go
2026-06-24 20:15:19 +03:00

132 lines
2.7 KiB
Go

package main
import (
"context"
"fmt"
"net"
"os"
"strings"
"time"
)
var (
ldapDNSServers []string
ldapStaticHosts map[string]string
ldapNetworkingSet bool
)
func initLDAPNetworking() {
if ldapNetworkingSet {
return
}
ldapDNSServers = parseCSV(os.Getenv("LDAP_DNS_SERVERS"))
ldapStaticHosts = parseStaticHostMap(os.Getenv("LDAP_EXTRA_HOSTS"))
ldapNetworkingSet = true
}
func parseCSV(raw string) []string {
parts := strings.Split(raw, ",")
result := make([]string, 0, len(parts))
for _, part := range parts {
part = strings.TrimSpace(part)
if part != "" {
result = append(result, part)
}
}
return result
}
func parseStaticHostMap(raw string) map[string]string {
result := make(map[string]string)
for _, part := range parseCSV(raw) {
host, ip, ok := strings.Cut(part, ":")
if !ok {
continue
}
host = strings.TrimSpace(host)
ip = strings.TrimSpace(ip)
if host == "" || ip == "" {
continue
}
result[strings.ToLower(host)] = ip
}
return result
}
func resolveHostAddress(host string) (string, error) {
initLDAPNetworking()
host = strings.TrimSpace(host)
if host == "" {
return "", fmt.Errorf("пустой LDAP host")
}
if net.ParseIP(host) != nil {
return host, nil
}
lowerHost := strings.ToLower(host)
if ip, ok := ldapStaticHosts[lowerHost]; ok {
return ip, nil
}
if len(ldapDNSServers) > 0 {
if ip, err := lookupViaCustomDNS(host, ldapDNSServers); err == nil {
return ip, nil
} else if len(ldapStaticHosts) == 0 {
return "", err
}
}
addrs, err := net.LookupHost(host)
if err != nil {
return "", err
}
if ip := firstIPv4(addrs); ip != "" {
return ip, nil
}
if len(addrs) > 0 {
return addrs[0], nil
}
return "", fmt.Errorf("не найден IP-адрес для %s", host)
}
func lookupViaCustomDNS(host string, servers []string) (string, error) {
var lastErr error
for _, server := range servers {
resolver := &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
dialer := net.Dialer{Timeout: 4 * time.Second}
return dialer.DialContext(ctx, "udp", net.JoinHostPort(server, "53"))
},
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
addrs, err := resolver.LookupHost(ctx, host)
cancel()
if err != nil {
lastErr = err
continue
}
if ip := firstIPv4(addrs); ip != "" {
return ip, nil
}
if len(addrs) > 0 {
return addrs[0], nil
}
}
if lastErr != nil {
return "", lastErr
}
return "", fmt.Errorf("DNS-серверы не вернули адрес для %s", host)
}
func firstIPv4(addrs []string) string {
for _, addr := range addrs {
if strings.Contains(addr, ".") {
return addr
}
}
return ""
}