2023-09-18 18:00:43 +02:00
|
|
|
package ipc
|
|
|
|
|
|
|
|
import (
|
2023-09-19 19:29:35 +02:00
|
|
|
"context"
|
2023-09-18 18:00:43 +02:00
|
|
|
"errors"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
2023-09-19 19:29:35 +02:00
|
|
|
ipcRpc "net/rpc"
|
2023-09-18 18:00:43 +02:00
|
|
|
"os"
|
2023-09-21 14:50:59 +02:00
|
|
|
"slices"
|
2023-09-20 00:50:44 +02:00
|
|
|
"strconv"
|
2023-09-19 19:29:35 +02:00
|
|
|
"time"
|
2023-09-18 18:00:43 +02:00
|
|
|
|
2023-09-19 14:45:49 +02:00
|
|
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
2023-09-19 19:29:35 +02:00
|
|
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver/rpc"
|
2023-09-20 00:50:44 +02:00
|
|
|
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
2023-09-19 19:29:35 +02:00
|
|
|
ipctypes "github.com/tim-beatham/wgmesh/pkg/ipc"
|
2023-09-28 17:55:37 +02:00
|
|
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
|
|
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
|
|
|
"github.com/tim-beatham/wgmesh/pkg/slaac"
|
2023-09-19 14:45:49 +02:00
|
|
|
"github.com/tim-beatham/wgmesh/pkg/wg"
|
2023-09-20 15:34:34 +02:00
|
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
2023-09-19 19:29:35 +02:00
|
|
|
"google.golang.org/grpc"
|
|
|
|
"google.golang.org/grpc/credentials/insecure"
|
2023-09-18 18:00:43 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
|
|
|
|
|
|
|
type Mesh struct {
|
2023-09-19 14:45:49 +02:00
|
|
|
Server *ctrlserver.MeshCtrlServer
|
2023-09-18 18:00:43 +02:00
|
|
|
}
|
|
|
|
|
2023-09-28 17:55:37 +02:00
|
|
|
const MeshIfName = "wgmesh"
|
|
|
|
|
2023-09-18 18:00:43 +02:00
|
|
|
/*
|
|
|
|
* Create a new WireGuard mesh network
|
|
|
|
*/
|
|
|
|
func (n Mesh) CreateNewMesh(name *string, reply *string) error {
|
2023-09-28 17:55:37 +02:00
|
|
|
wg.CreateInterface(MeshIfName)
|
2023-09-19 14:45:49 +02:00
|
|
|
|
|
|
|
mesh, err := n.Server.CreateMesh()
|
2023-09-28 17:55:37 +02:00
|
|
|
ula, _ := slaac.NewULA(n.Server.GetDevice().PublicKey, "0")
|
|
|
|
|
|
|
|
outBoundIp := lib.GetOutboundIP().String()
|
|
|
|
|
|
|
|
addHostArgs := ctrlserver.AddHostArgs{
|
|
|
|
HostEndpoint: outBoundIp + ":8080",
|
|
|
|
PublicKey: n.Server.GetDevice().PublicKey.String(),
|
|
|
|
WgEndpoint: outBoundIp + ":51820",
|
|
|
|
WgIp: ula.CGA.GetIpv6().String() + "/128",
|
|
|
|
MeshId: mesh.SharedKey.String(),
|
|
|
|
}
|
|
|
|
|
|
|
|
n.Server.AddHost(addHostArgs)
|
2023-09-18 18:00:43 +02:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-19 14:45:49 +02:00
|
|
|
*reply = mesh.SharedKey.String()
|
2023-09-18 18:00:43 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-19 14:45:49 +02:00
|
|
|
func (n Mesh) ListMeshes(name *string, reply *map[string]ctrlserver.Mesh) error {
|
2023-09-19 19:29:35 +02:00
|
|
|
meshes := n.Server.Meshes
|
|
|
|
*reply = meshes
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-20 15:34:34 +02:00
|
|
|
func updateMesh(n *Mesh, meshId string, endPoint string) error {
|
|
|
|
conn, err := grpc.Dial(endPoint, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer conn.Close()
|
|
|
|
c := rpc.NewMeshCtrlServerClient(conn)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
getMeshReq := rpc.GetMeshRequest{
|
|
|
|
MeshId: meshId,
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := c.GetMesh(ctx, &getMeshReq)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
key, err := wgtypes.ParseKey(meshId)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
mesh := new(ctrlserver.Mesh)
|
|
|
|
mesh.Nodes = make(map[string]ctrlserver.MeshNode)
|
|
|
|
mesh.SharedKey = &key
|
|
|
|
n.Server.Meshes[meshId] = *mesh
|
|
|
|
|
|
|
|
for _, node := range r.GetMeshNode() {
|
|
|
|
meshNode := ctrlserver.MeshNode{
|
|
|
|
PublicKey: node.PublicKey,
|
|
|
|
HostEndpoint: node.Endpoint,
|
|
|
|
WgEndpoint: node.WgEndpoint,
|
|
|
|
WgHost: node.WgHost,
|
|
|
|
}
|
|
|
|
|
2023-09-21 14:50:59 +02:00
|
|
|
n.Server.Meshes[meshId].Nodes[meshNode.HostEndpoint] = meshNode
|
2023-09-20 15:34:34 +02:00
|
|
|
ctrlserver.AddWgPeer(n.Server.IfName, n.Server.Client, meshNode)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-21 14:50:59 +02:00
|
|
|
func updatePeer(n *Mesh, node ctrlserver.MeshNode, wgHost string, meshId string) error {
|
|
|
|
conn, err := grpc.Dial(node.HostEndpoint, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
|
|
|
c := rpc.NewMeshCtrlServerClient(conn)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
dev := n.Server.GetDevice()
|
2023-09-28 17:55:37 +02:00
|
|
|
|
2023-09-21 14:50:59 +02:00
|
|
|
joinMeshReq := rpc.JoinMeshRequest{
|
|
|
|
MeshId: meshId,
|
|
|
|
HostPort: 8080,
|
|
|
|
PublicKey: dev.PublicKey.String(),
|
|
|
|
WgPort: int32(dev.ListenPort),
|
|
|
|
WgIp: wgHost,
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := c.JoinMesh(ctx, &joinMeshReq)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !r.GetSuccess() {
|
|
|
|
return errors.New("Could not join the mesh")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func updatePeers(n *Mesh, meshId string, wgHost string, nodesToExclude []string) error {
|
|
|
|
for _, node := range n.Server.Meshes[meshId].Nodes {
|
|
|
|
nodeEndpoint := node.HostEndpoint
|
|
|
|
|
|
|
|
if !slices.Contains(nodesToExclude, nodeEndpoint) {
|
|
|
|
// Best effort service
|
|
|
|
err := updatePeer(n, node, wgHost, meshId)
|
|
|
|
|
|
|
|
if err != nil {
|
2023-09-28 17:55:37 +02:00
|
|
|
return err
|
2023-09-21 14:50:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-09-20 20:05:29 +02:00
|
|
|
|
2023-09-19 19:29:35 +02:00
|
|
|
func (n Mesh) JoinMesh(args *ipctypes.JoinMeshArgs, reply *string) error {
|
|
|
|
conn, err := grpc.Dial(args.IpAdress+":8080", grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer conn.Close()
|
|
|
|
|
|
|
|
c := rpc.NewMeshCtrlServerClient(conn)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
|
|
|
defer cancel()
|
|
|
|
|
2023-09-20 00:50:44 +02:00
|
|
|
dev := n.Server.GetDevice()
|
2023-09-28 17:55:37 +02:00
|
|
|
ula, _ := slaac.NewULA(dev.PublicKey, "0")
|
2023-09-20 00:50:44 +02:00
|
|
|
|
2023-09-28 17:55:37 +02:00
|
|
|
logging.InfoLog.Println("WgIP: " + ula.CGA.GetIpv6().String())
|
2023-09-21 14:50:59 +02:00
|
|
|
|
2023-09-20 00:50:44 +02:00
|
|
|
joinMeshReq := rpc.JoinMeshRequest{
|
|
|
|
MeshId: args.MeshId,
|
|
|
|
HostPort: 8080,
|
|
|
|
PublicKey: dev.PublicKey.String(),
|
|
|
|
WgPort: int32(dev.ListenPort),
|
2023-09-28 17:55:37 +02:00
|
|
|
WgIp: ula.CGA.GetIpv6().String() + "/128",
|
2023-09-20 00:50:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
r, err := c.JoinMesh(ctx, &joinMeshReq)
|
2023-09-19 19:29:35 +02:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-20 15:34:34 +02:00
|
|
|
if r.GetSuccess() {
|
|
|
|
updateMesh(&n, args.MeshId, args.IpAdress+":8080")
|
|
|
|
}
|
|
|
|
|
2023-09-21 14:50:59 +02:00
|
|
|
err = updatePeers(&n, args.MeshId, r.GetMeshIp(), make([]string, 0))
|
|
|
|
|
2023-09-20 00:50:44 +02:00
|
|
|
*reply = strconv.FormatBool(r.GetSuccess())
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n Mesh) GetMesh(meshId string, reply *ipc.GetMeshReply) error {
|
|
|
|
mesh, contains := n.Server.Meshes[meshId]
|
|
|
|
|
|
|
|
if contains {
|
|
|
|
nodes := make([]ctrlserver.MeshNode, len(mesh.Nodes))
|
|
|
|
|
|
|
|
i := 0
|
|
|
|
for _, n := range mesh.Nodes {
|
|
|
|
nodes[i] = n
|
|
|
|
i += 1
|
|
|
|
}
|
|
|
|
|
|
|
|
*reply = ipc.GetMeshReply{Nodes: nodes}
|
|
|
|
} else {
|
2023-09-21 14:50:59 +02:00
|
|
|
return errors.New("mesh does not exist")
|
2023-09-20 00:50:44 +02:00
|
|
|
}
|
2023-09-19 19:29:35 +02:00
|
|
|
return nil
|
2023-09-19 14:45:49 +02:00
|
|
|
}
|
|
|
|
|
2023-09-21 19:43:29 +02:00
|
|
|
func (n Mesh) EnableInterface(meshId string, reply *string) error {
|
|
|
|
err := n.Server.EnableInterface(meshId)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
*reply = "up"
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-19 14:45:49 +02:00
|
|
|
func RunIpcHandler(server *ctrlserver.MeshCtrlServer) error {
|
2023-09-18 18:00:43 +02:00
|
|
|
if err := os.RemoveAll(SockAddr); err != nil {
|
|
|
|
return errors.New("Could not find to address")
|
|
|
|
}
|
|
|
|
|
|
|
|
newMeshIpc := new(Mesh)
|
2023-09-19 14:45:49 +02:00
|
|
|
newMeshIpc.Server = server
|
2023-09-19 19:29:35 +02:00
|
|
|
ipcRpc.Register(newMeshIpc)
|
|
|
|
ipcRpc.HandleHTTP()
|
2023-09-18 18:00:43 +02:00
|
|
|
|
|
|
|
l, e := net.Listen("unix", SockAddr)
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
http.Serve(l, nil)
|
|
|
|
return nil
|
|
|
|
}
|