github.com/tommi2day/gomodules@v1.13.2-0.20240423190010-b7d55d252a27/netlib/net.go (about) 1 // Package netlib provides a simple IP and DNS functions 2 package netlib 3 4 import ( 5 "net" 6 "time" 7 8 "github.com/tommi2day/gomodules/common" 9 10 log "github.com/sirupsen/logrus" 11 "golang.org/x/net/context" 12 ) 13 14 type DNSconfig struct { 15 Nameserver string 16 Port int 17 TCP bool 18 Resolver *net.Resolver 19 Timeout time.Duration 20 IPv4Only bool 21 IPv6Only bool 22 } 23 24 const defaultDNSTimeout = 5 * time.Second 25 26 // NewResolver returns a DNSconfig object 27 func NewResolver(nameserver string, port int, tcp bool) (dns *DNSconfig) { 28 dns = new(DNSconfig) 29 var resolver *net.Resolver 30 if nameserver != "" { 31 if port == 0 { 32 port = 53 33 } 34 // network type 35 n := "udp" 36 if tcp { 37 n = "tcp" 38 } 39 a := common.SetHostPort(nameserver, port) 40 log.Debugf("Configured custom DNS resolver: %s", a) 41 resolver = &net.Resolver{ 42 PreferGo: true, 43 Dial: func(ctx context.Context, _, _ string) (net.Conn, error) { 44 d := net.Dialer{} 45 return d.DialContext(ctx, n, a) 46 }, 47 } 48 } else { 49 resolver = net.DefaultResolver 50 log.Debug("use default DNS resolver") 51 } 52 dns.TCP = tcp 53 dns.Port = port 54 dns.Nameserver = nameserver 55 dns.Resolver = resolver 56 dns.Timeout = defaultDNSTimeout 57 dns.IPv4Only = false 58 dns.IPv6Only = false 59 return 60 } 61 62 // LookupSrv looks up the SRV record of a service 63 func (dns *DNSconfig) LookupSrv(srv string, domain string) (srvEntries []*net.SRV, err error) { 64 if dns.Resolver == nil { 65 dns.Resolver = &net.Resolver{} 66 dns.Timeout = defaultDNSTimeout 67 } 68 // add timeout 69 ctx, cancel := context.WithTimeout(context.Background(), dns.Timeout) 70 defer cancel() 71 72 // create SRV record query 73 _, srvEntries, err = dns.Resolver.LookupSRV(ctx, srv, "tcp", domain) 74 if err != nil { 75 log.Warnf("DNS: cannot resolve SRV with %s:%s", srv, err) 76 } 77 return 78 } 79 80 // LookupIP looks up the IP address of a hostname 81 func (dns *DNSconfig) LookupIP(hostname string) (ipEntires []net.IP, err error) { 82 // is ip 83 if IsValidIP(hostname) { 84 ipEntires = append(ipEntires, net.ParseIP(hostname)) 85 return 86 } 87 if dns.Resolver == nil { 88 dns.Resolver = &net.Resolver{} 89 dns.Timeout = defaultDNSTimeout 90 } 91 92 ctx, cancel := context.WithTimeout(context.Background(), dns.Timeout) 93 defer cancel() 94 95 // lookup type network 96 n := "ip" // default ipv4+ipv6 97 if dns.IPv4Only { 98 n = "ip4" 99 dns.IPv6Only = false 100 } 101 if dns.IPv6Only { 102 n = "ip6" 103 } 104 105 ipEntires, err = dns.Resolver.LookupIP(ctx, n, hostname) 106 if err != nil { 107 log.Warnf("DNS: cannot resolve Host %s:%s", hostname, err) 108 } 109 return 110 } 111 112 // LookupTXT looks up the TXT record of a hostname 113 func (dns *DNSconfig) LookupTXT(hostname string) (txt []string, err error) { 114 if dns.Resolver == nil { 115 dns.Resolver = &net.Resolver{} 116 dns.Timeout = defaultDNSTimeout 117 } 118 ctx, cancel := context.WithTimeout(context.Background(), dns.Timeout) 119 defer cancel() 120 txt, err = dns.Resolver.LookupTXT(ctx, hostname) 121 if err != nil { 122 log.Warnf("DNS: cannot resolve TXT for %s:%s", hostname, err) 123 return 124 } 125 return 126 } 127 128 // IsValidIP checks if the input string is a valid IP address 129 func IsValidIP(ip string) bool { 130 i := net.ParseIP(ip) 131 return i != nil 132 } 133 134 // IsPrivateIP checks if the input string is a private IP address 135 func IsPrivateIP(ip string) bool { 136 i := net.ParseIP(ip) 137 if i == nil { 138 return false 139 } 140 return i.IsPrivate() 141 } 142 143 // IsIPv4 checks if the input string is a validIPv4 address 144 func IsIPv4(ip string) bool { 145 i := net.ParseIP(ip) 146 if i == nil { 147 return false 148 } 149 ip4 := i.To4() 150 return ip4 != nil 151 } 152 153 // IsIPv6 checks if the input string is a valid IPv6 address 154 func IsIPv6(ip string) bool { 155 return IsValidIP(ip) && !IsIPv4(ip) 156 }