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  }