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 "" }