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
This commit is contained in:
HeshamTB 2024-03-27 09:28:13 +03:00
parent d6aa213461
commit 8e798706e3
6 changed files with 119 additions and 0 deletions

View File

@ -65,6 +65,7 @@ func run(ctx *cli.Context) {
apiMux.HandleFunc("POST /peer", hvpnnode3.HandlePostPeer(wgLink)) apiMux.HandleFunc("POST /peer", hvpnnode3.HandlePostPeer(wgLink))
apiMux.HandleFunc("DELETE /peer/{pubkey}", hvpnnode3.HandleDeletePeer(wgLink)) apiMux.HandleFunc("DELETE /peer/{pubkey}", hvpnnode3.HandleDeletePeer(wgLink))
apiMux.HandleFunc("GET /peers", hvpnnode3.HandleGetPeers(wgLink)) apiMux.HandleFunc("GET /peers", hvpnnode3.HandleGetPeers(wgLink))
apiMux.HandleFunc("GET /peer/new", hvpnnode3.HandleGetCreatePeer(wgLink))
var handler http.Handler = apiMux var handler http.Handler = apiMux
handler = hvpnnode3.HttpAuthToken(handler, ctx.String("http-api-key")) handler = hvpnnode3.HttpAuthToken(handler, ctx.String("http-api-key"))

View File

@ -1,5 +1,17 @@
package hvpnnode3 package hvpnnode3
import "net"
const ( const (
CONTENT_JSON = "application/json" 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"),
}
) )

View File

@ -8,12 +8,14 @@ import (
"log/slog" "log/slog"
"net/http" "net/http"
"net/url" "net/url"
"text/template"
"time" "time"
"github.com/felixge/httpsnoop" "github.com/felixge/httpsnoop"
"github.com/google/uuid" "github.com/google/uuid"
"gitea.hbanafa.com/HeshamTB/hvpn-node3/proto" "gitea.hbanafa.com/HeshamTB/hvpn-node3/proto"
"gitea.hbanafa.com/HeshamTB/hvpn-node3/templates"
) )
type CtxKey string 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 { func HttpLogHandler2(h http.Handler) http.Handler {
// https://blog.kowalczyk.info/article/e00e89c3841e4f8c8c769a78b8a90b47/logging-http-requests-in-go.html // https://blog.kowalczyk.info/article/e00e89c3841e4f8c8c769a78b8a90b47/logging-http-requests-in-go.html
fn := func(w http.ResponseWriter, r* http.Request) { fn := func(w http.ResponseWriter, r* http.Request) {

59
link.go
View File

@ -2,6 +2,7 @@ package hvpnnode3
import ( import (
"errors" "errors"
"fmt"
"net" "net"
"sync" "sync"
"time" "time"
@ -245,6 +246,64 @@ func (wg *WGLink) GetAllPeers() ([]wgtypes.Peer, error) {
return dev.Peers, nil 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 { func createARemovePeerCfg(publickey wgtypes.Key) wgtypes.Config {
rmPeerCfg := wgtypes.PeerConfig{ rmPeerCfg := wgtypes.PeerConfig{
Remove: true, Remove: true,

12
templates/client.ini.tmpl Normal file
View File

@ -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

6
templates/templates.go Normal file
View File

@ -0,0 +1,6 @@
package templates
import _ "embed"
//go:embed client.ini.tmpl
var ClientINI string