mirror of
				https://github.com/gravitl/netmaker.git
				synced 2025-10-31 12:16:29 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			150 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package local
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	//"github.com/davecgh/go-spew/spew"
 | |
| 	"log"
 | |
| 	"os/exec"
 | |
| 
 | |
| 	"github.com/gravitl/netmaker/logger"
 | |
| 	"github.com/gravitl/netmaker/models"
 | |
| 	"github.com/gravitl/netmaker/netclient/ncutils"
 | |
| )
 | |
| 
 | |
| const DNS_UNREACHABLE_ERROR = "nameserver unreachable"
 | |
| 
 | |
| // SetDNSWithRetry - Attempt setting dns, if it fails return true (to reset dns)
 | |
| func SetDNSWithRetry(node models.Node, address string) bool {
 | |
| 	var reachable bool
 | |
| 	if !hasPrereqs() {
 | |
| 		return true
 | |
| 	}
 | |
| 	for counter := 0; !reachable && counter < 5; counter++ {
 | |
| 		reachable = IsDNSReachable(address)
 | |
| 		time.Sleep(time.Second << 1)
 | |
| 	}
 | |
| 	if !reachable {
 | |
| 		logger.Log(0, "not setting dns (server unreachable), will try again later: "+address)
 | |
| 		return true
 | |
| 	} else if err := UpdateDNS(node.Interface, node.Network, address); err != nil {
 | |
| 		logger.Log(0, "error applying dns"+err.Error())
 | |
| 	} else if IsDNSWorking(node.Network, address) {
 | |
| 		return true
 | |
| 	}
 | |
| 	resetDNS()
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func resetDNS() {
 | |
| 	ncutils.RunCmd("systemctl restart systemd-resolved", true)
 | |
| }
 | |
| 
 | |
| // SetDNS - sets the DNS of a local machine
 | |
| func SetDNS(nameserver string) error {
 | |
| 	bytes, err := os.ReadFile("/etc/resolv.conf")
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	resolvstring := string(bytes)
 | |
| 	// //check whether s contains substring text
 | |
| 	hasdns := strings.Contains(resolvstring, nameserver)
 | |
| 	if hasdns {
 | |
| 		return nil
 | |
| 	}
 | |
| 	resolv, err := os.OpenFile("/etc/resolv.conf", os.O_APPEND|os.O_WRONLY, 0644)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	defer resolv.Close()
 | |
| 	_, err = resolv.WriteString("nameserver " + nameserver + "\n")
 | |
| 
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func hasPrereqs() bool {
 | |
| 	if !ncutils.IsLinux() {
 | |
| 		return false
 | |
| 	}
 | |
| 	_, err := exec.LookPath("resolvectl")
 | |
| 	return err == nil
 | |
| }
 | |
| 
 | |
| // UpdateDNS - updates local DNS of client
 | |
| func UpdateDNS(ifacename string, network string, nameserver string) error {
 | |
| 	if !ncutils.IsLinux() {
 | |
| 		return nil
 | |
| 	}
 | |
| 	if ifacename == "" {
 | |
| 		return fmt.Errorf("cannot set dns: interface name is blank")
 | |
| 	}
 | |
| 	if network == "" {
 | |
| 		return fmt.Errorf("cannot set dns: network name is blank")
 | |
| 	}
 | |
| 	if nameserver == "" {
 | |
| 		return fmt.Errorf("cannot set dns: nameserver is blank")
 | |
| 	}
 | |
| 	if !IsDNSReachable(nameserver) {
 | |
| 		return fmt.Errorf(DNS_UNREACHABLE_ERROR + " : " + nameserver + ":53")
 | |
| 	}
 | |
| 	_, err := exec.LookPath("resolvectl")
 | |
| 	if err != nil {
 | |
| 		log.Println(err)
 | |
| 		log.Println("WARNING: resolvectl not present. Unable to set dns. Install resolvectl or run manually.")
 | |
| 	} else {
 | |
| 		_, err = ncutils.RunCmd("resolvectl domain "+ifacename+" ~"+network, true)
 | |
| 		if err != nil {
 | |
| 			log.Println("WARNING: Error encountered setting domain on dns. Aborted setting dns.")
 | |
| 		} else {
 | |
| 			_, err = ncutils.RunCmd("resolvectl default-route "+ifacename+" false", true)
 | |
| 			if err != nil {
 | |
| 				log.Println("WARNING: Error encountered setting default-route on dns. Aborted setting dns.")
 | |
| 			} else {
 | |
| 				_, err = ncutils.RunCmd("resolvectl dns "+ifacename+" "+nameserver, true)
 | |
| 				if err != nil {
 | |
| 					log.Println("WARNING: Error encountered running resolvectl dns " + ifacename + " " + nameserver)
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // IsDNSReachable - checks if nameserver is reachable
 | |
| func IsDNSReachable(nameserver string) bool {
 | |
| 	port := "53"
 | |
| 	protocols := [2]string{"tcp", "udp"}
 | |
| 	for _, proto := range protocols {
 | |
| 		timeout := time.Second
 | |
| 		conn, err := net.DialTimeout(proto, net.JoinHostPort(nameserver, port), timeout)
 | |
| 		if err != nil {
 | |
| 			return false
 | |
| 		}
 | |
| 		if conn != nil {
 | |
| 			defer conn.Close()
 | |
| 		} else {
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // IsDNSWorking - checks if record is returned by correct nameserver
 | |
| func IsDNSWorking(network string, nameserver string) bool {
 | |
| 	var isworking bool
 | |
| 	servers, err := net.LookupNS("netmaker" + "." + network)
 | |
| 	if err != nil {
 | |
| 		return isworking
 | |
| 	}
 | |
| 	for _, ns := range servers {
 | |
| 		if strings.Contains(ns.Host, nameserver) {
 | |
| 			isworking = true
 | |
| 		}
 | |
| 	}
 | |
| 	return isworking
 | |
| }
 | 
