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 }