2023-09-29 16:00:20 +02:00
|
|
|
/*
|
|
|
|
* ctrlserver controls the WireGuard mesh. Contains an IpcHandler for
|
|
|
|
* handling commands fired by wgmesh command.
|
|
|
|
* Contains an RpcHandler for handling commands fired by another server.
|
|
|
|
*/
|
2023-09-18 16:52:28 +02:00
|
|
|
package ctrlserver
|
|
|
|
|
|
|
|
import (
|
2023-10-01 21:14:09 +02:00
|
|
|
"context"
|
2023-09-20 00:50:44 +02:00
|
|
|
"errors"
|
|
|
|
"net"
|
2023-10-01 20:01:35 +02:00
|
|
|
"time"
|
2023-09-18 16:52:28 +02:00
|
|
|
|
2023-10-01 20:01:35 +02:00
|
|
|
"github.com/tim-beatham/wgmesh/pkg/auth"
|
|
|
|
"github.com/tim-beatham/wgmesh/pkg/conn"
|
2023-09-20 20:05:29 +02:00
|
|
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
2023-09-21 19:43:29 +02:00
|
|
|
"github.com/tim-beatham/wgmesh/pkg/wg"
|
2023-09-19 14:45:49 +02:00
|
|
|
"golang.zx2c4.com/wireguard/wgctrl"
|
|
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
2023-10-01 21:14:09 +02:00
|
|
|
"google.golang.org/grpc/metadata"
|
2023-09-18 16:52:28 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
2023-09-29 16:00:20 +02:00
|
|
|
* NewCtrlServer creates a new instance of the ctrlserver.
|
|
|
|
* It is associated with a WireGuard client and an interface.
|
|
|
|
* wgClient: Represents the WireGuard control client.
|
|
|
|
* ifName: WireGuard interface name
|
2023-09-18 16:52:28 +02:00
|
|
|
*/
|
2023-10-01 20:01:35 +02:00
|
|
|
func NewCtrlServer(wgClient *wgctrl.Client, conn *conn.WgCtrlConnection, ifName string) *MeshCtrlServer {
|
2023-09-18 16:52:28 +02:00
|
|
|
ctrlServer := new(MeshCtrlServer)
|
2023-09-19 14:45:49 +02:00
|
|
|
ctrlServer.Meshes = make(map[string]Mesh)
|
|
|
|
ctrlServer.Client = wgClient
|
2023-10-01 20:01:35 +02:00
|
|
|
ctrlServer.Conn = conn
|
2023-09-20 00:50:44 +02:00
|
|
|
ctrlServer.IfName = ifName
|
2023-10-01 20:01:35 +02:00
|
|
|
ctrlServer.JwtManager = auth.NewJwtManager("bob123", 24*time.Hour)
|
2023-10-01 21:14:09 +02:00
|
|
|
ctrlServer.TokenManager = auth.NewTokenManager()
|
2023-09-18 16:52:28 +02:00
|
|
|
return ctrlServer
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2023-09-29 16:00:20 +02:00
|
|
|
* MeshExists returns true if the client is part of the mesh
|
2023-09-18 16:52:28 +02:00
|
|
|
* false otherwise.
|
|
|
|
*/
|
2023-09-29 16:00:20 +02:00
|
|
|
func (server *MeshCtrlServer) MeshExists(meshId string) bool {
|
2023-09-18 16:52:28 +02:00
|
|
|
_, inMesh := server.Meshes[meshId]
|
|
|
|
return inMesh
|
|
|
|
}
|
|
|
|
|
2023-09-29 16:00:20 +02:00
|
|
|
/*
|
|
|
|
* CreateMesh creates a new mesh instance, adds it to the map
|
|
|
|
* of meshes and returns the newly created mesh.
|
|
|
|
*/
|
2023-09-19 14:45:49 +02:00
|
|
|
func (server *MeshCtrlServer) CreateMesh() (*Mesh, error) {
|
|
|
|
key, err := wgtypes.GenerateKey()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var mesh Mesh = Mesh{
|
|
|
|
SharedKey: &key,
|
|
|
|
Nodes: make(map[string]MeshNode),
|
|
|
|
}
|
|
|
|
|
|
|
|
server.Meshes[key.String()] = mesh
|
|
|
|
return &mesh, nil
|
|
|
|
}
|
2023-09-20 00:50:44 +02:00
|
|
|
|
2023-09-29 16:00:20 +02:00
|
|
|
/*
|
|
|
|
* AddHostArgs parameters needed to add
|
|
|
|
* a host to the mesh network
|
|
|
|
*/
|
2023-09-20 00:50:44 +02:00
|
|
|
type AddHostArgs struct {
|
2023-09-29 16:00:20 +02:00
|
|
|
// HostEndpoint: Public IP and port of the gRPC server the node is running
|
2023-09-20 00:50:44 +02:00
|
|
|
HostEndpoint string
|
2023-09-29 16:00:20 +02:00
|
|
|
// PubilcKey: WireGuard public key of the device
|
|
|
|
PublicKey string
|
|
|
|
// MeshId: Mesh ID of the node the the host is joining
|
|
|
|
MeshId string
|
|
|
|
// WgEndpoint: Public IP and port of the WireGuard server that is running
|
|
|
|
WgEndpoint string
|
|
|
|
// WgIp: SLAAC generated WireGuard IP of the node
|
|
|
|
WgIp string
|
2023-09-20 00:50:44 +02:00
|
|
|
}
|
|
|
|
|
2023-09-29 16:00:20 +02:00
|
|
|
/*
|
|
|
|
* AddHost adds a host to the mesh
|
|
|
|
*/
|
2023-09-20 00:50:44 +02:00
|
|
|
func (server *MeshCtrlServer) AddHost(args AddHostArgs) error {
|
|
|
|
nodes, contains := server.Meshes[args.MeshId]
|
|
|
|
|
|
|
|
if !contains {
|
2023-09-21 19:43:29 +02:00
|
|
|
return errors.New("The mesh: " + args.MeshId + " does not exist")
|
2023-09-20 00:50:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_, contains = nodes.Nodes[args.HostEndpoint]
|
|
|
|
|
|
|
|
if contains {
|
|
|
|
return errors.New("The node already has an endpoint in the mesh network")
|
|
|
|
}
|
|
|
|
|
|
|
|
node := MeshNode{
|
|
|
|
HostEndpoint: args.HostEndpoint,
|
|
|
|
WgEndpoint: args.WgEndpoint,
|
|
|
|
PublicKey: args.PublicKey,
|
2023-09-21 14:50:59 +02:00
|
|
|
WgHost: args.WgIp,
|
2023-09-20 00:50:44 +02:00
|
|
|
}
|
|
|
|
|
2023-09-29 16:00:20 +02:00
|
|
|
err := server.AddWgPeer(node)
|
2023-09-20 00:50:44 +02:00
|
|
|
|
|
|
|
if err == nil {
|
2023-09-20 15:34:34 +02:00
|
|
|
nodes.Nodes[args.HostEndpoint] = node
|
2023-09-20 00:50:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-29 16:00:20 +02:00
|
|
|
/*
|
|
|
|
* GetDevice gets the WireGuard client associated with the
|
|
|
|
* interface name.
|
|
|
|
*/
|
2023-09-20 00:50:44 +02:00
|
|
|
func (server *MeshCtrlServer) GetDevice() *wgtypes.Device {
|
|
|
|
dev, err := server.Client.Device(server.IfName)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return dev
|
|
|
|
}
|
|
|
|
|
2023-09-29 16:00:20 +02:00
|
|
|
/*
|
|
|
|
* AddWgPeer Updates the WireGuard configuration to include the peer
|
|
|
|
*/
|
|
|
|
func (server *MeshCtrlServer) AddWgPeer(node MeshNode) error {
|
2023-09-20 00:50:44 +02:00
|
|
|
peer := make([]wgtypes.PeerConfig, 1)
|
|
|
|
|
|
|
|
peerPublic, err := wgtypes.ParseKey(node.PublicKey)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
peerEndpoint, err := net.ResolveUDPAddr("udp", node.WgEndpoint)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
allowedIps := make([]net.IPNet, 1)
|
|
|
|
_, ipnet, err := net.ParseCIDR(node.WgHost)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
allowedIps[0] = *ipnet
|
|
|
|
|
|
|
|
peer[0] = wgtypes.PeerConfig{
|
|
|
|
PublicKey: peerPublic,
|
|
|
|
Endpoint: peerEndpoint,
|
|
|
|
AllowedIPs: allowedIps,
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg := wgtypes.Config{
|
|
|
|
Peers: peer,
|
|
|
|
}
|
|
|
|
|
2023-09-29 16:00:20 +02:00
|
|
|
server.Client.ConfigureDevice(server.IfName, cfg)
|
2023-09-20 00:50:44 +02:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-09-21 19:43:29 +02:00
|
|
|
|
2023-09-29 16:00:20 +02:00
|
|
|
/*
|
|
|
|
* EnableInterface: Enables the given WireGuard interface.
|
|
|
|
*/
|
2023-09-21 19:43:29 +02:00
|
|
|
func (s *MeshCtrlServer) EnableInterface(meshId string) error {
|
|
|
|
mesh, contains := s.Meshes[meshId]
|
|
|
|
|
|
|
|
if !contains {
|
|
|
|
return errors.New("Mesh does not exist")
|
|
|
|
}
|
|
|
|
|
|
|
|
endPoint := lib.GetOutboundIP().String() + ":8080"
|
|
|
|
|
|
|
|
node, contains := mesh.Nodes[endPoint]
|
|
|
|
|
|
|
|
if !contains {
|
|
|
|
return errors.New("Node does not exist in the mesh")
|
|
|
|
}
|
|
|
|
|
|
|
|
return wg.EnableInterface(s.IfName, node.WgHost)
|
|
|
|
}
|
2023-10-01 21:14:09 +02:00
|
|
|
|
|
|
|
func (s *MeshCtrlServer) AddToken(ctx context.Context, endpoint, meshId string) (context.Context, error) {
|
|
|
|
token, err := s.TokenManager.GetToken(meshId, endpoint)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return metadata.AppendToOutgoingContext(ctx, "authorization", token), nil
|
|
|
|
}
|