github.com/telepresenceio/telepresence/v2@v2.20.0-pro.6.0.20240517030216-236ea954e789/pkg/client/rootd/dbus/resolved.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package dbus
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"net"
    11  	"strings"
    12  
    13  	"github.com/godbus/dbus/v5"
    14  	"golang.org/x/sys/unix"
    15  
    16  	"github.com/datawire/dlib/dlog"
    17  )
    18  
    19  type (
    20  	// A resolvedLinkAddress is the type of the array members of the argument to the SetLinkDNS DBus call. It consists
    21  	// of an address family (either AF_INET or AF_INET6), followed by a 4-byte or 16-byte array with the raw address data.
    22  	resolvedLinkAddress struct {
    23  		Dialect int32
    24  		IP      net.IP
    25  	}
    26  
    27  	// A resolvedDomain is the type of the array members of the argument to the SetLinkDomains DBus call. It is a domain
    28  	// name string and a parameter identifying whether to include that domain in the search path, or only to be used for
    29  	// deciding which DNS server to route a given request to.
    30  	resolvedDomain struct {
    31  		Name        string
    32  		RoutingOnly bool
    33  	}
    34  )
    35  
    36  func withDBus(c context.Context, f func(*dbus.Conn) error) error {
    37  	conn, err := dbus.ConnectSystemBus()
    38  	if err != nil {
    39  		err = fmt.Errorf("failed to connect to system bus: %w", err)
    40  		dlog.Error(c, err)
    41  		return err
    42  	}
    43  	defer conn.Close()
    44  	return f(conn)
    45  }
    46  
    47  func IsResolveDRunning(c context.Context) bool {
    48  	err := withDBus(c, func(conn *dbus.Conn) error {
    49  		var names []string
    50  		if err := conn.BusObject().CallWithContext(c, "org.freedesktop.DBus.ListNames", 0).Store(&names); err != nil {
    51  			return err
    52  		}
    53  		for _, name := range names {
    54  			if name == "org.freedesktop.resolve1" {
    55  				return nil
    56  			}
    57  		}
    58  		return errors.New("not found")
    59  	})
    60  	return err == nil
    61  }
    62  
    63  func SetLinkDNS(c context.Context, networkIndex int, ips ...net.IP) error {
    64  	return withDBus(c, func(conn *dbus.Conn) error {
    65  		addrs := make([]resolvedLinkAddress, len(ips))
    66  		for i, ip := range ips {
    67  			addr := &addrs[i]
    68  			switch len(ip) {
    69  			case 4:
    70  				addr.Dialect = unix.AF_INET
    71  			case 16:
    72  				addr.Dialect = unix.AF_INET6
    73  			default:
    74  				return errors.New("illegal IP (not AF_INET or AF_INET6")
    75  			}
    76  			addr.IP = ip
    77  		}
    78  		return conn.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1").CallWithContext(
    79  			c, "org.freedesktop.resolve1.Manager.SetLinkDNS", 0, int32(networkIndex), addrs).Err
    80  	})
    81  }
    82  
    83  func SetLinkDomains(c context.Context, networkIndex int, domains ...string) error {
    84  	return withDBus(c, func(conn *dbus.Conn) error {
    85  		dds := make([]resolvedDomain, 0, len(domains))
    86  		for _, domain := range domains {
    87  			if domain == "" {
    88  				continue
    89  			}
    90  			routing := false
    91  			if strings.HasPrefix(domain, "~") {
    92  				domain = domain[1:]
    93  				routing = true
    94  			}
    95  			dds = append(dds, resolvedDomain{Name: domain, RoutingOnly: routing})
    96  		}
    97  		return conn.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1").CallWithContext(
    98  			c, "org.freedesktop.resolve1.Manager.SetLinkDomains", 0, int32(networkIndex), dds).Err
    99  	})
   100  }
   101  
   102  func RevertLink(c context.Context, networkIndex int) error {
   103  	return withDBus(c, func(conn *dbus.Conn) error {
   104  		return conn.Object("org.freedesktop.resolve1", "/org/freedesktop/resolve1").CallWithContext(
   105  			c, "org.freedesktop.resolve1.Manager.RevertLink", 0, int32(networkIndex)).Err
   106  	})
   107  }