/ pkg / system / network / linux.go
linux.go
  1  package network
  2  
  3  import (
  4  	"errors"
  5  	"fmt"
  6  	"log"
  7  	"net"
  8  	"strings"
  9  
 10  	dogeboxd "github.com/dogeorg/dogeboxd/pkg"
 11  	network_connector "github.com/dogeorg/dogeboxd/pkg/system/network/connector"
 12  	network_persistor "github.com/dogeorg/dogeboxd/pkg/system/network/persistor"
 13  	network_wifi "github.com/dogeorg/dogeboxd/pkg/system/network/wifi"
 14  	"github.com/mdlayher/wifi"
 15  )
 16  
 17  var _ dogeboxd.NetworkManager = &NetworkManagerLinux{}
 18  
 19  type NetworkManagerLinux struct {
 20  	dogeboxd.NetworkManager
 21  
 22  	sm      dogeboxd.StateManager
 23  	scanner network_wifi.WifiScanner
 24  	nix     dogeboxd.NixManager
 25  }
 26  
 27  type WiFiNetwork struct {
 28  	SSID      string
 29  	Address   string
 30  	Signal    string
 31  	Channel   string
 32  	Frequency string
 33  }
 34  
 35  func (t NetworkManagerLinux) GetAvailableNetworks() []dogeboxd.NetworkConnection {
 36  	availableNetworkConnections := []dogeboxd.NetworkConnection{}
 37  	wifiInterfaceNames := []string{}
 38  
 39  	wifiClient, err := wifi.New()
 40  	if err != nil {
 41  		log.Println("Could not init a wifi interface client, skipping:", err)
 42  	} else {
 43  		defer wifiClient.Close()
 44  
 45  		wifiInterfaces, err := wifiClient.Interfaces()
 46  		if err != nil {
 47  			log.Println("Could not list wifi interfaces:", err)
 48  		}
 49  
 50  		for _, wifiInterface := range wifiInterfaces {
 51  			ssids, err := t.scanner.Scan(wifiInterface.Name)
 52  			if err != nil {
 53  				log.Printf("Failed to scan for Wifi networks on %s: %s", wifiInterface.Name, err)
 54  				continue
 55  			}
 56  
 57  			foundNetworks := []dogeboxd.NetworkWifiSSID{}
 58  
 59  			for _, n := range ssids {
 60  				// Ignore anything without an SSID
 61  				if n.SSID == "" {
 62  					continue
 63  				}
 64  
 65  				foundNetworks = append(foundNetworks, dogeboxd.NetworkWifiSSID{
 66  					Ssid:       n.SSID,
 67  					Bssid:      n.BSSID,
 68  					Encryption: n.Encryption,
 69  				})
 70  			}
 71  
 72  			availableNetworkConnections = append(availableNetworkConnections, dogeboxd.NetworkWifi{
 73  				Type:      "wifi",
 74  				Interface: wifiInterface.Name,
 75  				Ssids:     foundNetworks,
 76  			})
 77  			wifiInterfaceNames = append(wifiInterfaceNames, wifiInterface.Name)
 78  		}
 79  	}
 80  
 81  	allInterfaces, err := net.Interfaces()
 82  	if err != nil {
 83  		log.Printf("Failed to fetch system interfaces: %s", err)
 84  		return availableNetworkConnections
 85  	}
 86  
 87  outer:
 88  	for _, systemInterface := range allInterfaces {
 89  		// Ignore anything that doesn't have a hardware address.
 90  		if systemInterface.HardwareAddr == nil {
 91  			continue
 92  		}
 93  
 94  		// Ignore if it starts with "ve-pup-" as
 95  		// this is an internal pup-only interface.
 96  		if strings.HasPrefix(systemInterface.Name, "ve-pup-") {
 97  			continue
 98  		}
 99  
100  		// If we've seen this as a wifi network, ignore it.
101  		for _, v := range wifiInterfaceNames {
102  			if v == systemInterface.Name {
103  				continue outer
104  			}
105  		}
106  
107  		availableNetworkConnections = append(availableNetworkConnections, dogeboxd.NetworkEthernet{
108  			Type:      "ethernet",
109  			Interface: systemInterface.Name,
110  		})
111  	}
112  
113  	return availableNetworkConnections
114  }
115  
116  func (t NetworkManagerLinux) SetPendingNetwork(selectedNetwork dogeboxd.SelectedNetwork, j dogeboxd.Job) error {
117  	var selectedIface string
118  	log := j.Logger.Step("set network")
119  	switch network := selectedNetwork.(type) {
120  	case dogeboxd.SelectedNetworkEthernet:
121  		{
122  			log.Logf("Setting Ethernet network on interface: %s", network.Interface)
123  			selectedIface = network.Interface
124  		}
125  
126  	case dogeboxd.SelectedNetworkWifi:
127  		{
128  			log.Logf("Setting WiFi network on interface: %s", network.Interface)
129  			log.Logf("SSIDs: %s, password: %s, encryption: %s", network.Ssid, network.Password, network.Encryption)
130  			selectedIface = network.Interface
131  		}
132  
133  	default:
134  		log.Errf("Unknown network type: %T", selectedNetwork)
135  	}
136  
137  	allInterfaces, err := net.Interfaces()
138  	if err != nil {
139  		log.Errf("Failed to fetch system interfaces: %s", err)
140  		return err
141  	}
142  
143  	interfaceExists := false
144  	for _, iface := range allInterfaces {
145  		if iface.Name == selectedIface {
146  			interfaceExists = true
147  			break
148  		}
149  	}
150  
151  	if !interfaceExists {
152  		return fmt.Errorf("interface %s does not exist", selectedIface)
153  	}
154  
155  	ns := t.sm.Get().Network
156  	ns.PendingNetwork = selectedNetwork
157  	return t.sm.SetNetwork(ns)
158  }
159  
160  func (t NetworkManagerLinux) TryConnect(nixPatch dogeboxd.NixPatch) error {
161  	state := t.sm.Get().Network
162  
163  	if state.PendingNetwork == nil {
164  		return errors.New("no pending network to connect to")
165  	}
166  
167  	connector := network_connector.NewNetworkConnector(state.PendingNetwork)
168  
169  	err := connector.Connect(state.PendingNetwork)
170  	if err != nil {
171  		return err
172  	}
173  
174  	// Create an instance of our network persistor, we do this here
175  	// because depending on the type of network we want (ethernet/wifi)
176  	// may result in a different persistor-type being used.
177  	persistor, err := network_persistor.NewNetworkPersistor(t.nix, state.PendingNetwork)
178  	if err != nil {
179  		return err
180  	}
181  
182  	persistor.Persist(nixPatch, state.PendingNetwork)
183  
184  	// Swap out pending for current.
185  	state.CurrentNetwork = state.PendingNetwork
186  	state.PendingNetwork = nil
187  
188  	err = t.sm.SetNetwork(state)
189  	if err != nil {
190  		return err
191  	}
192  
193  	log.Printf("Successfully saved network configuration to disk")
194  	return nil
195  }
196  
197  func (t NetworkManagerLinux) GetLocalIP() (net.IP, error) {
198  	conn, err := net.Dial("udp", "dogecoin.org:443")
199  	if err != nil {
200  		return nil, err
201  	}
202  	defer conn.Close()
203  
204  	localAddr := conn.LocalAddr().(*net.UDPAddr)
205  	return localAddr.IP, nil
206  }