2025-03-12 22:35:36 +03:00

353 lines
9.9 KiB
Go
Raw Permalink 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 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)
}