mirror of
https://github.com/tim-beatham/smegmesh.git
synced 2025-07-02 21:40:10 +02:00
Compare commits
18 Commits
53-run-com
...
61-improve
Author | SHA1 | Date | |
---|---|---|---|
0cc3141b58 | |||
ceb43a1db1 | |||
bed59f120f | |||
8aab4e99d8 | |||
cf4be1ccab | |||
6ed32f3a79 | |||
b6199892f0 | |||
ad22f04b0d | |||
092d9a4af5 | |||
19abf712a6 | |||
b296e1f45a | |||
2dc89d171b | |||
13bea10638 | |||
3222d7e388 | |||
1789d203f6 | |||
a5074a536e | |||
acb90a5679 | |||
27ec23f133 |
@ -13,21 +13,20 @@ import (
|
||||
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
||||
|
||||
type CreateMeshParams struct {
|
||||
Client *ipcRpc.Client
|
||||
WgPort int
|
||||
Endpoint string
|
||||
Role string
|
||||
Client *ipcRpc.Client
|
||||
Endpoint string
|
||||
WgArgs ipc.WireGuardArgs
|
||||
AdvertiseRoutes bool
|
||||
AdvertiseDefault bool
|
||||
}
|
||||
|
||||
func createMesh(args *CreateMeshParams) string {
|
||||
func createMesh(params *CreateMeshParams) string {
|
||||
var reply string
|
||||
newMeshParams := ipc.NewMeshArgs{
|
||||
WgPort: args.WgPort,
|
||||
Endpoint: args.Endpoint,
|
||||
Role: args.Role,
|
||||
WgArgs: params.WgArgs,
|
||||
}
|
||||
|
||||
err := args.Client.Call("IpcHandler.CreateMesh", &newMeshParams, &reply)
|
||||
err := params.Client.Call("IpcHandler.CreateMesh", &newMeshParams, &reply)
|
||||
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
@ -52,13 +51,13 @@ func listMeshes(client *ipcRpc.Client) {
|
||||
}
|
||||
|
||||
type JoinMeshParams struct {
|
||||
Client *ipcRpc.Client
|
||||
MeshId string
|
||||
IpAddress string
|
||||
IfName string
|
||||
WgPort int
|
||||
Endpoint string
|
||||
Role string
|
||||
Client *ipcRpc.Client
|
||||
MeshId string
|
||||
IpAddress string
|
||||
Endpoint string
|
||||
WgArgs ipc.WireGuardArgs
|
||||
AdvertiseRoutes bool
|
||||
AdvertiseDefault bool
|
||||
}
|
||||
|
||||
func joinMesh(params *JoinMeshParams) string {
|
||||
@ -67,8 +66,7 @@ func joinMesh(params *JoinMeshParams) string {
|
||||
args := ipc.JoinMeshArgs{
|
||||
MeshId: params.MeshId,
|
||||
IpAdress: params.IpAddress,
|
||||
Port: params.WgPort,
|
||||
Role: params.Role,
|
||||
WgArgs: params.WgArgs,
|
||||
}
|
||||
|
||||
err := params.Client.Call("IpcHandler.JoinMesh", &args, &reply)
|
||||
@ -93,19 +91,6 @@ func leaveMesh(client *ipcRpc.Client, meshId string) {
|
||||
fmt.Println(reply)
|
||||
}
|
||||
|
||||
func enableInterface(client *ipcRpc.Client, meshId string) {
|
||||
var reply string
|
||||
|
||||
err := client.Call("IpcHandler.EnableInterface", &meshId, &reply)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(reply)
|
||||
}
|
||||
|
||||
func getGraph(client *ipcRpc.Client, meshId string) {
|
||||
var reply string
|
||||
|
||||
@ -191,31 +176,13 @@ func deleteService(client *ipcRpc.Client, service string) {
|
||||
fmt.Println(reply)
|
||||
}
|
||||
|
||||
func getNode(client *ipcRpc.Client, nodeId, meshId string) {
|
||||
var reply string
|
||||
args := &ipc.GetNodeArgs{
|
||||
NodeId: nodeId,
|
||||
MeshId: meshId,
|
||||
}
|
||||
|
||||
err := client.Call("IpcHandler.GetNode", &args, &reply)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(reply)
|
||||
}
|
||||
|
||||
func main() {
|
||||
parser := argparse.NewParser("wg-mesh",
|
||||
"wg-mesh Manipulate WireGuard meshes")
|
||||
"wg-mesh Manipulate WireGuard mesh networks")
|
||||
|
||||
newMeshCmd := parser.NewCommand("new-mesh", "Create a new mesh")
|
||||
listMeshCmd := parser.NewCommand("list-meshes", "List meshes the node is connected to")
|
||||
joinMeshCmd := parser.NewCommand("join-mesh", "Join a mesh network")
|
||||
enableInterfaceCmd := parser.NewCommand("enable-interface", "Enable A Specific Mesh Interface")
|
||||
getGraphCmd := parser.NewCommand("get-graph", "Convert a mesh into DOT format")
|
||||
leaveMeshCmd := parser.NewCommand("leave-mesh", "Leave a mesh network")
|
||||
queryMeshCmd := parser.NewCommand("query-mesh", "Query a mesh network using JMESPath")
|
||||
@ -223,38 +190,116 @@ func main() {
|
||||
putAliasCmd := parser.NewCommand("put-alias", "Place an alias for the node")
|
||||
setServiceCmd := parser.NewCommand("set-service", "Place a service into your advertisements")
|
||||
deleteServiceCmd := parser.NewCommand("delete-service", "Remove a service from your advertisements")
|
||||
getNodeCmd := parser.NewCommand("get-node", "Get a specific node from the mesh")
|
||||
|
||||
var newMeshPort *int = newMeshCmd.Int("p", "wgport", &argparse.Options{})
|
||||
var newMeshEndpoint *string = newMeshCmd.String("e", "endpoint", &argparse.Options{})
|
||||
var newMeshRole *string = newMeshCmd.Selector("r", "role", []string{"peer", "client"}, &argparse.Options{})
|
||||
var newMeshPort *int = newMeshCmd.Int("p", "wgport", &argparse.Options{
|
||||
Default: 0,
|
||||
Help: "WireGuard port to use to the interface. A default of 0 uses an unused ephmeral port.",
|
||||
})
|
||||
|
||||
var joinMeshId *string = joinMeshCmd.String("m", "mesh", &argparse.Options{Required: true})
|
||||
var joinMeshIpAddress *string = joinMeshCmd.String("i", "ip", &argparse.Options{Required: true})
|
||||
var joinMeshPort *int = joinMeshCmd.Int("p", "wgport", &argparse.Options{})
|
||||
var joinMeshEndpoint *string = joinMeshCmd.String("e", "endpoint", &argparse.Options{})
|
||||
var joinMeshRole *string = joinMeshCmd.Selector("r", "role", []string{"peer", "client"}, &argparse.Options{})
|
||||
var newMeshEndpoint *string = newMeshCmd.String("e", "endpoint", &argparse.Options{
|
||||
Help: "Publicly routeable endpoint to advertise within the mesh",
|
||||
})
|
||||
|
||||
var enableInterfaceMeshId *string = enableInterfaceCmd.String("m", "mesh", &argparse.Options{Required: true})
|
||||
var newMeshRole *string = newMeshCmd.Selector("r", "role", []string{"peer", "client"}, &argparse.Options{
|
||||
Default: "peer",
|
||||
Help: "Role in the mesh network. A value of peer means that the node is publicly routeable and thus considered" +
|
||||
" in the gossip protocol. Client means that the node is not publicly routeable and is not a candidate in the gossip" +
|
||||
" protocol",
|
||||
})
|
||||
var newMeshKeepAliveWg *int = newMeshCmd.Int("k", "KeepAliveWg", &argparse.Options{
|
||||
Default: 0,
|
||||
Help: "WireGuard KeepAlive value for NAT traversal and firewall holepunching",
|
||||
})
|
||||
|
||||
var getGraphMeshId *string = getGraphCmd.String("m", "mesh", &argparse.Options{Required: true})
|
||||
var newMeshAdvertiseRoutes *bool = newMeshCmd.Flag("a", "advertise", &argparse.Options{
|
||||
Help: "Advertise routes to other mesh network into the mesh",
|
||||
})
|
||||
|
||||
var leaveMeshMeshId *string = leaveMeshCmd.String("m", "mesh", &argparse.Options{Required: true})
|
||||
var newMeshAdvertiseDefaults *bool = newMeshCmd.Flag("d", "defaults", &argparse.Options{
|
||||
Help: "Advertise ::/0 into the mesh network",
|
||||
})
|
||||
|
||||
var queryMeshMeshId *string = queryMeshCmd.String("m", "mesh", &argparse.Options{Required: true})
|
||||
var queryMeshQuery *string = queryMeshCmd.String("q", "query", &argparse.Options{Required: true})
|
||||
var joinMeshId *string = joinMeshCmd.String("m", "meshid", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "MeshID of the mesh network to join",
|
||||
})
|
||||
|
||||
var description *string = putDescriptionCmd.String("d", "description", &argparse.Options{Required: true})
|
||||
var joinMeshIpAddress *string = joinMeshCmd.String("i", "ip", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "IP address of the bootstrapping node to join through",
|
||||
})
|
||||
|
||||
var alias *string = putAliasCmd.String("a", "alias", &argparse.Options{Required: true})
|
||||
var joinMeshEndpoint *string = joinMeshCmd.String("e", "endpoint", &argparse.Options{
|
||||
Help: "Publicly routeable endpoint to advertise within the mesh",
|
||||
})
|
||||
|
||||
var serviceKey *string = setServiceCmd.String("s", "service", &argparse.Options{Required: true})
|
||||
var serviceValue *string = setServiceCmd.String("v", "value", &argparse.Options{Required: true})
|
||||
var joinMeshRole *string = joinMeshCmd.Selector("r", "role", []string{"peer", "client"}, &argparse.Options{
|
||||
Default: "peer",
|
||||
Help: "Role in the mesh network. A value of peer means that the node is publicly routeable and thus considered" +
|
||||
" in the gossip protocol. Client means that the node is not publicly routeable and is not a candidate in the gossip" +
|
||||
" protocol",
|
||||
})
|
||||
|
||||
var deleteServiceKey *string = deleteServiceCmd.String("s", "service", &argparse.Options{Required: true})
|
||||
var joinMeshPort *int = joinMeshCmd.Int("p", "wgport", &argparse.Options{
|
||||
Default: 0,
|
||||
Help: "WireGuard port to use to the interface. A default of 0 uses an unused ephmeral port.",
|
||||
})
|
||||
|
||||
var getNodeNodeId *string = getNodeCmd.String("n", "nodeid", &argparse.Options{Required: true})
|
||||
var getNodeMeshId *string = getNodeCmd.String("m", "meshid", &argparse.Options{Required: true})
|
||||
var joinMeshKeepAliveWg *int = joinMeshCmd.Int("k", "KeepAliveWg", &argparse.Options{
|
||||
Default: 0,
|
||||
Help: "WireGuard KeepAlive value for NAT traversal and firewall ho;lepunching",
|
||||
})
|
||||
|
||||
var joinMeshAdvertiseRoutes *bool = joinMeshCmd.Flag("a", "advertise", &argparse.Options{
|
||||
Help: "Advertise routes to other mesh network into the mesh",
|
||||
})
|
||||
|
||||
var joinMeshAdvertiseDefaults *bool = joinMeshCmd.Flag("d", "defaults", &argparse.Options{
|
||||
Help: "Advertise ::/0 into the mesh network",
|
||||
})
|
||||
|
||||
var getGraphMeshId *string = getGraphCmd.String("m", "mesh", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "MeshID of the graph to get",
|
||||
})
|
||||
|
||||
var leaveMeshMeshId *string = leaveMeshCmd.String("m", "mesh", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "MeshID of the mesh to leave",
|
||||
})
|
||||
|
||||
var queryMeshMeshId *string = queryMeshCmd.String("m", "mesh", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "MeshID of the mesh to query",
|
||||
})
|
||||
var queryMeshQuery *string = queryMeshCmd.String("q", "query", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "JMESPath Query Of The Mesh Network To Query",
|
||||
})
|
||||
|
||||
var description *string = putDescriptionCmd.String("d", "description", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "Description of the node in the mesh",
|
||||
})
|
||||
|
||||
var alias *string = putAliasCmd.String("a", "alias", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "Alias of the node to set can be used in DNS to lookup an IP address",
|
||||
})
|
||||
|
||||
var serviceKey *string = setServiceCmd.String("s", "service", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "Key of the service to advertise in the mesh network",
|
||||
})
|
||||
var serviceValue *string = setServiceCmd.String("v", "value", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "Value of the service to advertise in the mesh network",
|
||||
})
|
||||
|
||||
var deleteServiceKey *string = deleteServiceCmd.String("s", "service", &argparse.Options{
|
||||
Required: true,
|
||||
Help: "Key of the service to remove",
|
||||
})
|
||||
|
||||
err := parser.Parse(os.Args)
|
||||
|
||||
@ -272,9 +317,15 @@ func main() {
|
||||
if newMeshCmd.Happened() {
|
||||
fmt.Println(createMesh(&CreateMeshParams{
|
||||
Client: client,
|
||||
WgPort: *newMeshPort,
|
||||
Endpoint: *newMeshEndpoint,
|
||||
Role: *newMeshRole,
|
||||
WgArgs: ipc.WireGuardArgs{
|
||||
Endpoint: *newMeshEndpoint,
|
||||
Role: *newMeshRole,
|
||||
WgPort: *newMeshPort,
|
||||
KeepAliveWg: *newMeshKeepAliveWg,
|
||||
AdvertiseDefaultRoute: *newMeshAdvertiseDefaults,
|
||||
AdvertiseRoutes: *newMeshAdvertiseRoutes,
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
@ -285,11 +336,17 @@ func main() {
|
||||
if joinMeshCmd.Happened() {
|
||||
fmt.Println(joinMesh(&JoinMeshParams{
|
||||
Client: client,
|
||||
WgPort: *joinMeshPort,
|
||||
IpAddress: *joinMeshIpAddress,
|
||||
MeshId: *joinMeshId,
|
||||
Endpoint: *joinMeshEndpoint,
|
||||
Role: *joinMeshRole,
|
||||
WgArgs: ipc.WireGuardArgs{
|
||||
Endpoint: *joinMeshEndpoint,
|
||||
Role: *joinMeshRole,
|
||||
WgPort: *joinMeshPort,
|
||||
KeepAliveWg: *joinMeshKeepAliveWg,
|
||||
AdvertiseDefaultRoute: *joinMeshAdvertiseDefaults,
|
||||
AdvertiseRoutes: *joinMeshAdvertiseRoutes,
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
@ -297,10 +354,6 @@ func main() {
|
||||
getGraph(client, *getGraphMeshId)
|
||||
}
|
||||
|
||||
if enableInterfaceCmd.Happened() {
|
||||
enableInterface(client, *enableInterfaceMeshId)
|
||||
}
|
||||
|
||||
if leaveMeshCmd.Happened() {
|
||||
leaveMesh(client, *leaveMeshMeshId)
|
||||
}
|
||||
@ -324,8 +377,4 @@ func main() {
|
||||
if deleteServiceCmd.Happened() {
|
||||
deleteService(client, *deleteServiceKey)
|
||||
}
|
||||
|
||||
if getNodeCmd.Happened() {
|
||||
getNode(client, *getNodeNodeId, *getNodeMeshId)
|
||||
}
|
||||
}
|
||||
|
14
go.mod
14
go.mod
@ -4,14 +4,18 @@ go 1.21.3
|
||||
|
||||
require (
|
||||
github.com/akamensky/argparse v1.4.0
|
||||
github.com/anandvarma/namegen v0.0.0-20230727084436-5197c6ea3255
|
||||
github.com/automerge/automerge-go v0.0.0-20230903201930-b80ce8aadbb9
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-playground/validator/v10 v10.16.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/jmespath/go-jmespath v0.4.0
|
||||
github.com/jsimonetti/rtnetlink v1.3.5
|
||||
github.com/miekg/dns v1.1.57
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
golang.org/x/sys v0.14.0
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||
gonum.org/v1/gonum v0.14.0
|
||||
google.golang.org/grpc v1.58.1
|
||||
google.golang.org/protobuf v1.31.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
@ -24,7 +28,6 @@ require (
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
@ -42,10 +45,13 @@ require (
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.13.0 // indirect
|
||||
golang.org/x/net v0.15.0 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sync v0.4.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/tools v0.13.0 // indirect
|
||||
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
|
||||
)
|
||||
|
143
go.sum
Normal file
143
go.sum
Normal file
@ -0,0 +1,143 @@
|
||||
github.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc=
|
||||
github.com/akamensky/argparse v1.4.0/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA=
|
||||
github.com/anandvarma/namegen v0.0.0-20230727084436-5197c6ea3255 h1:aIAyyj4XPrke9Tc/umbBCzP5SKX/CHf3dKrL/PhH2lo=
|
||||
github.com/anandvarma/namegen v0.0.0-20230727084436-5197c6ea3255/go.mod h1:MFyILur9tG8PxaCXGZVr/2BOnHtRIgxYejYFZdWLxr0=
|
||||
github.com/automerge/automerge-go v0.0.0-20230903201930-b80ce8aadbb9 h1:+6JSfuxZgmURoIlGdnYnY/FLRGWGagLyiBjt/VLtwi4=
|
||||
github.com/automerge/automerge-go v0.0.0-20230903201930-b80ce8aadbb9/go.mod h1:6UxoDE+thWsISXK93pxaOuOfkcAfCvDbg0eAnFmxL5E=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y=
|
||||
github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
|
||||
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
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/jsimonetti/rtnetlink v1.3.5 h1:hVlNQNRlLDGZz31gBPicsG7Q53rnlsz1l1Ix/9XlpVA=
|
||||
github.com/jsimonetti/rtnetlink v1.3.5/go.mod h1:0LFedyiTkebnd43tE4YAkWGIq9jQphow4CcwxaT2Y00=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
|
||||
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
|
||||
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
|
||||
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 h1:EY138uSo1JYlDq+97u1FtcOUwPpIU6WL1Lkt7WpYjPA=
|
||||
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
||||
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
|
||||
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
||||
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58=
|
||||
google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
@ -65,6 +65,12 @@ func (s *SmegServer) meshNodeToAPIMeshNode(meshNode ctrlserver.MeshNode) *SmegNo
|
||||
PublicKey: meshNode.PublicKey,
|
||||
Alias: alias,
|
||||
Services: meshNode.Services,
|
||||
Stats: SmegStats{
|
||||
TotalTransmit: meshNode.Stats.TransmitBytes,
|
||||
TotalReceived: meshNode.Stats.ReceivedBytes,
|
||||
KeepAliveInterval: meshNode.Stats.PersistentKeepAliveInterval,
|
||||
AllowedIps: meshNode.Stats.AllowedIPs,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,7 +99,9 @@ func (s *SmegServer) CreateMesh(c *gin.Context) {
|
||||
}
|
||||
|
||||
ipcRequest := ipc.NewMeshArgs{
|
||||
WgPort: createMesh.WgPort,
|
||||
WgArgs: ipc.WireGuardArgs{
|
||||
WgPort: createMesh.WgPort,
|
||||
},
|
||||
}
|
||||
|
||||
var reply string
|
||||
@ -126,7 +134,9 @@ func (s *SmegServer) JoinMesh(c *gin.Context) {
|
||||
ipcRequest := ipc.JoinMeshArgs{
|
||||
MeshId: joinMesh.MeshId,
|
||||
IpAdress: joinMesh.Bootstrap,
|
||||
Port: joinMesh.WgPort,
|
||||
WgArgs: ipc.WireGuardArgs{
|
||||
WgPort: joinMesh.WgPort,
|
||||
},
|
||||
}
|
||||
|
||||
var reply string
|
||||
|
@ -1,10 +1,19 @@
|
||||
package api
|
||||
|
||||
import "time"
|
||||
|
||||
type Route struct {
|
||||
Prefix string `json:"prefix"`
|
||||
Path []string `json:"path"`
|
||||
}
|
||||
|
||||
type SmegStats struct {
|
||||
TotalTransmit int64 `json:"totalTransmit"`
|
||||
TotalReceived int64 `json:"totalReceived"`
|
||||
KeepAliveInterval time.Duration `json:"keepaliveInterval"`
|
||||
AllowedIps []string `json:"allowedIps"`
|
||||
}
|
||||
|
||||
type SmegNode struct {
|
||||
Alias string `json:"alias"`
|
||||
WgHost string `json:"wgHost"`
|
||||
@ -15,6 +24,7 @@ type SmegNode struct {
|
||||
PublicKey string `json:"publicKey"`
|
||||
Routes []Route `json:"routes"`
|
||||
Services map[string]string `json:"services"`
|
||||
Stats SmegStats `json:"stats"`
|
||||
}
|
||||
|
||||
type SmegMesh struct {
|
||||
|
@ -40,7 +40,11 @@ func (c *CrdtMeshManager) AddNode(node mesh.MeshNode) {
|
||||
crdt.Services = make(map[string]string)
|
||||
crdt.Timestamp = time.Now().Unix()
|
||||
|
||||
c.doc.Path("nodes").Map().Set(crdt.PublicKey, crdt)
|
||||
err := c.doc.Path("nodes").Map().Set(crdt.PublicKey, crdt)
|
||||
|
||||
if err != nil {
|
||||
logging.Log.WriteInfof("error")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CrdtMeshManager) isPeer(nodeId string) bool {
|
||||
@ -161,7 +165,7 @@ func (m *CrdtMeshManager) GetNode(endpoint string) (mesh.MeshNode, error) {
|
||||
node, err := m.doc.Path("nodes").Map().Get(endpoint)
|
||||
|
||||
if node.Kind() != automerge.KindMap {
|
||||
return nil, fmt.Errorf("GetNode: something went wrong %s is not a map type")
|
||||
return nil, fmt.Errorf("getnode: node is not a map")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package automerge
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -22,7 +22,7 @@ func setUpTests() *TestParams {
|
||||
DevName: "wg0",
|
||||
Port: 5000,
|
||||
Client: nil,
|
||||
Conf: conf.DaemonConfiguration{},
|
||||
Conf: &conf.WgConfiguration{},
|
||||
})
|
||||
|
||||
return &TestParams{
|
||||
@ -31,22 +31,26 @@ func setUpTests() *TestParams {
|
||||
}
|
||||
|
||||
func getTestNode() mesh.MeshNode {
|
||||
pubKey, _ := wgtypes.GeneratePrivateKey()
|
||||
|
||||
return &MeshNodeCrdt{
|
||||
HostEndpoint: "public-endpoint:8080",
|
||||
WgEndpoint: "public-endpoint:21906",
|
||||
WgHost: "3e9a:1fb3:5e50:8173:9690:f917:b1ab:d218/128",
|
||||
PublicKey: "AAAAAAAAAAAA",
|
||||
PublicKey: pubKey.String(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
Description: "A node that we are adding",
|
||||
}
|
||||
}
|
||||
|
||||
func getTestNode2() mesh.MeshNode {
|
||||
pubKey, _ := wgtypes.GeneratePrivateKey()
|
||||
|
||||
return &MeshNodeCrdt{
|
||||
HostEndpoint: "public-endpoint:8081",
|
||||
WgEndpoint: "public-endpoint:21907",
|
||||
WgHost: "3e9a:1fb3:5e50:8173:9690:f917:b1ab:d219/128",
|
||||
PublicKey: "BBBBBBBBB",
|
||||
PublicKey: pubKey.String(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
Description: "A node that we are adding",
|
||||
}
|
||||
@ -54,9 +58,11 @@ func getTestNode2() mesh.MeshNode {
|
||||
|
||||
func TestAddNodeNodeExists(t *testing.T) {
|
||||
testParams := setUpTests()
|
||||
testParams.manager.AddNode(getTestNode())
|
||||
node := getTestNode()
|
||||
testParams.manager.AddNode(node)
|
||||
|
||||
node, err := testParams.manager.GetNode("public-endpoint:8080")
|
||||
pubKey, _ := node.GetPublicKey()
|
||||
node, err := testParams.manager.GetNode(pubKey.String())
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@ -70,25 +76,28 @@ func TestAddNodeNodeExists(t *testing.T) {
|
||||
func TestAddNodeAddRoute(t *testing.T) {
|
||||
testParams := setUpTests()
|
||||
testNode := getTestNode()
|
||||
testParams.manager.AddNode(testNode)
|
||||
testParams.manager.AddRoutes(testNode.GetHostEndpoint(), "fd:1c64:1d00::/48")
|
||||
pubKey, _ := testNode.GetPublicKey()
|
||||
|
||||
updatedNode, err := testParams.manager.GetNode(testNode.GetHostEndpoint())
|
||||
_, destination, _ := net.ParseCIDR("fd:1c64:1d00::/48")
|
||||
|
||||
testParams.manager.AddNode(testNode)
|
||||
testParams.manager.AddRoutes(pubKey.String(), &mesh.RouteStub{
|
||||
Destination: destination,
|
||||
HopCount: 0,
|
||||
Path: make([]string, 0),
|
||||
})
|
||||
updatedNode, err := testParams.manager.GetNode(pubKey.String())
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if updatedNode == nil {
|
||||
t.Fatalf(`Node does not exist in the mesh`)
|
||||
t.Fatalf(`node does not exist in the mesh`)
|
||||
}
|
||||
|
||||
routes := updatedNode.GetRoutes()
|
||||
|
||||
if !slices.Contains(routes, "fd:1c64:1d00::/48") {
|
||||
t.Fatal("Route node not added")
|
||||
}
|
||||
|
||||
if len(routes) != 1 {
|
||||
t.Fatal(`Route length mismatch`)
|
||||
}
|
||||
@ -253,7 +262,9 @@ func TestUpdateTimeStampNodeExists(t *testing.T) {
|
||||
node := getTestNode()
|
||||
|
||||
testParams.manager.AddNode(node)
|
||||
err := testParams.manager.UpdateTimeStamp(node.GetHostEndpoint())
|
||||
pubKey, _ := node.GetPublicKey()
|
||||
|
||||
err := testParams.manager.UpdateTimeStamp(pubKey.String())
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@ -282,7 +293,13 @@ func TestSetDescriptionNodeExists(t *testing.T) {
|
||||
func TestAddRoutesNodeDoesNotExist(t *testing.T) {
|
||||
testParams := setUpTests()
|
||||
|
||||
err := testParams.manager.AddRoutes("AAAAA", "fd:1c64:1d00::/48")
|
||||
_, destination, _ := net.ParseCIDR("fd:1c64:1d00::/48")
|
||||
|
||||
err := testParams.manager.AddRoutes("AAAAA", &mesh.RouteStub{
|
||||
Destination: destination,
|
||||
HopCount: 0,
|
||||
Path: make([]string, 0),
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
@ -293,16 +310,11 @@ func TestCompareComparesByPublicKey(t *testing.T) {
|
||||
node := getTestNode().(*MeshNodeCrdt)
|
||||
node2 := getTestNode2().(*MeshNodeCrdt)
|
||||
|
||||
if node.Compare(node2) != -1 {
|
||||
t.Fatalf(`node is alphabetically before node2`)
|
||||
}
|
||||
pubKey1, _ := node.GetPublicKey()
|
||||
pubKey2, _ := node2.GetPublicKey()
|
||||
|
||||
if node2.Compare(node) != 1 {
|
||||
t.Fatalf(`node is alphabetical;y before node2`)
|
||||
}
|
||||
|
||||
if node.Compare(node) != 0 {
|
||||
t.Fatalf(`node is equal to node`)
|
||||
if node.Compare(node2) != strings.Compare(pubKey1.String(), pubKey2.String()) {
|
||||
t.Fatalf(`compare failed`)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ type MeshNodeFactory struct {
|
||||
func (f *MeshNodeFactory) Build(params *mesh.MeshNodeFactoryParams) mesh.MeshNode {
|
||||
hostName := f.getAddress(params)
|
||||
|
||||
grpcEndpoint := fmt.Sprintf("%s:%s", hostName, f.Config.GrpcPort)
|
||||
grpcEndpoint := fmt.Sprintf("%s:%d", hostName, f.Config.GrpcPort)
|
||||
|
||||
if *params.MeshConfig.Role == conf.CLIENT_ROLE {
|
||||
grpcEndpoint = "-"
|
||||
|
@ -26,8 +26,8 @@ const (
|
||||
type IPDiscovery string
|
||||
|
||||
const (
|
||||
PUBLIC_IP_DISCOVERY = "public"
|
||||
DNS_IP_DISCOVERY = "dns"
|
||||
PUBLIC_IP_DISCOVERY IPDiscovery = "public"
|
||||
DNS_IP_DISCOVERY IPDiscovery = "dns"
|
||||
)
|
||||
|
||||
// WgConfiguration contains per-mesh WireGuard configuration. Contains poitner types only so we can
|
||||
@ -37,10 +37,10 @@ type WgConfiguration struct {
|
||||
// service for IPDiscoverability
|
||||
IPDiscovery *IPDiscovery `yaml:"ipDiscovery" validate:"required,eq=public|eq=dns"`
|
||||
// AdvertiseRoutes: specifies whether the node can act as a router routing packets between meshes
|
||||
AdvertiseRoutes *bool `yaml:"advertiseRoutes"`
|
||||
AdvertiseRoutes *bool `yaml:"advertiseRoute" validate:"required"`
|
||||
// AdvertiseDefaultRoute: specifies whether or not this route should advertise a default route
|
||||
// for all nodes to route their packets to
|
||||
AdvertiseDefaultRoute *bool `yaml:"advertiseDefaults"`
|
||||
AdvertiseDefaultRoute *bool `yaml:"advertiseDefaults" validate:"required"`
|
||||
// Endpoint contains what value should be set as the public endpoint of this node
|
||||
Endpoint *string `yaml:"publicEndpoint"`
|
||||
// Role specifies whether or not the user is globally accessible.
|
||||
@ -61,11 +61,11 @@ type WgConfiguration struct {
|
||||
|
||||
type DaemonConfiguration struct {
|
||||
// CertificatePath is the path to the certificate to use in mTLS
|
||||
CertificatePath string `yaml:"certificatePath" validate:"required,file"`
|
||||
CertificatePath string `yaml:"certificatePath" validate:"required"`
|
||||
// PrivateKeypath is the path to the clients private key in mTLS
|
||||
PrivateKeyPath string `yaml:"privateKeyPath" validate:"required,file"`
|
||||
PrivateKeyPath string `yaml:"privateKeyPath" validate:"required"`
|
||||
// CaCeritifcatePath path to the certificate of the trust certificate authority
|
||||
CaCertificatePath string `yaml:"caCertificatePath" validate:"required,file"`
|
||||
CaCertificatePath string `yaml:"caCertificatePath" validate:"required"`
|
||||
// SkipCertVerification specify to skip certificate verification. Should only be used
|
||||
// in test environments
|
||||
SkipCertVerification bool `yaml:"skipCertVerification"`
|
||||
@ -83,9 +83,9 @@ type DaemonConfiguration struct {
|
||||
// send to every member in the mesh
|
||||
KeepAliveTime int `yaml:"keepAliveTime" validate:"required,gte=1"`
|
||||
// ClusterSize specifies how many neighbours you should synchronise with per round
|
||||
ClusterSize int `yaml:"clusterSize" valdiate:"required,gt=0"`
|
||||
ClusterSize int `yaml:"clusterSize" validate:"gte=1"`
|
||||
// InterClusterChance specifies the probabilityof inter-cluster communication in a sync round
|
||||
InterClusterChance float64 `yaml:"interClusterChance" valdiate:"required,gt=0"`
|
||||
InterClusterChance float64 `yaml:"interClusterChance" validate:"gt=0"`
|
||||
// BranchRate specifies the number of nodes to synchronise with when a node has
|
||||
// new changes to send to the mesh
|
||||
BranchRate int `yaml:"branchRate" validate:"required,gte=1"`
|
||||
|
@ -1,13 +1,40 @@
|
||||
package conf
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getExampleConfiguration() *DaemonConfiguration {
|
||||
discovery := PUBLIC_IP_DISCOVERY
|
||||
advertiseRoutes := false
|
||||
advertiseDefaultRoute := false
|
||||
endpoint := "abc.com:123"
|
||||
nodeType := CLIENT_ROLE
|
||||
keepAliveWg := 0
|
||||
|
||||
return &DaemonConfiguration{
|
||||
CertificatePath: "./cert/cert.pem",
|
||||
PrivateKeyPath: "./cert/key.pem",
|
||||
CaCertificatePath: "./cert/ca.pems",
|
||||
CertificatePath: "../../../cert/cert.pem",
|
||||
PrivateKeyPath: "../../../cert/priv.pem",
|
||||
CaCertificatePath: "../../../cert/cacert.pem",
|
||||
SkipCertVerification: true,
|
||||
GrpcPort: 25,
|
||||
Timeout: 5,
|
||||
Profile: false,
|
||||
StubWg: false,
|
||||
SyncRate: 2,
|
||||
KeepAliveTime: 2,
|
||||
ClusterSize: 64,
|
||||
InterClusterChance: 0.15,
|
||||
BranchRate: 3,
|
||||
InfectionCount: 2,
|
||||
BaseConfiguration: WgConfiguration{
|
||||
IPDiscovery: &discovery,
|
||||
AdvertiseRoutes: &advertiseRoutes,
|
||||
AdvertiseDefaultRoute: &advertiseDefaultRoute,
|
||||
Endpoint: &endpoint,
|
||||
Role: &nodeType,
|
||||
KeepAliveWg: &keepAliveWg,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,9 +82,141 @@ func TestConfigurationGrpcPortEmpty(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIPDiscoveryNotSet(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
ipDiscovery := IPDiscovery("djdsjdskd")
|
||||
conf.BaseConfiguration.IPDiscovery = &ipDiscovery
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdvertiseRoutesNotSet(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
conf.BaseConfiguration.AdvertiseRoutes = nil
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdvertiseDefaultRouteNotSet(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
conf.BaseConfiguration.AdvertiseDefaultRoute = nil
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeepAliveWgNegative(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
keepAliveWg := -1
|
||||
conf.BaseConfiguration.KeepAliveWg = &keepAliveWg
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoleTypeNotValid(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
role := NodeType("bruhhh")
|
||||
conf.BaseConfiguration.Role = &role
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoleTypeNotSpecified(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
conf.BaseConfiguration.Role = nil
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`invalid role type`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBranchRateZero(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
conf.BranchRate = 0
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncRateZero(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
conf.SyncRate = 0
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeepAliveTimeZero(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
conf.KeepAliveTime = 0
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClusterSizeZero(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
conf.ClusterSize = 0
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterClusterChanceZero(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
conf.InterClusterChance = 0
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInfectionCountOne(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
conf.InfectionCount = 0
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err == nil {
|
||||
t.Fatal(`error should be thrown`)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidConfiguration(t *testing.T) {
|
||||
conf := getExampleConfiguration()
|
||||
|
||||
err := ValidateDaemonConfiguration(conf)
|
||||
|
||||
if err != nil {
|
||||
|
@ -55,12 +55,14 @@ func (i *ConnClusterImpl) GetNeighbours(global []string, selfId string) []string
|
||||
// you will communicate with a random node that is not in your cluster.
|
||||
func (i *ConnClusterImpl) GetInterCluster(global []string, selfId string) string {
|
||||
// Doesn't matter if not in it. Get index of where the node 'should' be
|
||||
slices.Sort(global)
|
||||
|
||||
index, _ := binarySearch(global, selfId, 1)
|
||||
numClusters := math.Ceil(float64(len(global)) / float64(i.clusterSize))
|
||||
|
||||
randomCluster := rand.Intn(int(numClusters)-1) + 1
|
||||
randomCluster := rand.Intn(2) + 1
|
||||
|
||||
neighbourIndex := (index + randomCluster) % len(global)
|
||||
// cluster is considered a heap
|
||||
neighbourIndex := (2*index + (randomCluster * i.clusterSize)) % len(global)
|
||||
return global[neighbourIndex]
|
||||
}
|
||||
|
||||
|
@ -1,84 +0,0 @@
|
||||
package conn
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"slices"
|
||||
|
||||
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||
)
|
||||
|
||||
// ConnectionWindow maintains a sliding window of connections between users
|
||||
type ConnectionWindow interface {
|
||||
// GetWindow is a list of connections to choose from
|
||||
GetWindow() []string
|
||||
// SlideConnection removes a node from the window and adds a random node
|
||||
// not already in the window. connList represents the list of possible
|
||||
// connections to choose from
|
||||
SlideConnection(connList []string) error
|
||||
// PushConneciton is used when connection list less than window size.
|
||||
PutConnection(conn []string) error
|
||||
// IsFull returns true if the window is full. In which case we must slide the window
|
||||
IsFull() bool
|
||||
}
|
||||
|
||||
type ConnectionWindowImpl struct {
|
||||
window []string
|
||||
windowSize int
|
||||
}
|
||||
|
||||
// GetWindow gets the current list of active connections in
|
||||
// the window
|
||||
func (c *ConnectionWindowImpl) GetWindow() []string {
|
||||
return c.window
|
||||
}
|
||||
|
||||
// SlideConnection slides the connection window by one shuffling items
|
||||
// in the windows
|
||||
func (c *ConnectionWindowImpl) SlideConnection(connList []string) error {
|
||||
// If the number of peer connections is less than the length of the window
|
||||
// then exit early. Can't slide the window it should contain all nodes!
|
||||
if len(c.window) < c.windowSize {
|
||||
return nil
|
||||
}
|
||||
|
||||
filter := func(node string) bool {
|
||||
return !slices.Contains(c.window, node)
|
||||
}
|
||||
|
||||
pool := lib.Filter(connList, filter)
|
||||
newNode := lib.RandomSubsetOfLength(pool, 1)
|
||||
|
||||
if len(newNode) == 0 {
|
||||
return errors.New("could not slide window")
|
||||
}
|
||||
|
||||
for i := len(c.window) - 1; i >= 1; i-- {
|
||||
c.window[i] = c.window[i-1]
|
||||
}
|
||||
|
||||
c.window[0] = newNode[0]
|
||||
return nil
|
||||
}
|
||||
|
||||
// PutConnection put random connections in the connection
|
||||
func (c *ConnectionWindowImpl) PutConnection(connList []string) error {
|
||||
if len(c.window) >= c.windowSize {
|
||||
return errors.New("cannot place connection. Window full need to slide")
|
||||
}
|
||||
|
||||
c.window = lib.RandomSubsetOfLength(connList, c.windowSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConnectionWindowImpl) IsFull() bool {
|
||||
return len(c.window) >= c.windowSize
|
||||
}
|
||||
|
||||
func NewConnectionWindow(windowLength int) ConnectionWindow {
|
||||
window := &ConnectionWindowImpl{
|
||||
window: make([]string, 0),
|
||||
windowSize: windowLength,
|
||||
}
|
||||
|
||||
return window
|
||||
}
|
@ -386,7 +386,7 @@ func (m *TwoPhaseStoreMeshManager) SetAlias(nodeId string, alias string) error {
|
||||
}
|
||||
|
||||
node := m.store.Get(nodeId)
|
||||
node.Description = alias
|
||||
node.Alias = alias
|
||||
|
||||
m.store.Put(nodeId, node)
|
||||
return nil
|
||||
|
@ -151,7 +151,7 @@ func (m *TwoPhaseMap[K, D]) GenerateMessage() *TwoPhaseMapState[K] {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *TwoPhaseMapState[K]) Difference(state *TwoPhaseMapState[K]) *TwoPhaseMapState[K] {
|
||||
func (m *TwoPhaseMapState[K]) Difference(highestStale uint64, state *TwoPhaseMapState[K]) *TwoPhaseMapState[K] {
|
||||
mapState := &TwoPhaseMapState[K]{
|
||||
AddContents: make(map[uint64]uint64),
|
||||
RemoveContents: make(map[uint64]uint64),
|
||||
@ -160,7 +160,7 @@ func (m *TwoPhaseMapState[K]) Difference(state *TwoPhaseMapState[K]) *TwoPhaseMa
|
||||
for key, value := range state.AddContents {
|
||||
otherValue, ok := m.AddContents[key]
|
||||
|
||||
if !ok || otherValue < value {
|
||||
if value > highestStale && (!ok || otherValue < value) {
|
||||
mapState.AddContents[key] = value
|
||||
}
|
||||
}
|
||||
@ -168,7 +168,7 @@ func (m *TwoPhaseMapState[K]) Difference(state *TwoPhaseMapState[K]) *TwoPhaseMa
|
||||
for key, value := range state.RemoveContents {
|
||||
otherValue, ok := m.RemoveContents[key]
|
||||
|
||||
if !ok || otherValue < value {
|
||||
if value > highestStale && (!ok || otherValue < value) {
|
||||
mapState.RemoveContents[key] = value
|
||||
}
|
||||
}
|
||||
|
@ -68,9 +68,16 @@ func prepare(syncer *TwoPhaseSyncer) ([]byte, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Increment the clock here so the clock gets
|
||||
// distributed to everyone else in the mesh
|
||||
syncer.manager.store.Clock.IncrementClock()
|
||||
|
||||
var buffer bytes.Buffer
|
||||
enc := gob.NewEncoder(&buffer)
|
||||
|
||||
mapState := syncer.manager.store.GenerateMessage()
|
||||
|
||||
syncer.mapState = mapState
|
||||
err = enc.Encode(*syncer.mapState)
|
||||
|
||||
if err != nil {
|
||||
@ -96,7 +103,7 @@ func present(syncer *TwoPhaseSyncer) ([]byte, bool) {
|
||||
logging.Log.WriteErrorf(err.Error())
|
||||
}
|
||||
|
||||
difference := syncer.mapState.Difference(&mapState)
|
||||
difference := syncer.mapState.Difference(syncer.manager.store.Clock.GetStaleCount(), &mapState)
|
||||
syncer.manager.store.Clock.Merge(mapState.Vectors)
|
||||
|
||||
var sendBuffer bytes.Buffer
|
||||
@ -164,9 +171,6 @@ func (t *TwoPhaseSyncer) RecvMessage(msg []byte) error {
|
||||
|
||||
func (t *TwoPhaseSyncer) Complete() {
|
||||
logging.Log.WriteInfof("SYNC COMPLETED")
|
||||
if t.state >= MERGE {
|
||||
t.manager.store.Clock.IncrementClock()
|
||||
}
|
||||
}
|
||||
|
||||
func NewTwoPhaseSyncer(manager *TwoPhaseStoreMeshManager) *TwoPhaseSyncer {
|
||||
@ -181,7 +185,6 @@ func NewTwoPhaseSyncer(manager *TwoPhaseStoreMeshManager) *TwoPhaseSyncer {
|
||||
return &TwoPhaseSyncer{
|
||||
manager: manager,
|
||||
state: HASH,
|
||||
mapState: manager.store.GenerateMessage(),
|
||||
generateMessageFSM: generateMessageFsm,
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ type VectorClock[K cmp.Ordered] struct {
|
||||
processID K
|
||||
staleTime uint64
|
||||
hashFunc func(K) uint64
|
||||
// highest update that's been garbage collected
|
||||
highestStale uint64
|
||||
}
|
||||
|
||||
// IncrementClock: increments the node's value in the vector clock
|
||||
@ -78,6 +80,7 @@ func (m *VectorClock[K]) getStale() []uint64 {
|
||||
for key, bucket := range m.vectors {
|
||||
if maxTimeStamp-bucket.lastUpdate > m.staleTime {
|
||||
toRemove = append(toRemove, key)
|
||||
m.highestStale = max(bucket.clock, m.highestStale)
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,6 +88,15 @@ func (m *VectorClock[K]) getStale() []uint64 {
|
||||
return toRemove
|
||||
}
|
||||
|
||||
// GetStaleCount: returns a vector clock which is considered to be stale.
|
||||
// all updates must be greater than this
|
||||
func (m *VectorClock[K]) GetStaleCount() uint64 {
|
||||
m.lock.RLock()
|
||||
staleCount := m.highestStale
|
||||
m.lock.RUnlock()
|
||||
return staleCount
|
||||
}
|
||||
|
||||
func (m *VectorClock[K]) Prune() {
|
||||
stale := m.getStale()
|
||||
|
||||
@ -120,7 +132,9 @@ func (m *VectorClock[K]) put(key uint64, value uint64) {
|
||||
clockValue = bucket.clock
|
||||
}
|
||||
|
||||
if value > clockValue {
|
||||
// Make sure that entries that were garbage collected don't get
|
||||
// addded back
|
||||
if value > clockValue && value > m.highestStale {
|
||||
newBucket := VectorBucket{
|
||||
clock: value,
|
||||
lastUpdate: uint64(time.Now().Unix()),
|
||||
|
@ -89,6 +89,7 @@ func NewCtrlServer(params *NewCtrlServerParams) (*MeshCtrlServer, error) {
|
||||
return ctrlServer, nil
|
||||
}
|
||||
|
||||
|
||||
func (s *MeshCtrlServer) GetConfiguration() *conf.DaemonConfiguration {
|
||||
return s.Conf
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
package ctrlserver
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||
"github.com/tim-beatham/wgmesh/pkg/conn"
|
||||
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||
"github.com/tim-beatham/wgmesh/pkg/query"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
@ -14,6 +18,14 @@ type MeshRoute struct {
|
||||
Path []string
|
||||
}
|
||||
|
||||
// Represents the WireGuard configuration attached to the node
|
||||
type WireGuardStats struct {
|
||||
AllowedIPs []string
|
||||
TransmitBytes int64
|
||||
ReceivedBytes int64
|
||||
PersistentKeepAliveInterval time.Duration
|
||||
}
|
||||
|
||||
// Represents a WireGuard MeshNode
|
||||
type MeshNode struct {
|
||||
HostEndpoint string
|
||||
@ -25,6 +37,7 @@ type MeshNode struct {
|
||||
Description string
|
||||
Alias string
|
||||
Services map[string]string
|
||||
Stats WireGuardStats
|
||||
}
|
||||
|
||||
// Represents a WireGuard Mesh
|
||||
@ -51,3 +64,53 @@ type MeshCtrlServer struct {
|
||||
Conf *conf.DaemonConfiguration
|
||||
Querier query.Querier
|
||||
}
|
||||
|
||||
// NewCtrlNode create an instance of a ctrl node to send over an
|
||||
// IPC call
|
||||
func NewCtrlNode(provider mesh.MeshProvider, node mesh.MeshNode) *MeshNode {
|
||||
pubKey, _ := node.GetPublicKey()
|
||||
|
||||
ctrlNode := MeshNode{
|
||||
HostEndpoint: node.GetHostEndpoint(),
|
||||
WgEndpoint: node.GetWgEndpoint(),
|
||||
PublicKey: pubKey.String(),
|
||||
WgHost: node.GetWgHost().String(),
|
||||
Timestamp: node.GetTimeStamp(),
|
||||
Routes: lib.Map(node.GetRoutes(), func(r mesh.Route) MeshRoute {
|
||||
return MeshRoute{
|
||||
Destination: r.GetDestination().String(),
|
||||
Path: r.GetPath(),
|
||||
}
|
||||
}),
|
||||
Description: node.GetDescription(),
|
||||
Alias: node.GetAlias(),
|
||||
Services: node.GetServices(),
|
||||
}
|
||||
|
||||
device, err := provider.GetDevice()
|
||||
|
||||
if err != nil {
|
||||
return &ctrlNode
|
||||
}
|
||||
|
||||
peers := lib.Filter(device.Peers, func(p wgtypes.Peer) bool {
|
||||
return p.PublicKey.String() == pubKey.String()
|
||||
})
|
||||
|
||||
if len(peers) > 0 {
|
||||
peer := peers[0]
|
||||
|
||||
stats := WireGuardStats{
|
||||
AllowedIPs: lib.Map(peer.AllowedIPs, func(i net.IPNet) string {
|
||||
return i.String()
|
||||
}),
|
||||
TransmitBytes: peer.TransmitBytes,
|
||||
ReceivedBytes: peer.ReceiveBytes,
|
||||
PersistentKeepAliveInterval: peer.PersistentKeepaliveInterval,
|
||||
}
|
||||
|
||||
ctrlNode.Stats = stats
|
||||
}
|
||||
|
||||
return &ctrlNode
|
||||
}
|
||||
|
@ -1,132 +0,0 @@
|
||||
// hosts: utility for modifying the /etc/hosts file
|
||||
package hosts
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HOSTS_FILE is the hosts file location
|
||||
const HOSTS_FILE = "/etc/hosts"
|
||||
|
||||
const DOMAIN_HEADER = "#WG AUTO GENERATED HOSTS"
|
||||
const DOMAIN_TRAILER = "#WG AUTO GENERATED HOSTS END"
|
||||
|
||||
type HostsEntry struct {
|
||||
Alias string
|
||||
Ip net.IP
|
||||
}
|
||||
|
||||
// Generic interface to manipulate /etc/hosts file
|
||||
type HostsManipulator interface {
|
||||
// AddrAddr associates an aliasd with a given IP address
|
||||
AddAddr(hosts ...HostsEntry)
|
||||
// Remove deletes the entry from /etc/hosts
|
||||
Remove(hosts ...HostsEntry)
|
||||
// Writes the changes to /etc/hosts file
|
||||
Write() error
|
||||
}
|
||||
|
||||
type HostsManipulatorImpl struct {
|
||||
hosts map[string]HostsEntry
|
||||
}
|
||||
|
||||
// AddAddr implements HostsManipulator.
|
||||
func (m *HostsManipulatorImpl) AddAddr(hosts ...HostsEntry) {
|
||||
changed := false
|
||||
|
||||
for _, host := range hosts {
|
||||
prev, ok := m.hosts[host.Ip.String()]
|
||||
|
||||
if !ok || prev.Alias != host.Alias {
|
||||
changed = true
|
||||
}
|
||||
|
||||
m.hosts[host.Ip.String()] = host
|
||||
}
|
||||
|
||||
if changed {
|
||||
m.Write()
|
||||
}
|
||||
}
|
||||
|
||||
// Remove implements HostsManipulator.
|
||||
func (m *HostsManipulatorImpl) Remove(hosts ...HostsEntry) {
|
||||
lenBefore := len(m.hosts)
|
||||
|
||||
for _, host := range hosts {
|
||||
delete(m.hosts, host.Alias)
|
||||
}
|
||||
|
||||
if lenBefore != len(m.hosts) {
|
||||
m.Write()
|
||||
}
|
||||
}
|
||||
|
||||
func (m *HostsManipulatorImpl) removeHosts() string {
|
||||
hostsFile, err := os.ReadFile(HOSTS_FILE)
|
||||
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
var contents strings.Builder
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewReader(hostsFile))
|
||||
|
||||
hostsSection := false
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if !hostsSection && strings.Contains(line, DOMAIN_HEADER) {
|
||||
hostsSection = true
|
||||
}
|
||||
|
||||
if !hostsSection {
|
||||
contents.WriteString(line + "\n")
|
||||
}
|
||||
|
||||
if hostsSection && strings.Contains(line, DOMAIN_TRAILER) {
|
||||
hostsSection = false
|
||||
}
|
||||
}
|
||||
|
||||
if scanner.Err() != nil && scanner.Err() != io.EOF {
|
||||
return ""
|
||||
}
|
||||
|
||||
return contents.String()
|
||||
}
|
||||
|
||||
// Write implements HostsManipulator
|
||||
func (m *HostsManipulatorImpl) Write() error {
|
||||
contents := m.removeHosts()
|
||||
|
||||
var nextHosts strings.Builder
|
||||
nextHosts.WriteString(contents)
|
||||
|
||||
nextHosts.WriteString(DOMAIN_HEADER + "\n")
|
||||
|
||||
for _, host := range m.hosts {
|
||||
nextHosts.WriteString(fmt.Sprintf("%s\t%s\n", host.Ip.String(), host.Alias))
|
||||
}
|
||||
|
||||
nextHosts.WriteString(DOMAIN_TRAILER + "\n")
|
||||
return os.WriteFile(HOSTS_FILE, []byte(nextHosts.String()), 0644)
|
||||
}
|
||||
|
||||
func NewHostsManipulator() HostsManipulator {
|
||||
return &HostsManipulatorImpl{hosts: make(map[string]HostsEntry)}
|
||||
}
|
@ -10,13 +10,29 @@ import (
|
||||
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||
)
|
||||
|
||||
type NewMeshArgs struct {
|
||||
// WireGuardArgs are provided args specific to WireGuard
|
||||
type WireGuardArgs struct {
|
||||
// WgPort is the WireGuard port to expose
|
||||
WgPort int
|
||||
// KeepAliveWg is the number of seconds to keep alive
|
||||
// for WireGuard NAT/firewall traversal
|
||||
KeepAliveWg int
|
||||
// AdvertiseRoutes whether or not to advertise routes to and from the
|
||||
// mesh network
|
||||
AdvertiseRoutes bool
|
||||
// AdvertiseDefaultRoute whether or not to advertise the default route
|
||||
// into the mesh network
|
||||
AdvertiseDefaultRoute bool
|
||||
// Endpoint is the routable alias of the machine. Can be an IP
|
||||
// or DNS entry
|
||||
Endpoint string
|
||||
Role string
|
||||
// Role is the role of the individual in the mesh
|
||||
Role string
|
||||
}
|
||||
|
||||
type NewMeshArgs struct {
|
||||
// WgArgs are specific WireGuard args to use
|
||||
WgArgs WireGuardArgs
|
||||
}
|
||||
|
||||
type JoinMeshArgs struct {
|
||||
@ -24,14 +40,8 @@ type JoinMeshArgs struct {
|
||||
MeshId string
|
||||
// IpAddress is a routable IP in another mesh
|
||||
IpAdress string
|
||||
// Port is the WireGuard port to expose
|
||||
Port int
|
||||
// Endpoint to use to override the default
|
||||
Endpoint string
|
||||
// Client specifies whether we should join as a client of the peer
|
||||
// we are connecting to
|
||||
Client bool
|
||||
Role string
|
||||
// WgArgs is the WireGuard parameters to use.
|
||||
WgArgs WireGuardArgs
|
||||
}
|
||||
|
||||
type PutServiceArgs struct {
|
||||
@ -52,11 +62,6 @@ type QueryMesh struct {
|
||||
Query string
|
||||
}
|
||||
|
||||
type GetNodeArgs struct {
|
||||
NodeId string
|
||||
MeshId string
|
||||
}
|
||||
|
||||
type MeshIpc interface {
|
||||
CreateMesh(args *NewMeshArgs, reply *string) error
|
||||
ListMeshes(name string, reply *ListMeshReply) error
|
||||
@ -68,7 +73,6 @@ type MeshIpc interface {
|
||||
PutDescription(description string, reply *string) error
|
||||
PutAlias(alias string, reply *string) error
|
||||
PutService(args PutServiceArgs, reply *string) error
|
||||
GetNode(args GetNodeArgs, reply *string) error
|
||||
DeleteService(service string, reply *string) error
|
||||
}
|
||||
|
||||
|
@ -225,8 +225,11 @@ type Route struct {
|
||||
}
|
||||
|
||||
func (r1 Route) equal(r2 Route) bool {
|
||||
mask1Ones, _ := r1.Destination.Mask.Size()
|
||||
mask2Ones, _ := r2.Destination.Mask.Size()
|
||||
|
||||
return r1.Gateway.String() == r2.Gateway.String() &&
|
||||
r1.Destination.String() == r2.Destination.String()
|
||||
(mask1Ones == 0 && mask2Ones == 0 || r1.Destination.IP.Equal(r2.Destination.IP))
|
||||
}
|
||||
|
||||
// DeleteRoutes deletes all routes not in exclude
|
||||
@ -257,18 +260,11 @@ func (c *RtNetlinkConfig) DeleteRoutes(ifName string, family uint8, exclude ...R
|
||||
|
||||
shouldExclude := func(r Route) bool {
|
||||
for _, route := range exclude {
|
||||
if route.equal(r) {
|
||||
return false
|
||||
}
|
||||
|
||||
if family == unix.AF_INET && route.Destination.IP.To4() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if family == unix.AF_INET6 && route.Destination.IP.To16() == nil {
|
||||
if r.equal(route) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
// lib contains helper functions for the implementation
|
||||
package lib
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"math"
|
||||
|
||||
"gonum.org/v1/gonum/stat"
|
||||
"gonum.org/v1/gonum/stat/distuv"
|
||||
)
|
||||
|
||||
// Modelling the distribution using a normal distribution get the count
|
||||
// of the outliers
|
||||
func GetOutliers[K cmp.Ordered](counts map[K]uint64, alpha float64) []K {
|
||||
n := float64(len(counts))
|
||||
|
||||
keys := MapKeys(counts)
|
||||
values := make([]float64, len(keys))
|
||||
|
||||
for index, key := range keys {
|
||||
values[index] = float64(counts[key])
|
||||
}
|
||||
|
||||
mean := stat.Mean(values, nil)
|
||||
stdDev := stat.StdDev(values, nil)
|
||||
|
||||
moe := distuv.Normal{Mu: 0, Sigma: 1}.Quantile(1-alpha/2) * (stdDev / math.Sqrt(n))
|
||||
|
||||
lowerBound := mean - moe
|
||||
|
||||
var outliers []K
|
||||
|
||||
for i, count := range values {
|
||||
if count < lowerBound {
|
||||
outliers = append(outliers, keys[i])
|
||||
}
|
||||
}
|
||||
|
||||
return outliers
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package mesh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tim-beatham/wgmesh/pkg/hosts"
|
||||
)
|
||||
|
||||
type MeshAliasManager interface {
|
||||
AddAliases(nodes []MeshNode)
|
||||
RemoveAliases(node []MeshNode)
|
||||
}
|
||||
|
||||
type AliasManager struct {
|
||||
hosts hosts.HostsManipulator
|
||||
}
|
||||
|
||||
// AddAliases: on node update or change add aliases to the hosts file
|
||||
func (a *AliasManager) AddAliases(nodes []MeshNode) {
|
||||
for _, node := range nodes {
|
||||
if node.GetAlias() != "" {
|
||||
a.hosts.AddAddr(hosts.HostsEntry{
|
||||
Alias: fmt.Sprintf("%s.smeg", node.GetAlias()),
|
||||
Ip: node.GetWgHost().IP,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveAliases: on node remove remove aliases from the hosts file
|
||||
func (a *AliasManager) RemoveAliases(nodes []MeshNode) {
|
||||
for _, node := range nodes {
|
||||
if node.GetAlias() != "" {
|
||||
a.hosts.Remove(hosts.HostsEntry{
|
||||
Alias: fmt.Sprintf("%s.smeg", node.GetAlias()),
|
||||
Ip: node.GetWgHost().IP,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewAliasManager() MeshAliasManager {
|
||||
return &AliasManager{
|
||||
hosts: hosts.NewHostsManipulator(),
|
||||
}
|
||||
}
|
@ -134,10 +134,7 @@ func (m *WgMeshConfigApplyer) getRoutes(meshProvider MeshProvider) map[string][]
|
||||
|
||||
for _, route := range node.GetRoutes() {
|
||||
if lib.Contains(meshPrefixes, func(prefix *net.IPNet) bool {
|
||||
v6Default, _, _ := net.ParseCIDR("::/0")
|
||||
v4Default, _, _ := net.ParseCIDR("0.0.0.0/0")
|
||||
|
||||
if (prefix.IP.Equal(v6Default) || prefix.IP.Equal(v4Default)) && *meshProvider.GetConfiguration().AdvertiseDefaultRoute {
|
||||
if prefix.IP.Equal(net.IPv6zero) && *meshProvider.GetConfiguration().AdvertiseDefaultRoute {
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,6 @@ type MeshManager interface {
|
||||
GetClient() *wgctrl.Client
|
||||
GetMeshes() map[string]MeshProvider
|
||||
Close() error
|
||||
GetMonitor() MeshMonitor
|
||||
GetNode(string, string) MeshNode
|
||||
GetRouteManager() RouteManager
|
||||
}
|
||||
@ -52,7 +51,6 @@ type MeshManagerImpl struct {
|
||||
idGenerator lib.IdGenerator
|
||||
ipAllocator ip.IPAllocator
|
||||
interfaceManipulator wg.WgInterfaceManipulator
|
||||
Monitor MeshMonitor
|
||||
cmdRunner cmd.CmdRunner
|
||||
OnDelete func(MeshProvider)
|
||||
}
|
||||
@ -104,11 +102,6 @@ func (m *MeshManagerImpl) GetNode(meshid, nodeId string) MeshNode {
|
||||
return node
|
||||
}
|
||||
|
||||
// GetMonitor implements MeshManager.
|
||||
func (m *MeshManagerImpl) GetMonitor() MeshMonitor {
|
||||
return m.Monitor
|
||||
}
|
||||
|
||||
// CreateMeshParams contains the parameters required to create a mesh
|
||||
type CreateMeshParams struct {
|
||||
Port int
|
||||
@ -510,7 +503,7 @@ func NewMeshManager(params *NewMeshManagerParams) MeshManager {
|
||||
m.RouteManager = params.RouteManager
|
||||
|
||||
if m.RouteManager == nil {
|
||||
m.RouteManager = NewRouteManager(m, ¶ms.Conf)
|
||||
m.RouteManager = NewRouteManager(m)
|
||||
}
|
||||
|
||||
if params.CommandRunner == nil {
|
||||
@ -521,11 +514,6 @@ func NewMeshManager(params *NewMeshManagerParams) MeshManager {
|
||||
m.ipAllocator = params.IPAllocator
|
||||
m.interfaceManipulator = params.InterfaceManipulator
|
||||
|
||||
m.Monitor = NewMeshMonitor(m)
|
||||
|
||||
aliasManager := NewAliasManager()
|
||||
m.Monitor.AddUpdateCallback(aliasManager.AddAliases)
|
||||
m.Monitor.AddRemoveCallback(aliasManager.RemoveAliases)
|
||||
m.OnDelete = params.OnDelete
|
||||
return m
|
||||
}
|
||||
|
@ -10,8 +10,32 @@ import (
|
||||
)
|
||||
|
||||
func getMeshConfiguration() *conf.DaemonConfiguration {
|
||||
advertiseRoutes := true
|
||||
advertiseDefaultRoute := true
|
||||
ipDiscovery := conf.PUBLIC_IP_DISCOVERY
|
||||
role := conf.PEER_ROLE
|
||||
|
||||
return &conf.DaemonConfiguration{
|
||||
GrpcPort: 8080,
|
||||
GrpcPort: 8080,
|
||||
CertificatePath: "./somecertificatepath",
|
||||
PrivateKeyPath: "./someprivatekeypath",
|
||||
CaCertificatePath: "./somecacertificatepath",
|
||||
SkipCertVerification: true,
|
||||
Timeout: 5,
|
||||
Profile: false,
|
||||
StubWg: true,
|
||||
SyncRate: 2,
|
||||
KeepAliveTime: 60,
|
||||
ClusterSize: 64,
|
||||
InterClusterChance: 0.15,
|
||||
BranchRate: 3,
|
||||
InfectionCount: 3,
|
||||
BaseConfiguration: conf.WgConfiguration{
|
||||
IPDiscovery: &ipDiscovery,
|
||||
AdvertiseRoutes: &advertiseRoutes,
|
||||
AdvertiseDefaultRoute: &advertiseDefaultRoute,
|
||||
Role: &role,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +58,10 @@ func getMeshManager() MeshManager {
|
||||
func TestCreateMeshCreatesANewMeshProvider(t *testing.T) {
|
||||
manager := getMeshManager()
|
||||
|
||||
meshId, err := manager.CreateMesh("wg0", 5000)
|
||||
meshId, err := manager.CreateMesh(&CreateMeshParams{
|
||||
Port: 0,
|
||||
Conf: &conf.WgConfiguration{},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@ -121,7 +148,7 @@ func TestAddSelfAddsSelfToTheMesh(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, ok := mesh.GetNodes()["abc.com"]
|
||||
_, ok := mesh.GetNodes()[manager.GetPublicKey().String()]
|
||||
|
||||
if !ok {
|
||||
t.Fatalf(`node has not been added`)
|
||||
@ -186,12 +213,51 @@ func TestLeaveMeshDeletesMesh(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetAlias(t *testing.T) {
|
||||
manager := getMeshManager()
|
||||
alias := "Firpo"
|
||||
|
||||
meshId, _ := manager.CreateMesh(&CreateMeshParams{
|
||||
Port: 5000,
|
||||
Conf: &conf.WgConfiguration{},
|
||||
})
|
||||
|
||||
manager.AddSelf(&AddSelfParams{
|
||||
MeshId: meshId,
|
||||
WgPort: 5000,
|
||||
Endpoint: "abc.com:8080",
|
||||
})
|
||||
|
||||
err := manager.SetAlias(alias)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(`failed to set the alias`)
|
||||
}
|
||||
|
||||
self, err := manager.GetSelf(meshId)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(`failed to set the alias err: %s`, err.Error())
|
||||
}
|
||||
|
||||
if alias != self.GetAlias() {
|
||||
t.Fatalf(`alias should be %s was %s`, alias, self.GetAlias())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDescription(t *testing.T) {
|
||||
manager := getMeshManager()
|
||||
description := "wooooo"
|
||||
|
||||
meshId1, _ := manager.CreateMesh(5000)
|
||||
meshId2, _ := manager.CreateMesh(5001)
|
||||
meshId1, _ := manager.CreateMesh(&CreateMeshParams{
|
||||
Port: 5000,
|
||||
Conf: &conf.WgConfiguration{},
|
||||
})
|
||||
|
||||
meshId2, _ := manager.CreateMesh(&CreateMeshParams{
|
||||
Port: 5001,
|
||||
Conf: &conf.WgConfiguration{},
|
||||
})
|
||||
|
||||
manager.AddSelf(&AddSelfParams{
|
||||
MeshId: meshId1,
|
||||
@ -209,13 +275,40 @@ func TestSetDescription(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf(`failed to set the descriptions`)
|
||||
}
|
||||
|
||||
self1, err := manager.GetSelf(meshId1)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(`failed to set the description`)
|
||||
}
|
||||
|
||||
if description != self1.GetDescription() {
|
||||
t.Fatalf(`description should be %s was %s`, description, self1.GetDescription())
|
||||
}
|
||||
|
||||
self2, err := manager.GetSelf(meshId2)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf(`failed to set the description`)
|
||||
}
|
||||
|
||||
if description != self2.GetDescription() {
|
||||
t.Fatalf(`description should be %s was %s`, description, self2.GetDescription())
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTimeStampUpdatesAllMeshes(t *testing.T) {
|
||||
manager := getMeshManager()
|
||||
|
||||
meshId1, _ := manager.CreateMesh(5000)
|
||||
meshId2, _ := manager.CreateMesh(5001)
|
||||
meshId1, _ := manager.CreateMesh(&CreateMeshParams{
|
||||
Port: 5000,
|
||||
Conf: &conf.WgConfiguration{},
|
||||
})
|
||||
|
||||
meshId2, _ := manager.CreateMesh(&CreateMeshParams{
|
||||
Port: 5001,
|
||||
Conf: &conf.WgConfiguration{},
|
||||
})
|
||||
|
||||
manager.AddSelf(&AddSelfParams{
|
||||
MeshId: meshId1,
|
||||
|
@ -1,81 +0,0 @@
|
||||
package mesh
|
||||
|
||||
type OnChange = func([]MeshNode)
|
||||
|
||||
type MeshMonitor interface {
|
||||
AddUpdateCallback(cb OnChange)
|
||||
AddRemoveCallback(cb OnChange)
|
||||
Trigger() error
|
||||
}
|
||||
|
||||
type MeshMonitorImpl struct {
|
||||
updateCbs []OnChange
|
||||
removeCbs []OnChange
|
||||
nodes map[string]MeshNode
|
||||
manager MeshManager
|
||||
}
|
||||
|
||||
// Trigger causes the mesh monitor to trigger all of
|
||||
// the callbacks.
|
||||
func (m *MeshMonitorImpl) Trigger() error {
|
||||
changedNodes := make([]MeshNode, 0)
|
||||
removedNodes := make([]MeshNode, 0)
|
||||
|
||||
nodes := make(map[string]MeshNode)
|
||||
|
||||
for _, mesh := range m.manager.GetMeshes() {
|
||||
snapshot, err := mesh.GetMesh()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, node := range snapshot.GetNodes() {
|
||||
previous, exists := m.nodes[node.GetWgHost().String()]
|
||||
|
||||
if !exists || !NodeEquals(previous, node) {
|
||||
changedNodes = append(changedNodes, node)
|
||||
}
|
||||
|
||||
nodes[node.GetWgHost().String()] = node
|
||||
}
|
||||
}
|
||||
|
||||
for _, previous := range m.nodes {
|
||||
_, ok := nodes[previous.GetWgHost().String()]
|
||||
|
||||
if !ok {
|
||||
removedNodes = append(removedNodes, previous)
|
||||
}
|
||||
}
|
||||
|
||||
if len(removedNodes) > 0 {
|
||||
for _, cb := range m.removeCbs {
|
||||
cb(removedNodes)
|
||||
}
|
||||
}
|
||||
|
||||
if len(changedNodes) > 0 {
|
||||
for _, cb := range m.updateCbs {
|
||||
cb(changedNodes)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MeshMonitorImpl) AddUpdateCallback(cb OnChange) {
|
||||
m.updateCbs = append(m.updateCbs, cb)
|
||||
}
|
||||
|
||||
func (m *MeshMonitorImpl) AddRemoveCallback(cb OnChange) {
|
||||
m.removeCbs = append(m.removeCbs, cb)
|
||||
}
|
||||
|
||||
func NewMeshMonitor(manager MeshManager) MeshMonitor {
|
||||
return &MeshMonitorImpl{
|
||||
updateCbs: make([]OnChange, 0),
|
||||
nodes: make(map[string]MeshNode),
|
||||
manager: manager,
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ package mesh
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||
"github.com/tim-beatham/wgmesh/pkg/ip"
|
||||
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||
)
|
||||
@ -14,7 +13,6 @@ type RouteManager interface {
|
||||
|
||||
type RouteManagerImpl struct {
|
||||
meshManager MeshManager
|
||||
conf *conf.DaemonConfiguration
|
||||
}
|
||||
|
||||
func (r *RouteManagerImpl) UpdateRoutes() error {
|
||||
@ -22,6 +20,10 @@ func (r *RouteManagerImpl) UpdateRoutes() error {
|
||||
routes := make(map[string][]Route)
|
||||
|
||||
for _, mesh1 := range meshes {
|
||||
if !*mesh1.GetConfiguration().AdvertiseRoutes {
|
||||
continue
|
||||
}
|
||||
|
||||
self, err := r.meshManager.GetSelf(mesh1.GetMeshId())
|
||||
|
||||
if err != nil {
|
||||
@ -32,23 +34,25 @@ func (r *RouteManagerImpl) UpdateRoutes() error {
|
||||
routes[mesh1.GetMeshId()] = make([]Route, 0)
|
||||
}
|
||||
|
||||
if *mesh1.GetConfiguration().AdvertiseDefaultRoute {
|
||||
_, ipv6Default, _ := net.ParseCIDR("::/0")
|
||||
|
||||
defaultRoute := &RouteStub{
|
||||
Destination: ipv6Default,
|
||||
HopCount: 0,
|
||||
Path: []string{mesh1.GetMeshId()},
|
||||
}
|
||||
|
||||
mesh1.AddRoutes(NodeID(self), defaultRoute)
|
||||
routes[mesh1.GetMeshId()] = append(routes[mesh1.GetMeshId()], defaultRoute)
|
||||
}
|
||||
|
||||
routeMap, err := mesh1.GetRoutes(NodeID(self))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if *r.conf.BaseConfiguration.AdvertiseDefaultRoute {
|
||||
_, ipv6Default, _ := net.ParseCIDR("::/0")
|
||||
|
||||
mesh1.AddRoutes(NodeID(self),
|
||||
&RouteStub{
|
||||
Destination: ipv6Default,
|
||||
HopCount: 0,
|
||||
Path: make([]string, 0),
|
||||
})
|
||||
}
|
||||
|
||||
for _, mesh2 := range meshes {
|
||||
routeValues, ok := routes[mesh2.GetMeshId()]
|
||||
|
||||
@ -75,8 +79,9 @@ func (r *RouteManagerImpl) UpdateRoutes() error {
|
||||
return s == mesh2.GetMeshId()
|
||||
}
|
||||
|
||||
// Ensure that the route does not see it's own IP
|
||||
return !r.GetDestination().IP.Equal(mesh2IpNet.IP) && !lib.Contains(r.GetPath()[1:], pathNotMesh)
|
||||
// Remove any potential routing loops
|
||||
return !r.GetDestination().IP.Equal(mesh2IpNet.IP) &&
|
||||
!lib.Contains(r.GetPath()[1:], pathNotMesh)
|
||||
})
|
||||
|
||||
routes[mesh2.GetMeshId()] = routeValues
|
||||
@ -106,6 +111,6 @@ func (r *RouteManagerImpl) UpdateRoutes() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewRouteManager(m MeshManager, conf *conf.DaemonConfiguration) RouteManager {
|
||||
return &RouteManagerImpl{meshManager: m, conf: conf}
|
||||
func NewRouteManager(m MeshManager) RouteManager {
|
||||
return &RouteManagerImpl{meshManager: m}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||
"golang.zx2c4.com/wireguard/wgctrl"
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
@ -19,6 +20,8 @@ type MeshNodeStub struct {
|
||||
routes []Route
|
||||
identifier string
|
||||
description string
|
||||
alias string
|
||||
services map[string]string
|
||||
}
|
||||
|
||||
// GetType implements MeshNode.
|
||||
@ -32,8 +35,8 @@ func (*MeshNodeStub) GetServices() map[string]string {
|
||||
}
|
||||
|
||||
// GetAlias implements MeshNode.
|
||||
func (*MeshNodeStub) GetAlias() string {
|
||||
return ""
|
||||
func (s *MeshNodeStub) GetAlias() string {
|
||||
return s.alias
|
||||
}
|
||||
|
||||
func (m *MeshNodeStub) GetHostEndpoint() string {
|
||||
@ -83,17 +86,26 @@ type MeshProviderStub struct {
|
||||
|
||||
// GetConfiguration implements MeshProvider.
|
||||
func (*MeshProviderStub) GetConfiguration() *conf.WgConfiguration {
|
||||
panic("unimplemented")
|
||||
advertiseRoutes := true
|
||||
advertiseDefaultRoute := true
|
||||
ipDiscovery := conf.PUBLIC_IP_DISCOVERY
|
||||
role := conf.PEER_ROLE
|
||||
|
||||
return &conf.WgConfiguration{
|
||||
IPDiscovery: &ipDiscovery,
|
||||
AdvertiseRoutes: &advertiseRoutes,
|
||||
AdvertiseDefaultRoute: &advertiseDefaultRoute,
|
||||
Role: &role,
|
||||
}
|
||||
}
|
||||
|
||||
// Mark implements MeshProvider.
|
||||
func (*MeshProviderStub) Mark(nodeId string) {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// RemoveNode implements MeshProvider.
|
||||
func (*MeshProviderStub) RemoveNode(nodeId string) error {
|
||||
panic("unimplemented")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*MeshProviderStub) GetRoutes(targetId string) (map[string]Route, error) {
|
||||
@ -106,32 +118,53 @@ func (*MeshProviderStub) GetPeers() []string {
|
||||
}
|
||||
|
||||
// GetNode implements MeshProvider.
|
||||
func (*MeshProviderStub) GetNode(string) (MeshNode, error) {
|
||||
return nil, nil
|
||||
func (m *MeshProviderStub) GetNode(nodeId string) (MeshNode, error) {
|
||||
return m.snapshot.nodes[nodeId], nil
|
||||
}
|
||||
|
||||
// NodeExists implements MeshProvider.
|
||||
func (*MeshProviderStub) NodeExists(string) bool {
|
||||
return false
|
||||
func (m *MeshProviderStub) NodeExists(nodeId string) bool {
|
||||
return m.snapshot.nodes[nodeId] != nil
|
||||
}
|
||||
|
||||
// AddService implements MeshProvider.
|
||||
func (*MeshProviderStub) AddService(nodeId string, key string, value string) error {
|
||||
func (m *MeshProviderStub) AddService(nodeId string, key string, value string) error {
|
||||
node := (m.snapshot.nodes[nodeId]).(*MeshNodeStub)
|
||||
node.services[key] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveService implements MeshProvider.
|
||||
func (*MeshProviderStub) RemoveService(nodeId string, key string) error {
|
||||
func (m *MeshProviderStub) RemoveService(nodeId string, key string) error {
|
||||
node := (m.snapshot.nodes[nodeId]).(*MeshNodeStub)
|
||||
delete(node.services, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetAlias implements MeshProvider.
|
||||
func (*MeshProviderStub) SetAlias(nodeId string, alias string) error {
|
||||
func (m *MeshProviderStub) SetAlias(nodeId string, alias string) error {
|
||||
node := (m.snapshot.nodes[nodeId]).(*MeshNodeStub)
|
||||
node.alias = alias
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRoutes implements
|
||||
func (m *MeshProviderStub) AddRoutes(nodeId string, route ...Route) error {
|
||||
node := (m.snapshot.nodes[nodeId]).(*MeshNodeStub)
|
||||
node.routes = append(node.routes, route...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveRoutes implements MeshProvider.
|
||||
func (*MeshProviderStub) RemoveRoutes(nodeId string, route ...Route) error {
|
||||
func (m *MeshProviderStub) RemoveRoutes(nodeId string, route ...Route) error {
|
||||
node := (m.snapshot.nodes[nodeId]).(*MeshNodeStub)
|
||||
|
||||
newRoutes := lib.Filter(node.routes, func(r1 Route) bool {
|
||||
return !lib.Contains(route, func(r2 Route) bool {
|
||||
return RouteEqual(r1, r2)
|
||||
})
|
||||
})
|
||||
node.routes = newRoutes
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -141,12 +174,15 @@ func (*MeshProviderStub) Prune() error {
|
||||
}
|
||||
|
||||
// UpdateTimeStamp implements MeshProvider.
|
||||
func (*MeshProviderStub) UpdateTimeStamp(nodeId string) error {
|
||||
func (m *MeshProviderStub) UpdateTimeStamp(nodeId string) error {
|
||||
node := (m.snapshot.nodes[nodeId]).(*MeshNodeStub)
|
||||
node.timeStamp = time.Now().Unix()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MeshProviderStub) AddNode(node MeshNode) {
|
||||
s.snapshot.nodes[node.GetHostEndpoint()] = node
|
||||
pubKey, _ := node.GetPublicKey()
|
||||
s.snapshot.nodes[pubKey.String()] = node
|
||||
}
|
||||
|
||||
func (s *MeshProviderStub) GetMesh() (MeshSnapshot, error) {
|
||||
@ -178,15 +214,13 @@ func (s *MeshProviderStub) HasChanges() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *MeshProviderStub) AddRoutes(nodeId string, route ...Route) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MeshProviderStub) GetSyncer() MeshSyncer {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MeshProviderStub) SetDescription(nodeId string, description string) error {
|
||||
meshNode := (s.snapshot.nodes[nodeId]).(*MeshNodeStub)
|
||||
meshNode.description = description
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -209,7 +243,7 @@ func (s *StubNodeFactory) Build(params *MeshNodeFactoryParams) MeshNode {
|
||||
return &MeshNodeStub{
|
||||
hostEndpoint: params.Endpoint,
|
||||
publicKey: *params.PublicKey,
|
||||
wgEndpoint: fmt.Sprintf("%s:%s", params.Endpoint, s.Config.GrpcPort),
|
||||
wgEndpoint: fmt.Sprintf("%s:%d", params.Endpoint, s.Config.GrpcPort),
|
||||
wgHost: wgHost,
|
||||
timeStamp: time.Now().Unix(),
|
||||
routes: make([]Route, 0),
|
||||
@ -255,11 +289,6 @@ func (*MeshManagerStub) SetService(service string, value string) error {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// GetMonitor implements MeshManager.
|
||||
func (*MeshManagerStub) GetMonitor() MeshMonitor {
|
||||
panic("unimplemented")
|
||||
}
|
||||
|
||||
// SetAlias implements MeshManager.
|
||||
func (*MeshManagerStub) SetAlias(alias string) error {
|
||||
panic("unimplemented")
|
||||
|
@ -20,6 +20,12 @@ type Route interface {
|
||||
GetPath() []string
|
||||
}
|
||||
|
||||
func RouteEqual(r1 Route, r2 Route) bool {
|
||||
return r1.GetDestination().IP.Equal(r2.GetDestination().IP) &&
|
||||
r1.GetHopCount() == r2.GetHopCount() &&
|
||||
slices.Equal(r1.GetPath(), r2.GetPath())
|
||||
}
|
||||
|
||||
func RouteEquals(r1, r2 Route) bool {
|
||||
return r1.GetDestination().String() == r2.GetDestination().String() &&
|
||||
r1.GetHopCount() == r2.GetHopCount() &&
|
||||
|
@ -2,7 +2,6 @@ package robin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
@ -11,9 +10,7 @@ import (
|
||||
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||
"github.com/tim-beatham/wgmesh/pkg/query"
|
||||
"github.com/tim-beatham/wgmesh/pkg/rpc"
|
||||
)
|
||||
|
||||
@ -21,8 +18,8 @@ type IpcHandler struct {
|
||||
Server ctrlserver.CtrlServer
|
||||
}
|
||||
|
||||
func (n *IpcHandler) CreateMesh(args *ipc.NewMeshArgs, reply *string) error {
|
||||
overrideConf := &conf.WgConfiguration{}
|
||||
func getOverrideConfiguration(args *ipc.WireGuardArgs) conf.WgConfiguration {
|
||||
overrideConf := conf.WgConfiguration{}
|
||||
|
||||
if args.Role != "" {
|
||||
role := conf.NodeType(args.Role)
|
||||
@ -33,13 +30,26 @@ func (n *IpcHandler) CreateMesh(args *ipc.NewMeshArgs, reply *string) error {
|
||||
overrideConf.Endpoint = &args.Endpoint
|
||||
}
|
||||
|
||||
if *overrideConf.Role == conf.CLIENT_ROLE {
|
||||
if args.KeepAliveWg != 0 {
|
||||
keepAliveWg := args.KeepAliveWg
|
||||
overrideConf.KeepAliveWg = &keepAliveWg
|
||||
}
|
||||
|
||||
overrideConf.AdvertiseRoutes = &args.AdvertiseRoutes
|
||||
overrideConf.AdvertiseDefaultRoute = &args.AdvertiseDefaultRoute
|
||||
return overrideConf
|
||||
}
|
||||
|
||||
func (n *IpcHandler) CreateMesh(args *ipc.NewMeshArgs, reply *string) error {
|
||||
overrideConf := getOverrideConfiguration(&args.WgArgs)
|
||||
|
||||
if overrideConf.Role != nil && *overrideConf.Role == conf.CLIENT_ROLE {
|
||||
return fmt.Errorf("cannot create a mesh with no public endpoint")
|
||||
}
|
||||
|
||||
meshId, err := n.Server.GetMeshManager().CreateMesh(&mesh.CreateMeshParams{
|
||||
Port: args.WgPort,
|
||||
Conf: overrideConf,
|
||||
Port: args.WgArgs.WgPort,
|
||||
Conf: &overrideConf,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@ -48,8 +58,8 @@ func (n *IpcHandler) CreateMesh(args *ipc.NewMeshArgs, reply *string) error {
|
||||
|
||||
err = n.Server.GetMeshManager().AddSelf(&mesh.AddSelfParams{
|
||||
MeshId: meshId,
|
||||
WgPort: args.WgPort,
|
||||
Endpoint: args.Endpoint,
|
||||
WgPort: args.WgArgs.WgPort,
|
||||
Endpoint: args.WgArgs.Endpoint,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@ -74,16 +84,7 @@ func (n *IpcHandler) ListMeshes(_ string, reply *ipc.ListMeshReply) error {
|
||||
}
|
||||
|
||||
func (n *IpcHandler) JoinMesh(args ipc.JoinMeshArgs, reply *string) error {
|
||||
overrideConf := &conf.WgConfiguration{}
|
||||
|
||||
if args.Role != "" {
|
||||
role := conf.NodeType(args.Role)
|
||||
overrideConf.Role = &role
|
||||
}
|
||||
|
||||
if args.Endpoint != "" {
|
||||
overrideConf.Endpoint = &args.Endpoint
|
||||
}
|
||||
overrideConf := getOverrideConfiguration(&args.WgArgs)
|
||||
|
||||
peerConnection, err := n.Server.GetConnectionManager().GetConnection(args.IpAdress)
|
||||
|
||||
@ -116,9 +117,9 @@ func (n *IpcHandler) JoinMesh(args ipc.JoinMeshArgs, reply *string) error {
|
||||
|
||||
err = n.Server.GetMeshManager().AddMesh(&mesh.AddMeshParams{
|
||||
MeshId: args.MeshId,
|
||||
WgPort: args.Port,
|
||||
WgPort: args.WgArgs.WgPort,
|
||||
MeshBytes: meshReply.Mesh,
|
||||
Conf: overrideConf,
|
||||
Conf: &overrideConf,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@ -127,8 +128,8 @@ func (n *IpcHandler) JoinMesh(args ipc.JoinMeshArgs, reply *string) error {
|
||||
|
||||
err = n.Server.GetMeshManager().AddSelf(&mesh.AddSelfParams{
|
||||
MeshId: args.MeshId,
|
||||
WgPort: args.Port,
|
||||
Endpoint: args.Endpoint,
|
||||
WgPort: args.WgArgs.WgPort,
|
||||
Endpoint: args.WgArgs.Endpoint,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@ -171,30 +172,9 @@ func (n *IpcHandler) GetMesh(meshId string, reply *ipc.GetMeshReply) error {
|
||||
|
||||
i := 0
|
||||
for _, node := range meshSnapshot.GetNodes() {
|
||||
pubKey, _ := node.GetPublicKey()
|
||||
node := ctrlserver.NewCtrlNode(theMesh, node)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
node := ctrlserver.MeshNode{
|
||||
HostEndpoint: node.GetHostEndpoint(),
|
||||
WgEndpoint: node.GetWgEndpoint(),
|
||||
PublicKey: pubKey.String(),
|
||||
WgHost: node.GetWgHost().String(),
|
||||
Timestamp: node.GetTimeStamp(),
|
||||
Routes: lib.Map(node.GetRoutes(), func(r mesh.Route) ctrlserver.MeshRoute {
|
||||
return ctrlserver.MeshRoute{
|
||||
Destination: r.GetDestination().String(),
|
||||
Path: r.GetPath(),
|
||||
}
|
||||
}),
|
||||
Description: node.GetDescription(),
|
||||
Alias: node.GetAlias(),
|
||||
Services: node.GetServices(),
|
||||
}
|
||||
|
||||
nodes[i] = node
|
||||
nodes[i] = *node
|
||||
i += 1
|
||||
}
|
||||
|
||||
@ -270,27 +250,6 @@ func (n *IpcHandler) DeleteService(service string, reply *string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *IpcHandler) GetNode(args ipc.GetNodeArgs, reply *string) error {
|
||||
node := n.Server.GetMeshManager().GetNode(args.MeshId, args.NodeId)
|
||||
|
||||
if node == nil {
|
||||
*reply = "nil"
|
||||
return nil
|
||||
}
|
||||
|
||||
queryNode := query.MeshNodeToQueryNode(node)
|
||||
|
||||
bytes, err := json.Marshal(queryNode)
|
||||
|
||||
if err != nil {
|
||||
*reply = err.Error()
|
||||
return nil
|
||||
}
|
||||
|
||||
*reply = string(bytes)
|
||||
return nil
|
||||
}
|
||||
|
||||
type RobinIpcParams struct {
|
||||
CtrlServer ctrlserver.CtrlServer
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package robin
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||
@ -17,9 +18,11 @@ func TestCreateMeshRepliesMeshId(t *testing.T) {
|
||||
requester := getRequester()
|
||||
|
||||
err := requester.CreateMesh(&ipc.NewMeshArgs{
|
||||
IfName: "wg0",
|
||||
WgPort: 5000,
|
||||
Endpoint: "abc.com",
|
||||
WgArgs: ipc.WireGuardArgs{
|
||||
WgPort: 500,
|
||||
Endpoint: "abc.com:1234",
|
||||
Role: "peer",
|
||||
},
|
||||
}, &reply)
|
||||
|
||||
if err != nil {
|
||||
@ -52,9 +55,8 @@ func TestListMeshesMeshesNotEmpty(t *testing.T) {
|
||||
|
||||
requester.Server.GetMeshManager().AddMesh(&mesh.AddMeshParams{
|
||||
MeshId: "tim123",
|
||||
DevName: "wg0",
|
||||
WgPort: 5000,
|
||||
MeshBytes: make([]byte, 0),
|
||||
Conf: &conf.WgConfiguration{},
|
||||
})
|
||||
|
||||
err := requester.ListMeshes("", &reply)
|
||||
|
@ -1,6 +1,8 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"time"
|
||||
@ -25,7 +27,7 @@ type SyncerImpl struct {
|
||||
syncCount int
|
||||
cluster conn.ConnCluster
|
||||
conf *conf.DaemonConfiguration
|
||||
lastSync uint64
|
||||
lastSync map[string]uint64
|
||||
}
|
||||
|
||||
// Sync: Sync random nodes
|
||||
@ -39,6 +41,12 @@ func (s *SyncerImpl) Sync(meshId string) error {
|
||||
|
||||
if self != nil && self.GetType() == conf.PEER_ROLE && !s.manager.HasChanges(meshId) && s.infectionCount == 0 {
|
||||
logging.Log.WriteInfof("No changes for %s", meshId)
|
||||
|
||||
// If not synchronised in certain pull from random neighbour
|
||||
if uint64(time.Now().Unix())-s.lastSync[meshId] > 20 {
|
||||
return s.Pull(meshId)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -110,7 +118,7 @@ func (s *SyncerImpl) Sync(meshId string) error {
|
||||
}
|
||||
|
||||
s.manager.GetMesh(meshId).SaveChanges()
|
||||
s.lastSync = uint64(time.Now().Unix())
|
||||
s.lastSync[meshId] = uint64(time.Now().Unix())
|
||||
|
||||
logging.Log.WriteInfof("UPDATING WG CONF")
|
||||
err := s.manager.ApplyConfig()
|
||||
@ -122,6 +130,51 @@ func (s *SyncerImpl) Sync(meshId string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pull one node in the cluster, if there has not been message dissemination
|
||||
// in a certain period of time pull a random node within the cluster
|
||||
func (s *SyncerImpl) Pull(meshId string) error {
|
||||
mesh := s.manager.GetMesh(meshId)
|
||||
self, err := s.manager.GetSelf(meshId)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pubKey, _ := self.GetPublicKey()
|
||||
|
||||
if mesh == nil {
|
||||
return errors.New("mesh is nil, invalid operation")
|
||||
}
|
||||
|
||||
peers := mesh.GetPeers()
|
||||
neighbours := s.cluster.GetNeighbours(peers, pubKey.String())
|
||||
neighbour := lib.RandomSubsetOfLength(neighbours, 1)
|
||||
|
||||
if len(neighbour) == 0 {
|
||||
logging.Log.WriteInfof("no neighbours")
|
||||
return nil
|
||||
}
|
||||
|
||||
logging.Log.WriteInfof("PULLING from node %s", neighbour[0])
|
||||
|
||||
pullNode, err := mesh.GetNode(neighbour[0])
|
||||
|
||||
if err != nil || pullNode == nil {
|
||||
return fmt.Errorf("node %s does not exist in the mesh", neighbour[0])
|
||||
}
|
||||
|
||||
err = s.requester.SyncMesh(meshId, pullNode)
|
||||
|
||||
if err == nil || err == io.EOF {
|
||||
s.lastSync[meshId] = uint64(time.Now().Unix())
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
|
||||
s.syncCount++
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncMeshes: Sync all meshes
|
||||
func (s *SyncerImpl) SyncMeshes() error {
|
||||
for meshId := range s.manager.GetMeshes() {
|
||||
@ -143,5 +196,6 @@ func NewSyncer(m mesh.MeshManager, conf *conf.DaemonConfiguration, r SyncRequest
|
||||
requester: r,
|
||||
infectionCount: 0,
|
||||
syncCount: 0,
|
||||
cluster: cluster}
|
||||
cluster: cluster,
|
||||
lastSync: make(map[string]uint64)}
|
||||
}
|
||||
|
@ -1,15 +1,20 @@
|
||||
package wg
|
||||
|
||||
import "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
type WgInterfaceManipulatorStub struct{}
|
||||
|
||||
func (i *WgInterfaceManipulatorStub) CreateInterface(port int) (string, error) {
|
||||
return "", nil
|
||||
// CreateInterface creates a WireGuard interface
|
||||
func (w *WgInterfaceManipulatorStub) CreateInterface(port int, privateKey *wgtypes.Key) (string, error) {
|
||||
return "aninterface", nil
|
||||
}
|
||||
|
||||
func (i *WgInterfaceManipulatorStub) AddAddress(ifName string, addr string) error {
|
||||
// AddAddress adds an address to the given interface name
|
||||
func (w *WgInterfaceManipulatorStub) AddAddress(ifName string, addr string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *WgInterfaceManipulatorStub) RemoveInterface(ifName string) error {
|
||||
// RemoveInterface removes the specified interface
|
||||
func (w *WgInterfaceManipulatorStub) RemoveInterface(ifName string) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -2,14 +2,6 @@ package wg
|
||||
|
||||
import "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
|
||||
type WgError struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (m *WgError) Error() string {
|
||||
return m.msg
|
||||
}
|
||||
|
||||
type WgInterfaceManipulator interface {
|
||||
// CreateInterface creates a WireGuard interface
|
||||
CreateInterface(port int, privateKey *wgtypes.Key) (string, error)
|
||||
@ -18,3 +10,11 @@ type WgInterfaceManipulator interface {
|
||||
// RemoveInterface removes the specified interface
|
||||
RemoveInterface(ifName string) error
|
||||
}
|
||||
|
||||
type WgError struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (m *WgError) Error() string {
|
||||
return m.msg
|
||||
}
|
||||
|
Reference in New Issue
Block a user