package wlan import ( "encoding/json" "fmt" "gopkg.in/yaml.v3" "log" "net" "net/http" "network_configurator/models" "os" "os/exec" "strings" ) const netplanFilePath = "/etc/netplan/wlan.yaml" // MacAdresWlan0 HTTP handler для получения MAC адреса интерфейса wlan0 func MacAdresWlan0(w http.ResponseWriter, r *http.Request) { interfaces, err := net.Interfaces() if err != nil { response := models.MacAddressResponse{ Error: fmt.Sprintf("Failed to get network interfaces: %v", err), } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(response) return } var wlan0Interface *net.Interface for _, iface := range interfaces { if iface.Name == "wlan0" { wlan0Interface = &iface break } } if wlan0Interface == nil { response := models.MacAddressResponse{ Error: "Interface wlan0 not found", Interface: "wlan0", } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) json.NewEncoder(w).Encode(response) return } macAddress := wlan0Interface.HardwareAddr.String() response := models.MacAddressResponse{ MacAddress: macAddress, Interface: "wlan0", } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) } // InterfaceIPsWlan0 HTTP handler для получения списка IP адресов интерфейса wlan0 func InterfaceIPsWlan0(w http.ResponseWriter, r *http.Request) { interfaces, err := net.Interfaces() if err != nil { response := models.InterfaceIPsResponse{ Error: fmt.Sprintf("Failed to get network interfaces: %v", err), } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(response) return } var wlan0Interface *net.Interface for _, iface := range interfaces { if iface.Name == "wlan0" { wlan0Interface = &iface break } } if wlan0Interface == nil { response := models.InterfaceIPsResponse{ Interface: "wlan0", Error: "Interface wlan0 not found", } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) json.NewEncoder(w).Encode(response) return } addrs, err := wlan0Interface.Addrs() if err != nil { response := models.InterfaceIPsResponse{ Interface: "wlan0", Error: fmt.Sprintf("Failed to get addresses for wlan0: %v", err), } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(response) return } ipAddresses := make([]string, 0) for _, addr := range addrs { if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ipnet.IP.To4() != nil || ipnet.IP.To16() != nil { ipAddresses = append(ipAddresses, ipnet.IP.String()) } } } response := models.InterfaceIPsResponse{ Interface: "wlan0", IPAddresses: ipAddresses, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) } // SSIDWlan0 HTTP handler для получения SSID интерфейса wlan0 func SSIDWlan0(w http.ResponseWriter, r *http.Request) { // Command to get SSID (Linux - iwgetid, macOS - airport, Windows - needs different approach) cmd := "iwgetid" // For Linux - you might need to install 'wireless-tools' package out, err := exec.Command(cmd, "wlan0", "-r").Output() if err != nil { response := models.SSIDResponse{ Interface: "wlan0", Error: fmt.Sprintf("Failed to get SSID using %s: %v", cmd, err), } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(response) return } ssid := strings.TrimSpace(string(out)) if ssid == "" { response := models.SSIDResponse{ Interface: "wlan0", Error: "SSID is empty or not connected", } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusNotFound) json.NewEncoder(w).Encode(response) return } response := models.SSIDResponse{ Interface: "wlan0", SSID: ssid, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) } func createTestNetplanFile() { initialYaml := ` network: version: 2 renderer: networkd wifis: wlan0: dhcp4: yes ` err := os.WriteFile(netplanFilePath, []byte(initialYaml), 0644) if err != nil { log.Fatalf("Failed to create test netplan file: %v", err) } fmt.Println("Test netplan file created at:", netplanFilePath) } func init() { if _, err := os.Stat(netplanFilePath); os.IsNotExist(err) { createTestNetplanFile() } } func NetplanHandler(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: getNetplanConfig(w, r) case http.MethodPut: updateNetplanConfig(w, r) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } func getNetplanConfig(w http.ResponseWriter, r *http.Request) { config, err := readNetplanConfig() if err != nil { http.Error(w, fmt.Sprintf("Failed to read config: %v", err), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(config) } func updateNetplanConfig(w http.ResponseWriter, r *http.Request) { var updatedConfig models.NetplanConfigWlan err := json.NewDecoder(r.Body).Decode(&updatedConfig) if err != nil { http.Error(w, fmt.Sprintf("Failed to decode request body: %v", err), http.StatusBadRequest) return } err = writeNetplanConfig(updatedConfig) if err != nil { http.Error(w, fmt.Sprintf("Failed to write config: %v", err), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) w.Write([]byte("Netplan configuration updated successfully")) } func readNetplanConfig() (*models.NetplanConfigWlan, error) { yamlFile, err := os.ReadFile(netplanFilePath) if err != nil { return nil, fmt.Errorf("failed to read netplan file: %w", err) } var config models.NetplanConfigWlan err = yaml.Unmarshal(yamlFile, &config) if err != nil { return nil, fmt.Errorf("failed to unmarshal yaml: %w", err) } return &config, nil } func writeNetplanConfig(config models.NetplanConfigWlan) error { savedConfig, err := readNetplanConfig() if err != nil { return fmt.Errorf("failed to read eth yaml: %w", err) } yamlData, err := yaml.Marshal(config) if err != nil { return fmt.Errorf("failed to marshal yaml: %w", err) } err = os.WriteFile(netplanFilePath, yamlData, 0644) if err != nil { return fmt.Errorf("failed to write netplan file: %w", err) } cmd := exec.Command("netplan", "apply") output, err := cmd.CombinedOutput() if err != nil { yamlData, err := yaml.Marshal(*savedConfig) if err != nil { return fmt.Errorf("failed to marshal yaml: %w", err) } err = os.WriteFile(netplanFilePath, yamlData, 0644) if err != nil { return fmt.Errorf("failed to write netplan file: %w", err) } return fmt.Errorf("Ошибка при выполнении команды: %s\n Вывод команды: %s\n", err, output) } return nil } // WifiNetworks HTTP handler для получения списка видимых WiFi сетей с уровнем сигнала и типом безопасности func WifiNetworks(w http.ResponseWriter, r *http.Request) { interfaceName := "wlan0" // Жестко задан интерфейс wlan0 для сканирования cmd := "iwlist" // Using 'iwlist' command to scan WiFi networks (Linux specific) out, err := exec.Command(cmd, interfaceName, "scan").Output() if err != nil { response := models.WifiNetworksResponse{ Error: fmt.Sprintf("Failed to scan WiFi networks using %s: %v", cmd, err), } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) json.NewEncoder(w).Encode(response) return } output := string(out) lines := strings.Split(output, "\n") networks := make([]models.NetworkInfo, 0) seenSSIDs := make(map[string]bool) var currentNetworkInfo models.NetworkInfo var signal string for _, line := range lines { line = strings.TrimSpace(line) if strings.Contains(line, "Signal level=") { signalLevel := strings.SplitN(line, "=", 2)[1] signalLevel = strings.Fields(signalLevel)[0] signal = signalLevel } if strings.Contains(line, "ESSID:") { ssid := strings.SplitN(line, ":", 2)[1] ssid = strings.Trim(ssid, "\"") if !seenSSIDs[ssid] { if currentNetworkInfo.SSID != "" { networks = append(networks, currentNetworkInfo) } currentNetworkInfo = models.NetworkInfo{SSID: ssid, Signal: signal} seenSSIDs[ssid] = true } } else if strings.Contains(line, "Encryption key:") && strings.Contains(line, "off") { currentNetworkInfo.Security = "Open" // No encryption, Open network } else if strings.Contains(line, "IE:") { // Information Element - for security type if strings.Contains(line, "WPA2") { currentNetworkInfo.Security = "WPA2" } else if strings.Contains(line, "WPA") { currentNetworkInfo.Security = "WPA" } else if strings.Contains(line, "WEP") { currentNetworkInfo.Security = "WEP" } else { if currentNetworkInfo.Security == "" { // If no specific WPA/WEP found and not marked as Open currentNetworkInfo.Security = "Secured" // Generic secured if IE present but type not identified } } } } if currentNetworkInfo.SSID != "" { networks = append(networks, currentNetworkInfo) } // If Security is still empty after all checks, and it's not Open, assume it's some form of Secured for i := range networks { if networks[i].Security == "" && networks[i].SSID != "" { networks[i].Security = "Secured" // Default to Secured if type not determined by IE and not explicitly Open } } response := models.WifiNetworksResponse{ Networks: networks, } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) }