From 8e798706e32aea054c612b2b9b7ddb22e60c8450 Mon Sep 17 00:00:00 2001 From: HeshamTB Date: Wed, 27 Mar 2024 09:28:13 +0300 Subject: [PATCH] WIP: create new peers server-side Creates a new peer server-side. - Gen keys - Allocate IP - Add to WG Link - Respond with a read wg config for the client to use --- cmd/hvpn-node/hvpn-node.go | 1 + const.go | 12 ++++++++ handlers.go | 29 +++++++++++++++++++ link.go | 59 ++++++++++++++++++++++++++++++++++++++ templates/client.ini.tmpl | 12 ++++++++ templates/templates.go | 6 ++++ 6 files changed, 119 insertions(+) create mode 100644 templates/client.ini.tmpl create mode 100644 templates/templates.go diff --git a/cmd/hvpn-node/hvpn-node.go b/cmd/hvpn-node/hvpn-node.go index 3757ea5..e1ad5f6 100644 --- a/cmd/hvpn-node/hvpn-node.go +++ b/cmd/hvpn-node/hvpn-node.go @@ -65,6 +65,7 @@ func run(ctx *cli.Context) { apiMux.HandleFunc("POST /peer", hvpnnode3.HandlePostPeer(wgLink)) apiMux.HandleFunc("DELETE /peer/{pubkey}", hvpnnode3.HandleDeletePeer(wgLink)) apiMux.HandleFunc("GET /peers", hvpnnode3.HandleGetPeers(wgLink)) + apiMux.HandleFunc("GET /peer/new", hvpnnode3.HandleGetCreatePeer(wgLink)) var handler http.Handler = apiMux handler = hvpnnode3.HttpAuthToken(handler, ctx.String("http-api-key")) diff --git a/const.go b/const.go index 0b8f1c5..e7da1a2 100644 --- a/const.go +++ b/const.go @@ -1,5 +1,17 @@ package hvpnnode3 +import "net" + const ( CONTENT_JSON = "application/json" + CONTENT_OCTET = "application/octet-stream" + CONTENT_PLAIN_TEXT = "text/plain" + WG_CLIENT_MTU = 1380 +) + +var ( + WG_CLIENT_DNS = []net.IP{ + net.ParseIP("1.1.1.1"), + net.ParseIP("8.8.8.8"), + } ) diff --git a/handlers.go b/handlers.go index 330e239..ef65b36 100644 --- a/handlers.go +++ b/handlers.go @@ -8,12 +8,14 @@ import ( "log/slog" "net/http" "net/url" + "text/template" "time" "github.com/felixge/httpsnoop" "github.com/google/uuid" "gitea.hbanafa.com/HeshamTB/hvpn-node3/proto" + "gitea.hbanafa.com/HeshamTB/hvpn-node3/templates" ) type CtxKey string @@ -176,6 +178,33 @@ func HandleDeletePeer(wg *WGLink) http.HandlerFunc { } } +func HandleGetCreatePeer(wg *WGLink) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + newPeer, err := wg.CreateNewPeer() + if err != nil { + slog.Error(err.Error()) + w.WriteHeader(http.StatusInternalServerError) + return + } + + tmpl, err := template.New("client.ini").Parse(templates.ClientINI) + if err != nil { + slog.Error(err.Error()) + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Add("Content-Type", CONTENT_PLAIN_TEXT) + err = tmpl.Execute(w, newPeer) + if err != nil { + slog.Error(err.Error()) + } + + // TODO: Add peer to device + + } +} + func HttpLogHandler2(h http.Handler) http.Handler { // https://blog.kowalczyk.info/article/e00e89c3841e4f8c8c769a78b8a90b47/logging-http-requests-in-go.html fn := func(w http.ResponseWriter, r* http.Request) { diff --git a/link.go b/link.go index 1aa9ab0..7d2385c 100644 --- a/link.go +++ b/link.go @@ -2,6 +2,7 @@ package hvpnnode3 import ( "errors" + "fmt" "net" "sync" "time" @@ -245,6 +246,64 @@ func (wg *WGLink) GetAllPeers() ([]wgtypes.Peer, error) { return dev.Peers, nil } +func (wg *WGLink) GetPublicKey() (*wgtypes.Key, error) { + dev, err := wg.Device(wg.Name) + if err != nil { + return nil, err + } + return &dev.PublicKey, nil +} + +// A peer config has it's own private key and the server node (peer section) endpoint and public key +type NewPeer struct { + Peer wgtypes.Peer // The server as a peer + PrivateKey wgtypes.Key + Address net.IP + DNS []net.IP + MTU uint + + Endpoint string // Domain name and port +} + +// Create a new peer. Used for server-side clinet config generation +// Peer is not added to the wglink +func (wg *WGLink) CreateNewPeer() (*NewPeer, error) { + dev, err := wg.Device(wg.Name) + if err != nil { + return nil, err + } + + privKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return nil, err + } + + serverPubkey, err := wg.GetPublicKey() + if err != nil { + return nil, err + } + + ip, err := wg.Allocate() + if err != nil { + return nil, err + } + + peer := NewPeer{ + Address: ip, + DNS: WG_CLIENT_DNS, + PrivateKey: privKey, + MTU: WG_CLIENT_MTU, + Peer: wgtypes.Peer{ + PublicKey: *serverPubkey, + AllowedIPs: []net.IPNet{wg.Network()}, + }, + Endpoint: fmt.Sprintf("%s:%d", wg.Endpoint, dev.ListenPort), + } + + return &peer, nil + +} + func createARemovePeerCfg(publickey wgtypes.Key) wgtypes.Config { rmPeerCfg := wgtypes.PeerConfig{ Remove: true, diff --git a/templates/client.ini.tmpl b/templates/client.ini.tmpl new file mode 100644 index 0000000..ab687ed --- /dev/null +++ b/templates/client.ini.tmpl @@ -0,0 +1,12 @@ +[Interface] +Address = {{ .Address }}/24 +PrivateKey = {{ .PrivateKey }} +DNS = {{$dnss := .DNS}}{{range $index, $element := .DNS}}{{if $index}}, {{end}}{{$element.String}}{{end}} +MTU = {{ .MTU }} + +[Peer] +PublicKey = {{ .Peer.PublicKey }} +Endpoint = {{ .Endpoint }} +AllowedIPs = 0.0.0.0/0, ::0/0 +PersistentKeepalive = 25 + diff --git a/templates/templates.go b/templates/templates.go new file mode 100644 index 0000000..5147e29 --- /dev/null +++ b/templates/templates.go @@ -0,0 +1,6 @@ +package templates + +import _ "embed" + +//go:embed client.ini.tmpl +var ClientINI string