feat: WGRplane Hybrid - Go-native with nftables + Multi-Webhook
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
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()
|
||||
}
|
||||
Reference in New Issue
Block a user