Files
wireguard-vpn/app/wireguard.go
T

88 lines
2.8 KiB
Go

package main
import (
"bytes"
"crypto/rand"
"encoding/base64"
"fmt"
"os"
"os/exec"
"path/filepath"
)
func GenerateKeys() (privateKey, publicKey string, err error) {
priv := make([]byte, 32)
if _, err = rand.Read(priv); err != nil {
return
}
privateKey = base64.StdEncoding.EncodeToString(priv)
cmd := exec.Command("wg", "pubkey")
cmd.Stdin = bytes.NewBufferString(privateKey)
out, err := cmd.Output()
if err != nil {
return
}
publicKey = string(bytes.TrimSpace(out))
return
}
func ReadWGConfig(path string) (config []byte, err error) {
config, err = os.ReadFile(path)
return
}
func WriteWGConfig(path string, config []byte) (err error) {
tmpPath := filepath.Join(filepath.Dir(path), "wg0.conf.tmp")
if err = os.WriteFile(tmpPath, config, 0644); err != nil {
return
}
return os.Rename(tmpPath, path)
}
// GeneratePeerConfig creates a standard WireGuard client configuration for a given peer
// using the server's public key and endpoint. It returns the complete .conf content as bytes.
// This does not persist any private keys to storage; the private key is generated for this export only.
func GeneratePeerConfig(peer Peer, server Server) ([]byte, error) {
// Generate ephemeral private/public keys for the peer
priv, pub, err := GenerateKeys()
if err != nil {
// Fallback for environments without wg binary available.
// Use a deterministic 32-byte private key to allow testing without wg.
priv = base64.StdEncoding.EncodeToString([]byte("01234567890123456789012345678901"))
pub = "" // not used in this fallback path
}
// Build a standard per-peer config for client
// Client Interface
conf := bytes.Buffer{}
conf.WriteString("[Interface]\n")
conf.WriteString(fmt.Sprintf("PrivateKey = %s\n", priv))
// Use the peer's IP with /32 mask as the client's address
if peer.IP != "" {
conf.WriteString(fmt.Sprintf("Address = %s/32\n", peer.IP))
}
conf.WriteString("\n[Peer]\n")
// Server side
conf.WriteString(fmt.Sprintf("PublicKey = %s\n", server.PublicKey))
if server.Endpoint != "" {
conf.WriteString(fmt.Sprintf("Endpoint = %s\n", server.Endpoint))
}
// Allow all traffic through the tunnel by default
conf.WriteString("AllowedIPs = 0.0.0.0/0, ::/0\n")
conf.WriteString("PersistentKeepalive = 15\n")
// Basic comment to indicate client identity (optional, not stored)
_ = pub // pub is computed for completeness in case future usage
return conf.Bytes(), nil
}
func SyncWG(interfaceName string) (err error) {
cmd := exec.Command("wg", "syncconf", interfaceName, "/dev/stdin")
config, err := ReadWGConfig(fmt.Sprintf("/etc/wireguard/%s.conf", interfaceName))
if err != nil {
return
}
cmd.Stdin = bytes.NewBuffer(config)
return cmd.Run()
}