353 lines
9.9 KiB
Go
Raw Normal View History

2025-03-11 14:07:01 +03:00
package wlan
import (
"encoding/json"
"fmt"
2025-03-12 22:35:36 +03:00
"gopkg.in/yaml.v3"
"log"
2025-03-11 14:07:01 +03:00
"net"
"net/http"
2025-03-12 22:35:36 +03:00
"network_configurator/models"
"os"
2025-03-11 14:07:01 +03:00
"os/exec"
"strings"
)
2025-03-12 22:35:36 +03:00
const netplanFilePath = "/etc/netplan/wlan.yaml"
2025-03-11 14:07:01 +03:00
2025-03-12 22:35:36 +03:00
// 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
}
2025-03-11 14:07:01 +03:00
2025-03-12 22:35:36 +03:00
var wlan0Interface *net.Interface
for _, iface := range interfaces {
if iface.Name == "wlan0" {
wlan0Interface = &iface
break
}
}
2025-03-11 14:07:01 +03:00
2025-03-12 22:35:36 +03:00
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)
2025-03-11 14:07:01 +03:00
return
}
2025-03-12 22:35:36 +03:00
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)
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
// InterfaceIPsWlan0 HTTP handler для получения списка IP адресов интерфейса wlan0
func InterfaceIPsWlan0(w http.ResponseWriter, r *http.Request) {
interfaces, err := net.Interfaces()
2025-03-11 14:07:01 +03:00
if err != nil {
2025-03-12 22:35:36 +03:00
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)
2025-03-11 14:07:01 +03:00
return
}
2025-03-12 22:35:36 +03:00
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
}
2025-03-11 14:07:01 +03:00
2025-03-12 22:35:36 +03:00
addrs, err := wlan0Interface.Addrs()
2025-03-11 14:07:01 +03:00
if err != nil {
2025-03-12 22:35:36 +03:00
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)
2025-03-11 14:07:01 +03:00
return
}
2025-03-12 22:35:36 +03:00
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)
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
// 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()
2025-03-11 14:07:01 +03:00
if err != nil {
2025-03-12 22:35:36 +03:00
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)
2025-03-11 14:07:01 +03:00
return
}
2025-03-12 22:35:36 +03:00
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)
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
func createTestNetplanFile() {
initialYaml := `
network:
version: 2
renderer: networkd
wifis:
wlan0:
dhcp4: yes
`
err := os.WriteFile(netplanFilePath, []byte(initialYaml), 0644)
2025-03-11 14:07:01 +03:00
if err != nil {
2025-03-12 22:35:36 +03:00
log.Fatalf("Failed to create test netplan file: %v", err)
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
fmt.Println("Test netplan file created at:", netplanFilePath)
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
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()
2025-03-11 14:07:01 +03:00
if err != nil {
2025-03-12 22:35:36 +03:00
http.Error(w, fmt.Sprintf("Failed to read config: %v", err), http.StatusInternalServerError)
2025-03-11 14:07:01 +03:00
return
}
w.Header().Set("Content-Type", "application/json")
2025-03-12 22:35:36 +03:00
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)
2025-03-11 14:07:01 +03:00
if err != nil {
2025-03-12 22:35:36 +03:00
http.Error(w, fmt.Sprintf("Failed to write config: %v", err), http.StatusInternalServerError)
2025-03-11 14:07:01 +03:00
return
}
2025-03-12 22:35:36 +03:00
w.WriteHeader(http.StatusOK)
w.Write([]byte("Netplan configuration updated successfully"))
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
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
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
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)
}
2025-03-11 14:07:01 +03:00
2025-03-12 22:35:36 +03:00
return fmt.Errorf("Ошибка при выполнении команды: %s\n Вывод команды: %s\n", err, output)
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
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
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
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)
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
// 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
}
2025-03-11 14:07:01 +03:00
}
2025-03-12 22:35:36 +03:00
response := models.WifiNetworksResponse{
Networks: networks,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(response)
2025-03-11 14:07:01 +03:00
}