88 lines
2.8 KiB
Go
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()
|
|
}
|