forked from extern/smegmesh
Compare commits
13 Commits
26-perform
...
25-modify-
Author | SHA1 | Date | |
---|---|---|---|
4c54022f63 | |||
bf0724f6e5 | |||
624bd6e921 | |||
7b939e0468 | |||
6e201ebaf5 | |||
06542da03c | |||
0d63cd6624 | |||
f13319cfc1 | |||
95f4495b0b | |||
330fa74ef4 | |||
3e5b57e41f | |||
b179cd3cf4 | |||
8f211aa116 |
@ -7,11 +7,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
apiServer, err := api.NewSmegServer()
|
apiServer, err := api.NewSmegServer(api.ApiServerConf{
|
||||||
|
WordsFile: "./cmd/api/words.txt",
|
||||||
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
apiServer.Run(":40000")
|
apiServer.Run(":8080")
|
||||||
}
|
}
|
||||||
|
257
cmd/api/words.txt
Normal file
257
cmd/api/words.txt
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
be
|
||||||
|
to
|
||||||
|
of
|
||||||
|
it
|
||||||
|
in
|
||||||
|
we
|
||||||
|
do
|
||||||
|
he
|
||||||
|
on
|
||||||
|
go
|
||||||
|
at
|
||||||
|
if
|
||||||
|
or
|
||||||
|
up
|
||||||
|
by
|
||||||
|
hi
|
||||||
|
the
|
||||||
|
and
|
||||||
|
you
|
||||||
|
not
|
||||||
|
for
|
||||||
|
but
|
||||||
|
say
|
||||||
|
get
|
||||||
|
she
|
||||||
|
one
|
||||||
|
all
|
||||||
|
can
|
||||||
|
out
|
||||||
|
who
|
||||||
|
now
|
||||||
|
see
|
||||||
|
way
|
||||||
|
how
|
||||||
|
lot
|
||||||
|
yes
|
||||||
|
use
|
||||||
|
any
|
||||||
|
day
|
||||||
|
try
|
||||||
|
put
|
||||||
|
let
|
||||||
|
why
|
||||||
|
new
|
||||||
|
off
|
||||||
|
big
|
||||||
|
too
|
||||||
|
ask
|
||||||
|
man
|
||||||
|
bit
|
||||||
|
end
|
||||||
|
may
|
||||||
|
own
|
||||||
|
run
|
||||||
|
pay
|
||||||
|
job
|
||||||
|
old
|
||||||
|
kid
|
||||||
|
bad
|
||||||
|
few
|
||||||
|
ago
|
||||||
|
far
|
||||||
|
buy
|
||||||
|
set
|
||||||
|
guy
|
||||||
|
car
|
||||||
|
sit
|
||||||
|
war
|
||||||
|
win
|
||||||
|
yet
|
||||||
|
top
|
||||||
|
law
|
||||||
|
cut
|
||||||
|
low
|
||||||
|
die
|
||||||
|
eat
|
||||||
|
age
|
||||||
|
hit
|
||||||
|
air
|
||||||
|
add
|
||||||
|
boy
|
||||||
|
act
|
||||||
|
tax
|
||||||
|
oil
|
||||||
|
eye
|
||||||
|
son
|
||||||
|
key
|
||||||
|
fun
|
||||||
|
dad
|
||||||
|
dog
|
||||||
|
arm
|
||||||
|
fly
|
||||||
|
box
|
||||||
|
gas
|
||||||
|
lie
|
||||||
|
hot
|
||||||
|
gun
|
||||||
|
per
|
||||||
|
art
|
||||||
|
red
|
||||||
|
fit
|
||||||
|
bed
|
||||||
|
fan
|
||||||
|
mix
|
||||||
|
mom
|
||||||
|
sex
|
||||||
|
bus
|
||||||
|
fix
|
||||||
|
bar
|
||||||
|
lay
|
||||||
|
ice
|
||||||
|
bet
|
||||||
|
bag
|
||||||
|
due
|
||||||
|
aid
|
||||||
|
tie
|
||||||
|
leg
|
||||||
|
ban
|
||||||
|
odd
|
||||||
|
cup
|
||||||
|
dry
|
||||||
|
cry
|
||||||
|
rid
|
||||||
|
pop
|
||||||
|
sir
|
||||||
|
cat
|
||||||
|
map
|
||||||
|
sad
|
||||||
|
sea
|
||||||
|
aim
|
||||||
|
sun
|
||||||
|
fat
|
||||||
|
row
|
||||||
|
egg
|
||||||
|
tea
|
||||||
|
god
|
||||||
|
wed
|
||||||
|
tip
|
||||||
|
ear
|
||||||
|
hat
|
||||||
|
net
|
||||||
|
ill
|
||||||
|
dig
|
||||||
|
fee
|
||||||
|
mad
|
||||||
|
gap
|
||||||
|
nor
|
||||||
|
bid
|
||||||
|
era
|
||||||
|
toy
|
||||||
|
sky
|
||||||
|
bin
|
||||||
|
owe
|
||||||
|
wet
|
||||||
|
tap
|
||||||
|
pro
|
||||||
|
ski
|
||||||
|
cow
|
||||||
|
pen
|
||||||
|
van
|
||||||
|
web
|
||||||
|
pot
|
||||||
|
sum
|
||||||
|
cap
|
||||||
|
log
|
||||||
|
pub
|
||||||
|
pig
|
||||||
|
joy
|
||||||
|
raw
|
||||||
|
rat
|
||||||
|
via
|
||||||
|
lip
|
||||||
|
two
|
||||||
|
six
|
||||||
|
ten
|
||||||
|
lab
|
||||||
|
ton
|
||||||
|
mid
|
||||||
|
bat
|
||||||
|
hip
|
||||||
|
gut
|
||||||
|
sin
|
||||||
|
non
|
||||||
|
rub
|
||||||
|
sub
|
||||||
|
par
|
||||||
|
pre
|
||||||
|
ray
|
||||||
|
cue
|
||||||
|
dye
|
||||||
|
fin
|
||||||
|
ion
|
||||||
|
neo
|
||||||
|
hey
|
||||||
|
wow
|
||||||
|
mum
|
||||||
|
bye
|
||||||
|
aye
|
||||||
|
jet
|
||||||
|
sue
|
||||||
|
pet
|
||||||
|
flu
|
||||||
|
cop
|
||||||
|
ooh
|
||||||
|
rip
|
||||||
|
spy
|
||||||
|
pie
|
||||||
|
bug
|
||||||
|
gum
|
||||||
|
wan
|
||||||
|
rap
|
||||||
|
nut
|
||||||
|
beg
|
||||||
|
pin
|
||||||
|
pit
|
||||||
|
jam
|
||||||
|
tag
|
||||||
|
fax
|
||||||
|
vet
|
||||||
|
fry
|
||||||
|
pad
|
||||||
|
lad
|
||||||
|
mud
|
||||||
|
bay
|
||||||
|
con
|
||||||
|
pan
|
||||||
|
gee
|
||||||
|
toe
|
||||||
|
dip
|
||||||
|
shy
|
||||||
|
gym
|
||||||
|
zoo
|
||||||
|
fox
|
||||||
|
bow
|
||||||
|
tin
|
||||||
|
hop
|
||||||
|
wee
|
||||||
|
kit
|
||||||
|
opt
|
||||||
|
vow
|
||||||
|
sew
|
||||||
|
cab
|
||||||
|
bee
|
||||||
|
rob
|
||||||
|
rig
|
||||||
|
yep
|
||||||
|
ego
|
||||||
|
rib
|
||||||
|
nod
|
||||||
|
hug
|
||||||
|
lap
|
||||||
|
ash
|
||||||
|
hum
|
||||||
|
dam
|
||||||
|
bum
|
||||||
|
yen
|
||||||
|
jar
|
@ -16,7 +16,6 @@ const SockAddr = "/tmp/wgmesh_ipc.sock"
|
|||||||
|
|
||||||
type CreateMeshParams struct {
|
type CreateMeshParams struct {
|
||||||
Client *ipcRpc.Client
|
Client *ipcRpc.Client
|
||||||
IfName string
|
|
||||||
WgPort int
|
WgPort int
|
||||||
Endpoint string
|
Endpoint string
|
||||||
}
|
}
|
||||||
@ -24,7 +23,6 @@ type CreateMeshParams struct {
|
|||||||
func createMesh(args *CreateMeshParams) string {
|
func createMesh(args *CreateMeshParams) string {
|
||||||
var reply string
|
var reply string
|
||||||
newMeshParams := ipc.NewMeshArgs{
|
newMeshParams := ipc.NewMeshArgs{
|
||||||
IfName: args.IfName,
|
|
||||||
WgPort: args.WgPort,
|
WgPort: args.WgPort,
|
||||||
Endpoint: args.Endpoint,
|
Endpoint: args.Endpoint,
|
||||||
}
|
}
|
||||||
@ -68,7 +66,6 @@ func joinMesh(params *JoinMeshParams) string {
|
|||||||
args := ipc.JoinMeshArgs{
|
args := ipc.JoinMeshArgs{
|
||||||
MeshId: params.MeshId,
|
MeshId: params.MeshId,
|
||||||
IpAdress: params.IpAddress,
|
IpAdress: params.IpAddress,
|
||||||
IfName: params.IfName,
|
|
||||||
Port: params.WgPort,
|
Port: params.WgPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +237,6 @@ func main() {
|
|||||||
newMeshCmd := parser.NewCommand("new-mesh", "Create a new mesh")
|
newMeshCmd := parser.NewCommand("new-mesh", "Create a new mesh")
|
||||||
listMeshCmd := parser.NewCommand("list-meshes", "List meshes the node is connected to")
|
listMeshCmd := parser.NewCommand("list-meshes", "List meshes the node is connected to")
|
||||||
joinMeshCmd := parser.NewCommand("join-mesh", "Join a mesh network")
|
joinMeshCmd := parser.NewCommand("join-mesh", "Join a mesh network")
|
||||||
// getMeshCmd := parser.NewCommand("get-mesh", "Get a mesh network")
|
|
||||||
enableInterfaceCmd := parser.NewCommand("enable-interface", "Enable A Specific Mesh Interface")
|
enableInterfaceCmd := parser.NewCommand("enable-interface", "Enable A Specific Mesh Interface")
|
||||||
getGraphCmd := parser.NewCommand("get-graph", "Convert a mesh into DOT format")
|
getGraphCmd := parser.NewCommand("get-graph", "Convert a mesh into DOT format")
|
||||||
leaveMeshCmd := parser.NewCommand("leave-mesh", "Leave a mesh network")
|
leaveMeshCmd := parser.NewCommand("leave-mesh", "Leave a mesh network")
|
||||||
@ -251,14 +247,12 @@ func main() {
|
|||||||
deleteServiceCmd := parser.NewCommand("delete-service", "Remove a service from 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")
|
getNodeCmd := parser.NewCommand("get-node", "Get a specific node from the mesh")
|
||||||
|
|
||||||
var newMeshIfName *string = newMeshCmd.String("f", "ifname", &argparse.Options{Required: true})
|
var newMeshPort *int = newMeshCmd.Int("p", "wgport", &argparse.Options{})
|
||||||
var newMeshPort *int = newMeshCmd.Int("p", "wgport", &argparse.Options{Required: true})
|
|
||||||
var newMeshEndpoint *string = newMeshCmd.String("e", "endpoint", &argparse.Options{})
|
var newMeshEndpoint *string = newMeshCmd.String("e", "endpoint", &argparse.Options{})
|
||||||
|
|
||||||
var joinMeshId *string = joinMeshCmd.String("m", "mesh", &argparse.Options{Required: true})
|
var joinMeshId *string = joinMeshCmd.String("m", "mesh", &argparse.Options{Required: true})
|
||||||
var joinMeshIpAddress *string = joinMeshCmd.String("i", "ip", &argparse.Options{Required: true})
|
var joinMeshIpAddress *string = joinMeshCmd.String("i", "ip", &argparse.Options{Required: true})
|
||||||
var joinMeshIfName *string = joinMeshCmd.String("f", "ifname", &argparse.Options{Required: true})
|
var joinMeshPort *int = joinMeshCmd.Int("p", "wgport", &argparse.Options{})
|
||||||
var joinMeshPort *int = joinMeshCmd.Int("p", "wgport", &argparse.Options{Required: true})
|
|
||||||
var joinMeshEndpoint *string = joinMeshCmd.String("e", "endpoint", &argparse.Options{})
|
var joinMeshEndpoint *string = joinMeshCmd.String("e", "endpoint", &argparse.Options{})
|
||||||
|
|
||||||
var enableInterfaceMeshId *string = enableInterfaceCmd.String("m", "mesh", &argparse.Options{Required: true})
|
var enableInterfaceMeshId *string = enableInterfaceCmd.String("m", "mesh", &argparse.Options{Required: true})
|
||||||
@ -298,7 +292,6 @@ func main() {
|
|||||||
if newMeshCmd.Happened() {
|
if newMeshCmd.Happened() {
|
||||||
fmt.Println(createMesh(&CreateMeshParams{
|
fmt.Println(createMesh(&CreateMeshParams{
|
||||||
Client: client,
|
Client: client,
|
||||||
IfName: *newMeshIfName,
|
|
||||||
WgPort: *newMeshPort,
|
WgPort: *newMeshPort,
|
||||||
Endpoint: *newMeshEndpoint,
|
Endpoint: *newMeshEndpoint,
|
||||||
}))
|
}))
|
||||||
@ -311,7 +304,6 @@ func main() {
|
|||||||
if joinMeshCmd.Happened() {
|
if joinMeshCmd.Happened() {
|
||||||
fmt.Println(joinMesh(&JoinMeshParams{
|
fmt.Println(joinMesh(&JoinMeshParams{
|
||||||
Client: client,
|
Client: client,
|
||||||
IfName: *joinMeshIfName,
|
|
||||||
WgPort: *joinMeshPort,
|
WgPort: *joinMeshPort,
|
||||||
IpAddress: *joinMeshIpAddress,
|
IpAddress: *joinMeshIpAddress,
|
||||||
MeshId: *joinMeshId,
|
MeshId: *joinMeshId,
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||||
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/what8words"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
||||||
@ -22,33 +23,59 @@ type ApiServer interface {
|
|||||||
type SmegServer struct {
|
type SmegServer struct {
|
||||||
router *gin.Engine
|
router *gin.Engine
|
||||||
client *ipcRpc.Client
|
client *ipcRpc.Client
|
||||||
|
words *what8words.What8Words
|
||||||
}
|
}
|
||||||
|
|
||||||
func meshNodeToAPIMeshNode(meshNode ctrlserver.MeshNode) *SmegNode {
|
func (s *SmegServer) routeToApiRoute(meshNode ctrlserver.MeshNode) []Route {
|
||||||
|
routes := make([]Route, len(meshNode.Routes))
|
||||||
|
|
||||||
|
for index, route := range meshNode.Routes {
|
||||||
|
word, err := s.words.Convert(route)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
routes[index] = Route{
|
||||||
|
Prefix: route,
|
||||||
|
RouteId: word,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return routes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SmegServer) meshNodeToAPIMeshNode(meshNode ctrlserver.MeshNode) *SmegNode {
|
||||||
if meshNode.Routes == nil {
|
if meshNode.Routes == nil {
|
||||||
meshNode.Routes = make([]string, 0)
|
meshNode.Routes = make([]string, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alias := meshNode.Alias
|
||||||
|
|
||||||
|
if alias == "" {
|
||||||
|
alias, _ = s.words.ConvertIdentifier(meshNode.WgHost)
|
||||||
|
}
|
||||||
|
|
||||||
return &SmegNode{
|
return &SmegNode{
|
||||||
WgHost: meshNode.WgHost,
|
WgHost: meshNode.WgHost,
|
||||||
WgEndpoint: meshNode.WgEndpoint,
|
WgEndpoint: meshNode.WgEndpoint,
|
||||||
Endpoint: meshNode.HostEndpoint,
|
Endpoint: meshNode.HostEndpoint,
|
||||||
Timestamp: int(meshNode.Timestamp),
|
Timestamp: int(meshNode.Timestamp),
|
||||||
Description: meshNode.Description,
|
Description: meshNode.Description,
|
||||||
Routes: meshNode.Routes,
|
Routes: s.routeToApiRoute(meshNode),
|
||||||
PublicKey: meshNode.PublicKey,
|
PublicKey: meshNode.PublicKey,
|
||||||
Alias: meshNode.Alias,
|
Alias: alias,
|
||||||
Services: meshNode.Services,
|
Services: meshNode.Services,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func meshToAPIMesh(meshId string, nodes []ctrlserver.MeshNode) SmegMesh {
|
func (s *SmegServer) meshToAPIMesh(meshId string, nodes []ctrlserver.MeshNode) SmegMesh {
|
||||||
var smegMesh SmegMesh
|
var smegMesh SmegMesh
|
||||||
smegMesh.MeshId = meshId
|
smegMesh.MeshId = meshId
|
||||||
smegMesh.Nodes = make(map[string]SmegNode)
|
smegMesh.Nodes = make(map[string]SmegNode)
|
||||||
|
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
smegMesh.Nodes[node.WgHost] = *meshNodeToAPIMeshNode(node)
|
smegMesh.Nodes[node.WgHost] = *s.meshNodeToAPIMeshNode(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
return smegMesh
|
return smegMesh
|
||||||
@ -62,11 +89,11 @@ func (s *SmegServer) CreateMesh(c *gin.Context) {
|
|||||||
c.JSON(http.StatusBadRequest, &gin.H{
|
c.JSON(http.StatusBadRequest, &gin.H{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRequest := ipc.NewMeshArgs{
|
ipcRequest := ipc.NewMeshArgs{
|
||||||
IfName: createMesh.IfName,
|
|
||||||
WgPort: createMesh.WgPort,
|
WgPort: createMesh.WgPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +127,6 @@ func (s *SmegServer) JoinMesh(c *gin.Context) {
|
|||||||
ipcRequest := ipc.JoinMeshArgs{
|
ipcRequest := ipc.JoinMeshArgs{
|
||||||
MeshId: joinMesh.MeshId,
|
MeshId: joinMesh.MeshId,
|
||||||
IpAdress: joinMesh.Bootstrap,
|
IpAdress: joinMesh.Bootstrap,
|
||||||
IfName: joinMesh.IfName,
|
|
||||||
Port: joinMesh.WgPort,
|
Port: joinMesh.WgPort,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +165,7 @@ func (s *SmegServer) GetMesh(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh := meshToAPIMesh(meshidParam, getMeshReply.Nodes)
|
mesh := s.meshToAPIMesh(meshidParam, getMeshReply.Nodes)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, mesh)
|
c.JSON(http.StatusOK, mesh)
|
||||||
}
|
}
|
||||||
@ -168,7 +194,7 @@ func (s *SmegServer) GetMeshes(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
meshes = append(meshes, meshToAPIMesh(mesh, getMeshReply.Nodes))
|
meshes = append(meshes, s.meshToAPIMesh(mesh, getMeshReply.Nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, meshes)
|
c.JSON(http.StatusOK, meshes)
|
||||||
@ -179,13 +205,19 @@ func (s *SmegServer) Run(addr string) error {
|
|||||||
return s.router.Run(addr)
|
return s.router.Run(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSmegServer() (ApiServer, error) {
|
func NewSmegServer(conf ApiServerConf) (ApiServer, error) {
|
||||||
client, err := ipcRpc.DialHTTP("unix", SockAddr)
|
client, err := ipcRpc.DialHTTP("unix", SockAddr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
words, err := what8words.NewWhat8Words(conf.WordsFile)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
|
|
||||||
router.Use(gin.LoggerWithConfig(gin.LoggerConfig{
|
router.Use(gin.LoggerWithConfig(gin.LoggerConfig{
|
||||||
@ -195,6 +227,7 @@ func NewSmegServer() (ApiServer, error) {
|
|||||||
smegServer := &SmegServer{
|
smegServer := &SmegServer{
|
||||||
router: router,
|
router: router,
|
||||||
client: client,
|
client: client,
|
||||||
|
words: words,
|
||||||
}
|
}
|
||||||
|
|
||||||
router.GET("/meshes", smegServer.GetMeshes)
|
router.GET("/meshes", smegServer.GetMeshes)
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
|
type Route struct {
|
||||||
|
RouteId string `json:"routeId"`
|
||||||
|
Prefix string `json:"prefix"`
|
||||||
|
}
|
||||||
|
|
||||||
type SmegNode struct {
|
type SmegNode struct {
|
||||||
Alias string `json:"alias"`
|
Alias string `json:"alias"`
|
||||||
WgHost string `json:"wgHost"`
|
WgHost string `json:"wgHost"`
|
||||||
@ -8,7 +13,7 @@ type SmegNode struct {
|
|||||||
Timestamp int `json:"timestamp"`
|
Timestamp int `json:"timestamp"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
PublicKey string `json:"publicKey"`
|
PublicKey string `json:"publicKey"`
|
||||||
Routes []string `json:"routes"`
|
Routes []Route `json:"routes"`
|
||||||
Services map[string]string `json:"services"`
|
Services map[string]string `json:"services"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,13 +23,15 @@ type SmegMesh struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CreateMeshRequest struct {
|
type CreateMeshRequest struct {
|
||||||
IfName string `json:"ifName" binding:"required"`
|
WgPort int `json:"port" binding:"omitempty,gte=1024,lt=65535"`
|
||||||
WgPort int `json:"port" binding:"required,gte=1024,lt=65535"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type JoinMeshRequest struct {
|
type JoinMeshRequest struct {
|
||||||
IfName string `json:"ifName" binding:"required"`
|
WgPort int `json:"port" binding:"omitempty,gte=1024,lt=65535"`
|
||||||
WgPort int `json:"port" binding:"required,gte=1024,lt=65535"`
|
|
||||||
Bootstrap string `json:"bootstrap" binding:"required"`
|
Bootstrap string `json:"bootstrap" binding:"required"`
|
||||||
MeshId string `json:"meshid" binding:"required"`
|
MeshId string `json:"meshid" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ApiServerConf struct {
|
||||||
|
WordsFile string
|
||||||
|
}
|
||||||
|
@ -42,8 +42,29 @@ func (c *CrdtMeshManager) AddNode(node mesh.MeshNode) {
|
|||||||
c.doc.Path("nodes").Map().Set(crdt.HostEndpoint, crdt)
|
c.doc.Path("nodes").Map().Set(crdt.HostEndpoint, crdt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CrdtMeshManager) GetNodeIds() []string {
|
func (c *CrdtMeshManager) isPeer(nodeId string) bool {
|
||||||
|
node, err := c.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
|
if err != nil || node.Kind() != automerge.KindMap {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeType, err := node.Map().Get("type")
|
||||||
|
|
||||||
|
if err != nil || nodeType.Kind() != automerge.KindStr {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeType.Str() == string(conf.PEER_ROLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CrdtMeshManager) GetPeers() []string {
|
||||||
keys, _ := c.doc.Path("nodes").Map().Keys()
|
keys, _ := c.doc.Path("nodes").Map().Keys()
|
||||||
|
|
||||||
|
keys = lib.Filter(keys, func(s string) bool {
|
||||||
|
return c.isPeer(s)
|
||||||
|
})
|
||||||
|
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +76,7 @@ func (c *CrdtMeshManager) GetMesh() (mesh.MeshSnapshot, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.cache == nil || len(changes) > 3 {
|
if c.cache == nil || len(changes) > 0 {
|
||||||
c.lastCacheHash = c.LastHash
|
c.lastCacheHash = c.LastHash
|
||||||
cache, err := automerge.As[*MeshCrdt](c.doc.Root())
|
cache, err := automerge.As[*MeshCrdt](c.doc.Root())
|
||||||
|
|
||||||
@ -113,7 +134,7 @@ func NewCrdtNodeManager(params *NewCrdtNodeMangerParams) (*CrdtMeshManager, erro
|
|||||||
// NodeExists: returns true if the node exists. Returns false
|
// NodeExists: returns true if the node exists. Returns false
|
||||||
func (m *CrdtMeshManager) NodeExists(key string) bool {
|
func (m *CrdtMeshManager) NodeExists(key string) bool {
|
||||||
node, err := m.doc.Path("nodes").Map().Get(key)
|
node, err := m.doc.Path("nodes").Map().Get(key)
|
||||||
return node.Kind() == automerge.KindMap && err != nil
|
return node.Kind() == automerge.KindMap && err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CrdtMeshManager) GetNode(endpoint string) (mesh.MeshNode, error) {
|
func (m *CrdtMeshManager) GetNode(endpoint string) (mesh.MeshNode, error) {
|
||||||
@ -450,6 +471,12 @@ func (m *MeshNodeCrdt) GetServices() map[string]string {
|
|||||||
return services
|
return services
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetType refers to the type of the node. Peer means that the node is globally accessible
|
||||||
|
// Client means the node is only accessible through another peer
|
||||||
|
func (n *MeshNodeCrdt) GetType() conf.NodeType {
|
||||||
|
return conf.NodeType(n.Type)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MeshCrdt) GetNodes() map[string]mesh.MeshNode {
|
func (m *MeshCrdt) GetNodes() map[string]mesh.MeshNode {
|
||||||
nodes := make(map[string]mesh.MeshNode)
|
nodes := make(map[string]mesh.MeshNode)
|
||||||
|
|
||||||
@ -464,6 +491,7 @@ func (m *MeshCrdt) GetNodes() map[string]mesh.MeshNode {
|
|||||||
Description: node.Description,
|
Description: node.Description,
|
||||||
Alias: node.Alias,
|
Alias: node.Alias,
|
||||||
Services: node.GetServices(),
|
Services: node.GetServices(),
|
||||||
|
Type: node.Type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ func (f *MeshNodeFactory) Build(params *mesh.MeshNodeFactoryParams) mesh.MeshNod
|
|||||||
Routes: map[string]interface{}{},
|
Routes: map[string]interface{}{},
|
||||||
Description: "",
|
Description: "",
|
||||||
Alias: "",
|
Alias: "",
|
||||||
|
Type: string(params.Role),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +51,13 @@ func (f *MeshNodeFactory) getAddress(params *mesh.MeshNodeFactoryParams) string
|
|||||||
} else if len(f.Config.Endpoint) != 0 {
|
} else if len(f.Config.Endpoint) != 0 {
|
||||||
hostName = f.Config.Endpoint
|
hostName = f.Config.Endpoint
|
||||||
} else {
|
} else {
|
||||||
hostName = lib.GetOutboundIP().String()
|
ip, err := lib.GetPublicIP()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
hostName = ip.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
return hostName
|
return hostName
|
||||||
|
@ -11,6 +11,7 @@ type MeshNodeCrdt struct {
|
|||||||
Alias string `automerge:"alias"`
|
Alias string `automerge:"alias"`
|
||||||
Description string `automerge:"description"`
|
Description string `automerge:"description"`
|
||||||
Services map[string]string `automerge:"services"`
|
Services map[string]string `automerge:"services"`
|
||||||
|
Type string `automerge:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MeshCrdt: Represents the mesh network as a whole
|
// MeshCrdt: Represents the mesh network as a whole
|
||||||
|
@ -16,6 +16,13 @@ func (m *WgMeshConfigurationError) Error() string {
|
|||||||
return m.msg
|
return m.msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NodeType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PEER_ROLE NodeType = "peer"
|
||||||
|
CLIENT_ROLE NodeType = "client"
|
||||||
|
)
|
||||||
|
|
||||||
type WgMeshConfiguration struct {
|
type WgMeshConfiguration struct {
|
||||||
// CertificatePath is the path to the certificate to use in mTLS
|
// CertificatePath is the path to the certificate to use in mTLS
|
||||||
CertificatePath string `yaml:"certificatePath"`
|
CertificatePath string `yaml:"certificatePath"`
|
||||||
@ -53,6 +60,12 @@ type WgMeshConfiguration struct {
|
|||||||
Profile bool `yaml:"profile"`
|
Profile bool `yaml:"profile"`
|
||||||
// StubWg whether or not to stub the WireGuard types
|
// StubWg whether or not to stub the WireGuard types
|
||||||
StubWg bool `yaml:"stubWg"`
|
StubWg bool `yaml:"stubWg"`
|
||||||
|
// Role specifies whether or not the user is globally accessible.
|
||||||
|
// If the user is globaly accessible they specify themselves as a client.
|
||||||
|
Role NodeType `yaml:"role"`
|
||||||
|
// KeepAliveWg configures the implementation so that we send keep alive packets to peers.
|
||||||
|
// KeepAlive can only be set if role is type client
|
||||||
|
KeepAliveWg int `yaml:"keepAliveWg"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateConfiguration(c *WgMeshConfiguration) error {
|
func ValidateConfiguration(c *WgMeshConfiguration) error {
|
||||||
@ -134,6 +147,10 @@ func ValidateConfiguration(c *WgMeshConfiguration) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Role == "" {
|
||||||
|
c.Role = PEER_ROLE
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ func NewCtrlServer(params *NewCtrlServerParams) (*MeshCtrlServer, error) {
|
|||||||
ipAllocator := &ip.ULABuilder{}
|
ipAllocator := &ip.ULABuilder{}
|
||||||
interfaceManipulator := wg.NewWgInterfaceManipulator(params.Client)
|
interfaceManipulator := wg.NewWgInterfaceManipulator(params.Client)
|
||||||
|
|
||||||
configApplyer := mesh.NewWgMeshConfigApplyer()
|
configApplyer := mesh.NewWgMeshConfigApplyer(params.Conf)
|
||||||
|
|
||||||
meshManagerParams := &mesh.NewMeshManagerParams{
|
meshManagerParams := &mesh.NewMeshManagerParams{
|
||||||
Conf: *params.Conf,
|
Conf: *params.Conf,
|
||||||
|
@ -11,8 +11,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type NewMeshArgs struct {
|
type NewMeshArgs struct {
|
||||||
// IfName is the interface that the mesh instance will run on
|
|
||||||
IfName string
|
|
||||||
// WgPort is the WireGuard port to expose
|
// WgPort is the WireGuard port to expose
|
||||||
WgPort int
|
WgPort int
|
||||||
// Endpoint is the routable alias of the machine. Can be an IP
|
// Endpoint is the routable alias of the machine. Can be an IP
|
||||||
@ -25,13 +23,14 @@ type JoinMeshArgs struct {
|
|||||||
MeshId string
|
MeshId string
|
||||||
// IpAddress is a routable IP in another mesh
|
// IpAddress is a routable IP in another mesh
|
||||||
IpAdress string
|
IpAdress string
|
||||||
// IfName is the interface name of the mesh
|
|
||||||
IfName string
|
|
||||||
// Port is the WireGuard port to expose
|
// Port is the WireGuard port to expose
|
||||||
Port int
|
Port int
|
||||||
// Endpoint is the routable address of this machine. If not provided
|
// Endpoint is the routable address of this machine. If not provided
|
||||||
// defaults to the default address
|
// defaults to the default address
|
||||||
Endpoint string
|
Endpoint string
|
||||||
|
// Client specifies whether we should join as a client of the peer
|
||||||
|
// we are connecting to
|
||||||
|
Client bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type PutServiceArgs struct {
|
type PutServiceArgs struct {
|
||||||
|
46
pkg/lib/hashing.go
Normal file
46
pkg/lib/hashing.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package lib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hash/fnv"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
type consistentHashRecord[V any] struct {
|
||||||
|
record V
|
||||||
|
value int
|
||||||
|
}
|
||||||
|
|
||||||
|
func HashString(value string) int {
|
||||||
|
f := fnv.New32a()
|
||||||
|
f.Write([]byte(value))
|
||||||
|
return int(f.Sum32())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsistentHash implementation. Traverse the values until we find a key
|
||||||
|
// less than ours.
|
||||||
|
func ConsistentHash[V any](values []V, client V, keyFunc func(V) int) V {
|
||||||
|
if len(values) == 0 {
|
||||||
|
panic("values is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
vs := Map(values, func(v V) consistentHashRecord[V] {
|
||||||
|
return consistentHashRecord[V]{
|
||||||
|
v,
|
||||||
|
keyFunc(v),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
sort.SliceStable(vs, func(i, j int) bool {
|
||||||
|
return vs[i].value < vs[j].value
|
||||||
|
})
|
||||||
|
|
||||||
|
ourKey := keyFunc(client)
|
||||||
|
|
||||||
|
for _, record := range vs {
|
||||||
|
if ourKey < record.value {
|
||||||
|
return record.record
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return vs[0].record
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
package lib
|
package lib
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetOutboundIP: gets the oubound IP of this packet
|
// GetOutboundIP: gets the oubound IP of this packet
|
||||||
@ -15,3 +18,44 @@ func GetOutboundIP() net.IP {
|
|||||||
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
||||||
return localAddr.IP
|
return localAddr.IP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IP_SERVICE = "https://api.ipify.org?format=json"
|
||||||
|
|
||||||
|
type IpResponse struct {
|
||||||
|
Ip string `json:"ip"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IpResponse) GetIP() net.IP {
|
||||||
|
return net.ParseIP(i.Ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPublicIP: get the nodes public IP address. For when a node is behind NAT
|
||||||
|
func GetPublicIP() (net.IP, error) {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, IP_SERVICE, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resBody, err := io.ReadAll(res.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonResponse IpResponse
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(resBody), &jsonResponse)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonResponse.GetIP(), nil
|
||||||
|
}
|
||||||
|
@ -3,7 +3,11 @@ package mesh
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/route"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,10 +20,12 @@ type MeshConfigApplyer interface {
|
|||||||
|
|
||||||
// WgMeshConfigApplyer applies WireGuard configuration
|
// WgMeshConfigApplyer applies WireGuard configuration
|
||||||
type WgMeshConfigApplyer struct {
|
type WgMeshConfigApplyer struct {
|
||||||
meshManager MeshManager
|
meshManager MeshManager
|
||||||
|
config *conf.WgMeshConfiguration
|
||||||
|
routeInstaller route.RouteInstaller
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertMeshNode(node MeshNode) (*wgtypes.PeerConfig, error) {
|
func (m *WgMeshConfigApplyer) convertMeshNode(node MeshNode, peerToClients map[string][]net.IPNet) (*wgtypes.PeerConfig, error) {
|
||||||
endpoint, err := net.ResolveUDPAddr("udp", node.GetWgEndpoint())
|
endpoint, err := net.ResolveUDPAddr("udp", node.GetWgEndpoint())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -40,10 +46,19 @@ func convertMeshNode(node MeshNode) (*wgtypes.PeerConfig, error) {
|
|||||||
allowedips = append(allowedips, *ipnet)
|
allowedips = append(allowedips, *ipnet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clients, ok := peerToClients[node.GetWgHost().String()]
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
allowedips = append(allowedips, clients...)
|
||||||
|
}
|
||||||
|
|
||||||
|
keepAlive := time.Duration(m.config.KeepAliveWg) * time.Second
|
||||||
|
|
||||||
peerConfig := wgtypes.PeerConfig{
|
peerConfig := wgtypes.PeerConfig{
|
||||||
PublicKey: pubKey,
|
PublicKey: pubKey,
|
||||||
Endpoint: endpoint,
|
Endpoint: endpoint,
|
||||||
AllowedIPs: allowedips,
|
AllowedIPs: allowedips,
|
||||||
|
PersistentKeepaliveInterval: &keepAlive,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &peerConfig, nil
|
return &peerConfig, nil
|
||||||
@ -56,13 +71,66 @@ func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes := snap.GetNodes()
|
nodes := lib.MapValues(snap.GetNodes())
|
||||||
peerConfigs := make([]wgtypes.PeerConfig, len(nodes))
|
peerConfigs := make([]wgtypes.PeerConfig, len(nodes))
|
||||||
|
|
||||||
|
peers := lib.Filter(nodes, func(mn MeshNode) bool {
|
||||||
|
return mn.GetType() == conf.PEER_ROLE
|
||||||
|
})
|
||||||
|
|
||||||
var count int = 0
|
var count int = 0
|
||||||
|
|
||||||
|
self, err := m.meshManager.GetSelf(mesh.GetMeshId())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rtnl, err := lib.NewRtNetlinkConfig()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
peerToClients := make(map[string][]net.IPNet)
|
||||||
|
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
peer, err := convertMeshNode(n)
|
if NodeEquals(n, self) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.GetType() == conf.CLIENT_ROLE && len(peers) > 0 && self.GetType() == conf.CLIENT_ROLE {
|
||||||
|
peer := lib.ConsistentHash(peers, n, func(mn MeshNode) int {
|
||||||
|
return lib.HashString(mn.GetWgHost().String())
|
||||||
|
})
|
||||||
|
|
||||||
|
dev, err := mesh.GetDevice()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rtnl.AddRoute(dev.Name, lib.Route{
|
||||||
|
Gateway: peer.GetWgHost().IP,
|
||||||
|
Destination: *n.GetWgHost(),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
clients, ok := peerToClients[peer.GetWgHost().String()]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
clients = make([]net.IPNet, 0)
|
||||||
|
peerToClients[peer.GetWgHost().String()] = clients
|
||||||
|
}
|
||||||
|
|
||||||
|
peerToClients[peer.GetWgHost().String()] = append(clients, *n.GetWgHost())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
peer, err := m.convertMeshNode(n, peerToClients)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -122,6 +190,9 @@ func (m *WgMeshConfigApplyer) SetMeshManager(manager MeshManager) {
|
|||||||
m.meshManager = manager
|
m.meshManager = manager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWgMeshConfigApplyer() MeshConfigApplyer {
|
func NewWgMeshConfigApplyer(config *conf.WgMeshConfiguration) MeshConfigApplyer {
|
||||||
return &WgMeshConfigApplyer{}
|
return &WgMeshConfigApplyer{
|
||||||
|
config: config,
|
||||||
|
routeInstaller: route.NewRouteInstaller(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type MeshManager interface {
|
type MeshManager interface {
|
||||||
CreateMesh(devName string, port int) (string, error)
|
CreateMesh(port int) (string, error)
|
||||||
AddMesh(params *AddMeshParams) error
|
AddMesh(params *AddMeshParams) error
|
||||||
HasChanges(meshid string) bool
|
HasChanges(meshid string) bool
|
||||||
GetMesh(meshId string) MeshProvider
|
GetMesh(meshId string) MeshProvider
|
||||||
@ -115,15 +115,25 @@ func (m *MeshManagerImpl) Prune() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateMesh: Creates a new mesh, stores it and returns the mesh id
|
// CreateMesh: Creates a new mesh, stores it and returns the mesh id
|
||||||
func (m *MeshManagerImpl) CreateMesh(devName string, port int) (string, error) {
|
func (m *MeshManagerImpl) CreateMesh(port int) (string, error) {
|
||||||
meshId, err := m.idGenerator.GetId()
|
meshId, err := m.idGenerator.GetId()
|
||||||
|
|
||||||
|
var ifName string = ""
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !m.conf.StubWg {
|
||||||
|
ifName, err = m.interfaceManipulator.CreateInterface(port)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error creating mesh: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nodeManager, err := m.meshProviderFactory.CreateMesh(&MeshProviderFactoryParams{
|
nodeManager, err := m.meshProviderFactory.CreateMesh(&MeshProviderFactoryParams{
|
||||||
DevName: devName,
|
DevName: ifName,
|
||||||
Port: port,
|
Port: port,
|
||||||
Conf: m.conf,
|
Conf: m.conf,
|
||||||
Client: m.Client,
|
Client: m.Client,
|
||||||
@ -134,32 +144,31 @@ func (m *MeshManagerImpl) CreateMesh(devName string, port int) (string, error) {
|
|||||||
return "", fmt.Errorf("error creating mesh: %w", err)
|
return "", fmt.Errorf("error creating mesh: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !m.conf.StubWg {
|
|
||||||
err = m.interfaceManipulator.CreateInterface(&wg.CreateInterfaceParams{
|
|
||||||
IfName: devName,
|
|
||||||
Port: port,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("error creating mesh: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Meshes[meshId] = nodeManager
|
m.Meshes[meshId] = nodeManager
|
||||||
return meshId, nil
|
return meshId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddMeshParams struct {
|
type AddMeshParams struct {
|
||||||
MeshId string
|
MeshId string
|
||||||
DevName string
|
|
||||||
WgPort int
|
WgPort int
|
||||||
MeshBytes []byte
|
MeshBytes []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddMesh: Add the mesh to the list of meshes
|
// AddMesh: Add the mesh to the list of meshes
|
||||||
func (m *MeshManagerImpl) AddMesh(params *AddMeshParams) error {
|
func (m *MeshManagerImpl) AddMesh(params *AddMeshParams) error {
|
||||||
|
var ifName string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if !m.conf.StubWg {
|
||||||
|
ifName, err = m.interfaceManipulator.CreateInterface(params.WgPort)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
meshProvider, err := m.meshProviderFactory.CreateMesh(&MeshProviderFactoryParams{
|
meshProvider, err := m.meshProviderFactory.CreateMesh(&MeshProviderFactoryParams{
|
||||||
DevName: params.DevName,
|
DevName: ifName,
|
||||||
Port: params.WgPort,
|
Port: params.WgPort,
|
||||||
Conf: m.conf,
|
Conf: m.conf,
|
||||||
Client: m.Client,
|
Client: m.Client,
|
||||||
@ -177,14 +186,6 @@ func (m *MeshManagerImpl) AddMesh(params *AddMeshParams) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m.Meshes[params.MeshId] = meshProvider
|
m.Meshes[params.MeshId] = meshProvider
|
||||||
|
|
||||||
if !m.conf.StubWg {
|
|
||||||
return m.interfaceManipulator.CreateInterface(&wg.CreateInterfaceParams{
|
|
||||||
IfName: params.DevName,
|
|
||||||
Port: params.WgPort,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,6 +256,16 @@ func (s *MeshManagerImpl) AddSelf(params *AddSelfParams) error {
|
|||||||
return fmt.Errorf("addself: mesh %s does not exist", params.MeshId)
|
return fmt.Errorf("addself: mesh %s does not exist", params.MeshId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if params.WgPort == 0 && !s.conf.StubWg {
|
||||||
|
device, err := mesh.GetDevice()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
params.WgPort = device.ListenPort
|
||||||
|
}
|
||||||
|
|
||||||
pubKey, err := s.GetPublicKey(params.MeshId)
|
pubKey, err := s.GetPublicKey(params.MeshId)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -272,6 +283,7 @@ func (s *MeshManagerImpl) AddSelf(params *AddSelfParams) error {
|
|||||||
NodeIP: nodeIP,
|
NodeIP: nodeIP,
|
||||||
WgPort: params.WgPort,
|
WgPort: params.WgPort,
|
||||||
Endpoint: params.Endpoint,
|
Endpoint: params.Endpoint,
|
||||||
|
Role: s.conf.Role,
|
||||||
})
|
})
|
||||||
|
|
||||||
if !s.conf.StubWg {
|
if !s.conf.StubWg {
|
||||||
@ -327,6 +339,7 @@ func (s *MeshManagerImpl) GetSelf(meshId string) (MeshNode, error) {
|
|||||||
return nil, fmt.Errorf("mesh %s does not exist", meshId)
|
return nil, fmt.Errorf("mesh %s does not exist", meshId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logging.Log.WriteInfof(s.HostParameters.HostEndpoint)
|
||||||
node, err := meshInstance.GetNode(s.HostParameters.HostEndpoint)
|
node, err := meshInstance.GetNode(s.HostParameters.HostEndpoint)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -337,6 +350,10 @@ func (s *MeshManagerImpl) GetSelf(meshId string) (MeshNode, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *MeshManagerImpl) ApplyConfig() error {
|
func (s *MeshManagerImpl) ApplyConfig() error {
|
||||||
|
if s.conf.StubWg {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
err := s.configApplyer.ApplyConfig()
|
err := s.configApplyer.ApplyConfig()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -439,7 +456,8 @@ func NewMeshManager(params *NewMeshManagerParams) MeshManager {
|
|||||||
|
|
||||||
switch params.Conf.Endpoint {
|
switch params.Conf.Endpoint {
|
||||||
case "":
|
case "":
|
||||||
hostParams.HostEndpoint = fmt.Sprintf("%s:%s", lib.GetOutboundIP().String(), params.Conf.GrpcPort)
|
ip, _ := lib.GetPublicIP()
|
||||||
|
hostParams.HostEndpoint = fmt.Sprintf("%s:%s", ip.String(), params.Conf.GrpcPort)
|
||||||
default:
|
default:
|
||||||
hostParams.HostEndpoint = fmt.Sprintf("%s:%s", params.Conf.Endpoint, params.Conf.GrpcPort)
|
hostParams.HostEndpoint = fmt.Sprintf("%s:%s", params.Conf.Endpoint, params.Conf.GrpcPort)
|
||||||
}
|
}
|
||||||
|
@ -201,8 +201,8 @@ func TestSetDescription(t *testing.T) {
|
|||||||
manager := getMeshManager()
|
manager := getMeshManager()
|
||||||
description := "wooooo"
|
description := "wooooo"
|
||||||
|
|
||||||
meshId1, _ := manager.CreateMesh("wg0", 5000)
|
meshId1, _ := manager.CreateMesh(5000)
|
||||||
meshId2, _ := manager.CreateMesh("wg0", 5001)
|
meshId2, _ := manager.CreateMesh(5001)
|
||||||
|
|
||||||
manager.AddSelf(&AddSelfParams{
|
manager.AddSelf(&AddSelfParams{
|
||||||
MeshId: meshId1,
|
MeshId: meshId1,
|
||||||
@ -225,8 +225,8 @@ func TestSetDescription(t *testing.T) {
|
|||||||
func TestUpdateTimeStampUpdatesAllMeshes(t *testing.T) {
|
func TestUpdateTimeStampUpdatesAllMeshes(t *testing.T) {
|
||||||
manager := getMeshManager()
|
manager := getMeshManager()
|
||||||
|
|
||||||
meshId1, _ := manager.CreateMesh("wg0", 5000)
|
meshId1, _ := manager.CreateMesh(5000)
|
||||||
meshId2, _ := manager.CreateMesh("wg0", 5001)
|
meshId2, _ := manager.CreateMesh(5001)
|
||||||
|
|
||||||
manager.AddSelf(&AddSelfParams{
|
manager.AddSelf(&AddSelfParams{
|
||||||
MeshId: meshId1,
|
MeshId: meshId1,
|
||||||
|
@ -21,6 +21,11 @@ type MeshNodeStub struct {
|
|||||||
description string
|
description string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetType implements MeshNode.
|
||||||
|
func (*MeshNodeStub) GetType() conf.NodeType {
|
||||||
|
return PEER
|
||||||
|
}
|
||||||
|
|
||||||
// GetServices implements MeshNode.
|
// GetServices implements MeshNode.
|
||||||
func (*MeshNodeStub) GetServices() map[string]string {
|
func (*MeshNodeStub) GetServices() map[string]string {
|
||||||
return make(map[string]string)
|
return make(map[string]string)
|
||||||
@ -77,28 +82,28 @@ type MeshProviderStub struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetNodeIds implements MeshProvider.
|
// GetNodeIds implements MeshProvider.
|
||||||
func (*MeshProviderStub) GetNodeIds() []string {
|
func (*MeshProviderStub) GetPeers() []string {
|
||||||
panic("unimplemented")
|
return make([]string, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNode implements MeshProvider.
|
// GetNode implements MeshProvider.
|
||||||
func (*MeshProviderStub) GetNode(string) (MeshNode, error) {
|
func (*MeshProviderStub) GetNode(string) (MeshNode, error) {
|
||||||
panic("unimplemented")
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeExists implements MeshProvider.
|
// NodeExists implements MeshProvider.
|
||||||
func (*MeshProviderStub) NodeExists(string) bool {
|
func (*MeshProviderStub) NodeExists(string) bool {
|
||||||
panic("unimplemented")
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddService implements MeshProvider.
|
// AddService implements MeshProvider.
|
||||||
func (*MeshProviderStub) AddService(nodeId string, key string, value string) error {
|
func (*MeshProviderStub) AddService(nodeId string, key string, value string) error {
|
||||||
panic("unimplemented")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveService implements MeshProvider.
|
// RemoveService implements MeshProvider.
|
||||||
func (*MeshProviderStub) RemoveService(nodeId string, key string) error {
|
func (*MeshProviderStub) RemoveService(nodeId string, key string) error {
|
||||||
panic("unimplemented")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAlias implements MeshProvider.
|
// SetAlias implements MeshProvider.
|
||||||
@ -108,7 +113,7 @@ func (*MeshProviderStub) SetAlias(nodeId string, alias string) error {
|
|||||||
|
|
||||||
// RemoveRoutes implements MeshProvider.
|
// RemoveRoutes implements MeshProvider.
|
||||||
func (*MeshProviderStub) RemoveRoutes(nodeId string, route ...string) error {
|
func (*MeshProviderStub) RemoveRoutes(nodeId string, route ...string) error {
|
||||||
panic("unimplemented")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prune implements MeshProvider.
|
// Prune implements MeshProvider.
|
||||||
@ -250,7 +255,7 @@ func NewMeshManagerStub() MeshManager {
|
|||||||
return &MeshManagerStub{meshes: make(map[string]MeshProvider)}
|
return &MeshManagerStub{meshes: make(map[string]MeshProvider)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MeshManagerStub) CreateMesh(devName string, port int) (string, error) {
|
func (m *MeshManagerStub) CreateMesh(port int) (string, error) {
|
||||||
return "tim123", nil
|
return "tim123", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,13 +4,19 @@ package mesh
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"slices"
|
|
||||||
|
|
||||||
"github.com/tim-beatham/wgmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Data Exchanged Between Peers
|
||||||
|
PEER conf.NodeType = "peer"
|
||||||
|
// Data Exchanged Between Clients
|
||||||
|
CLIENT conf.NodeType = "client"
|
||||||
|
)
|
||||||
|
|
||||||
// MeshNode represents an implementation of a node in a mesh
|
// MeshNode represents an implementation of a node in a mesh
|
||||||
type MeshNode interface {
|
type MeshNode interface {
|
||||||
// GetHostEndpoint: gets the gRPC endpoint of the node
|
// GetHostEndpoint: gets the gRPC endpoint of the node
|
||||||
@ -34,46 +40,12 @@ type MeshNode interface {
|
|||||||
GetAlias() string
|
GetAlias() string
|
||||||
// GetServices: returns a list of services offered by the node
|
// GetServices: returns a list of services offered by the node
|
||||||
GetServices() map[string]string
|
GetServices() map[string]string
|
||||||
|
GetType() conf.NodeType
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeEquals: determines if two mesh nodes are equivalent to one another
|
// NodeEquals: determines if two mesh nodes are equivalent to one another
|
||||||
func NodeEquals(node1, node2 MeshNode) bool {
|
func NodeEquals(node1, node2 MeshNode) bool {
|
||||||
if node1.GetHostEndpoint() != node2.GetHostEndpoint() {
|
return node1.GetHostEndpoint() == node2.GetHostEndpoint()
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
node1Pub, _ := node1.GetPublicKey()
|
|
||||||
node2Pub, _ := node2.GetPublicKey()
|
|
||||||
|
|
||||||
if node1Pub != node2Pub {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if node1.GetWgEndpoint() != node2.GetWgEndpoint() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if node1.GetWgHost() != node2.GetWgHost() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !slices.Equal(node1.GetRoutes(), node2.GetRoutes()) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if node1.GetIdentifier() != node2.GetIdentifier() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if node1.GetDescription() != node2.GetDescription() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if node1.GetAlias() != node2.GetAlias() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type MeshSnapshot interface {
|
type MeshSnapshot interface {
|
||||||
@ -129,7 +101,7 @@ type MeshProvider interface {
|
|||||||
// Prune: prunes all nodes that have not updated their timestamp in
|
// Prune: prunes all nodes that have not updated their timestamp in
|
||||||
// pruneAmount seconds
|
// pruneAmount seconds
|
||||||
Prune(pruneAmount int) error
|
Prune(pruneAmount int) error
|
||||||
GetNodeIds() []string
|
GetPeers() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// HostParameters contains the IDs of a node
|
// HostParameters contains the IDs of a node
|
||||||
@ -158,6 +130,7 @@ type MeshNodeFactoryParams struct {
|
|||||||
NodeIP net.IP
|
NodeIP net.IP
|
||||||
WgPort int
|
WgPort int
|
||||||
Endpoint string
|
Endpoint string
|
||||||
|
Role conf.NodeType
|
||||||
}
|
}
|
||||||
|
|
||||||
// MeshBuilder build the hosts mesh node for it to be added to the mesh
|
// MeshBuilder build the hosts mesh node for it to be added to the mesh
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/jmespath/go-jmespath"
|
"github.com/jmespath/go-jmespath"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/wgmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
)
|
)
|
||||||
@ -28,11 +29,12 @@ type QueryNode struct {
|
|||||||
PublicKey string `json:"publicKey"`
|
PublicKey string `json:"publicKey"`
|
||||||
WgEndpoint string `json:"wgEndpoint"`
|
WgEndpoint string `json:"wgEndpoint"`
|
||||||
WgHost string `json:"wgHost"`
|
WgHost string `json:"wgHost"`
|
||||||
Timestamp int64 `json:"timestmap"`
|
Timestamp int64 `json:"timestamp"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Routes []string `json:"routes"`
|
Routes []string `json:"routes"`
|
||||||
Alias string `json:"alias"`
|
Alias string `json:"alias"`
|
||||||
Services map[string]string `json:"services"`
|
Services map[string]string `json:"services"`
|
||||||
|
Type conf.NodeType `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *QueryError) Error() string {
|
func (m *QueryError) Error() string {
|
||||||
@ -80,6 +82,7 @@ func MeshNodeToQueryNode(node mesh.MeshNode) *QueryNode {
|
|||||||
queryNode.Description = node.GetDescription()
|
queryNode.Description = node.GetDescription()
|
||||||
queryNode.Alias = node.GetAlias()
|
queryNode.Alias = node.GetAlias()
|
||||||
queryNode.Services = node.GetServices()
|
queryNode.Services = node.GetServices()
|
||||||
|
queryNode.Type = node.GetType()
|
||||||
|
|
||||||
return queryNode
|
return queryNode
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ type IpcHandler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *IpcHandler) CreateMesh(args *ipc.NewMeshArgs, reply *string) error {
|
func (n *IpcHandler) CreateMesh(args *ipc.NewMeshArgs, reply *string) error {
|
||||||
meshId, err := n.Server.GetMeshManager().CreateMesh(args.IfName, args.WgPort)
|
meshId, err := n.Server.GetMeshManager().CreateMesh(args.WgPort)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -83,7 +83,6 @@ func (n *IpcHandler) JoinMesh(args ipc.JoinMeshArgs, reply *string) error {
|
|||||||
|
|
||||||
err = n.Server.GetMeshManager().AddMesh(&mesh.AddMeshParams{
|
err = n.Server.GetMeshManager().AddMesh(&mesh.AddMeshParams{
|
||||||
MeshId: args.MeshId,
|
MeshId: args.MeshId,
|
||||||
DevName: args.IfName,
|
|
||||||
WgPort: args.Port,
|
WgPort: args.Port,
|
||||||
MeshBytes: meshReply.Mesh,
|
MeshBytes: meshReply.Mesh,
|
||||||
})
|
})
|
||||||
|
@ -44,7 +44,7 @@ func (s *SyncerImpl) Sync(meshId string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeNames := s.manager.GetMesh(meshId).GetNodeIds()
|
nodeNames := s.manager.GetMesh(meshId).GetPeers()
|
||||||
|
|
||||||
self, err := s.manager.GetSelf(meshId)
|
self, err := s.manager.GetSelf(meshId)
|
||||||
|
|
||||||
|
@ -50,7 +50,6 @@ func (s *SyncRequesterImpl) GetMesh(meshId string, ifName string, port int, endP
|
|||||||
|
|
||||||
err = s.server.MeshManager.AddMesh(&mesh.AddMeshParams{
|
err = s.server.MeshManager.AddMesh(&mesh.AddMeshParams{
|
||||||
MeshId: meshId,
|
MeshId: meshId,
|
||||||
DevName: ifName,
|
|
||||||
WgPort: port,
|
WgPort: port,
|
||||||
MeshBytes: reply.Mesh,
|
MeshBytes: reply.Mesh,
|
||||||
})
|
})
|
||||||
|
@ -5,20 +5,6 @@ import (
|
|||||||
"github.com/tim-beatham/wgmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SyncScheduler: Loops through all nodes in the mesh and runs a schedule to
|
|
||||||
// sync each event
|
|
||||||
type SyncScheduler interface {
|
|
||||||
Run() error
|
|
||||||
Stop() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// SyncSchedulerImpl scheduler for sync scheduling
|
|
||||||
type SyncSchedulerImpl struct {
|
|
||||||
quit chan struct{}
|
|
||||||
server *ctrlserver.MeshCtrlServer
|
|
||||||
syncer Syncer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run implements SyncScheduler.
|
// Run implements SyncScheduler.
|
||||||
func syncFunction(syncer Syncer) lib.TimerFunc {
|
func syncFunction(syncer Syncer) lib.TimerFunc {
|
||||||
return func() error {
|
return func() error {
|
||||||
|
@ -64,11 +64,11 @@ func (s *SyncServiceImpl) SyncMesh(stream rpc.SyncService_SyncMeshServer) error
|
|||||||
|
|
||||||
syncer = mesh.GetSyncer()
|
syncer = mesh.GetSyncer()
|
||||||
} else if meshId != in.MeshId {
|
} else if meshId != in.MeshId {
|
||||||
return errors.New("Differing MeshIDs")
|
return errors.New("differing meshids")
|
||||||
}
|
}
|
||||||
|
|
||||||
if syncer == nil {
|
if syncer == nil {
|
||||||
return errors.New("Syncer should not be nil")
|
return errors.New("syncer should not be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, moreMessages := syncer.GenerateMessage()
|
msg, moreMessages := syncer.GenerateMessage()
|
||||||
|
@ -2,8 +2,8 @@ package wg
|
|||||||
|
|
||||||
type WgInterfaceManipulatorStub struct{}
|
type WgInterfaceManipulatorStub struct{}
|
||||||
|
|
||||||
func (i *WgInterfaceManipulatorStub) CreateInterface(params *CreateInterfaceParams) error {
|
func (i *WgInterfaceManipulatorStub) CreateInterface(port int) (string, error) {
|
||||||
return nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *WgInterfaceManipulatorStub) AddAddress(ifName string, addr string) error {
|
func (i *WgInterfaceManipulatorStub) AddAddress(ifName string, addr string) error {
|
||||||
|
@ -8,14 +8,9 @@ func (m *WgError) Error() string {
|
|||||||
return m.msg
|
return m.msg
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateInterfaceParams struct {
|
|
||||||
IfName string
|
|
||||||
Port int
|
|
||||||
}
|
|
||||||
|
|
||||||
type WgInterfaceManipulator interface {
|
type WgInterfaceManipulator interface {
|
||||||
// CreateInterface creates a WireGuard interface
|
// CreateInterface creates a WireGuard interface
|
||||||
CreateInterface(params *CreateInterfaceParams) error
|
CreateInterface(port int) (string, error)
|
||||||
// AddAddress adds an address to the given interface name
|
// AddAddress adds an address to the given interface name
|
||||||
AddAddress(ifName string, addr string) error
|
AddAddress(ifName string, addr string) error
|
||||||
// RemoveInterface removes the specified interface
|
// RemoveInterface removes the specified interface
|
||||||
|
37
pkg/wg/wg.go
37
pkg/wg/wg.go
@ -1,6 +1,9 @@
|
|||||||
package wg
|
package wg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/tim-beatham/wgmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
@ -13,40 +16,54 @@ type WgInterfaceManipulatorImpl struct {
|
|||||||
client *wgctrl.Client
|
client *wgctrl.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hashLength = 6
|
||||||
|
|
||||||
// CreateInterface creates a WireGuard interface
|
// CreateInterface creates a WireGuard interface
|
||||||
func (m *WgInterfaceManipulatorImpl) CreateInterface(params *CreateInterfaceParams) error {
|
func (m *WgInterfaceManipulatorImpl) CreateInterface(port int) (string, error) {
|
||||||
rtnl, err := lib.NewRtNetlinkConfig()
|
rtnl, err := lib.NewRtNetlinkConfig()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to access link: %w", err)
|
return "", fmt.Errorf("failed to access link: %w", err)
|
||||||
}
|
}
|
||||||
defer rtnl.Close()
|
defer rtnl.Close()
|
||||||
|
|
||||||
err = rtnl.CreateLink(params.IfName)
|
randomBuf := make([]byte, 32)
|
||||||
|
_, err = rand.Read(randomBuf)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create link: %w", err)
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
md5 := crypto.MD5.New().Sum(randomBuf)
|
||||||
|
|
||||||
|
md5Str := fmt.Sprintf("wg%s", base64.StdEncoding.EncodeToString(md5)[:hashLength])
|
||||||
|
|
||||||
|
err = rtnl.CreateLink(md5Str)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to create link: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
privateKey, err := wgtypes.GeneratePrivateKey()
|
privateKey, err := wgtypes.GeneratePrivateKey()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create private key: %w", err)
|
return "", fmt.Errorf("failed to create private key: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var cfg wgtypes.Config = wgtypes.Config{
|
var cfg wgtypes.Config = wgtypes.Config{
|
||||||
PrivateKey: &privateKey,
|
PrivateKey: &privateKey,
|
||||||
ListenPort: ¶ms.Port,
|
ListenPort: &port,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.client.ConfigureDevice(params.IfName, cfg)
|
err = m.client.ConfigureDevice(md5Str, cfg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to configure dev: %w", err)
|
m.RemoveInterface(md5Str)
|
||||||
|
return "", fmt.Errorf("failed to configure dev: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.Log.WriteInfof("ip link set up dev %s type wireguard", params.IfName)
|
logging.Log.WriteInfof("ip link set up dev %s type wireguard", md5Str)
|
||||||
return nil
|
return md5Str, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an address to the given interface
|
// Add an address to the given interface
|
||||||
|
92
pkg/what8words/what8words.go
Normal file
92
pkg/what8words/what8words.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Package to convert an IPV6 addres into 8 words
|
||||||
|
package what8words
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type What8Words struct {
|
||||||
|
words []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert implements What8Words.
|
||||||
|
func (w *What8Words) Convert(ipStr string) (string, error) {
|
||||||
|
ip, ipNet, err := net.ParseCIDR(ipStr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
ip16 := ip.To16()
|
||||||
|
|
||||||
|
if ip16 == nil {
|
||||||
|
return "", fmt.Errorf("cannot convert ip to 16 representation")
|
||||||
|
}
|
||||||
|
|
||||||
|
representation := make([]string, 7)
|
||||||
|
|
||||||
|
for i := 2; i <= net.IPv6len-2; i += 2 {
|
||||||
|
word1 := w.words[ip16[i]]
|
||||||
|
word2 := w.words[ip16[i+1]]
|
||||||
|
|
||||||
|
representation[i/2-1] = fmt.Sprintf("%s-%s", word1, word2)
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixSize, _ := ipNet.Mask.Size()
|
||||||
|
return strings.Join(representation[:prefixSize/16-1], "."), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert implements What8Words.
|
||||||
|
func (w *What8Words) ConvertIdentifier(ipStr string) (string, error) {
|
||||||
|
ip, err := w.Convert(ipStr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
constituents := strings.Split(ip, ".")
|
||||||
|
|
||||||
|
return strings.Join(constituents[3:], "."), nil
|
||||||
|
}
|
||||||
|
func NewWhat8Words(pathToWords string) (*What8Words, error) {
|
||||||
|
words, err := ReadWords(pathToWords)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &What8Words{words: words}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadWords reads the what 8 words txt file
|
||||||
|
func ReadWords(wordFile string) ([]string, error) {
|
||||||
|
f, err := os.ReadFile(wordFile)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
words := make([]string, 257)
|
||||||
|
|
||||||
|
reader := bufio.NewScanner(bytes.NewReader(f))
|
||||||
|
|
||||||
|
counter := 0
|
||||||
|
|
||||||
|
for reader.Scan() && counter <= len(words) {
|
||||||
|
text := reader.Text()
|
||||||
|
|
||||||
|
words[counter] = text
|
||||||
|
counter++
|
||||||
|
|
||||||
|
if reader.Err() != nil {
|
||||||
|
return nil, reader.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return words, nil
|
||||||
|
}
|
Reference in New Issue
Block a user