package network import ( "bufio" "encoding/json" "fmt" "net" "net/http" "os" "os/exec" "regexp" "strconv" "strings" ) // NetworkInterface представляет информацию о сетевом интерфейсе type NetworkInterface struct { Name string `json:"name"` IP string `json:"ip"` Netmask string `json:"netmask"` Gateway string `json:"gateway"` } // WiFiNetwork представляет информацию о WiFi сети type WiFiNetwork struct { SSID string `json:"ssid"` Signal int `json:"signal"` // Пример, можно добавить больше информации Security string `json:"security"` // Пример, можно добавить больше информации } // ErrorResponse для JSON ответов с ошибками type ErrorResponse struct { Error string `json:"error"` } // ScanWiFiNetworks сканирует доступные WiFi сети func ScanWiFiNetworks() ([]WiFiNetwork, error) { networks, err := ScanWiFiNetworksImpl() // Реализация зависит от ОС if err != nil { return nil, err } return networks, nil } // ConnectToWiFi подключается к WiFi сети func ConnectToWiFi(ssid, password string) error { return ConnectToWiFiImpl(ssid, password) // Реализация зависит от ОС } // GetNetworkStatus получает статус сетевых интерфейсов (wlan0, eth0) func GetNetworkStatus() ([]NetworkInterface, error) { interfaces, err := getNetworkStatusImpl() // Реализация зависит от ОС if err != nil { return nil, err } return interfaces, nil } // ConfigureNetworkInterface настраивает статический IP для интерфейса func ConfigureNetworkInterface(iface, ip, netmask, gateway string) error { return configureNetworkInterfaceImpl(iface, ip, netmask, gateway) // Реализация зависит от ОС } // Функция для выполнения команд shell func executeCommand(command string, args ...string) (string, error) { cmd := exec.Command(command, args...) output, err := cmd.CombinedOutput() if err != nil { return "", fmt.Errorf("ошибка выполнения команды: %s %s, вывод: %s, ошибка: %v", command, strings.Join(args, " "), string(output), err) } return string(output), nil } // Функция для отправки JSON ответа func SendJSONResponse(w http.ResponseWriter, data interface{}, statusCode int) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) json.NewEncoder(w).Encode(data) } // Функция для отправки JSON ошибки func SendJSONError(w http.ResponseWriter, message string, statusCode int) { SendJSONResponse(w, ErrorResponse{Error: message}, statusCode) } // GetConnectedWiFiSSID получает SSID текущей подключенной WiFi сети func GetConnectedWiFiSSID() (string, error) { ssid, err := getConnectedWiFiSSIDImpl() // Реализация зависит от ОС if err != nil { return "", err } return ssid, nil } // DisconnectWiFi отключается от текущей WiFi сети func DisconnectWiFi() error { return disconnectWiFiImpl() // Реализация зависит от ОС } // ScanWiFiNetworksImpl реализация для Linux func ScanWiFiNetworksImpl() ([]WiFiNetwork, error) { output, err := executeCommand("sudo", "iwlist", "wlan0", "scan") if err != nil { return nil, fmt.Errorf("ошибка сканирования WiFi: %v", err) } networks := []WiFiNetwork{} scanner := bufio.NewScanner(strings.NewReader(output)) currentNetwork := WiFiNetwork{} reSSID := regexp.MustCompile(`ESSID:"([^"]*)"`) reSignal := regexp.MustCompile(`level=(-?\d+)`) reEncryption := regexp.MustCompile(`IE: .*?(WPA|WPA2|WEP).*`) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, "ESSID:") { matches := reSSID.FindStringSubmatch(line) if len(matches) > 1 { currentNetwork.SSID = matches[1] } } if strings.Contains(line, "Signal level=") { matches := reSignal.FindStringSubmatch(line) if len(matches) > 1 { signalLevel, _ := strconv.Atoi(matches[1]) currentNetwork.Signal = signalLevel } } if strings.Contains(line, "IE:") && reEncryption.MatchString(line) { matches := reEncryption.FindStringSubmatch(line) if len(matches) > 1 { currentNetwork.Security = matches[1] } else { currentNetwork.Security = "Open" // Если не найдено, считаем открытой } } if currentNetwork.SSID != "" { networks = append(networks, currentNetwork) currentNetwork = WiFiNetwork{} // Сброс для следующей сети } } return networks, nil } // ConnectToWiFiImpl реализация для Linux func ConnectToWiFiImpl(ssid, password string) error { // Создаем файл конфигурации wpa_supplicant.conf conf := fmt.Sprintf(`ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 country=RU network={ ssid="%s" psk="%s" } `, ssid, password) err := os.WriteFile("/etc/wpa_supplicant/wpa_supplicant.conf", []byte(conf), 0600) if err != nil { return fmt.Errorf("ошибка записи в wpa_supplicant.conf: %v", err) } // Перезапускаем wpa_supplicant _, err = executeCommand("sudo", "wpa_cli", "-i", "wlan0", "reconfigure") if err != nil { // Попробуем перезапустить службу wpa_supplicant, если wpa_cli не сработал _, errRestartService := executeCommand("sudo", "systemctl", "restart", "wpa_supplicant") if errRestartService != nil { return fmt.Errorf("ошибка перезапуска wpa_supplicant: %v, также ошибка wpa_cli: %v", errRestartService, err) } } // Переподключаем интерфейс wlan0 _, err = executeCommand("sudo", "ifdown", "wlan0") if err != nil { fmt.Printf("Предупреждение: ошибка ifdown wlan0: %v\n", err) // Не критическая ошибка } _, err = executeCommand("sudo", "ifup", "wlan0") if err != nil { return fmt.Errorf("ошибка ifup wlan0: %v", err) } return nil } // getNetworkStatusImpl реализация для Linux func getNetworkStatusImpl() ([]NetworkInterface, error) { interfaces := []NetworkInterface{} // Получаем статус для eth0 eth0Status, err := getInterfaceStatus("eth0") if err == nil { interfaces = append(interfaces, eth0Status) } // Получаем статус для wlan0 wlan0Status, err := getInterfaceStatus("wlan0") if err == nil { interfaces = append(interfaces, wlan0Status) } return interfaces, nil } func getInterfaceStatus(ifaceName string) (NetworkInterface, error) { ifconfigOutput, err := executeCommand("ifconfig", ifaceName) if err != nil { return NetworkInterface{}, fmt.Errorf("ошибка ifconfig %s: %v", ifaceName, err) } ip, netmask, err := parseIfconfigOutput(ifconfigOutput) if err != nil && !strings.Contains(err.Error(), "interface is down") { // Игнорируем ошибку, если интерфейс выключен fmt.Printf("Предупреждение: ошибка парсинга ifconfig %s: %v\n", ifaceName, err) return NetworkInterface{Name: ifaceName}, nil // Возвращаем интерфейс без IP и маски, но без критической ошибки } gateway, err := getDefaultGateway(ifaceName) if err != nil { fmt.Printf("Предупреждение: ошибка получения шлюза для %s: %v\n", ifaceName, err) gateway = "" // Шлюз может быть не задан } return NetworkInterface{ Name: ifaceName, IP: ip, Netmask: netmask, Gateway: gateway, }, nil } func parseIfconfigOutput(output string) (ip, netmask string, err error) { reIP := regexp.MustCompile(`inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`) reNetmask := regexp.MustCompile(`netmask (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`) ipMatches := reIP.FindStringSubmatch(output) if len(ipMatches) > 1 { ip = ipMatches[1] } else { return "", "", fmt.Errorf("IP адрес не найден или интерфейс выключен") // Изменено сообщение об ошибке } netmaskMatches := reNetmask.FindStringSubmatch(output) if len(netmaskMatches) > 1 { netmask = netmaskMatches[1] } else { netmask = "" // Маска может быть не найдена, не критично } return ip, netmask, nil } func getDefaultGateway(ifaceName string) (string, error) { routeOutput, err := executeCommand("route", "-n") if err != nil { return "", fmt.Errorf("ошибка route -n: %v", err) } scanner := bufio.NewScanner(strings.NewReader(routeOutput)) for scanner.Scan() { line := scanner.Text() fields := strings.Fields(line) if len(fields) >= 4 && fields[0] == "0.0.0.0" && fields[5] == ifaceName { return fields[1], nil // Шлюз находится во втором поле } } return "", fmt.Errorf("шлюз по умолчанию для интерфейса %s не найден", ifaceName) } // configureNetworkInterfaceImpl реализация для Linux func configureNetworkInterfaceImpl(iface, ip, netmask, gateway string) error { // Проверяем валидность IP и маски if net.ParseIP(ip) == nil { return fmt.Errorf("неверный формат IP адреса: %s", ip) } if net.ParseIP(netmask) == nil { return fmt.Errorf("неверный формат маски подсети: %s", netmask) } // Настраиваем IP и маску _, err := executeCommand("sudo", "ifconfig", iface, ip, "netmask", netmask) if err != nil { return fmt.Errorf("ошибка настройки IP и маски: %v", err) } // Настраиваем шлюз, только если он указан if gateway != "" { if net.ParseIP(gateway) == nil { return fmt.Errorf("неверный формат шлюза: %s", gateway) } _, err = executeCommand("sudo", "route", "del", "default", "gw", "0.0.0.0", "dev", iface) // Удаляем старый шлюз, если есть if err != nil && !strings.Contains(err.Error(), "No such process") && !strings.Contains(err.Error(), "not in table") { // Игнорируем ошибки, если шлюз не был установлен fmt.Printf("Предупреждение: ошибка удаления старого шлюза: %v\n", err) } _, err = executeCommand("sudo", "route", "add", "default", "gw", gateway, "dev", iface) if err != nil { return fmt.Errorf("ошибка настройки шлюза: %v", err) } } else { // Если шлюз не указан, удаляем шлюз по умолчанию для этого интерфейса _, err = executeCommand("sudo", "route", "del", "default", "gw", "0.0.0.0", "dev", iface) if err != nil && !strings.Contains(err.Error(), "No such process") && !strings.Contains(err.Error(), "not in table") { fmt.Printf("Предупреждение: ошибка удаления шлюза по умолчанию: %v\n", err) } } return nil } // getConnectedWiFiSSIDImpl реализация для Linux func getConnectedWiFiSSIDImpl() (string, error) { output, err := executeCommand("iwconfig", "wlan0") if err != nil { return "", fmt.Errorf("ошибка выполнения iwconfig wlan0: %v", err) } reSSID := regexp.MustCompile(`ESSID:"([^"]*)"`) matches := reSSID.FindStringSubmatch(output) if len(matches) > 1 { return matches[1], nil } return "", fmt.Errorf("не удалось получить SSID из вывода iwconfig, возможно, не подключено к WiFi") } // disconnectWiFiImpl реализация для Linux func disconnectWiFiImpl() error { // Отключаем интерфейс wlan0 _, err := executeCommand("sudo", "ifdown", "wlan0") if err != nil { return fmt.Errorf("ошибка ifdown wlan0: %v", err) } return nil }