feat: Add, Check, Get, and Delete peers
This commit is contained in:
parent
4a1039e5b1
commit
eb97d49d1f
@ -6,6 +6,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"time"
|
"time"
|
||||||
@ -58,8 +59,9 @@ func run(ctx *cli.Context) {
|
|||||||
slog.Debug("Starting run()")
|
slog.Debug("Starting run()")
|
||||||
|
|
||||||
apiMux := http.NewServeMux()
|
apiMux := http.NewServeMux()
|
||||||
apiMux.HandleFunc("GET /peer", hvpnnode3.HandleGetPeer(wgLink))
|
apiMux.HandleFunc("GET /peer/{pubkey}", hvpnnode3.HandleGetPeer(wgLink))
|
||||||
apiMux.HandleFunc("POST /peer", hvpnnode3.HandlePostPeer(IPPool, wgLink))
|
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 /peers", hvpnnode3.HandleGetPeers(wgLink))
|
||||||
|
|
||||||
var handler http.Handler = apiMux
|
var handler http.Handler = apiMux
|
||||||
@ -262,6 +264,7 @@ func setup() error {
|
|||||||
slog.Debug("main.testVip: Test IP Freed")
|
slog.Debug("main.testVip: Test IP Freed")
|
||||||
|
|
||||||
IPPool = ipPool
|
IPPool = ipPool
|
||||||
|
wgLink.IPPool = ipPool
|
||||||
|
|
||||||
//defer wgLink.Close()
|
//defer wgLink.Close()
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
@ -289,7 +292,10 @@ func testWgPeerAdd(wgLink *hvpnnode3.WGLink) error {
|
|||||||
}
|
}
|
||||||
publicKey := privateKey.PublicKey()
|
publicKey := privateKey.PublicKey()
|
||||||
|
|
||||||
ip, err := IPPool.Allocate()
|
urlsafe := url.QueryEscape(publicKey.String())
|
||||||
|
slog.Debug(urlsafe)
|
||||||
|
|
||||||
|
ip, err := wgLink.Allocate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -323,7 +329,7 @@ func testWgPeerAdd(wgLink *hvpnnode3.WGLink) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
slog.Debug("Removed test peer")
|
slog.Debug("Removed test peer")
|
||||||
IPPool.Free(ip)
|
wgLink.Free(ip)
|
||||||
slog.Debug("Freed test peer ip")
|
slog.Debug("Freed test peer ip")
|
||||||
|
|
||||||
|
|
||||||
|
1
go.mod
1
go.mod
@ -4,6 +4,7 @@ go 1.22.0
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/felixge/httpsnoop v1.0.4
|
github.com/felixge/httpsnoop v1.0.4
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
github.com/urfave/cli/v2 v2.27.1
|
github.com/urfave/cli/v2 v2.27.1
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||||
|
2
go.sum
2
go.sum
@ -4,6 +4,8 @@ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2
|
|||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||||
|
187
handlers.go
187
handlers.go
@ -1,29 +1,51 @@
|
|||||||
package hvpnnode3
|
package hvpnnode3
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/felixge/httpsnoop"
|
"github.com/felixge/httpsnoop"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"gitea.hbanafa.com/HeshamTB/hvpn-node3/proto"
|
"gitea.hbanafa.com/HeshamTB/hvpn-node3/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CtxKey string
|
||||||
|
const CtxReqID CtxKey = "request_id"
|
||||||
|
|
||||||
func HandleGetPeer(wgLink *WGLink) http.HandlerFunc {
|
func HandleGetPeer(wgLink *WGLink) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusNotImplemented)
|
reqID := r.Context().Value(CtxReqID).(uuid.UUID)
|
||||||
slog.Info("GET Peer is not implemented")
|
pubkey := r.PathValue("pubkey")
|
||||||
|
debug(pubkey, reqID)
|
||||||
|
peer, err := wgLink.GetPeer(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, proto.PeerDoesNotExist){
|
||||||
|
json.NewEncoder(w).Encode(
|
||||||
|
proto.ErrJSONResponse{Message: "Peer does not exist"},
|
||||||
|
)
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.NewEncoder(w).Encode(proto.WgPeerToPeer(*peer))
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleGetPeers(wgLink *WGLink) http.HandlerFunc {
|
func HandleGetPeers(wgLink *WGLink) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
reqID := r.Context().Value(CtxReqID).(uuid.UUID)
|
||||||
|
debug("GET Peers for", reqID)
|
||||||
dev, err := wgLink.Device(wgLink.Name)
|
dev, err := wgLink.Device(wgLink.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
@ -32,13 +54,7 @@ func HandleGetPeers(wgLink *WGLink) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
var peers []proto.Peer
|
var peers []proto.Peer
|
||||||
for _, peer := range dev.Peers {
|
for _, peer := range dev.Peers {
|
||||||
p := proto.Peer{
|
p := proto.WgPeerToPeer(peer)
|
||||||
Address: peer.AllowedIPs[0].IP,
|
|
||||||
PublicKey: peer.PublicKey.String(),
|
|
||||||
PersistentKeepalive: peer.PersistentKeepaliveInterval,
|
|
||||||
TX: peer.TransmitBytes,
|
|
||||||
RX: peer.ReceiveBytes,
|
|
||||||
}
|
|
||||||
peers = append(peers, p)
|
peers = append(peers, p)
|
||||||
}
|
}
|
||||||
err = json.NewEncoder(w).Encode(peers)
|
err = json.NewEncoder(w).Encode(peers)
|
||||||
@ -48,8 +64,11 @@ func HandleGetPeers(wgLink *WGLink) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func HandlePostPeer(IPPool IPPool, wgLink *WGLink) http.HandlerFunc {
|
|
||||||
|
func HandlePostPeer(wgLink *WGLink) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r* http.Request) {
|
return func(w http.ResponseWriter, r* http.Request) {
|
||||||
|
reqID := r.Context().Value(CtxReqID).(uuid.UUID)
|
||||||
|
debug("POST Peer for", reqID)
|
||||||
peerRequest := proto.CreatePeerRequest{}
|
peerRequest := proto.CreatePeerRequest{}
|
||||||
err := json.NewDecoder(r.Body).Decode(&peerRequest)
|
err := json.NewDecoder(r.Body).Decode(&peerRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -59,79 +78,105 @@ func HandlePostPeer(IPPool IPPool, wgLink *WGLink) http.HandlerFunc {
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO: Check if pubkey is already registered
|
|
||||||
dev, err := wgLink.Device(wgLink.Name)
|
|
||||||
if err != nil {
|
|
||||||
slog.Error(err.Error())
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, peer := range dev.Peers {
|
|
||||||
if peer.PublicKey.String() == peerRequest.PublicKey {
|
|
||||||
w.WriteHeader(http.StatusAccepted)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newIP, err := IPPool.Allocate()
|
|
||||||
if err != nil {
|
|
||||||
slog.Error(err.Error())
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add peer to wg device
|
|
||||||
// TODO: Declare subnet mask for the service
|
|
||||||
pkey, _ := wgtypes.GeneratePrivateKey()
|
|
||||||
newPeer := wgtypes.PeerConfig{
|
|
||||||
PublicKey: pkey.PublicKey(),
|
|
||||||
ReplaceAllowedIPs: true,
|
|
||||||
AllowedIPs: []net.IPNet{
|
|
||||||
{
|
|
||||||
IP: newIP,
|
|
||||||
Mask: net.IPv4Mask(255, 255, 255, 255),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
err = wgLink.ConfigureDevice(
|
|
||||||
wgLink.Name,
|
|
||||||
wgtypes.Config{
|
|
||||||
Peers: []wgtypes.PeerConfig{
|
|
||||||
newPeer,
|
|
||||||
},
|
|
||||||
ReplacePeers: false,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
slog.Error(err.Error())
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if valid := ValidKey(peerRequest.PublicKey); !valid {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
json.NewEncoder(w).Encode(
|
json.NewEncoder(w).Encode(
|
||||||
&proto.Peer{
|
proto.ErrJSONResponse{Message: "Invalid public key"},
|
||||||
Address: newIP,
|
|
||||||
MTU: 1384,
|
|
||||||
PublicKey: peerRequest.PublicKey,
|
|
||||||
Endpoint: "vpn.test.com:8487",
|
|
||||||
AllowedIPs: net.ParseIP("0.0.0.0/0"),
|
|
||||||
PersistentKeepalive: 25,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
exists, err := wgLink.Exists(peerRequest.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
json.NewEncoder(w).Encode(
|
||||||
|
proto.ErrJSONResponse{Message: "Error while checking peer existance"},
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
debugf("Peer %s already exists", reqID, peerRequest.PublicKey)
|
||||||
|
w.WriteHeader(http.StatusFound)
|
||||||
|
peer, err := wgLink.GetPeer(peerRequest.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
json.NewEncoder(w).Encode(
|
||||||
|
proto.WgPeerToPeer(*peer),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
peer, err := wgLink.AddPeer(peerRequest.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error(err.Error())
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
json.NewEncoder(w).Encode(
|
||||||
|
proto.ErrJSONResponse{Message: "Error while adding peer"},
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
debugf("Allocated IP: %s", reqID, peer.AllowedIPs[0].IP.String())
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
json.NewEncoder(w).Encode(
|
||||||
|
proto.WgPeerToPeer(*peer),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HandleDeletePeer(wg *WGLink) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
reqId := r.Context().Value(CtxReqID).(uuid.UUID)
|
||||||
|
pubkey := r.PathValue("pubkey")
|
||||||
|
debugf("DELETE Peer %s", reqId, pubkey)
|
||||||
|
exists, err := wg.Exists(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
slog.Error(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
json.NewEncoder(w).Encode(
|
||||||
|
proto.ErrJSONResponse{Message: "Peer does not exist"},
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = wg.DeletePeer(pubkey)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
json.NewEncoder(w).Encode(
|
||||||
|
proto.ErrJSONResponse{Message: "Error while deleting peer"},
|
||||||
|
)
|
||||||
|
slog.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
reqID, _ := uuid.NewRandom()
|
||||||
|
rCtx := context.WithValue(r.Context(), CtxReqID, reqID)
|
||||||
|
r = r.WithContext(rCtx)
|
||||||
|
slog.Info(fmt.Sprintf("Starting request with ID: %s", reqID.String()))
|
||||||
m := httpsnoop.CaptureMetrics(h, w, r)
|
m := httpsnoop.CaptureMetrics(h, w, r)
|
||||||
msg := fmt.Sprintf(
|
msg := fmt.Sprintf(
|
||||||
"%s %s %s %d %s", r.RemoteAddr, r.Method,
|
"[HTTP] %s %s %s %d %s %s", r.RemoteAddr, r.Method,
|
||||||
r.URL.String(),m.Code, m.Duration)
|
r.URL.String(),m.Code, m.Duration, reqID.String())
|
||||||
slog.Info(msg)
|
slog.Info(msg)
|
||||||
}
|
}
|
||||||
return http.HandlerFunc(fn)
|
return http.HandlerFunc(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func debugf(format string, reqID uuid.UUID, args ...any) {
|
||||||
|
format = format + " " + reqID.String()
|
||||||
|
slog.Debug(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func debug(msg string, reqID uuid.UUID) {
|
||||||
|
msg = msg + " " + reqID.String()
|
||||||
|
debugf("%s", reqID, msg)
|
||||||
|
}
|
||||||
|
138
link.go
138
link.go
@ -2,15 +2,26 @@ package hvpnnode3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.hbanafa.com/HeshamTB/hvpn-node3/proto"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var SINGLE_IP_MASK net.IPMask = net.IPv4Mask(255, 255, 255, 255)
|
||||||
|
var PEER_KEEP_ALIVE_INTERVAL time.Duration = time.Second * 25
|
||||||
|
|
||||||
type WGLink struct {
|
type WGLink struct {
|
||||||
*netlink.LinkAttrs
|
*netlink.LinkAttrs
|
||||||
*wgctrl.Client
|
*wgctrl.Client
|
||||||
|
IPPool
|
||||||
|
lock *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retruns an existing or create a WGLink
|
// Retruns an existing or create a WGLink
|
||||||
@ -48,6 +59,8 @@ func InitWGLink(ifName string, privateKey *wgtypes.Key, port int) (*WGLink, erro
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wg.lock = &sync.Mutex{}
|
||||||
|
|
||||||
return &wg, netlink.LinkSetUp(&wg)
|
return &wg, netlink.LinkSetUp(&wg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +85,131 @@ func (wg *WGLink) initClient() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adds a peer to the wireguard netlink.
|
||||||
|
func (wg *WGLink) AddPeer(publicKey string) (*wgtypes.Peer, error) {
|
||||||
|
slog.Debug(fmt.Sprintf("Trying to add peer %s", publicKey))
|
||||||
|
pubKey, err := wgtypes.ParseKey(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
exists, err := wg.exists(pubKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if exists {
|
||||||
|
return nil, proto.PeerExistsErr{PublicKey: publicKey}
|
||||||
|
}
|
||||||
|
|
||||||
|
peerIp, err := wg.Allocate()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
peerConfig := wgtypes.PeerConfig{
|
||||||
|
PublicKey: pubKey,
|
||||||
|
AllowedIPs: []net.IPNet{
|
||||||
|
{
|
||||||
|
IP: peerIp,
|
||||||
|
Mask: SINGLE_IP_MASK,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PersistentKeepaliveInterval: &PEER_KEEP_ALIVE_INTERVAL,
|
||||||
|
ReplaceAllowedIPs: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
wgConf := wgtypes.Config{
|
||||||
|
ReplacePeers: false,
|
||||||
|
Peers: []wgtypes.PeerConfig{peerConfig},
|
||||||
|
}
|
||||||
|
|
||||||
|
err = wg.ApplyConfig(wgConf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return wg.getPeer(pubKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WGLink) DeletePeer(publickey string) error {
|
||||||
|
pkey, err := wgtypes.ParseKey(publickey)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return wg.deletePeer(pkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WGLink) deletePeer(publickey wgtypes.Key) error {
|
||||||
|
rmCfg := createARemovePeerCfg(publickey)
|
||||||
|
return wg.ApplyConfig(rmCfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WGLink) Exists(publicKey string) (bool, error) {
|
||||||
|
pubkey, err := wgtypes.ParseKey(publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return wg.exists(pubkey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WGLink) exists(pubkey wgtypes.Key) (bool, error) {
|
||||||
|
|
||||||
|
dev, err := wg.Client.Device(wg.Name)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, peer := range dev.Peers {
|
||||||
|
if peer.PublicKey == pubkey {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calls wgctrl.ConfigureDevice wrapped with a Mutex to ensure sync
|
||||||
|
func (wg *WGLink) ApplyConfig(cfg wgtypes.Config) error {
|
||||||
|
wg.lock.Lock()
|
||||||
|
defer wg.lock.Unlock()
|
||||||
|
return wg.ConfigureDevice(wg.Name, cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WGLink) GetPeer(publickey string) (*wgtypes.Peer, error) {
|
||||||
|
k, err := wgtypes.ParseKey(publickey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return wg.getPeer(k)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wg *WGLink) getPeer(pubkey wgtypes.Key) (*wgtypes.Peer, error) {
|
||||||
|
dev, err := wg.Device(wg.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, peer := range dev.Peers {
|
||||||
|
if peer.PublicKey == pubkey {
|
||||||
|
return &peer, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, proto.PeerDoesNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
func createARemovePeerCfg(publickey wgtypes.Key) wgtypes.Config {
|
||||||
|
rmPeerCfg := wgtypes.PeerConfig{
|
||||||
|
Remove: true,
|
||||||
|
PublicKey: publickey,
|
||||||
|
}
|
||||||
|
return wgtypes.Config{
|
||||||
|
Peers: []wgtypes.PeerConfig{rmPeerCfg},
|
||||||
|
ReplacePeers: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidKey(key string) bool {
|
||||||
|
_, err := wgtypes.ParseKey(key)
|
||||||
|
if err != nil { return false }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
20
proto/conv.go
Normal file
20
proto/conv.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package proto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WgPeerToPeer(peer wgtypes.Peer) Peer {
|
||||||
|
|
||||||
|
return Peer{
|
||||||
|
PublicKey: peer.PublicKey.String(),
|
||||||
|
PublicKeyUrlSafe: url.QueryEscape(peer.PublicKey.String()),
|
||||||
|
MTU: 1380,
|
||||||
|
TX: peer.TransmitBytes,
|
||||||
|
RX: peer.ReceiveBytes,
|
||||||
|
AllowedIPs: peer.AllowedIPs[0].IP,
|
||||||
|
PersistentKeepalive: peer.PersistentKeepaliveInterval,
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,18 @@
|
|||||||
package proto
|
package proto
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
type ErrJSONResponse struct {
|
type ErrJSONResponse struct {
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PeerExistsErr struct {
|
||||||
|
PublicKey string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e PeerExistsErr) Error() string {
|
||||||
|
return e.PublicKey
|
||||||
|
}
|
||||||
|
|
||||||
|
var PeerDoesNotExist = errors.New("Peer does not exist")
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ type CreatePeerRequest struct {
|
|||||||
/* JSON returned for user to use. This means that the peer can connect with
|
/* JSON returned for user to use. This means that the peer can connect with
|
||||||
these parameters as a wireguard peer */
|
these parameters as a wireguard peer */
|
||||||
type Peer struct {
|
type Peer struct {
|
||||||
Address net.IP `json:"address"`
|
|
||||||
MTU uint16 `json:"mtu"`
|
MTU uint16 `json:"mtu"`
|
||||||
PublicKey string `json:"public_key"`
|
PublicKey string `json:"public_key"`
|
||||||
|
PublicKeyUrlSafe string `json:"public_key_url_safe"`
|
||||||
Endpoint string `json:"endpoint"`
|
Endpoint string `json:"endpoint"`
|
||||||
AllowedIPs net.IP `json:"allowed_ips"`
|
AllowedIPs net.IP `json:"allowed_ips"`
|
||||||
PersistentKeepalive time.Duration `json:"presistent_keepalive"`
|
PersistentKeepalive time.Duration `json:"presistent_keepalive"`
|
||||||
@ -23,4 +23,3 @@ type Peer struct {
|
|||||||
RX int64
|
RX int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user