2025-03-11 14:07:01 +03:00

334 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}