Files
wgServer/internal/wireguard/server.go
2025-10-16 16:27:36 +07:00

197 lines
6.0 KiB
Go

package wireguard
import (
"fmt"
"log"
"os"
"os/exec"
"strconv"
"strings"
"time"
"wg-panel/internal/database"
)
// UpdateServerConfig обновляет конфиг файл сервера
func UpdateServerConfig(server *database.Server, db *database.Database) error {
configContent := fmt.Sprintf(`[Interface]
PrivateKey = %s
Address = %s
ListenPort = %d
PostUp = %s
PostDown = %s
`, server.PrivateKey, server.Address, server.ListenPort, server.PostUp, server.PostDown)
// Добавляем всех клиентов
for _, client := range db.Clients {
if client.ServerID == server.ID && client.Enabled {
configContent += fmt.Sprintf("\n[Peer]\nPublicKey = %s\nAllowedIPs = %s/32\n",
client.PublicKey, client.Address)
}
}
configPath := fmt.Sprintf("/etc/wireguard/%s.conf", server.Interface)
return os.WriteFile(configPath, []byte(configContent), 0600)
}
// CreateServer создает новый WireGuard сервер
func CreateServer(db *database.Database, name, address string, port int, dns string) (*database.Server, error) {
// Генерируем ключи
privateKey, publicKey, err := database.GenerateKeys()
if err != nil {
return nil, err
}
// Определяем имя интерфейса
interfaceName := fmt.Sprintf("wg%d", len(db.Servers))
// Получаем основной сетевой интерфейс
netInterface := database.GetDefaultInterface()
log.Printf("📡 Определен сетевой интерфейс для NAT: %s", netInterface)
// Создаем сервер
server := database.Server{
ID: fmt.Sprintf("%d", time.Now().UnixNano()),
Name: name,
Interface: interfaceName,
PrivateKey: privateKey,
PublicKey: publicKey,
Address: address,
ListenPort: port,
DNS: dns,
Enabled: true, // Запускаем сразу
CreatedAt: time.Now(),
PostUp: fmt.Sprintf("iptables -I FORWARD 1 -i %%i -j ACCEPT; iptables -I FORWARD 1 -o %%i -j ACCEPT; iptables -t nat -A POSTROUTING -o %s -j MASQUERADE", netInterface),
PostDown: fmt.Sprintf("iptables -D FORWARD -i %%i -j ACCEPT; iptables -D FORWARD -o %%i -j ACCEPT; iptables -t nat -D POSTROUTING -o %s -j MASQUERADE", netInterface),
NextClientIP: 2,
}
// Включаем IP forwarding
log.Println("🔧 Включаю IP forwarding...")
if err := database.EnableIPForwarding(); err != nil {
log.Println("⚠️ Предупреждение: не удалось включить IP forwarding:", err)
} else {
log.Println("✅ IP forwarding включен")
}
// Создаем конфиг файл
log.Printf("📝 Создаю конфиг %s...", interfaceName)
configContent := fmt.Sprintf(`[Interface]
PrivateKey = %s
Address = %s
ListenPort = %d
PostUp = %s
PostDown = %s
`, server.PrivateKey, server.Address, server.ListenPort, server.PostUp, server.PostDown)
configPath := fmt.Sprintf("/etc/wireguard/%s.conf", interfaceName)
if err := os.WriteFile(configPath, []byte(configContent), 0600); err != nil {
return nil, err
}
// Запускаем интерфейс сразу (так как Enabled = true)
log.Printf("🚀 Запускаю интерфейс %s...", interfaceName)
cmd := exec.Command("wg-quick", "up", interfaceName)
output, err := cmd.CombinedOutput()
if err != nil {
log.Printf("❌ Ошибка запуска: %s", string(output))
return nil, fmt.Errorf("failed to start interface: %v, output: %s", err, string(output))
}
log.Printf("✅ Интерфейс %s запущен", interfaceName)
return &server, nil
}
// ToggleServer включает/выключает сервер
func ToggleServer(server *database.Server) error {
if server.Enabled {
// Выключаем
cmd := exec.Command("wg-quick", "down", server.Interface)
if err := cmd.Run(); err != nil {
return err
}
server.Enabled = false
} else {
// Включаем IP forwarding перед запуском
database.EnableIPForwarding()
// Включаем
cmd := exec.Command("wg-quick", "up", server.Interface)
if err := cmd.Run(); err != nil {
return err
}
server.Enabled = true
}
return nil
}
// DeleteServer удаляет сервер
func DeleteServer(server *database.Server) error {
// Останавливаем интерфейс
if server.Enabled {
exec.Command("wg-quick", "down", server.Interface).Run()
}
// Удаляем конфиг файл
configPath := fmt.Sprintf("/etc/wireguard/%s.conf", server.Interface)
return os.Remove(configPath)
}
// UpdateStats обновляет статистику из WireGuard
func UpdateStats(db *database.Database) {
for _, server := range db.Servers {
if !server.Enabled {
continue
}
cmd := exec.Command("wg", "show", server.Interface, "dump")
output, err := cmd.Output()
if err != nil {
continue
}
lines := strings.Split(string(output), "\n")
for _, line := range lines[1:] { // Пропускаем первую строку (заголовок)
if line == "" {
continue
}
fields := strings.Split(line, "\t")
if len(fields) < 8 {
continue
}
pubKey := fields[0]
endpoint := fields[2] // IP:Port клиента
lastHandshake, _ := strconv.ParseInt(fields[4], 10, 64)
rxBytes, _ := strconv.ParseInt(fields[5], 10, 64) // received
txBytes, _ := strconv.ParseInt(fields[6], 10, 64) // sent
// Обновляем статистику клиента
for i := range db.Clients {
if db.Clients[i].PublicKey == pubKey && db.Clients[i].ServerID == server.ID {
db.Clients[i].RxBytes = rxBytes
db.Clients[i].TxBytes = txBytes
db.Clients[i].Endpoint = endpoint
if lastHandshake > 0 {
db.Clients[i].LastHandshake = time.Unix(lastHandshake, 0)
}
break
}
}
}
}
database.SaveDatabase(db)
}
// UpdateStatsLoop обновляет статистику каждые 5 секунд
func UpdateStatsLoop(db *database.Database) {
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for range ticker.C {
UpdateStats(db)
}
}