132 lines
2.7 KiB
Go
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 ""
|
|
}
|