From 498a0321bdc5ff510d6332e76ccda3d2a32c18f7 Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Sat, 30 Nov 2024 19:29:07 +0400 Subject: [PATCH 01/13] base for new infrastructure Signed-off-by: Matthieu Pignolet --- .goreleaser.yaml | 6 + bin/oriond-mock/.gitignore | 1 + bin/oriond-mock/oriond.go | 132 +++ bin/oriond/implementation/events.go | 54 -- bin/oriond/implementation/frr/frr_manager.go | 170 ---- .../implementation/handler_member_connect.go | 121 --- .../handler_member_connect_response.go | 44 - .../handler_member_disconnected.go | 24 - .../implementation/handler_new_member.go | 108 --- bin/oriond/implementation/identity.go | 43 - bin/oriond/implementation/link/background.go | 70 -- bin/oriond/implementation/link/dispose.go | 17 - bin/oriond/implementation/link/holepunch.go | 90 -- bin/oriond/implementation/link/initialize.go | 79 -- bin/oriond/implementation/link/link.go | 99 -- bin/oriond/implementation/login.go | 91 -- bin/oriond/implementation/oriond.go | 105 -- bin/oriond/oriond.go | 119 --- bin/registry-ws/.gitignore | 1 + bin/registry-ws/main.go | 82 ++ bin/registry-ws/registry.pem | 58 ++ .../server/errors/auth-required.html | 11 + bin/registry-ws/server/protocol/client.go | 131 +++ .../server/protocol/messages/event.go | 8 + .../server/protocol/messages/hello.go | 12 + .../server/protocol/messages/kinds.go | 23 + bin/registry-ws/server/server.go | 23 + bin/registry-ws/server/static.go | 11 + bin/registry-ws/server/static/index.html | 11 + bin/registry-ws/server/upgrade.go | 53 ++ bin/registry-ws/server/whoami.go | 29 + .../implementation/holepunching_impl.go | 158 ---- bin/registry/implementation/registry_impl.go | 128 --- bin/registry/implementation/session/auth.go | 163 ---- bin/registry/implementation/session/events.go | 107 --- .../implementation/session/handler_connect.go | 28 - .../session/handler_connect_response.go | 28 - bin/registry/implementation/session/meta.go | 6 - .../implementation/session/session.go | 94 -- .../implementation/session/session_manager.go | 37 - bin/registry/server.go | 105 -- go.mod | 12 +- go.sum | 16 +- internal/nonce_utils.go | 69 -- internal/proto/orion_holepunch.pb.go | 440 --------- internal/proto/orion_holepunch_grpc.pb.go | 132 --- internal/proto/orion_registry.pb.go | 895 ------------------ internal/proto/orion_registry_grpc.pb.go | 139 --- internal/state/dispatch.go | 78 ++ internal/state/edge.go | 22 + internal/state/event.go | 3 + internal/state/orion_registry.go | 28 + internal/state/router.go | 131 +++ internal/state/router_connect.go | 5 + internal/state/router_disconnect.go | 5 + internal/version.go | 8 + proto/orion_holepunch.proto | 38 - proto/orion_registry.proto | 65 -- 58 files changed, 875 insertions(+), 3891 deletions(-) create mode 100644 bin/oriond-mock/.gitignore create mode 100644 bin/oriond-mock/oriond.go delete mode 100644 bin/oriond/implementation/events.go delete mode 100644 bin/oriond/implementation/frr/frr_manager.go delete mode 100644 bin/oriond/implementation/handler_member_connect.go delete mode 100644 bin/oriond/implementation/handler_member_connect_response.go delete mode 100644 bin/oriond/implementation/handler_member_disconnected.go delete mode 100644 bin/oriond/implementation/handler_new_member.go delete mode 100644 bin/oriond/implementation/identity.go delete mode 100644 bin/oriond/implementation/link/background.go delete mode 100644 bin/oriond/implementation/link/dispose.go delete mode 100644 bin/oriond/implementation/link/holepunch.go delete mode 100644 bin/oriond/implementation/link/initialize.go delete mode 100644 bin/oriond/implementation/link/link.go delete mode 100644 bin/oriond/implementation/login.go delete mode 100644 bin/oriond/implementation/oriond.go delete mode 100644 bin/oriond/oriond.go create mode 100644 bin/registry-ws/.gitignore create mode 100644 bin/registry-ws/main.go create mode 100644 bin/registry-ws/registry.pem create mode 100644 bin/registry-ws/server/errors/auth-required.html create mode 100644 bin/registry-ws/server/protocol/client.go create mode 100644 bin/registry-ws/server/protocol/messages/event.go create mode 100644 bin/registry-ws/server/protocol/messages/hello.go create mode 100644 bin/registry-ws/server/protocol/messages/kinds.go create mode 100644 bin/registry-ws/server/server.go create mode 100644 bin/registry-ws/server/static.go create mode 100644 bin/registry-ws/server/static/index.html create mode 100644 bin/registry-ws/server/upgrade.go create mode 100644 bin/registry-ws/server/whoami.go delete mode 100644 bin/registry/implementation/holepunching_impl.go delete mode 100644 bin/registry/implementation/registry_impl.go delete mode 100644 bin/registry/implementation/session/auth.go delete mode 100644 bin/registry/implementation/session/events.go delete mode 100644 bin/registry/implementation/session/handler_connect.go delete mode 100644 bin/registry/implementation/session/handler_connect_response.go delete mode 100644 bin/registry/implementation/session/meta.go delete mode 100644 bin/registry/implementation/session/session.go delete mode 100644 bin/registry/implementation/session/session_manager.go delete mode 100644 bin/registry/server.go delete mode 100644 internal/nonce_utils.go delete mode 100644 internal/proto/orion_holepunch.pb.go delete mode 100644 internal/proto/orion_holepunch_grpc.pb.go delete mode 100644 internal/proto/orion_registry.pb.go delete mode 100644 internal/proto/orion_registry_grpc.pb.go create mode 100644 internal/state/dispatch.go create mode 100644 internal/state/edge.go create mode 100644 internal/state/event.go create mode 100644 internal/state/orion_registry.go create mode 100644 internal/state/router.go create mode 100644 internal/state/router_connect.go create mode 100644 internal/state/router_disconnect.go create mode 100644 internal/version.go delete mode 100644 proto/orion_holepunch.proto delete mode 100644 proto/orion_registry.proto diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 6631e95..eb7b526 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -22,6 +22,12 @@ builds: main: ./bin/oriond id: "oriond" binary: oriond + # Custom ldflags. + # + # Default: '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser'. + # Templates: allowed. + ldflags: + - s -w -X internal.Version={{.Version}} -X internal.Commit={{.Commit}} -X internal.Date={{.Date}} -X internal.BuiltBy=goreleaser # Build for the `orion-registry` daemon - env: - CGO_ENABLED=0 diff --git a/bin/oriond-mock/.gitignore b/bin/oriond-mock/.gitignore new file mode 100644 index 0000000..612424a --- /dev/null +++ b/bin/oriond-mock/.gitignore @@ -0,0 +1 @@ +*.pem \ No newline at end of file diff --git a/bin/oriond-mock/oriond.go b/bin/oriond-mock/oriond.go new file mode 100644 index 0000000..cb0c4a5 --- /dev/null +++ b/bin/oriond-mock/oriond.go @@ -0,0 +1,132 @@ +package main + +import ( + "crypto/tls" + "encoding/json" + "flag" + "fmt" + "net/http" + "net/url" + "os" + "os/signal" + "time" + + "github.com/MatthieuCoder/OrionV3/bin/registry-ws/server/protocol/messages" + "github.com/MatthieuCoder/OrionV3/internal" + "github.com/gorilla/websocket" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +var ( + enable_prof = flag.Bool("enable-pprof", false, "enable pprof for debugging") + debug = flag.Bool("debug", false, "change the log level to debug") + registryServer = flag.String("registry-server", "reg.orionet.re", "the address of the registry server") + pprof = flag.String("debug-pprof", "0.0.0.0:6061", "") + registryPort = flag.Uint("registry-port", 6443, "the port used by the registry") +) + +func main() { + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt) + // Setup logging + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix + flag.Parse() + + // Default level for this example is info, unless debug flag is present + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) + zerolog.SetGlobalLevel(zerolog.InfoLevel) + if *enable_prof { + go func() { + fmt.Println(http.ListenAndServe(*pprof, nil)) + }() + } + if *debug { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } + + url := url.URL{ + Scheme: "wss", + Host: "reg.orionet.re:6443", + Path: "/ws", + } + + privateKey, chain := internal.LoadPemFile() + certificateKeyPair := internal.LoadX509KeyPair(privateKey, chain) + authorityPool, err := internal.LoadAuthorityPool() + if err != nil { + panic(err) + } + + dialer := &websocket.Dialer{ + Proxy: http.ProxyFromEnvironment, + HandshakeTimeout: 45 * time.Second, + TLSClientConfig: &tls.Config{ + Certificates: []tls.Certificate{certificateKeyPair}, + RootCAs: authorityPool, + MinVersion: tls.VersionTLS13, + MaxVersion: tls.VersionTLS13, + }, + Subprotocols: []string{"orion-reg-rpc"}, + } + + c, _, err := dialer.Dial(url.String(), nil) + if err != nil { + log.Fatal().Msgf("dial: %s", err) + } + defer c.Close() + + done := make(chan struct{}) + + go func() { + defer close(done) + for { + _, message, err := c.ReadMessage() + if err != nil { + log.Print("read:", err) + return + } + log.Printf("recv: %s", message) + + msg := messages.Event{} + json.Unmarshal(message, &msg) + + log.Printf("received %s... handling", msg.Kind) + + switch msg.Content { + case messages.MessageKindHello: + hello := msg.Content.(*messages.Hello) + log.Printf("Hello message: %s", hello.Message) + } + + } + }() + + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + + case <-done: + return + case <-interrupt: + log.Print("interrupt") + + // Cleanly close the connection by sending a close message and then + // waiting (with timeout) for the server to close the connection. + err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) + if err != nil { + log.Print("write close:", err) + return + } + select { + case <-done: + case <-time.After(time.Second): + } + return + } + } + +} diff --git a/bin/oriond/implementation/events.go b/bin/oriond/implementation/events.go deleted file mode 100644 index dbe3da1..0000000 --- a/bin/oriond/implementation/events.go +++ /dev/null @@ -1,54 +0,0 @@ -package implementation - -import ( - "context" - "time" - - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" -) - -func (c *OrionClientDaemon) initializeStream() error { - ctx := c.Context - - stream, err := c.registryClient.SubscribeToStream(ctx) - if err != nil { - return err - } - c.registryStream = stream - return nil -} - -func (c *OrionClientDaemon) listener() error { - defer func() { - log.Info().Msg("listener is finished") - c.ctxCancel() - }() - - for { - event, err := c.registryStream.Recv() - if err != nil { - log.Error(). - Err(err). - Msg("failed to read the stream from the registry") - return err - } - - subCtx, cancel := context.WithTimeout(c.Context, time.Second*10) - switch event.Event.(type) { - case *proto.RPCServerEvent_NewMember: - c.handleNewClient(subCtx, event.Event.(*proto.RPCServerEvent_NewMember).NewMember) - case *proto.RPCServerEvent_MemberConnect: - c.handleWantsToConnect(subCtx, event.Event.(*proto.RPCServerEvent_MemberConnect).MemberConnect) - case *proto.RPCServerEvent_DisconnectedMember: - c.handleRemovedClient(event.Event.(*proto.RPCServerEvent_DisconnectedMember).DisconnectedMember) - case *proto.RPCServerEvent_MemberConnectResponse: - c.handleWantsToConnectResponse(event.Event.(*proto.RPCServerEvent_MemberConnectResponse).MemberConnectResponse) - case *proto.RPCServerEvent_SessionId: - log.Info(). - Msg("got a sessionId from the registry server") - c.sID = event.Event.(*proto.RPCServerEvent_SessionId).SessionId - } - cancel() - } -} diff --git a/bin/oriond/implementation/frr/frr_manager.go b/bin/oriond/implementation/frr/frr_manager.go deleted file mode 100644 index 459b9e9..0000000 --- a/bin/oriond/implementation/frr/frr_manager.go +++ /dev/null @@ -1,170 +0,0 @@ -package frr - -import ( - "flag" - "fmt" - "os" - "os/exec" - "sync" - "text/template" - - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" -) - -var ( - frrTmplPath = flag.String("frr-config-template", "/etc/oriond/frr.conf.tmpl", "Configuration template for configuring FRR") - frrReloadBinary = flag.String("frr-reload-script", "/usr/lib/frr/frr-reload.py", "Path to the frr-reload.py utility executable") -) - -// Struct containing the information regarding someone ASN on the network. -type group struct { - ASN uint32 - Weight uint32 -} - -// Struct containing a peer in the orion network, this is typically -// on-per-connection. -type Peer struct { - Address string - OrionId uint32 - ASN uint32 - Weight uint32 -} - -// Contest representing th entire state of the frr config file. -type tmplContext struct { - ASN uint32 - OrionId uint32 - Groups []group - Peers []Peer -} - -// Struct used to interact and issue the FRR configuration file updates. -type FrrConfigManager struct { - peers map[uint32]*Peer - selfASN uint32 - OrionId uint32 - template *template.Template - peersLock *sync.RWMutex -} - -// Function used to load the template files. -func loadTmpl() (*template.Template, error) { - content, err := os.ReadFile(*frrTmplPath) - if err != nil { - return nil, err - } - return template.New(*frrTmplPath).Parse(string(content)) -} - -// Function used to create a config-manager instance. -func NewFrrConfigManager(ASN uint32, OrionId uint32) (*FrrConfigManager, error) { - tmpl, err := loadTmpl() - if err != nil { - return nil, err - } - config := &FrrConfigManager{ - peers: map[uint32]*Peer{}, - selfASN: ASN, - OrionId: OrionId, - template: tmpl, - peersLock: &sync.RWMutex{}, - } - - if err = config.Update(); err != nil { - return nil, err - } - - return config, nil -} - -// This functions takes the simplified BGP configuration stored in memory -// and renders a new configuration for the `frr` daemon used to implement -// `bgpd` which is the BGP daemon used through the Orion network. -func (c *FrrConfigManager) Update() error { - log.Debug().Msg("applying a FRR configuration update") - peers := []Peer{} - - c.peersLock.RLock() - defer c.peersLock.RUnlock() - for _, value := range c.peers { - if value != nil { - peers = append(peers, *value) - } - } - - // We initialize some basic information regarding the BGP sessions - // configured for FRR's bgpd. - context := tmplContext{ - ASN: c.selfASN, - OrionId: c.OrionId, - Peers: peers, - Groups: []group{}, - } - - // From the list of peers we infer the list of bgp groups to connect to. - for _, peer := range context.Peers { - if peer.ASN != 0 { - log.Debug().Uint32("asn", peer.ASN).Msg("new group computed") - context.Groups = append(context.Groups, group{ - ASN: peer.ASN, - }) - } - } - - // In order to call the frr-reload.py script, we must render the configuration - // to a file, we choosed to use a temporary file for this purpose. - tempConfig, err := os.CreateTemp("/tmp", "orion-conf-update*.conf") - if err != nil { - log.Error().Err(err).Msg("failed to create the new frr configuration temporary file") - return err - } - // Since all temporary files are in the /tmp directory, we can simply infer the full path. - absolutePath := tempConfig.Name() - - defer func() { - log.Debug().Msg("cleaning up temporary files") - // We do not delete the temporary files when running in debug mode. - if zerolog.GlobalLevel() != zerolog.DebugLevel { - os.Remove(absolutePath) - } - tempConfig.Close() - }() - - // We execute the template with the current context. - err = c.template.Execute(tempConfig, context) - if err != nil { - log.Debug().Err(err).Msg("failed to template the config file") - return err - } - - log.Debug().Str("config-file", absolutePath).Msg("running frr-reload.py") - execReload := exec.Command(*frrReloadBinary, "--reload", absolutePath) - // For debug purposes, we might want to link the frr-reload.py script stdout and stderr to - // the current process ones. - if zerolog.GlobalLevel() == zerolog.DebugLevel { - execReload.Stdout = os.Stdout - execReload.Stderr = os.Stderr - } - - if err := execReload.Run(); err != nil { - // In case of an errornous error code. - if exitError, ok := err.(*exec.ExitError); ok { - return fmt.Errorf("the frr-reload.py script exited with the code %s", exitError) - } - } - - return nil -} - -func (c *FrrConfigManager) UpdatePeer(id uint32, peer *Peer) { - // Locks the peer - c.peersLock.Lock() - defer c.peersLock.Unlock() - c.peers[id] = peer -} - -func (c *FrrConfigManager) GetPeer(id uint32) *Peer { - return c.peers[id] -} diff --git a/bin/oriond/implementation/handler_member_connect.go b/bin/oriond/implementation/handler_member_connect.go deleted file mode 100644 index 4cf798d..0000000 --- a/bin/oriond/implementation/handler_member_connect.go +++ /dev/null @@ -1,121 +0,0 @@ -package implementation - -import ( - "context" - "net" - "time" - - "github.com/MatthieuCoder/OrionV3/bin/oriond/implementation/link" - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -func (c *OrionClientDaemon) handleWantsToConnect( - ctx context.Context, - event *proto.MemberConnectEvent, -) { - // We ignore requests that are coming from ourself - if event.DestinationPeerId != c.memberId || event.SourcePeerId == c.memberId { - log.Error(). - Uint32("peer-id", event.SourcePeerId). - Msg("received a message not destinated to this host") - return - } - c.tunnelsLock.Lock() - defer c.tunnelsLock.Unlock() - if c.tunnels[event.SourcePeerId] != nil { - log.Error(). - Uint32("peer-id", event.SourcePeerId). - Msg("received a want to connect event for a already-initialized event") - c.tunnels[event.SourcePeerId].Dispose() - } - - // It's our job to generate the pre-shared key information - // according the the protocol. - preshared, err := wgtypes.GenerateKey() - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", event.SourcePeerId). - Msg("failed to send the message to the server") - return - } - - // We initialize a new peer link object to hold this new link context - peer, err := link.NewPeerLink( - c.Context, - c.memberId, - event.SourcePeerId, - c.wgClient, - c.frrManager, - ) - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", event.SourcePeerId). - Msg("failed to initialize the peer link object") - return - } - publicKey := peer.PublicKey() - - c.tunnels[event.SourcePeerId] = peer - - // We initialize a one minte context for getting the hole-punching details - holePunchingContext, cancel := context.WithTimeout(ctx, time.Minute) - defer cancel() - - // We get the nat-ed tunnel details - holePunching, err := peer.HolePunchTunnel( - holePunchingContext, - c.holePunchingClient, - ) - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", event.SourcePeerId). - Msg("failed to hole-punch the interface") - peer.Dispose() - return - } - - // We initialize the peer to configure the peer & bgp sessions - err = peer.InitializePeerConnection( - &net.UDPAddr{ - IP: net.ParseIP(event.EndpointAddr), - Port: int(event.EndpointPort), - }, - wgtypes.Key(event.PublicKey), - preshared, - ) - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", event.SourcePeerId). - Msg("failed to initialize the connection to the peer") - peer.Dispose() - return - } - - err = c.registryStream.Send(&proto.RPCClientEvent{ - Event: &proto.RPCClientEvent_ConnectResponse{ - ConnectResponse: &proto.MemberConnectResponseEvent{ - EndpointAddr: holePunching.ClientEndpointAddr, - EndpointPort: holePunching.ClientEndpointPort, - PublicKey: publicKey[:], - FriendlyName: *friendlyName, - SourcePeerId: c.memberId, - DestinationPeerId: event.SourcePeerId, - PresharedKey: preshared[:], - }, - }, - }) - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", event.SourcePeerId). - Msg("failed to send the initialization response to the remote peer") - peer.Dispose() - return - } -} diff --git a/bin/oriond/implementation/handler_member_connect_response.go b/bin/oriond/implementation/handler_member_connect_response.go deleted file mode 100644 index 2d2f135..0000000 --- a/bin/oriond/implementation/handler_member_connect_response.go +++ /dev/null @@ -1,44 +0,0 @@ -package implementation - -import ( - "net" - - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -func (c *OrionClientDaemon) handleWantsToConnectResponse(event *proto.MemberConnectResponseEvent) { - c.tunnelsLock.Lock() - defer c.tunnelsLock.Unlock() - - // If we get a response to a initialization request, we check if we already created the tunnel - peerLink := c.tunnels[event.SourcePeerId] - - if peerLink == nil || peerLink.Initialized() { - log.Error(). - Uint32("peer-id", event.SourcePeerId). - Msg("received an invalid connect response") - return - } - - // If everything is allright we initialize the connection to the peer - err := peerLink.InitializePeerConnection( - &net.UDPAddr{ - IP: net.ParseIP(event.EndpointAddr), - Port: int(event.EndpointPort), - }, - wgtypes.Key(event.PublicKey), - wgtypes.Key(event.PresharedKey), - ) - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", event.SourcePeerId). - Msg("failed to initiate a connection to the peer after a connect initialization response") - peerLink.Dispose() - } - - // Ends the waiting stream in the new_client handler - c.establishedStream.Notify(event.SourcePeerId) -} diff --git a/bin/oriond/implementation/handler_member_disconnected.go b/bin/oriond/implementation/handler_member_disconnected.go deleted file mode 100644 index 326c9bf..0000000 --- a/bin/oriond/implementation/handler_member_disconnected.go +++ /dev/null @@ -1,24 +0,0 @@ -package implementation - -import ( - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" -) - -func (c *OrionClientDaemon) handleRemovedClient(event *proto.MemberDisconnectedEvent) { - c.tunnelsLock.Lock() - defer c.tunnelsLock.Unlock() - - peer := c.tunnels[event.PeerId] - - if peer == nil { - log.Error(). - Uint32("peer-id", event.PeerId). - Msgf("received a removed client event, but no such tunnel initialized") - return - } - // Since every ressource link to a peer is linked to a PeerLink - // we simply have to dispose the peer to remove all resources - peer.Dispose() - c.tunnels[event.PeerId] = nil -} diff --git a/bin/oriond/implementation/handler_new_member.go b/bin/oriond/implementation/handler_new_member.go deleted file mode 100644 index fab2dae..0000000 --- a/bin/oriond/implementation/handler_new_member.go +++ /dev/null @@ -1,108 +0,0 @@ -package implementation - -import ( - "context" - "time" - - "github.com/MatthieuCoder/OrionV3/bin/oriond/implementation/link" - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" -) - -func (c *OrionClientDaemon) handleNewClient( - ctx context.Context, - event *proto.NewMemberEvent, -) { - c.tunnelsLock.Lock() - defer c.tunnelsLock.Unlock() - - log.Info(). - Uint32("peer-id", event.PeerId). - Msg("Initiating a new link") - - if c.tunnels[event.PeerId] != nil { - log.Error(). - Uint32("peer-id", event.PeerId). - Msg("received a new_client event for a already-initialized event") - return - } - - peer, err := link.NewPeerLink( - c.Context, - c.memberId, - event.PeerId, - c.wgClient, - c.frrManager, - ) - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", event.PeerId). - Msgf("failed to initialize the peer object") - return - } - // We save the peer in the tunnels map - c.tunnels[event.PeerId] = peer - publickey := peer.PublicKey() - - // We initialize a one minte context for getting the hole-punching details - holePunchingContext, cancel := context.WithTimeout(ctx, time.Minute) - holePunching, err := peer.HolePunchTunnel( - holePunchingContext, - c.holePunchingClient, - ) - cancel() - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", event.PeerId). - Msg("failed to hole-punch the interface") - peer.Dispose() - return - } - - // Inform the peer that we re ready for connection - err = c.registryStream.Send(&proto.RPCClientEvent{ - Event: &proto.RPCClientEvent_Connect{ - Connect: &proto.MemberConnectEvent{ - EndpointAddr: holePunching.ClientEndpointAddr, - EndpointPort: holePunching.ClientEndpointPort, - PublicKey: publickey[:], - FriendlyName: *friendlyName, - DestinationPeerId: event.PeerId, - SourcePeerId: c.memberId, - }, - }, - }) - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", event.PeerId). - Msgf("couldn't write the initialization message to the gRPC connection") - peer.Dispose() - return - } - go func() { - waitingForResponse, cancel := context.WithTimeout(c.Context, time.Minute) - defer cancel() - establshed_stream := c.establishedStream.Listener(10) - defer establshed_stream.Close() - for { - select { - case establishedStreamID := <-establshed_stream.Ch(): - // Our connection got succesfully established - if establishedStreamID == event.PeerId { - return - } - case <-waitingForResponse.Done(): - // timeout reached while establishing the peer connection - log.Error(). - Err(waitingForResponse.Err()). - Uint32("peer-id", event.PeerId). - Msgf("timeout exceeded while waiting for a response from the peer") - peer.Dispose() - return - } - } - }() -} diff --git a/bin/oriond/implementation/identity.go b/bin/oriond/implementation/identity.go deleted file mode 100644 index 27b1c18..0000000 --- a/bin/oriond/implementation/identity.go +++ /dev/null @@ -1,43 +0,0 @@ -package implementation - -import ( - "flag" - "strconv" - "strings" - - "github.com/rs/zerolog/log" -) - -var ( - memberIdOverride = flag.Uint("override-member-id", 0, "An override of the memberID of this instance") - asn = flag.Uint("override-asn", 0, "An override of the ASN number used by this instance") -) - -func (c *OrionClientDaemon) resolveIdentity() error { - // If we have a memver-id override - if *memberIdOverride != 0 { - c.memberId = uint32(*memberIdOverride) - } else { - name := c.chain[0].Subject.CommonName - nameParts := strings.Split(name, ":") - - number, err := strconv.ParseInt(nameParts[0], 10, 32) - if err != nil { - log.Error(). - Err(err). - Msg("the member_id field in the certificate couldn't be parsed, please use -override-member-id to specify the member-id") - return err - } - c.memberId = uint32(number) - } - - // We check if we have a asn number override - if *asn != 0 { - c.asn = uint32(*asn) - } else { - // The regular orion as allocation - c.asn = 64511 + c.memberId - } - - return nil -} diff --git a/bin/oriond/implementation/link/background.go b/bin/oriond/implementation/link/background.go deleted file mode 100644 index d6ed025..0000000 --- a/bin/oriond/implementation/link/background.go +++ /dev/null @@ -1,70 +0,0 @@ -package link - -import ( - "math" - "time" - - probing "github.com/prometheus-community/pro-bing" - "github.com/rs/zerolog/log" -) - -func (c *PeerLink) updateWeights() error { - log.Debug().Msg("starting to ping") - pinger, err := probing.NewPinger(c.otherIP.IP.String()) - if err != nil { - return err - } - pinger.SetPrivileged(true) - - // Ping one time - pinger.Count = 1 - pinger.Timeout = time.Second * 5 - pinger.InterfaceName = c.wireguardTunnel.WgLink.InterfaceAttrs.Name - - err = pinger.Run() // Blocks until finished. - if err != nil { - return err - } - stats := pinger.Statistics() // get send/receive/duplicate/rtt stats - - latency := stats.AvgRtt - if stats.PacketLoss > 0 { - log.Debug().Msg("ping failed") - latency = time.Hour * 24 * 7 - } - - log.Debug().Dur("ping-reponse", latency).Msg("ping(ed) peer") - - // max( 0, latency ), more when less latency & less with more latency - metric := math.Max(float64(0), float64(int64(500)-latency.Milliseconds())) - peer := c.frrManager.GetPeer(c.otherID) - peer.Weight = uint32(metric) - c.frrManager.UpdatePeer(c.otherID, peer) - c.frrManager.Update() - - return nil -} - -func (c *PeerLink) backgroundTask() { - // We check the status every 60 seconds - timer := time.NewTicker(time.Second * 60) - - for { - select { - case <-timer.C: - if err := c.updateWeights(); err != nil { - log.Error(). - Err(err). - Uint32("peer-id", c.otherID). - Msgf("failed to adjust the weight") - } - - case <-c.ctx.Done(): - log.Error(). - Err(c.ctx.Err()). - Uint32("peer-id", c.otherID). - Msgf("ending the background task") - return - } - } -} diff --git a/bin/oriond/implementation/link/dispose.go b/bin/oriond/implementation/link/dispose.go deleted file mode 100644 index 3bbb059..0000000 --- a/bin/oriond/implementation/link/dispose.go +++ /dev/null @@ -1,17 +0,0 @@ -package link - -func (c *PeerLink) Dispose() error { - // cancel all the running tasks with the peer's context - c.cancel() - // we remove the frr peer - c.frrManager.UpdatePeer(c.otherID, nil) - err := c.frrManager.Update() - if err != nil { - return err - } - - // we dispose the vpn tunnel - c.wireguardTunnel.Dispose() - - return nil -} diff --git a/bin/oriond/implementation/link/holepunch.go b/bin/oriond/implementation/link/holepunch.go deleted file mode 100644 index f0a02e7..0000000 --- a/bin/oriond/implementation/link/holepunch.go +++ /dev/null @@ -1,90 +0,0 @@ -package link - -import ( - "context" - "flag" - "fmt" - "net" - "time" - - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -var ( - holePunchOverrideAddress = flag.String("override-hole-punch-address", "", "Override the public port for this instance") -) - -func (c *PeerLink) HolePunchTunnel( - parentCtx context.Context, - holepunchClient proto.HolePunchingServiceClient, -) (*proto.HolePunchingCompleteResponse, error) { - ctx := context.WithoutCancel(parentCtx) - device, err := c.wgClient.Device(c.wireguardTunnel.WgLink.InterfaceAttrs.Name) - if err != nil { - return nil, err - } - - if *holePunchOverrideAddress != "" { - return &proto.HolePunchingCompleteResponse{ - ClientEndpointAddr: *holePunchOverrideAddress, - ClientEndpointPort: uint32(device.ListenPort), - }, nil - } - - session, err := holepunchClient.Session(ctx, &proto.HolePunchingInitialize{ - PublicKey: (device.PublicKey)[:], - }) - if err != nil { - return nil, err - } - - message, err := session.Recv() - if err != nil { - return nil, err - } - - // The first message is a initialization response message - if initializationResponse := message.GetInitializationResponse(); initializationResponse != nil { - five := time.Second * 5 - presharedKey := wgtypes.Key(initializationResponse.PresharedKey) - ips, _ := net.LookupIP(initializationResponse.EndpointAddr) - if len(ips) == 0 { - return nil, fmt.Errorf("invalid server name") - } - log.Debug().IPAddr("server", ips[0]).Uint32("port", initializationResponse.EndpointPort).Msg("connecting to the server") - err = c.wgClient.ConfigureDevice(c.wireguardTunnel.WgLink.InterfaceAttrs.Name, wgtypes.Config{ - ReplacePeers: true, - Peers: []wgtypes.PeerConfig{ - { - PublicKey: wgtypes.Key(initializationResponse.PublicKey), - PresharedKey: &presharedKey, - Endpoint: &net.UDPAddr{ - IP: ips[0], - Port: int(initializationResponse.EndpointPort), - }, - PersistentKeepaliveInterval: &five, - }, - }, - }) - if err != nil { - return nil, err - } - } else { - return nil, fmt.Errorf("hole-punching protocol error") - } - - // We now wait for the response from the server, which should contain the public address and port - message, err = session.Recv() - if err != nil { - return nil, err - } - - if completeMessage := message.GetComplete(); completeMessage != nil { - log.Debug().Str("address", completeMessage.ClientEndpointAddr).Uint32("port", completeMessage.ClientEndpointPort).Msg("finished hole punching") - return completeMessage, nil - } else { - return nil, fmt.Errorf("hole-punching protocol error") - } -} diff --git a/bin/oriond/implementation/link/initialize.go b/bin/oriond/implementation/link/initialize.go deleted file mode 100644 index b572c29..0000000 --- a/bin/oriond/implementation/link/initialize.go +++ /dev/null @@ -1,79 +0,0 @@ -package link - -import ( - "flag" - "net" - "time" - - "github.com/MatthieuCoder/OrionV3/bin/oriond/implementation/frr" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -var ( - keepAlive = flag.Duration("wireguard-keepalive", time.Second*5, "") - - allIP4Ranges = net.IPNet{ - IP: net.IPv4zero, - Mask: net.CIDRMask(0, 32), - } - allIP6Ranges = net.IPNet{ - IP: net.IPv6zero, - Mask: net.CIDRMask(0, 128), - } -) - -func (c *PeerLink) InitializePeerConnection( - Endpoint *net.UDPAddr, - PublicKey wgtypes.Key, - PresharedKey wgtypes.Key, -) error { - c.initialized = true - - // We update our wireguard tunnel to finalize the connection request - err := c.wireguardTunnel.SetPeers( - c.wgClient, - []wgtypes.PeerConfig{ - { - Endpoint: &net.UDPAddr{ - IP: Endpoint.IP, - Port: Endpoint.Port, - }, - PresharedKey: &PresharedKey, - PublicKey: PublicKey, - PersistentKeepaliveInterval: keepAlive, - AllowedIPs: []net.IPNet{ - allIP4Ranges, - allIP6Ranges, - }, - }, - }, - ) - if err != nil { - return err - } - - err = c.wireguardTunnel.SetAddress(c.selfIP) - if err != nil { - return err - } - - // We register our peering to frr - c.frrManager.UpdatePeer(c.otherID, &frr.Peer{ - ASN: c.otherID + 64511, - Address: c.otherIP.IP.String(), - OrionId: c.otherID, - Weight: 0, - }) - err = c.frrManager.Update() - if err != nil { - return err - } - - // We launch our monitoring task - go func() { - time.Sleep(time.Second * 5) - c.backgroundTask() - }() - - return nil -} diff --git a/bin/oriond/implementation/link/link.go b/bin/oriond/implementation/link/link.go deleted file mode 100644 index 37f13d7..0000000 --- a/bin/oriond/implementation/link/link.go +++ /dev/null @@ -1,99 +0,0 @@ -package link - -import ( - "context" - "flag" - "fmt" - "net" - - "github.com/MatthieuCoder/OrionV3/bin/oriond/implementation/frr" - "github.com/MatthieuCoder/OrionV3/internal" - "github.com/rs/zerolog/log" - "github.com/vishvananda/netlink" - "golang.zx2c4.com/wireguard/wgctrl" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -var ( - basePort = flag.Uint("override-base-port", 65000, "Override the public port for this instance") -) - -type PeerLink struct { - ctx context.Context - frrManager *frr.FrrConfigManager - wireguardTunnel *internal.WireguardInterface - wgClient *wgctrl.Client - - publicKey wgtypes.Key - selfIP *net.IPNet - otherIP *net.IPNet - selfID uint32 - otherID uint32 - cancel context.CancelFunc - initialized bool -} - -func NewPeerLink( - parentCtx context.Context, - selfID uint32, - otherID uint32, - wgClient *wgctrl.Client, - frrManager *frr.FrrConfigManager, -) (*PeerLink, error) { - selfIP, otherIP, err := internal.GetSelfAddress(selfID, otherID) - if err != nil { - log.Error().Err(err).Msg("failed to compute the self address") - return nil, err - } - privatekey, err := wgtypes.GeneratePrivateKey() - if err != nil { - return nil, err - } - port := int(*basePort + uint(otherID)) - tunnel, err := internal.NewWireguardInterface(wgClient, &netlink.LinkAttrs{ - Name: fmt.Sprintf("orion%d", otherID), - Group: 30, - }, wgtypes.Config{ - PrivateKey: &privatekey, - ReplacePeers: true, - Peers: []wgtypes.PeerConfig{}, - ListenPort: &port, - }) - if err != nil { - return nil, err - } - err = tunnel.SetAddress(selfIP) - if err != nil { - defer tunnel.Dispose() - return nil, err - } - - ctx, cancel := context.WithCancel(parentCtx) - link := &PeerLink{ - ctx: ctx, - frrManager: frrManager, - wireguardTunnel: tunnel, - wgClient: wgClient, - selfID: selfID, - otherID: otherID, - selfIP: selfIP, - otherIP: otherIP, - publicKey: privatekey.PublicKey(), - cancel: cancel, - initialized: false, - } - - return link, nil -} - -func (c *PeerLink) PublicKey() wgtypes.Key { - return c.publicKey -} - -func (c *PeerLink) Initialized() bool { - return c.initialized -} - -func (c *PeerLink) RemoteID() uint32 { - return c.otherID -} diff --git a/bin/oriond/implementation/login.go b/bin/oriond/implementation/login.go deleted file mode 100644 index 93452a6..0000000 --- a/bin/oriond/implementation/login.go +++ /dev/null @@ -1,91 +0,0 @@ -package implementation - -import ( - "bytes" - "context" - "encoding/pem" - "fmt" - "os" - - "github.com/MatthieuCoder/OrionV3/internal" - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" -) - -func (c *OrionClientDaemon) login() error { - log.Info().Msg("loading the certificate") - - // Load the certificates - certificateFile, err := os.ReadFile(*internal.TLSPath) - if err != nil { - log.Error(). - Err(err). - Str("file", *internal.TLSPath). - Msg("cannot open the certificate path") - return err - } - - var buffer bytes.Buffer - - for block, rest := pem.Decode(certificateFile); block != nil; block, rest = pem.Decode(rest) { - if block.Type == "CERTIFICATE" { - err := pem.Encode(&buffer, block) - if err != nil { - log.Error(). - Err(err). - Msg("cannot encode to pem") - return err - } - } - } - - // We compute the nonce with all the data - nonce, err := internal.CalculateNonce(c.memberId, *friendlyName, buffer.Bytes(), c.privateKey) - if err != nil { - err = fmt.Errorf("couldn't compute the nonce given from the given information about this node") - log.Error(). - Err(err). - Msg(err.Error()) - return err - } - - if c.sID != "" { - nonce.SessionId = c.sID - nonce.Reconnect = true - } - - // We send the login-initialize information to the server - if err = c.registryStream.Send(&proto.RPCClientEvent{ - Event: &proto.RPCClientEvent_Initialize{ - Initialize: nonce, - }, - }); err != nil { - log.Error(). - Err(err). - Msg("couldn't send the login signature to the server") - } - - return nil -} - -func (c *OrionClientDaemon) Start() error { - if c.ctxCancel != nil && c.Context != nil { - c.ctxCancel() - } - - ctx, cancel := context.WithCancel(c.ParentCtx) - c.ctxCancel = cancel - c.Context = ctx - - // Intialize the streams to the signaling server - if err := c.initializeStream(); err != nil { - return err - } - if err := c.login(); err != nil { - return err - } - - // Start the listener as a background task - go c.listener() - return nil -} diff --git a/bin/oriond/implementation/oriond.go b/bin/oriond/implementation/oriond.go deleted file mode 100644 index 5cfe6f8..0000000 --- a/bin/oriond/implementation/oriond.go +++ /dev/null @@ -1,105 +0,0 @@ -package implementation - -import ( - "context" - "crypto/ecdsa" - "crypto/x509" - "flag" - "sync" - - "github.com/MatthieuCoder/OrionV3/bin/oriond/implementation/frr" - "github.com/MatthieuCoder/OrionV3/bin/oriond/implementation/link" - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" - "github.com/teivah/broadcast" - "golang.zx2c4.com/wireguard/wgctrl" - "google.golang.org/grpc" -) - -var ( - friendlyName = flag.String("friendly-name", "Standard OrionD Instance", "The name of the software connecting to Orion") -) - -type OrionClientDaemon struct { - // Metadata regarding the client - memberId uint32 - friendlyName string - asn uint32 - sID string - - // Structs used to manage the state of OrionD - frrManager *frr.FrrConfigManager - wgClient *wgctrl.Client - - // GRPC Clients - registryClient proto.RegistryClient - holePunchingClient proto.HolePunchingServiceClient - registryStream proto.Registry_SubscribeToStreamClient - - tunnels map[uint32]*link.PeerLink - tunnelsLock *sync.RWMutex - - // Runtime information - Context context.Context - ParentCtx context.Context - ctxCancel context.CancelFunc - establishedStream *broadcast.Relay[uint32] - - privateKey *ecdsa.PrivateKey - chain []*x509.Certificate -} - -// Creates and initializes a new Orion client -func NewOrionClientDaemon( - Context context.Context, - ClientConnection *grpc.ClientConn, - privateKey *ecdsa.PrivateKey, - chain []*x509.Certificate, -) (*OrionClientDaemon, error) { - orionClient := OrionClientDaemon{ - registryClient: proto.NewRegistryClient(ClientConnection), - holePunchingClient: proto.NewHolePunchingServiceClient(ClientConnection), - friendlyName: *friendlyName, - ParentCtx: Context, - establishedStream: broadcast.NewRelay[uint32](), - tunnels: map[uint32]*link.PeerLink{}, - tunnelsLock: &sync.RWMutex{}, - privateKey: privateKey, - chain: chain, - } - - wgClient, err := wgctrl.New() - if err != nil { - return nil, err - } - orionClient.wgClient = wgClient - - // Resolve our current identity using the data from the certificates, - // taking the overrides into acocunt - if err := orionClient.resolveIdentity(); err != nil { - return nil, err - } - - // Initializing the FRR config manager, which is used to change the bgp configuration - if frrManager, err := frr.NewFrrConfigManager(orionClient.asn, orionClient.memberId); err == nil { - orionClient.frrManager = frrManager - } else { - return nil, err - } - - return &orionClient, nil -} - -// Disposing interfaces and frr peers -func (c *OrionClientDaemon) Dispose() { - log.Info().Msg("Disposing all the client") - for _, tunnel := range c.tunnels { - err := tunnel.Dispose() - if err != nil { - log.Error(). - Err(err). - Uint32("peer-id", tunnel.RemoteID()). - Msg("failed to dispose the client") - } - } -} diff --git a/bin/oriond/oriond.go b/bin/oriond/oriond.go deleted file mode 100644 index 78ec57b..0000000 --- a/bin/oriond/oriond.go +++ /dev/null @@ -1,119 +0,0 @@ -package main - -import ( - "context" - "crypto/tls" - "flag" - "fmt" - "net/http" - _ "net/http/pprof" - "os" - "os/signal" - "syscall" - "time" - - "github.com/MatthieuCoder/OrionV3/bin/oriond/implementation" - "github.com/MatthieuCoder/OrionV3/internal" - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/keepalive" -) - -var ( - enable_prof = flag.Bool("enable-pprof", false, "enable pprof for debugging") - debug = flag.Bool("debug", false, "change the log level to debug") - registryServer = flag.String("registry-server", "reg.orionet.re", "the address of the registry server") - pprof = flag.String("debug-pprof", "0.0.0.0:6060", "") - registryPort = flag.Uint("registry-port", 6443, "the port used by the registry") -) - -func main() { - // Setup logging - zerolog.TimeFieldFormat = zerolog.TimeFormatUnix - flag.Parse() - - // Default level for this example is info, unless debug flag is present - log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) - zerolog.SetGlobalLevel(zerolog.InfoLevel) - if *enable_prof { - go func() { - fmt.Println(http.ListenAndServe(*pprof, nil)) - }() - } - if *debug { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - } - - privateKey, chain := internal.LoadPemFile() - certificateKeyPair := internal.LoadX509KeyPair(privateKey, chain) - authorityPool, err := internal.LoadAuthorityPool() - - keyChain := credentials.NewTLS( - &tls.Config{ - Certificates: []tls.Certificate{certificateKeyPair}, - RootCAs: authorityPool, - MinVersion: tls.VersionTLS13, - MaxVersion: tls.VersionTLS13, - }, - ) - - conn, err := grpc.NewClient( - fmt.Sprintf("%s:%d", *registryServer, *registryPort), - grpc.WithTransportCredentials(keyChain), - grpc.WithIdleTimeout(time.Second*120), - grpc.WithKeepaliveParams(keepalive.ClientParameters{ - Time: time.Second * 20, - Timeout: time.Second * 1, - PermitWithoutStream: false, - }), - ) - if err != nil { - log.Error().Err(err).Msg("failed to start the grpc client") - return - } - ctx, cancel := context.WithCancel(context.Background()) - orionDaemon, err := implementation.NewOrionClientDaemon( - ctx, - conn, - privateKey, - chain, - ) - if err != nil { - log.Error().Err(err).Msgf("failed to bring up orion client daemon") - return - } - err = orionDaemon.Start() - if err != nil { - log.Error().Err(err).Msgf("failed to bring up orion client daemon") - return - } - - defer orionDaemon.Dispose() - defer cancel() - - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) - - restartCounter := 0 - for { - select { - case <-sigs: - return - case <-ctx.Done(): - return - case <-orionDaemon.Context.Done(): - restartCounter += 1 - if restartCounter > 10 { - return - } - time.Sleep(time.Second * 5) - err := orionDaemon.Start() - if err != nil { - log.Error().Err(err).Msgf("failed to bring up orion client daemon") - return - } - } - } -} diff --git a/bin/registry-ws/.gitignore b/bin/registry-ws/.gitignore new file mode 100644 index 0000000..612424a --- /dev/null +++ b/bin/registry-ws/.gitignore @@ -0,0 +1 @@ +*.pem \ No newline at end of file diff --git a/bin/registry-ws/main.go b/bin/registry-ws/main.go new file mode 100644 index 0000000..103f221 --- /dev/null +++ b/bin/registry-ws/main.go @@ -0,0 +1,82 @@ +package main + +import ( + "crypto/tls" + "flag" + "fmt" + "net" + "net/http" + "os" + + "github.com/MatthieuCoder/OrionV3/bin/registry-ws/server" + "github.com/MatthieuCoder/OrionV3/internal" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +var ( + pprof = flag.String("debug-pprof", ":6060", "") + enable_prof = flag.Bool("enable-pprof", false, "enable pprof for debugging") + debug = flag.Bool("debug", false, "change the log level to debug") + listeningHost = flag.String("listen-host", "127.0.0.1:6443", "the port the server will listen on") +) + +func main() { + // Setup logging + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix + flag.Parse() + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) + // Default level for this example is info, unless debug flag is present + zerolog.SetGlobalLevel(zerolog.InfoLevel) + if *enable_prof { + go func() { + fmt.Println(http.ListenAndServe(*pprof, nil)) + }() + } + if *debug { + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } + privateKey, chain := internal.LoadPemFile() + certificateKeyPair := internal.LoadX509KeyPair(privateKey, chain) + authorityPool, err := internal.LoadAuthorityPool() + if err != nil { + log.Error().Err(err).Msgf("Failed to start listener") + return + } + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{certificateKeyPair}, + ClientCAs: authorityPool, + ClientAuth: tls.VerifyClientCertIfGiven, + MinVersion: tls.VersionTLS13, + CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, + PreferServerCipherSuites: true, + CipherSuites: []uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_RSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, + } + + srv := server.NewServer() + + server := http.Server{ + Addr: *listeningHost, + Handler: srv.Handler(), + TLSConfig: tlsConfig, + } + + ln, err := net.Listen("tcp", *listeningHost) + if err != nil { + panic(err) + } + defer ln.Close() + + tlsListener := tls.NewListener(ln, tlsConfig) + if err := server.Serve(tlsListener); err != nil { + log.Fatal().Msgf("(HTTPS) error listening to port: %v", err) + } +} diff --git a/bin/registry-ws/registry.pem b/bin/registry-ws/registry.pem new file mode 100644 index 0000000..7e72efa --- /dev/null +++ b/bin/registry-ws/registry.pem @@ -0,0 +1,58 @@ +Bag Attributes + friendlyName: Orion Registry X1 +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgClp+WDoXBwI2U7RH +/idtWmo2zNZ8JWs49W2I/MfN3MKgCgYIKoZIzj0DAQehRANCAAT0bHPFd7RXBFee +YmVnIMYoXnjfzSPtAnML8g1zyWNz3rjzcB7/WldHCfIABKXKhHED3KWwCMDRV4t+ +2RtUpn9c +-----END PRIVATE KEY----- +Bag Attributes + friendlyName: Orion Registry X1 +subject=/CN=Orion Registry X1/O=Orion/C=FR +issuer=/CN=Orion Intermediate X2/O=Orion/C=FR +-----BEGIN CERTIFICATE----- +MIICFTCCAbqgAwIBAgIUBmthVeKv65ExaUMH/qeKz1I30UcwCgYIKoZIzj0EAwIw +PTEeMBwGA1UEAwwVT3Jpb24gSW50ZXJtZWRpYXRlIFgyMQ4wDAYDVQQKDAVPcmlv +bjELMAkGA1UEBhMCRlIwHhcNMjQxMTI4MDYzNzM5WhcNMjYxMTI4MDYzNzM4WjA5 +MRowGAYDVQQDDBFPcmlvbiBSZWdpc3RyeSBYMTEOMAwGA1UECgwFT3Jpb24xCzAJ +BgNVBAYTAkZSMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9GxzxXe0VwRXnmJl +ZyDGKF54380j7QJzC/INc8ljc96483Ae/1pXRwnyAASlyoRxA9ylsAjA0VeLftkb +VKZ/XKOBmzCBmDAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFOtJd6xSSbldMrfi +NlIgEbtCn2sMMBkGA1UdEQQSMBCCDnJlZy5vcmlvbmV0LnJlMB0GA1UdJQQWMBQG +CCsGAQUFBwMEBggrBgEFBQcDATAdBgNVHQ4EFgQUKowEjlCQx7CxeTOJynBrEAPX +JNQwDgYDVR0PAQH/BAQDAgXgMAoGCCqGSM49BAMCA0kAMEYCIQCinYgPGwxnb+Et +ukVRNyyzqmZxJRCBRdn5Bxqcg7l+swIhALJnlFUbiy9RXPFnZXiWhCu/SvsZ8bT+ +MSrzxo3/dweN +-----END CERTIFICATE----- +Bag Attributes + friendlyName: Unknown +subject=/CN=Orion Intermediate X2/O=Orion/C=FR +issuer=/CN=Orion Root X2/O=Orion/C=FR +-----BEGIN CERTIFICATE----- +MIIB2DCCAX2gAwIBAgIUA4Nj5hLdcsQA3wioQeMKmUcKOm8wCgYIKoZIzj0EAwIw +NTEWMBQGA1UEAwwNT3Jpb24gUm9vdCBYMjEOMAwGA1UECgwFT3Jpb24xCzAJBgNV +BAYTAkZSMB4XDTI0MTAxODEyNDUzM1oXDTM0MTAxNjEyNDUzMlowPTEeMBwGA1UE +AwwVT3Jpb24gSW50ZXJtZWRpYXRlIFgyMQ4wDAYDVQQKDAVPcmlvbjELMAkGA1UE +BhMCRlIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATjdn41rcbi2A7Ekz55DRfa +zDy70fe1VtMjC7ej2VIzUdqw6KsL0Ywe6mkd2kOzwJUuPoRxQZKfe9qYoW1c7szw +o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFD5EFqFa4wRBj4hM85d7 +Tq31ZsKwMB0GA1UdDgQWBBTrSXesUkm5XTK34jZSIBG7Qp9rDDAOBgNVHQ8BAf8E +BAMCAYYwCgYIKoZIzj0EAwIDSQAwRgIhAMYrJfGBvHuouWm7ku1wbzts14qXyxrI +GVcq8dDnPMfTAiEAuQ/pdtshaGUI8+hzHDAr9+Kk4p7KBbPEiIkrRHnll8c= +-----END CERTIFICATE----- +Bag Attributes + friendlyName: Unknown +subject=/CN=Orion Root X2/O=Orion/C=FR +issuer=/CN=Orion Root X2/O=Orion/C=FR +-----BEGIN CERTIFICATE----- +MIIB0DCCAXWgAwIBAgIUYlSd5D84oBGQa2UtAXKi80Hwvx4wCgYIKoZIzj0EAwIw +NTEWMBQGA1UEAwwNT3Jpb24gUm9vdCBYMjEOMAwGA1UECgwFT3Jpb24xCzAJBgNV +BAYTAkZSMB4XDTI0MTAxODEyNDEzMVoXDTQ5MTAxOTEyNDEzMFowNTEWMBQGA1UE +AwwNT3Jpb24gUm9vdCBYMjEOMAwGA1UECgwFT3Jpb24xCzAJBgNVBAYTAkZSMFkw +EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5HChn5wgvzL1rPizAcJl84BdoS29HqsI +iA1xTROVlZdP5slCHRg4CqTGTT4zW0i9BBEQX4GXF2PU3uQIPpnPK6NjMGEwDwYD +VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ+RBahWuMEQY+ITPOXe06t9WbCsDAd +BgNVHQ4EFgQUPkQWoVrjBEGPiEzzl3tOrfVmwrAwDgYDVR0PAQH/BAQDAgGGMAoG +CCqGSM49BAMCA0kAMEYCIQC9hK9/R+jRtNNUT8tzJ58EWglfieUcBNPkTJqVe+Up +YwIhAI4sw3ufFskXJINmrbVnb0xd5FxjUCByuqLYtY3xYaSA +-----END CERTIFICATE----- diff --git a/bin/registry-ws/server/errors/auth-required.html b/bin/registry-ws/server/errors/auth-required.html new file mode 100644 index 0000000..66111c8 --- /dev/null +++ b/bin/registry-ws/server/errors/auth-required.html @@ -0,0 +1,11 @@ + + + + + + Authentication required + + + Authentication is required to access this page + + \ No newline at end of file diff --git a/bin/registry-ws/server/protocol/client.go b/bin/registry-ws/server/protocol/client.go new file mode 100644 index 0000000..61bfe50 --- /dev/null +++ b/bin/registry-ws/server/protocol/client.go @@ -0,0 +1,131 @@ +package protocol + +import ( + "context" + "fmt" + + "github.com/MatthieuCoder/OrionV3/bin/registry-ws/server/protocol/messages" + "github.com/MatthieuCoder/OrionV3/internal" + "github.com/MatthieuCoder/OrionV3/internal/state" + "github.com/gorilla/websocket" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +var orionRegistryState *state.OrionRegistryState = state.NewOrionRegistryState() + +type Client struct { + ctx context.Context + router *state.Router + identity state.RouterIdentity + ws *websocket.Conn + + log zerolog.Logger +} + +func NewClient(ws *websocket.Conn, identity state.RouterIdentity) *Client { + c := &Client{ + ws: ws, + identity: identity, + ctx: context.Background(), + log: log.With().Uint32("router-identity", uint32(identity)).Logger(), + } + + c.log.Debug().Msg("starting new client connection") + go c.startRoutine() + return c +} + +func (c *Client) send(k string, msg state.Event) error { + err := c.ws.WriteJSON(messages.Event{ + Kind: k, + Content: msg, + }) + if err != nil { + c.log.Error().Err(err).Msg("failed to send message") + } + return err +} + +func (c *Client) startRoutine() { + c.log.Debug().Msg("connection handling routine started") + c.send(messages.MessageKindHello, messages.Hello{ + Message: "Hi. This is orion-registry.", + Identity: c.identity, + Version: internal.Version, + Commit: internal.Commit, + }) + + // check if the router exists + rtrs := orionRegistryState.GetRouters() + rtr := rtrs[c.identity] + if rtr == nil { + c.log.Debug().Msg("initialized a new state plane router object") + rtr = state.NewRouter(context.Background(), c.identity, orionRegistryState) + // dispatch new router if the given router doesn't exist + orionRegistryState.DispatchNewRouterEvent( + rtr, + ) + c.router = rtr + } else { + c.log.Debug().Msg("re-using an existing router object system") + // we inform the router object, in the registry state + // that the connection is still ongoing and should not + // be idle-disposed. + c.router = rtr + } + + sub := c.router.Subscribe() + channel := sub.Ch() + ctx, cancel := context.WithCancelCause(c.ctx) + defer sub.Close() + + go func() { + // listening for events + for { + select { + case event := <-channel: + switch event := event.(type) { + case state.RouterConnect: + c.log.Debug().Msg("sending a new router connect event") + c.send(messages.MessageKindRouterConnect, event) + case state.RouterDisconnect: + c.log.Debug().Msg("sending a new disconnect event") + c.send(messages.MessageKindRouterDisconnect, event) + } + case <-c.ctx.Done(): + goto end + } + } + + end: + cancel(fmt.Errorf("the state-internal event listener is finished")) + }() + + // We start listening for events once the listener go-routine is setup + // this is because the increment connection count trigers a recovery + // of a lost connection + rtr.IncrementConnectionCount() + + go func() { + for { + _, _, err := c.ws.ReadMessage() + if err != nil { + goto end + } + + // todo: handle clients events + } + + end: + cancel(fmt.Errorf("the websocket listening is finished")) + }() + + // wait for the context to be finished + <-ctx.Done() + + c.log.Info().Msg("connection ended") + c.router.DecrementConnectionCount() + + c.ws.Close() +} diff --git a/bin/registry-ws/server/protocol/messages/event.go b/bin/registry-ws/server/protocol/messages/event.go new file mode 100644 index 0000000..eee83c4 --- /dev/null +++ b/bin/registry-ws/server/protocol/messages/event.go @@ -0,0 +1,8 @@ +package messages + +import "github.com/MatthieuCoder/OrionV3/internal/state" + +type Event struct { + Kind string `json:"k"` + Content state.Event `json:"e"` +} diff --git a/bin/registry-ws/server/protocol/messages/hello.go b/bin/registry-ws/server/protocol/messages/hello.go new file mode 100644 index 0000000..084dfab --- /dev/null +++ b/bin/registry-ws/server/protocol/messages/hello.go @@ -0,0 +1,12 @@ +package messages + +import ( + "github.com/MatthieuCoder/OrionV3/internal/state" +) + +type Hello struct { + Message string `json:"message"` + Identity state.RouterIdentity `json:"identity"` + Version string `json:"version"` + Commit string `json:"commit"` +} diff --git a/bin/registry-ws/server/protocol/messages/kinds.go b/bin/registry-ws/server/protocol/messages/kinds.go new file mode 100644 index 0000000..97d5d79 --- /dev/null +++ b/bin/registry-ws/server/protocol/messages/kinds.go @@ -0,0 +1,23 @@ +package messages + +const ( + // Event sent at the beginning for a new connection + // allows version negotiation + MessageKindHello = "hello" + // Sent when a new router joined the network, + // this is so that a user, can choose to initiate + // a new connection to this new router. + MessageKindRouterConnect = "new_router" + // Sent when a router session ended meaning + // a disconnection from the orion registry + // this will triger a teardown of the client + // and thus a end of all wireguard tunnels + MessageKindRouterDisconnect = "router_disconnect" + // A message sent by a router wanting to connect + // to another one. + // step1. (peer1) ---> (registry) ---> (peer2) + MessageKindRouterEdgeInitStep1 = "edge_initiate" + // A message considered as a response of stage1. + // step2. (peer2) ---> (registry) ---> (peer1) + MessageKindRouterEdgeInitStep2 = "edge_create_request" +) diff --git a/bin/registry-ws/server/server.go b/bin/registry-ws/server/server.go new file mode 100644 index 0000000..1d7280d --- /dev/null +++ b/bin/registry-ws/server/server.go @@ -0,0 +1,23 @@ +package server + +import ( + "net/http" +) + +type Server struct{} + +func (c *Server) Handler() *http.ServeMux { + mux := http.NewServeMux() + + // Serve the static files + fs := http.FileServer(http.FS(assets)) + mux.Handle("/", http.StripPrefix("/static", fs)) + mux.HandleFunc("/whoami", c.whoami) + mux.HandleFunc("/ws", c.upgrade) + + return mux +} + +func NewServer() *Server { + return &Server{} +} diff --git a/bin/registry-ws/server/static.go b/bin/registry-ws/server/static.go new file mode 100644 index 0000000..51d6738 --- /dev/null +++ b/bin/registry-ws/server/static.go @@ -0,0 +1,11 @@ +package server + +import ( + "embed" +) + +//go:embed static +var assets embed.FS + +//go:embed errors +var errors embed.FS diff --git a/bin/registry-ws/server/static/index.html b/bin/registry-ws/server/static/index.html new file mode 100644 index 0000000..05e7cb1 --- /dev/null +++ b/bin/registry-ws/server/static/index.html @@ -0,0 +1,11 @@ + + + + + + Orion Registry + + + Welcome to the Orion Registry ;) + + \ No newline at end of file diff --git a/bin/registry-ws/server/upgrade.go b/bin/registry-ws/server/upgrade.go new file mode 100644 index 0000000..d9103f2 --- /dev/null +++ b/bin/registry-ws/server/upgrade.go @@ -0,0 +1,53 @@ +package server + +import ( + "net/http" + "strconv" + "strings" + + "github.com/MatthieuCoder/OrionV3/bin/registry-ws/server/protocol" + "github.com/MatthieuCoder/OrionV3/internal/state" + "github.com/gorilla/websocket" + "github.com/rs/zerolog/log" +) + +var upgrader = websocket.Upgrader{} + +func upgradeErrorPage(w http.ResponseWriter) { + file, _ := errors.ReadFile("auth-required.html") + w.WriteHeader(http.StatusOK) + w.Header().Set("Content-Type", "application/html") + w.Write(file) +} + +func (c *Server) upgrade(w http.ResponseWriter, r *http.Request) { + if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 { + upgradeErrorPage(w) + return + } + + cz, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Error().Err(err).Msg("Failed to upgrade a http(s) connection to a websocket connection") + return + } + // todo: close websocket connections cleanly + // defer cz.Close() + + leaf := r.TLS.PeerCertificates[0] + cn := leaf.Subject.CommonName + cnParts := strings.Split(cn, ":") + if len(cnParts) != 2 || cnParts[1] != "oriond" { + log.Error().Err(err).Msg("The given certificate is not valid for logging-in into oriond") + return + } + + routerId, err := strconv.Atoi(cnParts[0]) + if err != nil { + log.Error().Err(err).Msg("The given certificate is not valid for logging-in into oriond") + return + } + identity := state.RouterIdentity(routerId) + + protocol.NewClient(cz, identity) +} diff --git a/bin/registry-ws/server/whoami.go b/bin/registry-ws/server/whoami.go new file mode 100644 index 0000000..bb67230 --- /dev/null +++ b/bin/registry-ws/server/whoami.go @@ -0,0 +1,29 @@ +package server + +import ( + "fmt" + "net/http" +) + +func (c *Server) whoami(w http.ResponseWriter, r *http.Request) { + if r.TLS == nil && len(r.TLS.PeerCertificates) > 0 { + return + } + state := r.TLS + + fmt.Fprint(w, ">>>>>>>>>>>>>>>> State <<<<<<<<<<<<<<<<\n") + + fmt.Fprintf(w, "Version: %x\n", state.Version) + fmt.Fprintf(w, "HandshakeComplete: %t\n", state.HandshakeComplete) + fmt.Fprintf(w, "DidResume: %t\n", state.DidResume) + fmt.Fprintf(w, "CipherSuite: %x\n", state.CipherSuite) + fmt.Fprintf(w, "NegotiatedProtocol: %s\n", state.NegotiatedProtocol) + + fmt.Fprintf(w, "Certificate chain:\n") + for i, cert := range state.PeerCertificates { + subject := cert.Subject + issuer := cert.Issuer + fmt.Fprintf(w, " %d s:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s\n", i, subject.Country, subject.Province, subject.Locality, subject.Organization, subject.OrganizationalUnit, subject.CommonName) + fmt.Fprintf(w, " i:/C=%v/ST=%v/L=%v/O=%v/OU=%v/CN=%s\n", issuer.Country, issuer.Province, issuer.Locality, issuer.Organization, issuer.OrganizationalUnit, issuer.CommonName) + } +} diff --git a/bin/registry/implementation/holepunching_impl.go b/bin/registry/implementation/holepunching_impl.go deleted file mode 100644 index b64c30e..0000000 --- a/bin/registry/implementation/holepunching_impl.go +++ /dev/null @@ -1,158 +0,0 @@ -package implementation - -import ( - "context" - "flag" - "fmt" - "time" - - "github.com/MatthieuCoder/OrionV3/internal" - "github.com/MatthieuCoder/OrionV3/internal/proto" - "golang.zx2c4.com/wireguard/wgctrl" - - "github.com/rs/zerolog/log" - "github.com/vishvananda/netlink" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" -) - -var ( - holePunchingInstances = flag.Int("hole-punching-concurrent-instances", 16, "Concurrent hole-punching instances") - holePunchingHost = flag.String("hole-punching-server-address", "reg.orionet.re", "The address or name to give to the client") - holePunchingBasePort = flag.Int("hole-punching-base-port", 42000, "The base port for hole-punching wireguard-tunnels") - holePunchingInterfacePrefix = flag.String("hole-punching-interface-prefix", "reg", "The prefix added to each wireguard instance used for hole punching") - holePunchingHandshakeTimeout = flag.Int("hole-punching-handshake-timeout-seconds", 16, "The number of seconds to wait for a client handshake") -) - -type OrionHolePunchingImplementation struct { - wgClient *wgctrl.Client - tasksAssigner internal.LockableTasks - proto.UnimplementedHolePunchingServiceServer -} - -func NewOrionHolePunchingImplementation() (*OrionHolePunchingImplementation, error) { - wg, err := wgctrl.New() - if err != nil { - log.Error().Err(err).Msg("failed to initialize the wireguard control system") - return nil, err - } - - log.Info().Msg("initialized the Orion hole-punching api implementation") - return &OrionHolePunchingImplementation{ - wgClient: wg, - tasksAssigner: internal.NewLockableTasks(*holePunchingInstances), - }, nil -} - -func (r *OrionHolePunchingImplementation) Session(sessionInit *proto.HolePunchingInitialize, sessionServer proto.HolePunchingService_SessionServer) error { - log.Debug().Msg("handling a hole-punching request") - - task, err := r.tasksAssigner.AssignSessionId(sessionServer.Context()) - if err != nil { - return err - } - defer task.Release() - - // Parameters for the new wireguard tunnel instance used for hole-punching. - device := wgtypes.Config{} - port := *holePunchingBasePort + task.Id - device.ListenPort = &port - - // Generate a preshared-key for the wireguard peer - presharedKey, err := wgtypes.GenerateKey() - if err != nil { - return err - } - - // Add a new peer for this client - device.Peers = append(device.Peers, wgtypes.PeerConfig{ - PublicKey: wgtypes.Key(sessionInit.PublicKey), - PresharedKey: &presharedKey, - }) - - // Generate a private-key for this wireguard instance - key, err := wgtypes.GeneratePrivateKey() - if err != nil { - return err - } - device.PrivateKey = &key - - // Create a new wireguard interface - interfaceName := fmt.Sprintf("%s%d", *holePunchingInterfacePrefix, task.Id) - log.Info().Str("interface-name", interfaceName).Msg("creating interface") - - wgInt, err := internal.NewWireguardInterface( - r.wgClient, - &netlink.LinkAttrs{ - Name: interfaceName, - }, - device, - ) - if err != nil { - return err - } - defer wgInt.Dispose() - - log.Debug().Msg("sending the connection information to the client") - - public_key_bytes := [wgtypes.KeyLen]byte(device.PrivateKey.PublicKey()) - preshared_key_bytes := [wgtypes.KeyLen]byte(presharedKey) - - // Send the login information the the client - sessionServer.Send(&proto.HolePunchingEvent{ - Event: &proto.HolePunchingEvent_InitializationResponse{ - InitializationResponse: &proto.HolePunchingInitializationResponse{ - EndpointAddr: *holePunchingHost, - EndpointPort: uint32(port), - PublicKey: public_key_bytes[:], - PresharedKey: preshared_key_bytes[:], - }, - }, - }) - - // Create a new context for waiting for the first handshake from the client - timeoutTime := time.Second * time.Duration(*holePunchingHandshakeTimeout) - waitingCtx, ctxCancel := context.WithTimeout(sessionServer.Context(), timeoutTime) - defer ctxCancel() - // We're checking the status every second - ticker := time.NewTicker(time.Second) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - // We verify if an handshake was made - log.Debug().Str("interface", interfaceName).Msg("checking the wireguard interface for handshakes") - dev, err := r.wgClient.Device(interfaceName) - if err != nil { - log.Error().Err(err).Msg("error while reading the interface information") - return err - } - - if len(dev.Peers) != 1 { - err = fmt.Errorf("more than one peer is connected to the hole-punching instance") - log.Error().Err(err).Msg("this should be not possible") - return err - } - - peer := dev.Peers[0] - // We check if an endpoint was recorded - if peer.Endpoint != nil { - log.Debug().Int("task-id", task.Id).IPAddr("address", peer.Endpoint.IP).Int("port", peer.Endpoint.Port).Msg("got a connection to the wireguard instance") - - sessionServer.Send(&proto.HolePunchingEvent{ - Event: &proto.HolePunchingEvent_Complete{ - Complete: &proto.HolePunchingCompleteResponse{ - ClientEndpointAddr: peer.Endpoint.IP.String(), - ClientEndpointPort: uint32(peer.Endpoint.Port), - }, - }, - }) - - return nil - } - - case <-waitingCtx.Done(): - return waitingCtx.Err() - } - } -} diff --git a/bin/registry/implementation/registry_impl.go b/bin/registry/implementation/registry_impl.go deleted file mode 100644 index aea27f3..0000000 --- a/bin/registry/implementation/registry_impl.go +++ /dev/null @@ -1,128 +0,0 @@ -package implementation - -import ( - "crypto/x509" - "fmt" - "os" - - "github.com/MatthieuCoder/OrionV3/bin/registry/implementation/session" - "github.com/MatthieuCoder/OrionV3/internal" - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" -) - -type OrionRegistryImplementation struct { - rootCertPool *x509.CertPool - sessionManager *session.SessionManager - proto.UnimplementedRegistryServer -} - -func NewOrionRegistryImplementation() (*OrionRegistryImplementation, error) { - // Reading the root certificate - ca, err := os.ReadFile(*internal.AuthorityPath) - if err != nil { - log.Debug(). - Err(err). - Msg("failed to import the root ca certificate") - return nil, err - } - - // Create a new certificate pool containing the root certificates - root := x509.NewCertPool() - // Append the root certificate to the pool - ok := root.AppendCertsFromPEM(ca) - if !ok { - return nil, fmt.Errorf("the root certificate failed to be imported") - } - - return &OrionRegistryImplementation{ - sessionManager: session.NewSessionManager(), - rootCertPool: root, - }, nil -} - -func (r *OrionRegistryImplementation) SubscribeToStream(subscibeEvent proto.Registry_SubscribeToStreamServer) error { - // Used to store the current session - var currentSession *session.Session - // Used to handle the events - eventsStream := make(chan *proto.RPCClientEvent) - - // Simple subroutine to handle end various events - go func() { - for { - event, err := subscibeEvent.Recv() - if err != nil { - return - } - - eventsStream <- event - } - }() - - select { - case clientEvent := <-eventsStream: - if event := clientEvent.GetInitialize(); event != nil { - - // check session_id - var newSession *session.Session - - if !event.Reconnect { - if session := r.sessionManager.GetSession(event.MemberId); session != nil { - log.Info().Msg("Disposing old session for re-login") - session.DisposeInstant() - } - - var err error - newSession = session.New( - r.sessionManager, - ) - - err = newSession.Authenticate( - event, - r.rootCertPool, - ) - - if err != nil { - return err - } - } else { - newSession = r.sessionManager.GetSessionFromSessionId(event.SessionId) - if newSession == nil { - return fmt.Errorf("no such session id") - } - newSession.Restore() - } - - // Set the session - currentSession = newSession - // Start the disposal when exiting the routine - defer currentSession.Dispose() - } - - case <-subscibeEvent.Context().Done(): - return subscibeEvent.Context().Err() - } - listenerServer := currentSession.Ch() - defer listenerServer.Close() - - for { - select { - // Handle all the events from the client - case event := <-eventsStream: - err := currentSession.HandleClientEvent(event) - if err != nil { - return err - } - // This is not working. - case serverMessage := <-listenerServer.Ch(): - err := subscibeEvent.Send(serverMessage) - if err != nil { - return err - } - case <-currentSession.Context.Done(): - return currentSession.Context.Err() - case <-subscibeEvent.Context().Done(): - return subscibeEvent.Context().Err() - } - } -} diff --git a/bin/registry/implementation/session/auth.go b/bin/registry/implementation/session/auth.go deleted file mode 100644 index 90bf783..0000000 --- a/bin/registry/implementation/session/auth.go +++ /dev/null @@ -1,163 +0,0 @@ -package session - -import ( - "context" - "crypto/ecdsa" - "crypto/rand" - "crypto/x509" - "encoding/pem" - "fmt" - "math/big" - "time" - - "github.com/MatthieuCoder/OrionV3/internal" - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" - "software.sslmate.com/src/ocsputil" -) - -func generateRandomString(n int) (string, error) { - const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" - ret := make([]byte, n) - for i := 0; i < n; i++ { - num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) - if err != nil { - return "", err - } - ret[i] = letters[num.Int64()] - } - - return string(ret), nil -} - -func (c *Session) Authenticate( - Event *proto.InitializeRequest, - RootCertPool *x509.CertPool, -) error { - // Verify that the date only has a variation inferior to 2s - time := time.Now().Unix() - if time-Event.TimestampSigned > 2 { - err := fmt. - Errorf("the verification timestamp is too far from the current time") - log.Debug(). - Err(err). - Msg("user supplied an invalid date/time") - return err - } - intermediates := x509.NewCertPool() - var userCertificate *x509.Certificate - - for block, rest := pem.Decode(Event.Certificate); block != nil; block, rest = pem.Decode(rest) { - if block.Type == "CERTIFICATE" { - certificate, err := x509.ParseCertificate(block.Bytes) - if certificate.IsCA && err == nil { - intermediates.AddCert(certificate) - } else if err == nil { - userCertificate = certificate - } - } - } - - var issuer *x509.Certificate - for block, rest := pem.Decode(Event.Certificate); block != nil; block, rest = pem.Decode(rest) { - if block.Type == "CERTIFICATE" { - certificate, err := x509.ParseCertificate(block.Bytes) - if err == nil && certificate.Subject.String() == userCertificate.Issuer.String() { - issuer = certificate - } - } - } - if issuer == nil { - err := fmt.Errorf("cannot find the issuing certificate") - log.Error(). - Err(err). - Msg("cannot find the issuing certificate") - return err - } - - if _, err := userCertificate.Verify(x509.VerifyOptions{ - Roots: RootCertPool, - Intermediates: intermediates, - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, - }); err != nil { - log.Debug(). - Err(err). - Msg("user supplied an orion-invalid certificate") - return err - } - - revoked, _, _ := ocsputil.CheckCert(context.Background(), userCertificate, issuer, &ocsputil.Config{}) - if revoked { - err := fmt.Errorf("certificate is revoked") - log.Error(). - Err(err). - Msg("certificate is revoked") - return err - } - - log.Debug(). - Msgf("Certificate verification succesful, checking common names (%d memberid => %s common name ?)", Event.MemberId, userCertificate.Subject.CommonName) - - if userCertificate.Subject.CommonName != fmt.Sprintf("%d:oriond", Event.MemberId) { - err := fmt.Errorf("this certificate is not valid for oriond") - log.Error(). - Err(err). - Msg("user supplied an orion-invalid certificate") - return err - } - - // Calculate the hash given in order to check the client signature - nonce := internal.CalculateNonceBytes(Event.MemberId, Event.FriendlyName, Event.TimestampSigned) - - // Verify that the user-provided data matches the signature created using the client root key - successful := ecdsa.VerifyASN1(userCertificate.PublicKey.(*ecdsa.PublicKey), nonce, Event.Signed) - if !successful { - err := fmt.Errorf("this signature does not seem to be a valid ECDSA signature") - log.Debug(). - Err(err). - Msg("the user authentication failed, invalid signature") - return err - } - - log.Info(). - Msgf("User %s (%d) auth with certificate with serial: %s", Event.FriendlyName, Event.MemberId, userCertificate.SerialNumber) - - // the user is authenticated, we start listening for global events - - log.Debug().Msg("client created") - // registering in the manager - c.meta = &SessionMeta{ - memberId: Event.MemberId, - friendlyName: Event.FriendlyName, - } - c.sessionManager.sessions[Event.MemberId] = c - - log.Debug().Msg("broadcasting the new client message") - c.sessionManager.newClients.Notify( - &proto.NewMemberEvent{ - FriendlyName: Event.FriendlyName, - PeerId: Event.MemberId, - }, - ) - - log.Debug().Msg("random session id generation") - sessionId, err := generateRandomString(64) - if err != nil { - return err - } - c.sID = sessionId - // Since the registry is not handling the channel while login, we simply wait by launching a goroutine - go func() { - c.streamSend.Broadcast(&proto.RPCServerEvent{ - Event: &proto.RPCServerEvent_SessionId{ - SessionId: sessionId, - }, - }) - }() - c.sessionManager.sessionIdsMap[sessionId] = &c.meta.memberId - - log.Debug().Msg("starting listeners") - go c.eventListeners() - - return nil -} diff --git a/bin/registry/implementation/session/events.go b/bin/registry/implementation/session/events.go deleted file mode 100644 index 6b1ec07..0000000 --- a/bin/registry/implementation/session/events.go +++ /dev/null @@ -1,107 +0,0 @@ -package session - -import ( - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" -) - -func (c *Session) HandleClientEvent( - Event *proto.RPCClientEvent, -) error { - log.Debug().Msg("handling client event") - switch Event.Event.(type) { - case *proto.RPCClientEvent_Connect: - return c.handle_Connect(Event.Event.(*proto.RPCClientEvent_Connect)) - case *proto.RPCClientEvent_ConnectResponse: - return c.handle_ConnectResponse(Event.Event.(*proto.RPCClientEvent_ConnectResponse)) - } - - return nil -} - -func (c *Session) eventListeners() { - newClient := c.sessionManager.newClients.Listener(1) - disposedClient := c.sessionManager.disposedClients.Listener(1) - defer newClient.Close() - defer disposedClient.Close() - - for { - select { - // Handling the events from the newClients stream - case newClient := <-newClient.Ch(): - if c.meta != nil { - // When a new client joins, we send a notification message - log.Debug(). - Uint32("new-member-id", newClient.PeerId). - Uint32("session", c.meta.memberId). - Msgf("notifying of new client") - - c.streamSend.Broadcast(&proto.RPCServerEvent{ - Event: &proto.RPCServerEvent_NewMember{ - NewMember: newClient, - }, - }) - } - // Handling the events from the invitation stream - case invitation := <-c.invitations: - if c.meta != nil { - if invitation.DestinationPeerId == c.meta.memberId { - log.Debug(). - Uint32("src-member-id", invitation.SourcePeerId). - Uint32("dst-member-id", invitation.DestinationPeerId). - Msg("notifying of new session invitation") - - c.streamSend.Broadcast(&proto.RPCServerEvent{ - Event: &proto.RPCServerEvent_MemberConnect{ - MemberConnect: invitation, - }, - }) - } else { - log.Error(). - Uint32("src-member-id", invitation.SourcePeerId). - Uint32("dst-member-id", invitation.DestinationPeerId). - Uint32("routine-member-id", c.meta.memberId). - Msg("wrong dst-id for this routine") - } - } - // Handling the events from the invitation responses - case invitation_response := <-c.invitationsResponses: - if c.meta != nil { - if invitation_response.DestinationPeerId == c.meta.memberId { - log.Debug(). - Uint32("src-member-id", invitation_response.SourcePeerId). - Uint32("dst-member-id", c.meta.memberId). - Msg("notifying of new invitation request") - - c.streamSend.Broadcast(&proto.RPCServerEvent{ - Event: &proto.RPCServerEvent_MemberConnectResponse{ - MemberConnectResponse: invitation_response, - }, - }) - } else { - log.Error(). - Uint32("src-member-id", invitation_response.SourcePeerId). - Uint32("dst-member-id", invitation_response.DestinationPeerId). - Uint32("routine-member-id", c.meta.memberId). - Msg("wrong dst-id for this routine") - } - } - - case disposed := <-disposedClient.Ch(): - if c.meta != nil { - log.Debug(). - Uint32("disposed-member-id", disposed.PeerId). - Uint32("member-id", c.meta.memberId). - Msg("disposing client") - - c.streamSend.Broadcast(&proto.RPCServerEvent{ - Event: &proto.RPCServerEvent_DisconnectedMember{ - DisconnectedMember: disposed, - }, - }) - } - case <-c.Context.Done(): - return - } - } -} diff --git a/bin/registry/implementation/session/handler_connect.go b/bin/registry/implementation/session/handler_connect.go deleted file mode 100644 index 974f7ad..0000000 --- a/bin/registry/implementation/session/handler_connect.go +++ /dev/null @@ -1,28 +0,0 @@ -package session - -import ( - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" -) - -func (r *Session) handle_Connect( - event *proto.RPCClientEvent_Connect, -) error { - connect := event.Connect - - if connect.SourcePeerId == r.meta.memberId && - connect.DestinationPeerId != r.meta.memberId { - log.Debug(). - Uint32("source", r.meta.memberId). - Uint32("destination", connect.DestinationPeerId). - Msgf("Connect Init") - - if session := r.sessionManager.GetSession(connect.DestinationPeerId); session != nil { - session.invitations <- connect - } else { - log.Error().Msgf("%d is not available", connect.DestinationPeerId) - } - } - - return nil -} diff --git a/bin/registry/implementation/session/handler_connect_response.go b/bin/registry/implementation/session/handler_connect_response.go deleted file mode 100644 index 616c127..0000000 --- a/bin/registry/implementation/session/handler_connect_response.go +++ /dev/null @@ -1,28 +0,0 @@ -package session - -import ( - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" -) - -func (r *Session) handle_ConnectResponse( - event *proto.RPCClientEvent_ConnectResponse, -) error { - connectResponse := event.ConnectResponse - - if connectResponse.SourcePeerId == r.meta.memberId && - connectResponse.DestinationPeerId != r.meta.memberId { - log.Debug(). - Uint32("source", r.meta.memberId). - Uint32("destination", connectResponse.DestinationPeerId). - Msgf("Connect Response") - - if session := r.sessionManager.GetSession(connectResponse.DestinationPeerId); session != nil { - session.invitationsResponses <- connectResponse - } else { - log.Error().Msgf("%d is not available", connectResponse.DestinationPeerId) - } - } - - return nil -} diff --git a/bin/registry/implementation/session/meta.go b/bin/registry/implementation/session/meta.go deleted file mode 100644 index fb0ac72..0000000 --- a/bin/registry/implementation/session/meta.go +++ /dev/null @@ -1,6 +0,0 @@ -package session - -type SessionMeta struct { - memberId uint32 - friendlyName string -} diff --git a/bin/registry/implementation/session/session.go b/bin/registry/implementation/session/session.go deleted file mode 100644 index d43e0ba..0000000 --- a/bin/registry/implementation/session/session.go +++ /dev/null @@ -1,94 +0,0 @@ -package session - -import ( - "context" - "time" - - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" - "github.com/teivah/broadcast" -) - -type Session struct { - invitations chan *proto.MemberConnectEvent - invitationsResponses chan *proto.MemberConnectResponseEvent - meta *SessionMeta - sessionManager *SessionManager - - streamSend *broadcast.Relay[*proto.RPCServerEvent] - Context context.Context - cancel context.CancelFunc - sID string - - cancelCancelation chan struct{} -} - -func (c *Session) Dispose() { - // Checking if the client is auth'ed - if c.meta != nil { - c.cancelCancelation = make(chan struct{}) - // wait 2 minutes before ending a session - go func() { - log.Debug().Uint32("uid", c.meta.memberId).Msg("starting to tick for session expitation") - timer := time.NewTimer(time.Second * 20) - - select { - case <-c.cancelCancelation: - c.cancelCancelation = nil - return - case <-timer.C: - c.cancelCancelation = nil - c.DisposeInstant() - } - }() - } -} - -func (c *Session) DisposeInstant() { - if c.cancelCancelation != nil { - c.cancelCancelation <- struct{}{} - } - - meta := c.meta - // we should dispose the client - c.cancel() - c.sessionManager.disposedClients.Notify(&proto.MemberDisconnectedEvent{ - PeerId: meta.memberId, - FriendlyName: meta.friendlyName, - }) - - c.sessionManager.sessionIdsMap[c.sID] = nil - c.sessionManager.sessions[c.meta.memberId] = nil - - // todo: implements ack in the protocol - time.Sleep(2 * time.Second) -} - -func (c *Session) Restore() { - if c.meta != nil && c.cancelCancelation != nil { - log.Info().Uint32("uid", c.meta.memberId).Msg("Session restored") - c.cancelCancelation <- struct{}{} - } -} - -func New( - sessionManager *SessionManager, -) *Session { - ctx, cancel := context.WithCancel(context.Background()) - - session := &Session{ - meta: nil, - invitations: make(chan *proto.MemberConnectEvent), - invitationsResponses: make(chan *proto.MemberConnectResponseEvent), - sessionManager: sessionManager, - streamSend: broadcast.NewRelay[*proto.RPCServerEvent](), - Context: ctx, - cancel: cancel, - } - - return session -} - -func (c *Session) Ch() *broadcast.Listener[*proto.RPCServerEvent] { - return c.streamSend.Listener(10) -} diff --git a/bin/registry/implementation/session/session_manager.go b/bin/registry/implementation/session/session_manager.go deleted file mode 100644 index 45cd9d1..0000000 --- a/bin/registry/implementation/session/session_manager.go +++ /dev/null @@ -1,37 +0,0 @@ -package session - -import ( - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" - "github.com/teivah/broadcast" -) - -type SessionManager struct { - sessions map[uint32]*Session - sessionIdsMap map[string]*uint32 - - newClients *broadcast.Relay[*proto.NewMemberEvent] - disposedClients *broadcast.Relay[*proto.MemberDisconnectedEvent] -} - -func (c *SessionManager) GetSession(session uint32) *Session { - return c.sessions[session] -} - -func (c *SessionManager) GetSessionFromSessionId(id string) *Session { - log.Debug().Str("session-id", id).Msg("getting by session id") - uid := c.sessionIdsMap[id] - if uid == nil { - return nil - } - return c.GetSession(*uid) -} - -func NewSessionManager() *SessionManager { - return &SessionManager{ - sessions: map[uint32]*Session{}, - sessionIdsMap: make(map[string]*uint32), - newClients: broadcast.NewRelay[*proto.NewMemberEvent](), - disposedClients: broadcast.NewRelay[*proto.MemberDisconnectedEvent](), - } -} diff --git a/bin/registry/server.go b/bin/registry/server.go deleted file mode 100644 index cbbd284..0000000 --- a/bin/registry/server.go +++ /dev/null @@ -1,105 +0,0 @@ -package main - -import ( - "crypto/tls" - "flag" - "fmt" - "net" - "os" - "time" - - "net/http" - _ "net/http/pprof" - - "github.com/MatthieuCoder/OrionV3/bin/registry/implementation" - "github.com/MatthieuCoder/OrionV3/internal" - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/keepalive" -) - -var ( - pprof = flag.String("debug-pprof", ":6060", "") - enable_prof = flag.Bool("enable-pprof", false, "enable pprof for debugging") - debug = flag.Bool("debug", false, "change the log level to debug") - listeningHost = flag.String("listen-host", "127.0.0.1:6443", "the port the server will listen on") -) - -func main() { - // Setup logging - zerolog.TimeFieldFormat = zerolog.TimeFormatUnix - flag.Parse() - log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) - // Default level for this example is info, unless debug flag is present - zerolog.SetGlobalLevel(zerolog.InfoLevel) - if *enable_prof { - go func() { - fmt.Println(http.ListenAndServe(*pprof, nil)) - }() - } - if *debug { - zerolog.SetGlobalLevel(zerolog.DebugLevel) - } - privateKey, chain := internal.LoadPemFile() - certificateKeyPair := internal.LoadX509KeyPair(privateKey, chain) - authorityPool, err := internal.LoadAuthorityPool() - if err != nil { - log.Error().Err(err).Msgf("Failed to start listener") - return - } - - keyChain := credentials.NewTLS( - &tls.Config{ - Certificates: []tls.Certificate{certificateKeyPair}, - RootCAs: authorityPool, - MinVersion: tls.VersionTLS13, - MaxVersion: tls.VersionTLS13, - ClientAuth: tls.RequireAndVerifyClientCert, - }, - ) - - lis, err := net.Listen("tcp", *listeningHost) - - if err != nil { - log.Error().Err(err).Msgf("Failed to start listener") - return - } - - // Create a new gRPC server - s := grpc.NewServer( - grpc.Creds(keyChain), - grpc.KeepaliveParams(keepalive.ServerParameters{ - Time: time.Second * 20, - Timeout: time.Second * 1, - MaxConnectionIdle: time.Second * 20, - }), - grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{ - MinTime: time.Second * 15, - PermitWithoutStream: false, - }), - ) - - registry, err := implementation.NewOrionRegistryImplementation() - if err != nil { - log.Error().Err(err).Msgf("Failed to create the registry") - return - } - holepunch, err := implementation.NewOrionHolePunchingImplementation() - if err != nil { - log.Error().Err(err).Msgf("Failed to create the holepunching service") - return - } - - proto.RegisterRegistryServer(s, registry) - proto.RegisterHolePunchingServiceServer(s, holepunch) - - // Start the gRPC server - log.Info().Str("listening-address", lis.Addr().String()).Msgf("Server listening") - if err := s.Serve(lis); err != nil { - log.Error().Err(err).Msg("Failed to serve") - return - } -} diff --git a/go.mod b/go.mod index d576772..7a0269a 100644 --- a/go.mod +++ b/go.mod @@ -2,22 +2,15 @@ module github.com/MatthieuCoder/OrionV3 go 1.22.5 -require ( - google.golang.org/grpc v1.67.1 - google.golang.org/protobuf v1.34.2 -) - -require github.com/google/uuid v1.6.0 // indirect - require ( github.com/google/go-cmp v0.6.0 // indirect + github.com/gorilla/websocket v1.5.3 github.com/josharian/native v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect - github.com/prometheus-community/pro-bing v0.4.2-0.20241031101218-a36072f1081e github.com/rs/zerolog v1.33.0 github.com/teivah/broadcast v0.1.0 github.com/vishvananda/netlink v1.1.0 @@ -26,9 +19,6 @@ require ( golang.org/x/net v0.29.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 - google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect - software.sslmate.com/src/ocsputil v0.5.0 ) diff --git a/go.sum b/go.sum index 0cf7c6d..387a240 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -21,8 +21,6 @@ github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8Ku 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/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/prometheus-community/pro-bing v0.4.2-0.20241031101218-a36072f1081e h1:VoFed15jO7ilBiu7KdpzWWcPvl25K+/TCWhJBD3SN7U= -github.com/prometheus-community/pro-bing v0.4.2-0.20241031101218-a36072f1081e/go.mod h1:LMb7HcSRQQCn3jYlT3Jnq6WTpP3v4IuOwGKmYrwqpIM= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -44,17 +42,7 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx3wnr6L04cJFbWoceSK9JWBdglINo= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/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= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -software.sslmate.com/src/ocsputil v0.5.0 h1:mJrX5z7XbHyVFqTpDvCWy+8KuCLn1Dro+5tUoFhix7I= -software.sslmate.com/src/ocsputil v0.5.0/go.mod h1:cYsyBW9ycE4100TeKI8zqFy74W6/LIj95hZXoh0UBm4= diff --git a/internal/nonce_utils.go b/internal/nonce_utils.go deleted file mode 100644 index 1b887bc..0000000 --- a/internal/nonce_utils.go +++ /dev/null @@ -1,69 +0,0 @@ -package internal - -import ( - "crypto/ecdsa" - "crypto/rand" - "crypto/sha512" - "crypto/x509" - "encoding/pem" - "fmt" - "time" - - "github.com/MatthieuCoder/OrionV3/internal/proto" - "github.com/rs/zerolog/log" -) - -// Calculate the nonce bytes -func CalculateNonceBytes(MemberId uint32, FriendlyName string, time int64) []byte { - return sha512.New().Sum([]byte(fmt.Sprintf("%d:%s:%d", MemberId, FriendlyName, time))) -} - -// Used to calculate the nonce and sign it -func CalculateNonce( - MemberId uint32, - FriendlyName string, - Certificate []byte, - PrivateKey *ecdsa.PrivateKey, -) (*proto.InitializeRequest, error) { - time := time.Now().Unix() - authHash := CalculateNonceBytes(MemberId, FriendlyName, time) - - signed, err := ecdsa.SignASN1(rand.Reader, PrivateKey, authHash) - - if err != nil { - log.Error().Err(err).Msgf("couldn't sign the nonce data") - return nil, err - } - - return &proto.InitializeRequest{ - FriendlyName: FriendlyName, - TimestampSigned: time, - MemberId: MemberId, - Certificate: Certificate, - Signed: signed, - }, nil -} - -// Parse a pem file and adds all the pem-encoded certificates to a cert-pool -func CreateCertPoolFromPEM(PEMData []byte) (*x509.CertPool, error) { - // Create a cert-pool containing the user-provided intermediary certificates - pool := x509.NewCertPool() - ok := pool.AppendCertsFromPEM(PEMData) - if !ok { - user_err := fmt.Errorf("failed to import the User-given intermediate CAs") - log.Debug().Err(user_err).Msg("failed to import the root ca certificate") - return nil, user_err - } - return pool, nil -} - -func ParsePEMCertificate(Certificate []byte) (*x509.Certificate, error) { - // Parsing the pem-encoded used-given certificate in order to parse the certificate - block, _ := pem.Decode(Certificate) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - log.Error().Err(err).Msg("failed to parse certificate") - return nil, err - } - return cert, nil -} diff --git a/internal/proto/orion_holepunch.pb.go b/internal/proto/orion_holepunch.pb.go deleted file mode 100644 index b66c13f..0000000 --- a/internal/proto/orion_holepunch.pb.go +++ /dev/null @@ -1,440 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.1 -// protoc v5.27.2 -// source: proto/orion_holepunch.proto - -package proto - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// Message sent to initialize a hole-punching session for a given Wireguard Tunnel. -type HolePunchingInitialize struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PublicKey []byte `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` -} - -func (x *HolePunchingInitialize) Reset() { - *x = HolePunchingInitialize{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_holepunch_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HolePunchingInitialize) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HolePunchingInitialize) ProtoMessage() {} - -func (x *HolePunchingInitialize) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_holepunch_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HolePunchingInitialize.ProtoReflect.Descriptor instead. -func (*HolePunchingInitialize) Descriptor() ([]byte, []int) { - return file_proto_orion_holepunch_proto_rawDescGZIP(), []int{0} -} - -func (x *HolePunchingInitialize) GetPublicKey() []byte { - if x != nil { - return x.PublicKey - } - return nil -} - -// Message send to inform the client of the Wireguard credentials and ip adresses -type HolePunchingInitializationResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The public endpoint and port of the registry server. - EndpointAddr string `protobuf:"bytes,1,opt,name=endpoint_addr,json=endpointAddr,proto3" json:"endpoint_addr,omitempty"` - EndpointPort uint32 `protobuf:"varint,2,opt,name=endpoint_port,json=endpointPort,proto3" json:"endpoint_port,omitempty"` - // The public key of the registry server. - PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` - // The preshared key assigned by the server for this session. - PresharedKey []byte `protobuf:"bytes,4,opt,name=preshared_key,json=presharedKey,proto3" json:"preshared_key,omitempty"` -} - -func (x *HolePunchingInitializationResponse) Reset() { - *x = HolePunchingInitializationResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_holepunch_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HolePunchingInitializationResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HolePunchingInitializationResponse) ProtoMessage() {} - -func (x *HolePunchingInitializationResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_holepunch_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HolePunchingInitializationResponse.ProtoReflect.Descriptor instead. -func (*HolePunchingInitializationResponse) Descriptor() ([]byte, []int) { - return file_proto_orion_holepunch_proto_rawDescGZIP(), []int{1} -} - -func (x *HolePunchingInitializationResponse) GetEndpointAddr() string { - if x != nil { - return x.EndpointAddr - } - return "" -} - -func (x *HolePunchingInitializationResponse) GetEndpointPort() uint32 { - if x != nil { - return x.EndpointPort - } - return 0 -} - -func (x *HolePunchingInitializationResponse) GetPublicKey() []byte { - if x != nil { - return x.PublicKey - } - return nil -} - -func (x *HolePunchingInitializationResponse) GetPresharedKey() []byte { - if x != nil { - return x.PresharedKey - } - return nil -} - -// Message send to inform that the information was gathered by the registry server -type HolePunchingCompleteResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ClientEndpointAddr string `protobuf:"bytes,1,opt,name=client_endpoint_addr,json=clientEndpointAddr,proto3" json:"client_endpoint_addr,omitempty"` - ClientEndpointPort uint32 `protobuf:"varint,2,opt,name=client_endpoint_port,json=clientEndpointPort,proto3" json:"client_endpoint_port,omitempty"` -} - -func (x *HolePunchingCompleteResponse) Reset() { - *x = HolePunchingCompleteResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_holepunch_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HolePunchingCompleteResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HolePunchingCompleteResponse) ProtoMessage() {} - -func (x *HolePunchingCompleteResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_holepunch_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HolePunchingCompleteResponse.ProtoReflect.Descriptor instead. -func (*HolePunchingCompleteResponse) Descriptor() ([]byte, []int) { - return file_proto_orion_holepunch_proto_rawDescGZIP(), []int{2} -} - -func (x *HolePunchingCompleteResponse) GetClientEndpointAddr() string { - if x != nil { - return x.ClientEndpointAddr - } - return "" -} - -func (x *HolePunchingCompleteResponse) GetClientEndpointPort() uint32 { - if x != nil { - return x.ClientEndpointPort - } - return 0 -} - -// Message after the connection of the client to the holepunching-dedicated server endpoint. -type HolePunchingEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Event: - // - // *HolePunchingEvent_InitializationResponse - // *HolePunchingEvent_Complete - Event isHolePunchingEvent_Event `protobuf_oneof:"event"` -} - -func (x *HolePunchingEvent) Reset() { - *x = HolePunchingEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_holepunch_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *HolePunchingEvent) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*HolePunchingEvent) ProtoMessage() {} - -func (x *HolePunchingEvent) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_holepunch_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use HolePunchingEvent.ProtoReflect.Descriptor instead. -func (*HolePunchingEvent) Descriptor() ([]byte, []int) { - return file_proto_orion_holepunch_proto_rawDescGZIP(), []int{3} -} - -func (m *HolePunchingEvent) GetEvent() isHolePunchingEvent_Event { - if m != nil { - return m.Event - } - return nil -} - -func (x *HolePunchingEvent) GetInitializationResponse() *HolePunchingInitializationResponse { - if x, ok := x.GetEvent().(*HolePunchingEvent_InitializationResponse); ok { - return x.InitializationResponse - } - return nil -} - -func (x *HolePunchingEvent) GetComplete() *HolePunchingCompleteResponse { - if x, ok := x.GetEvent().(*HolePunchingEvent_Complete); ok { - return x.Complete - } - return nil -} - -type isHolePunchingEvent_Event interface { - isHolePunchingEvent_Event() -} - -type HolePunchingEvent_InitializationResponse struct { - InitializationResponse *HolePunchingInitializationResponse `protobuf:"bytes,1,opt,name=initialization_response,json=initializationResponse,proto3,oneof"` -} - -type HolePunchingEvent_Complete struct { - Complete *HolePunchingCompleteResponse `protobuf:"bytes,2,opt,name=complete,proto3,oneof"` -} - -func (*HolePunchingEvent_InitializationResponse) isHolePunchingEvent_Event() {} - -func (*HolePunchingEvent_Complete) isHolePunchingEvent_Event() {} - -var File_proto_orion_holepunch_proto protoreflect.FileDescriptor - -var file_proto_orion_holepunch_proto_rawDesc = []byte{ - 0x0a, 0x1b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x72, 0x69, 0x6f, 0x6e, 0x5f, 0x68, 0x6f, - 0x6c, 0x65, 0x70, 0x75, 0x6e, 0x63, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x37, 0x0a, - 0x16, 0x48, 0x6f, 0x6c, 0x65, 0x50, 0x75, 0x6e, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x69, - 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0xb2, 0x01, 0x0a, 0x22, 0x48, 0x6f, 0x6c, 0x65, 0x50, - 0x75, 0x6e, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, - 0x0d, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x64, - 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x70, - 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x73, 0x68, 0x61, - 0x72, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, - 0x72, 0x65, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0x82, 0x01, 0x0a, 0x1c, - 0x48, 0x6f, 0x6c, 0x65, 0x50, 0x75, 0x6e, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x14, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x30, - 0x0a, 0x14, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, - 0x74, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x50, 0x6f, 0x72, 0x74, - 0x22, 0xb9, 0x01, 0x0a, 0x11, 0x48, 0x6f, 0x6c, 0x65, 0x50, 0x75, 0x6e, 0x63, 0x68, 0x69, 0x6e, - 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x5e, 0x0a, 0x17, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x48, 0x6f, 0x6c, 0x65, 0x50, 0x75, - 0x6e, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x16, - 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x48, 0x6f, 0x6c, 0x65, 0x50, - 0x75, 0x6e, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x32, 0x4f, 0x0a, 0x13, - 0x48, 0x6f, 0x6c, 0x65, 0x50, 0x75, 0x6e, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x12, 0x38, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x17, - 0x2e, 0x48, 0x6f, 0x6c, 0x65, 0x50, 0x75, 0x6e, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x69, - 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x1a, 0x12, 0x2e, 0x48, 0x6f, 0x6c, 0x65, 0x50, 0x75, - 0x6e, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x42, 0x09, 0x5a, - 0x07, 0x2e, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_proto_orion_holepunch_proto_rawDescOnce sync.Once - file_proto_orion_holepunch_proto_rawDescData = file_proto_orion_holepunch_proto_rawDesc -) - -func file_proto_orion_holepunch_proto_rawDescGZIP() []byte { - file_proto_orion_holepunch_proto_rawDescOnce.Do(func() { - file_proto_orion_holepunch_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_orion_holepunch_proto_rawDescData) - }) - return file_proto_orion_holepunch_proto_rawDescData -} - -var file_proto_orion_holepunch_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_proto_orion_holepunch_proto_goTypes = []interface{}{ - (*HolePunchingInitialize)(nil), // 0: HolePunchingInitialize - (*HolePunchingInitializationResponse)(nil), // 1: HolePunchingInitializationResponse - (*HolePunchingCompleteResponse)(nil), // 2: HolePunchingCompleteResponse - (*HolePunchingEvent)(nil), // 3: HolePunchingEvent -} -var file_proto_orion_holepunch_proto_depIdxs = []int32{ - 1, // 0: HolePunchingEvent.initialization_response:type_name -> HolePunchingInitializationResponse - 2, // 1: HolePunchingEvent.complete:type_name -> HolePunchingCompleteResponse - 0, // 2: HolePunchingService.Session:input_type -> HolePunchingInitialize - 3, // 3: HolePunchingService.Session:output_type -> HolePunchingEvent - 3, // [3:4] is the sub-list for method output_type - 2, // [2:3] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name -} - -func init() { file_proto_orion_holepunch_proto_init() } -func file_proto_orion_holepunch_proto_init() { - if File_proto_orion_holepunch_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_proto_orion_holepunch_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HolePunchingInitialize); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_orion_holepunch_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HolePunchingInitializationResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_orion_holepunch_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HolePunchingCompleteResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_orion_holepunch_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HolePunchingEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_proto_orion_holepunch_proto_msgTypes[3].OneofWrappers = []interface{}{ - (*HolePunchingEvent_InitializationResponse)(nil), - (*HolePunchingEvent_Complete)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_proto_orion_holepunch_proto_rawDesc, - NumEnums: 0, - NumMessages: 4, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_proto_orion_holepunch_proto_goTypes, - DependencyIndexes: file_proto_orion_holepunch_proto_depIdxs, - MessageInfos: file_proto_orion_holepunch_proto_msgTypes, - }.Build() - File_proto_orion_holepunch_proto = out.File - file_proto_orion_holepunch_proto_rawDesc = nil - file_proto_orion_holepunch_proto_goTypes = nil - file_proto_orion_holepunch_proto_depIdxs = nil -} diff --git a/internal/proto/orion_holepunch_grpc.pb.go b/internal/proto/orion_holepunch_grpc.pb.go deleted file mode 100644 index d24f781..0000000 --- a/internal/proto/orion_holepunch_grpc.pb.go +++ /dev/null @@ -1,132 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v5.27.2 -// source: proto/orion_holepunch.proto - -package proto - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// HolePunchingServiceClient is the client API for HolePunchingService service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type HolePunchingServiceClient interface { - Session(ctx context.Context, in *HolePunchingInitialize, opts ...grpc.CallOption) (HolePunchingService_SessionClient, error) -} - -type holePunchingServiceClient struct { - cc grpc.ClientConnInterface -} - -func NewHolePunchingServiceClient(cc grpc.ClientConnInterface) HolePunchingServiceClient { - return &holePunchingServiceClient{cc} -} - -func (c *holePunchingServiceClient) Session(ctx context.Context, in *HolePunchingInitialize, opts ...grpc.CallOption) (HolePunchingService_SessionClient, error) { - stream, err := c.cc.NewStream(ctx, &HolePunchingService_ServiceDesc.Streams[0], "/HolePunchingService/Session", opts...) - if err != nil { - return nil, err - } - x := &holePunchingServiceSessionClient{stream} - if err := x.ClientStream.SendMsg(in); err != nil { - return nil, err - } - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - return x, nil -} - -type HolePunchingService_SessionClient interface { - Recv() (*HolePunchingEvent, error) - grpc.ClientStream -} - -type holePunchingServiceSessionClient struct { - grpc.ClientStream -} - -func (x *holePunchingServiceSessionClient) Recv() (*HolePunchingEvent, error) { - m := new(HolePunchingEvent) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// HolePunchingServiceServer is the server API for HolePunchingService service. -// All implementations must embed UnimplementedHolePunchingServiceServer -// for forward compatibility -type HolePunchingServiceServer interface { - Session(*HolePunchingInitialize, HolePunchingService_SessionServer) error - mustEmbedUnimplementedHolePunchingServiceServer() -} - -// UnimplementedHolePunchingServiceServer must be embedded to have forward compatible implementations. -type UnimplementedHolePunchingServiceServer struct { -} - -func (UnimplementedHolePunchingServiceServer) Session(*HolePunchingInitialize, HolePunchingService_SessionServer) error { - return status.Errorf(codes.Unimplemented, "method Session not implemented") -} -func (UnimplementedHolePunchingServiceServer) mustEmbedUnimplementedHolePunchingServiceServer() {} - -// UnsafeHolePunchingServiceServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to HolePunchingServiceServer will -// result in compilation errors. -type UnsafeHolePunchingServiceServer interface { - mustEmbedUnimplementedHolePunchingServiceServer() -} - -func RegisterHolePunchingServiceServer(s grpc.ServiceRegistrar, srv HolePunchingServiceServer) { - s.RegisterService(&HolePunchingService_ServiceDesc, srv) -} - -func _HolePunchingService_Session_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(HolePunchingInitialize) - if err := stream.RecvMsg(m); err != nil { - return err - } - return srv.(HolePunchingServiceServer).Session(m, &holePunchingServiceSessionServer{stream}) -} - -type HolePunchingService_SessionServer interface { - Send(*HolePunchingEvent) error - grpc.ServerStream -} - -type holePunchingServiceSessionServer struct { - grpc.ServerStream -} - -func (x *holePunchingServiceSessionServer) Send(m *HolePunchingEvent) error { - return x.ServerStream.SendMsg(m) -} - -// HolePunchingService_ServiceDesc is the grpc.ServiceDesc for HolePunchingService service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var HolePunchingService_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "HolePunchingService", - HandlerType: (*HolePunchingServiceServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{ - { - StreamName: "Session", - Handler: _HolePunchingService_Session_Handler, - ServerStreams: true, - }, - }, - Metadata: "proto/orion_holepunch.proto", -} diff --git a/internal/proto/orion_registry.pb.go b/internal/proto/orion_registry.pb.go deleted file mode 100644 index 517dd17..0000000 --- a/internal/proto/orion_registry.pb.go +++ /dev/null @@ -1,895 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.1 -// protoc v5.27.2 -// source: proto/orion_registry.proto - -package proto - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type NewMemberEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - FriendlyName string `protobuf:"bytes,1,opt,name=friendly_name,json=friendlyName,proto3" json:"friendly_name,omitempty"` - PeerId uint32 `protobuf:"varint,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` -} - -func (x *NewMemberEvent) Reset() { - *x = NewMemberEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_registry_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *NewMemberEvent) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*NewMemberEvent) ProtoMessage() {} - -func (x *NewMemberEvent) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_registry_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use NewMemberEvent.ProtoReflect.Descriptor instead. -func (*NewMemberEvent) Descriptor() ([]byte, []int) { - return file_proto_orion_registry_proto_rawDescGZIP(), []int{0} -} - -func (x *NewMemberEvent) GetFriendlyName() string { - if x != nil { - return x.FriendlyName - } - return "" -} - -func (x *NewMemberEvent) GetPeerId() uint32 { - if x != nil { - return x.PeerId - } - return 0 -} - -type MemberDisconnectedEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - FriendlyName string `protobuf:"bytes,1,opt,name=friendly_name,json=friendlyName,proto3" json:"friendly_name,omitempty"` - PeerId uint32 `protobuf:"varint,2,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"` -} - -func (x *MemberDisconnectedEvent) Reset() { - *x = MemberDisconnectedEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_registry_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MemberDisconnectedEvent) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MemberDisconnectedEvent) ProtoMessage() {} - -func (x *MemberDisconnectedEvent) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_registry_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MemberDisconnectedEvent.ProtoReflect.Descriptor instead. -func (*MemberDisconnectedEvent) Descriptor() ([]byte, []int) { - return file_proto_orion_registry_proto_rawDescGZIP(), []int{1} -} - -func (x *MemberDisconnectedEvent) GetFriendlyName() string { - if x != nil { - return x.FriendlyName - } - return "" -} - -func (x *MemberDisconnectedEvent) GetPeerId() uint32 { - if x != nil { - return x.PeerId - } - return 0 -} - -type MemberConnectEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - EndpointAddr string `protobuf:"bytes,1,opt,name=endpoint_addr,json=endpointAddr,proto3" json:"endpoint_addr,omitempty"` - EndpointPort uint32 `protobuf:"varint,2,opt,name=endpoint_port,json=endpointPort,proto3" json:"endpoint_port,omitempty"` - PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` - FriendlyName string `protobuf:"bytes,5,opt,name=friendly_name,json=friendlyName,proto3" json:"friendly_name,omitempty"` - DestinationPeerId uint32 `protobuf:"varint,6,opt,name=destination_peer_id,json=destinationPeerId,proto3" json:"destination_peer_id,omitempty"` - SourcePeerId uint32 `protobuf:"varint,7,opt,name=source_peer_id,json=sourcePeerId,proto3" json:"source_peer_id,omitempty"` -} - -func (x *MemberConnectEvent) Reset() { - *x = MemberConnectEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_registry_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MemberConnectEvent) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MemberConnectEvent) ProtoMessage() {} - -func (x *MemberConnectEvent) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_registry_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MemberConnectEvent.ProtoReflect.Descriptor instead. -func (*MemberConnectEvent) Descriptor() ([]byte, []int) { - return file_proto_orion_registry_proto_rawDescGZIP(), []int{2} -} - -func (x *MemberConnectEvent) GetEndpointAddr() string { - if x != nil { - return x.EndpointAddr - } - return "" -} - -func (x *MemberConnectEvent) GetEndpointPort() uint32 { - if x != nil { - return x.EndpointPort - } - return 0 -} - -func (x *MemberConnectEvent) GetPublicKey() []byte { - if x != nil { - return x.PublicKey - } - return nil -} - -func (x *MemberConnectEvent) GetFriendlyName() string { - if x != nil { - return x.FriendlyName - } - return "" -} - -func (x *MemberConnectEvent) GetDestinationPeerId() uint32 { - if x != nil { - return x.DestinationPeerId - } - return 0 -} - -func (x *MemberConnectEvent) GetSourcePeerId() uint32 { - if x != nil { - return x.SourcePeerId - } - return 0 -} - -type MemberConnectResponseEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - EndpointAddr string `protobuf:"bytes,1,opt,name=endpoint_addr,json=endpointAddr,proto3" json:"endpoint_addr,omitempty"` - EndpointPort uint32 `protobuf:"varint,2,opt,name=endpoint_port,json=endpointPort,proto3" json:"endpoint_port,omitempty"` - PublicKey []byte `protobuf:"bytes,3,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` - FriendlyName string `protobuf:"bytes,4,opt,name=friendly_name,json=friendlyName,proto3" json:"friendly_name,omitempty"` - DestinationPeerId uint32 `protobuf:"varint,5,opt,name=destination_peer_id,json=destinationPeerId,proto3" json:"destination_peer_id,omitempty"` - PresharedKey []byte `protobuf:"bytes,7,opt,name=preshared_key,json=presharedKey,proto3" json:"preshared_key,omitempty"` - SourcePeerId uint32 `protobuf:"varint,6,opt,name=source_peer_id,json=sourcePeerId,proto3" json:"source_peer_id,omitempty"` -} - -func (x *MemberConnectResponseEvent) Reset() { - *x = MemberConnectResponseEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_registry_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MemberConnectResponseEvent) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MemberConnectResponseEvent) ProtoMessage() {} - -func (x *MemberConnectResponseEvent) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_registry_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use MemberConnectResponseEvent.ProtoReflect.Descriptor instead. -func (*MemberConnectResponseEvent) Descriptor() ([]byte, []int) { - return file_proto_orion_registry_proto_rawDescGZIP(), []int{3} -} - -func (x *MemberConnectResponseEvent) GetEndpointAddr() string { - if x != nil { - return x.EndpointAddr - } - return "" -} - -func (x *MemberConnectResponseEvent) GetEndpointPort() uint32 { - if x != nil { - return x.EndpointPort - } - return 0 -} - -func (x *MemberConnectResponseEvent) GetPublicKey() []byte { - if x != nil { - return x.PublicKey - } - return nil -} - -func (x *MemberConnectResponseEvent) GetFriendlyName() string { - if x != nil { - return x.FriendlyName - } - return "" -} - -func (x *MemberConnectResponseEvent) GetDestinationPeerId() uint32 { - if x != nil { - return x.DestinationPeerId - } - return 0 -} - -func (x *MemberConnectResponseEvent) GetPresharedKey() []byte { - if x != nil { - return x.PresharedKey - } - return nil -} - -func (x *MemberConnectResponseEvent) GetSourcePeerId() uint32 { - if x != nil { - return x.SourcePeerId - } - return 0 -} - -type RPCServerEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Event: - // - // *RPCServerEvent_NewMember - // *RPCServerEvent_DisconnectedMember - // *RPCServerEvent_MemberConnect - // *RPCServerEvent_MemberConnectResponse - // *RPCServerEvent_SessionId - Event isRPCServerEvent_Event `protobuf_oneof:"event"` -} - -func (x *RPCServerEvent) Reset() { - *x = RPCServerEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_registry_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RPCServerEvent) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RPCServerEvent) ProtoMessage() {} - -func (x *RPCServerEvent) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_registry_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RPCServerEvent.ProtoReflect.Descriptor instead. -func (*RPCServerEvent) Descriptor() ([]byte, []int) { - return file_proto_orion_registry_proto_rawDescGZIP(), []int{4} -} - -func (m *RPCServerEvent) GetEvent() isRPCServerEvent_Event { - if m != nil { - return m.Event - } - return nil -} - -func (x *RPCServerEvent) GetNewMember() *NewMemberEvent { - if x, ok := x.GetEvent().(*RPCServerEvent_NewMember); ok { - return x.NewMember - } - return nil -} - -func (x *RPCServerEvent) GetDisconnectedMember() *MemberDisconnectedEvent { - if x, ok := x.GetEvent().(*RPCServerEvent_DisconnectedMember); ok { - return x.DisconnectedMember - } - return nil -} - -func (x *RPCServerEvent) GetMemberConnect() *MemberConnectEvent { - if x, ok := x.GetEvent().(*RPCServerEvent_MemberConnect); ok { - return x.MemberConnect - } - return nil -} - -func (x *RPCServerEvent) GetMemberConnectResponse() *MemberConnectResponseEvent { - if x, ok := x.GetEvent().(*RPCServerEvent_MemberConnectResponse); ok { - return x.MemberConnectResponse - } - return nil -} - -func (x *RPCServerEvent) GetSessionId() string { - if x, ok := x.GetEvent().(*RPCServerEvent_SessionId); ok { - return x.SessionId - } - return "" -} - -type isRPCServerEvent_Event interface { - isRPCServerEvent_Event() -} - -type RPCServerEvent_NewMember struct { - NewMember *NewMemberEvent `protobuf:"bytes,1,opt,name=new_member,json=newMember,proto3,oneof"` -} - -type RPCServerEvent_DisconnectedMember struct { - DisconnectedMember *MemberDisconnectedEvent `protobuf:"bytes,2,opt,name=disconnected_member,json=disconnectedMember,proto3,oneof"` -} - -type RPCServerEvent_MemberConnect struct { - MemberConnect *MemberConnectEvent `protobuf:"bytes,3,opt,name=member_connect,json=memberConnect,proto3,oneof"` -} - -type RPCServerEvent_MemberConnectResponse struct { - MemberConnectResponse *MemberConnectResponseEvent `protobuf:"bytes,4,opt,name=member_connect_response,json=memberConnectResponse,proto3,oneof"` -} - -type RPCServerEvent_SessionId struct { - SessionId string `protobuf:"bytes,5,opt,name=session_id,json=sessionId,proto3,oneof"` -} - -func (*RPCServerEvent_NewMember) isRPCServerEvent_Event() {} - -func (*RPCServerEvent_DisconnectedMember) isRPCServerEvent_Event() {} - -func (*RPCServerEvent_MemberConnect) isRPCServerEvent_Event() {} - -func (*RPCServerEvent_MemberConnectResponse) isRPCServerEvent_Event() {} - -func (*RPCServerEvent_SessionId) isRPCServerEvent_Event() {} - -type InitializeRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - FriendlyName string `protobuf:"bytes,1,opt,name=friendly_name,json=friendlyName,proto3" json:"friendly_name,omitempty"` - TimestampSigned int64 `protobuf:"varint,2,opt,name=timestamp_signed,json=timestampSigned,proto3" json:"timestamp_signed,omitempty"` - Signed []byte `protobuf:"bytes,3,opt,name=signed,proto3" json:"signed,omitempty"` - MemberId uint32 `protobuf:"varint,4,opt,name=member_id,json=memberId,proto3" json:"member_id,omitempty"` - Certificate []byte `protobuf:"bytes,5,opt,name=certificate,proto3" json:"certificate,omitempty"` - SessionId string `protobuf:"bytes,6,opt,name=session_id,json=sessionId,proto3" json:"session_id,omitempty"` - Reconnect bool `protobuf:"varint,7,opt,name=reconnect,proto3" json:"reconnect,omitempty"` -} - -func (x *InitializeRequest) Reset() { - *x = InitializeRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_registry_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *InitializeRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*InitializeRequest) ProtoMessage() {} - -func (x *InitializeRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_registry_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use InitializeRequest.ProtoReflect.Descriptor instead. -func (*InitializeRequest) Descriptor() ([]byte, []int) { - return file_proto_orion_registry_proto_rawDescGZIP(), []int{5} -} - -func (x *InitializeRequest) GetFriendlyName() string { - if x != nil { - return x.FriendlyName - } - return "" -} - -func (x *InitializeRequest) GetTimestampSigned() int64 { - if x != nil { - return x.TimestampSigned - } - return 0 -} - -func (x *InitializeRequest) GetSigned() []byte { - if x != nil { - return x.Signed - } - return nil -} - -func (x *InitializeRequest) GetMemberId() uint32 { - if x != nil { - return x.MemberId - } - return 0 -} - -func (x *InitializeRequest) GetCertificate() []byte { - if x != nil { - return x.Certificate - } - return nil -} - -func (x *InitializeRequest) GetSessionId() string { - if x != nil { - return x.SessionId - } - return "" -} - -func (x *InitializeRequest) GetReconnect() bool { - if x != nil { - return x.Reconnect - } - return false -} - -type RPCClientEvent struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Event: - // - // *RPCClientEvent_Initialize - // *RPCClientEvent_Connect - // *RPCClientEvent_ConnectResponse - Event isRPCClientEvent_Event `protobuf_oneof:"event"` -} - -func (x *RPCClientEvent) Reset() { - *x = RPCClientEvent{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_orion_registry_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *RPCClientEvent) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*RPCClientEvent) ProtoMessage() {} - -func (x *RPCClientEvent) ProtoReflect() protoreflect.Message { - mi := &file_proto_orion_registry_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use RPCClientEvent.ProtoReflect.Descriptor instead. -func (*RPCClientEvent) Descriptor() ([]byte, []int) { - return file_proto_orion_registry_proto_rawDescGZIP(), []int{6} -} - -func (m *RPCClientEvent) GetEvent() isRPCClientEvent_Event { - if m != nil { - return m.Event - } - return nil -} - -func (x *RPCClientEvent) GetInitialize() *InitializeRequest { - if x, ok := x.GetEvent().(*RPCClientEvent_Initialize); ok { - return x.Initialize - } - return nil -} - -func (x *RPCClientEvent) GetConnect() *MemberConnectEvent { - if x, ok := x.GetEvent().(*RPCClientEvent_Connect); ok { - return x.Connect - } - return nil -} - -func (x *RPCClientEvent) GetConnectResponse() *MemberConnectResponseEvent { - if x, ok := x.GetEvent().(*RPCClientEvent_ConnectResponse); ok { - return x.ConnectResponse - } - return nil -} - -type isRPCClientEvent_Event interface { - isRPCClientEvent_Event() -} - -type RPCClientEvent_Initialize struct { - Initialize *InitializeRequest `protobuf:"bytes,1,opt,name=initialize,proto3,oneof"` -} - -type RPCClientEvent_Connect struct { - Connect *MemberConnectEvent `protobuf:"bytes,2,opt,name=connect,proto3,oneof"` -} - -type RPCClientEvent_ConnectResponse struct { - ConnectResponse *MemberConnectResponseEvent `protobuf:"bytes,3,opt,name=connect_response,json=connectResponse,proto3,oneof"` -} - -func (*RPCClientEvent_Initialize) isRPCClientEvent_Event() {} - -func (*RPCClientEvent_Connect) isRPCClientEvent_Event() {} - -func (*RPCClientEvent_ConnectResponse) isRPCClientEvent_Event() {} - -var File_proto_orion_registry_proto protoreflect.FileDescriptor - -var file_proto_orion_registry_proto_rawDesc = []byte{ - 0x0a, 0x1a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6f, 0x72, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4e, 0x0a, 0x0e, - 0x4e, 0x65, 0x77, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x23, - 0x0a, 0x0d, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0x57, 0x0a, 0x17, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, - 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x69, 0x65, 0x6e, - 0x64, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x07, - 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x70, - 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0xf8, 0x01, 0x0a, 0x12, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, - 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x41, 0x64, 0x64, - 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x70, 0x6f, - 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, - 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x72, - 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x65, - 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, - 0x22, 0xa5, 0x02, 0x0a, 0x1a, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, - 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x41, 0x64, 0x64, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x65, 0x6e, 0x64, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x69, 0x65, - 0x6e, 0x64, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, - 0x13, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x65, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, - 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x23, 0x0a, - 0x0d, 0x70, 0x72, 0x65, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, - 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x65, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x50, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0xce, 0x02, 0x0a, 0x0e, 0x52, 0x50, 0x43, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x0a, 0x6e, - 0x65, 0x77, 0x5f, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x4e, 0x65, 0x77, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, - 0x48, 0x00, 0x52, 0x09, 0x6e, 0x65, 0x77, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x4b, 0x0a, - 0x13, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x4d, 0x65, 0x6d, - 0x62, 0x65, 0x72, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x12, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x3c, 0x0a, 0x0e, 0x6d, 0x65, - 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x55, 0x0a, 0x17, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x4d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x15, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x1f, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, - 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0xf7, 0x01, 0x0a, 0x11, 0x49, 0x6e, - 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x12, - 0x16, 0x0a, 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x06, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x62, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x62, - 0x65, 0x72, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x6e, - 0x65, 0x63, 0x74, 0x22, 0xca, 0x01, 0x0a, 0x0e, 0x52, 0x50, 0x43, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x49, 0x6e, 0x69, - 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, - 0x52, 0x0a, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x12, 0x2f, 0x0a, 0x07, - 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, - 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x48, 0x0a, - 0x10, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x32, 0x45, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, 0x39, 0x0a, 0x11, - 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x54, 0x6f, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x12, 0x0f, 0x2e, 0x52, 0x50, 0x43, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x1a, 0x0f, 0x2e, 0x52, 0x50, 0x43, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x28, 0x01, 0x30, 0x01, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x3b, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_proto_orion_registry_proto_rawDescOnce sync.Once - file_proto_orion_registry_proto_rawDescData = file_proto_orion_registry_proto_rawDesc -) - -func file_proto_orion_registry_proto_rawDescGZIP() []byte { - file_proto_orion_registry_proto_rawDescOnce.Do(func() { - file_proto_orion_registry_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_orion_registry_proto_rawDescData) - }) - return file_proto_orion_registry_proto_rawDescData -} - -var file_proto_orion_registry_proto_msgTypes = make([]protoimpl.MessageInfo, 7) -var file_proto_orion_registry_proto_goTypes = []interface{}{ - (*NewMemberEvent)(nil), // 0: NewMemberEvent - (*MemberDisconnectedEvent)(nil), // 1: MemberDisconnectedEvent - (*MemberConnectEvent)(nil), // 2: MemberConnectEvent - (*MemberConnectResponseEvent)(nil), // 3: MemberConnectResponseEvent - (*RPCServerEvent)(nil), // 4: RPCServerEvent - (*InitializeRequest)(nil), // 5: InitializeRequest - (*RPCClientEvent)(nil), // 6: RPCClientEvent -} -var file_proto_orion_registry_proto_depIdxs = []int32{ - 0, // 0: RPCServerEvent.new_member:type_name -> NewMemberEvent - 1, // 1: RPCServerEvent.disconnected_member:type_name -> MemberDisconnectedEvent - 2, // 2: RPCServerEvent.member_connect:type_name -> MemberConnectEvent - 3, // 3: RPCServerEvent.member_connect_response:type_name -> MemberConnectResponseEvent - 5, // 4: RPCClientEvent.initialize:type_name -> InitializeRequest - 2, // 5: RPCClientEvent.connect:type_name -> MemberConnectEvent - 3, // 6: RPCClientEvent.connect_response:type_name -> MemberConnectResponseEvent - 6, // 7: Registry.SubscribeToStream:input_type -> RPCClientEvent - 4, // 8: Registry.SubscribeToStream:output_type -> RPCServerEvent - 8, // [8:9] is the sub-list for method output_type - 7, // [7:8] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name -} - -func init() { file_proto_orion_registry_proto_init() } -func file_proto_orion_registry_proto_init() { - if File_proto_orion_registry_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_proto_orion_registry_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NewMemberEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_orion_registry_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MemberDisconnectedEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_orion_registry_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MemberConnectEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_orion_registry_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MemberConnectResponseEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_orion_registry_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCServerEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_orion_registry_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InitializeRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_orion_registry_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RPCClientEvent); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_proto_orion_registry_proto_msgTypes[4].OneofWrappers = []interface{}{ - (*RPCServerEvent_NewMember)(nil), - (*RPCServerEvent_DisconnectedMember)(nil), - (*RPCServerEvent_MemberConnect)(nil), - (*RPCServerEvent_MemberConnectResponse)(nil), - (*RPCServerEvent_SessionId)(nil), - } - file_proto_orion_registry_proto_msgTypes[6].OneofWrappers = []interface{}{ - (*RPCClientEvent_Initialize)(nil), - (*RPCClientEvent_Connect)(nil), - (*RPCClientEvent_ConnectResponse)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_proto_orion_registry_proto_rawDesc, - NumEnums: 0, - NumMessages: 7, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_proto_orion_registry_proto_goTypes, - DependencyIndexes: file_proto_orion_registry_proto_depIdxs, - MessageInfos: file_proto_orion_registry_proto_msgTypes, - }.Build() - File_proto_orion_registry_proto = out.File - file_proto_orion_registry_proto_rawDesc = nil - file_proto_orion_registry_proto_goTypes = nil - file_proto_orion_registry_proto_depIdxs = nil -} diff --git a/internal/proto/orion_registry_grpc.pb.go b/internal/proto/orion_registry_grpc.pb.go deleted file mode 100644 index 75b3566..0000000 --- a/internal/proto/orion_registry_grpc.pb.go +++ /dev/null @@ -1,139 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v5.27.2 -// source: proto/orion_registry.proto - -package proto - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// RegistryClient is the client API for Registry service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type RegistryClient interface { - // Subscribe to the event stream - SubscribeToStream(ctx context.Context, opts ...grpc.CallOption) (Registry_SubscribeToStreamClient, error) -} - -type registryClient struct { - cc grpc.ClientConnInterface -} - -func NewRegistryClient(cc grpc.ClientConnInterface) RegistryClient { - return ®istryClient{cc} -} - -func (c *registryClient) SubscribeToStream(ctx context.Context, opts ...grpc.CallOption) (Registry_SubscribeToStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[0], "/Registry/SubscribeToStream", opts...) - if err != nil { - return nil, err - } - x := ®istrySubscribeToStreamClient{stream} - return x, nil -} - -type Registry_SubscribeToStreamClient interface { - Send(*RPCClientEvent) error - Recv() (*RPCServerEvent, error) - grpc.ClientStream -} - -type registrySubscribeToStreamClient struct { - grpc.ClientStream -} - -func (x *registrySubscribeToStreamClient) Send(m *RPCClientEvent) error { - return x.ClientStream.SendMsg(m) -} - -func (x *registrySubscribeToStreamClient) Recv() (*RPCServerEvent, error) { - m := new(RPCServerEvent) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// RegistryServer is the server API for Registry service. -// All implementations must embed UnimplementedRegistryServer -// for forward compatibility -type RegistryServer interface { - // Subscribe to the event stream - SubscribeToStream(Registry_SubscribeToStreamServer) error - mustEmbedUnimplementedRegistryServer() -} - -// UnimplementedRegistryServer must be embedded to have forward compatible implementations. -type UnimplementedRegistryServer struct { -} - -func (UnimplementedRegistryServer) SubscribeToStream(Registry_SubscribeToStreamServer) error { - return status.Errorf(codes.Unimplemented, "method SubscribeToStream not implemented") -} -func (UnimplementedRegistryServer) mustEmbedUnimplementedRegistryServer() {} - -// UnsafeRegistryServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to RegistryServer will -// result in compilation errors. -type UnsafeRegistryServer interface { - mustEmbedUnimplementedRegistryServer() -} - -func RegisterRegistryServer(s grpc.ServiceRegistrar, srv RegistryServer) { - s.RegisterService(&Registry_ServiceDesc, srv) -} - -func _Registry_SubscribeToStream_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(RegistryServer).SubscribeToStream(®istrySubscribeToStreamServer{stream}) -} - -type Registry_SubscribeToStreamServer interface { - Send(*RPCServerEvent) error - Recv() (*RPCClientEvent, error) - grpc.ServerStream -} - -type registrySubscribeToStreamServer struct { - grpc.ServerStream -} - -func (x *registrySubscribeToStreamServer) Send(m *RPCServerEvent) error { - return x.ServerStream.SendMsg(m) -} - -func (x *registrySubscribeToStreamServer) Recv() (*RPCClientEvent, error) { - m := new(RPCClientEvent) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// Registry_ServiceDesc is the grpc.ServiceDesc for Registry service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Registry_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "Registry", - HandlerType: (*RegistryServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{ - { - StreamName: "SubscribeToStream", - Handler: _Registry_SubscribeToStream_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "proto/orion_registry.proto", -} diff --git a/internal/state/dispatch.go b/internal/state/dispatch.go new file mode 100644 index 0000000..d29a41b --- /dev/null +++ b/internal/state/dispatch.go @@ -0,0 +1,78 @@ +package state + +import ( + "slices" +) + +func (c *OrionRegistryState) GetRouters() OrionRegistryRoutersState { + return c.routers +} + +// Called once a new member is joining the network +func (c *OrionRegistryState) DispatchNewRouterEvent( + newRouter *Router, +) { + c.routersLock.Lock() + defer c.routersLock.Unlock() + + c.routers[RouterIdentity(newRouter.Identity)] = newRouter + + for _, router := range c.routers { + if router.Identity != newRouter.Identity { + router.DispatchNewRouterEvent( + router, + ) + } + } +} + +// Called once a member is removed +func (c *OrionRegistryState) DispatchRouterRemovedEvent( + deletedRouter *Router, +) { + if c.routers[deletedRouter.Identity] == nil { + return + } + + c.routersLock.Lock() + defer c.routersLock.Unlock() + + for _, router := range c.routers { + // todo: send event to other peers + if router.Identity != deletedRouter.Identity { + // todo: send event + // router.DeletedRouterEvent() + } + } + + c.routers[deletedRouter.Identity].Dispose() + c.routers[deletedRouter.Identity] = nil +} + +// Dispatch new connection +func (c *OrionRegistryState) DispatchNewEdge( + edge *Edge, +) { + c.edgesLock.Lock() + defer c.edgesLock.Unlock() + + edgeA := edge.RouterA + edgeB := edge.RouterB + + // check that the routers are existing + if edgeA == nil || edgeB == nil { + // todo: report error + return + } + + ids := []uint32{uint32(edgeA.Identity), uint32(edgeB.Identity)} + slices.Sort(ids) + + // concatenate the bits + edgeId := uint64(ids[0]) << 32 & uint64(ids[1]) + + c.edges[edgeId] = edge + //edgeA.NewEdge(edge) + //edgeB.NewEdge(edge) + +} diff --git a/internal/state/edge.go b/internal/state/edge.go new file mode 100644 index 0000000..15a810c --- /dev/null +++ b/internal/state/edge.go @@ -0,0 +1,22 @@ +package state + +type Edge struct { + RouterA *Router + RouterB *Router +} + +// Sends a new initialization step to both the peers +// asking for a random one to choose a pre-shared key +// The hole-punching logic is done locally by the peers +func (c *Edge) Initialize() { + + go func() { + select { + case <-c.RouterA.routerObjectContext.Done(): + case <-c.RouterB.routerObjectContext.Done(): + } + + // the edge lifetime is finished + // todo: teardown edge + }() +} diff --git a/internal/state/event.go b/internal/state/event.go new file mode 100644 index 0000000..50deeb5 --- /dev/null +++ b/internal/state/event.go @@ -0,0 +1,3 @@ +package state + +type Event interface{} diff --git a/internal/state/orion_registry.go b/internal/state/orion_registry.go new file mode 100644 index 0000000..07ad8fb --- /dev/null +++ b/internal/state/orion_registry.go @@ -0,0 +1,28 @@ +package state + +import ( + "sync" +) + +type OrionRegistryRoutersState map[RouterIdentity]*Router +type OrionRegistryEdgesState map[uint64]*Edge + +// State related to the Orion-Registry +// component, that handles all the connection +// initialization system. +type OrionRegistryState struct { + routers OrionRegistryRoutersState // List of routers + routersLock sync.Mutex + + edges OrionRegistryEdgesState // List of edges in the orion graph + edgesLock sync.Mutex +} + +func NewOrionRegistryState() *OrionRegistryState { + return &OrionRegistryState{ + routers: make(OrionRegistryRoutersState), + routersLock: sync.Mutex{}, + edges: make(OrionRegistryEdgesState), + edgesLock: sync.Mutex{}, + } +} diff --git a/internal/state/router.go b/internal/state/router.go new file mode 100644 index 0000000..7216a98 --- /dev/null +++ b/internal/state/router.go @@ -0,0 +1,131 @@ +package state + +import ( + "context" + "fmt" + "sync/atomic" + "time" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "github.com/teivah/broadcast" +) + +type RouterIdentity uint32 +type Router struct { + Identity RouterIdentity + + sending *broadcast.Relay[Event] + + routerObjectContext context.Context + routerObjectContextCancel context.CancelCauseFunc + connectionsCount atomic.Int32 + connectionTimeoutContextCancel context.CancelCauseFunc + + globalState *OrionRegistryState + log zerolog.Logger +} + +func NewRouter( + globalContext context.Context, + identity RouterIdentity, + globalState *OrionRegistryState, +) *Router { + ctx, cancel := context.WithCancelCause(globalContext) + return &Router{ + Identity: identity, + connectionsCount: atomic.Int32{}, + sending: broadcast.NewRelay[Event](), + routerObjectContext: ctx, + routerObjectContextCancel: cancel, + globalState: globalState, + log: log.With().Uint32("router-identity", uint32(identity)).Logger(), + } +} + +func (c *Router) Subscribe() *broadcast.Listener[Event] { + return c.sending.Listener(1) +} + +func (c *Router) IncrementConnectionCount() { + c.connectionsCount.Add(1) + c.updateConnectionsCountRoutine() +} +func (c *Router) DecrementConnectionCount() { + c.connectionsCount.Add(-1) + c.updateConnectionsCountRoutine() +} + +func (c *Router) updateConnectionsCountRoutine() { + current := c.connectionsCount.Load() + + c.log.Debug(). + Int32("connections-count", current). + Msg("connection count ended, updating") + + if c.connectionTimeoutContextCancel != nil { + c.connectionTimeoutContextCancel(fmt.Errorf("connections count updated, canceling previous tasks")) + } + + if current == 0 { + ctx, e := context.WithCancelCause(context.Background()) + c.connectionTimeoutContextCancel = e + + // TODO: we must implement a way to deal with not-sent messages + + // we launch a background task ticking for either + // 1. the session timeout mechanism + // 2. a new connection + go func() { + timeout := time.NewTimer(time.Minute) + c.log.Debug().Msg("ticking a minute before session expiration") + + subscribe := c.Subscribe() + replayPending := make([]*Event, 1000) + replayEventsCount := 0 + + for { + select { + case message := <-subscribe.Ch(): + log.Debug().Msg("appending to replay pending messages") + replayPending[replayEventsCount] = &message + replayEventsCount += 1 + case <-ctx.Done(): + subscribe.Close() + + c.log.Debug(). + Int("events-count", replayEventsCount). + Msg("session resumed, replaying events") + + // dequeue events + for i, event := range replayPending { + c.sending.Broadcast(event) + if i == replayEventsCount { + break + } + } + goto end + case <-timeout.C: + log.Debug().Msg("session expired") + subscribe.Close() + c.globalState.DispatchRouterRemovedEvent(c) + goto end + } + } + end: + c.connectionTimeoutContextCancel = nil + }() + } + +} + +func (c *Router) DispatchNewRouterEvent(router *Router) { + newRouterEvent := RouterConnect{ + Router: router, + } + c.sending.Broadcast(newRouterEvent) +} + +func (c *Router) Dispose() { + log.Info().Msg("disposing of router") +} diff --git a/internal/state/router_connect.go b/internal/state/router_connect.go new file mode 100644 index 0000000..20d399d --- /dev/null +++ b/internal/state/router_connect.go @@ -0,0 +1,5 @@ +package state + +type RouterConnect struct { + Router *Router +} diff --git a/internal/state/router_disconnect.go b/internal/state/router_disconnect.go new file mode 100644 index 0000000..1dead8d --- /dev/null +++ b/internal/state/router_disconnect.go @@ -0,0 +1,5 @@ +package state + +type RouterDisconnect struct { + Router *Router +} diff --git a/internal/version.go b/internal/version.go new file mode 100644 index 0000000..ff31bb3 --- /dev/null +++ b/internal/version.go @@ -0,0 +1,8 @@ +package internal + +var ( + Version = "dev" + Commit = "none" + Date = "unknown" + BuiltBy = "go" +) diff --git a/proto/orion_holepunch.proto b/proto/orion_holepunch.proto deleted file mode 100644 index 3b4c4bc..0000000 --- a/proto/orion_holepunch.proto +++ /dev/null @@ -1,38 +0,0 @@ -syntax = "proto3"; - -option go_package=".;proto"; - -// Message sent to initialize a hole-punching session for a given Wireguard Tunnel. -message HolePunchingInitialize { - bytes public_key = 1; -} - -// Message send to inform the client of the Wireguard credentials and ip adresses -message HolePunchingInitializationResponse { - // The public endpoint and port of the registry server. - string endpoint_addr = 1; - uint32 endpoint_port = 2; - - // The public key of the registry server. - bytes public_key = 3; - // The preshared key assigned by the server for this session. - bytes preshared_key = 4; -} - -// Message send to inform that the information was gathered by the registry server -message HolePunchingCompleteResponse { - string client_endpoint_addr = 1; - uint32 client_endpoint_port = 2; -} - -// Message after the connection of the client to the holepunching-dedicated server endpoint. -message HolePunchingEvent { - oneof event { - HolePunchingInitializationResponse initialization_response = 1; - HolePunchingCompleteResponse complete = 2; - } -} - -service HolePunchingService { - rpc Session(HolePunchingInitialize) returns (stream HolePunchingEvent); -} diff --git a/proto/orion_registry.proto b/proto/orion_registry.proto deleted file mode 100644 index 1139f00..0000000 --- a/proto/orion_registry.proto +++ /dev/null @@ -1,65 +0,0 @@ -syntax = "proto3"; - -option go_package = ".;proto"; - -service Registry { - // Subscribe to the event stream - rpc SubscribeToStream(stream RPCClientEvent) returns(stream RPCServerEvent); -} - -message NewMemberEvent { - string friendly_name = 1; - uint32 peer_id = 2; -} - -message MemberDisconnectedEvent { - string friendly_name = 1; - uint32 peer_id = 2; -} - -message MemberConnectEvent { - string endpoint_addr = 1; - uint32 endpoint_port = 2; - bytes public_key = 3; - string friendly_name = 5; - uint32 destination_peer_id = 6; - uint32 source_peer_id = 7; -} - -message MemberConnectResponseEvent { - string endpoint_addr = 1; - uint32 endpoint_port = 2; - bytes public_key = 3; - string friendly_name = 4; - uint32 destination_peer_id = 5; - bytes preshared_key = 7; - uint32 source_peer_id = 6; -} - -message RPCServerEvent { - oneof event { - NewMemberEvent new_member = 1; - MemberDisconnectedEvent disconnected_member = 2; - MemberConnectEvent member_connect = 3; - MemberConnectResponseEvent member_connect_response = 4; - string session_id = 5; - } -} - -message InitializeRequest { - string friendly_name = 1; - int64 timestamp_signed = 2; - bytes signed = 3; - uint32 member_id = 4; - bytes certificate = 5; - string session_id = 6; - bool reconnect = 7; -} - -message RPCClientEvent { - oneof event { - InitializeRequest initialize = 1; - MemberConnectEvent connect = 2; - MemberConnectResponseEvent connect_response = 3; - } -} \ No newline at end of file From 9344ce47df9840a5bc372e18b0625089cb79d78d Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Mon, 2 Dec 2024 12:34:24 +0400 Subject: [PATCH 02/13] move folders to make ci work Signed-off-by: Matthieu Pignolet --- bin/oriond-mock/oriond.go | 2 +- bin/registry-ws/registry.pem | 58 ------------------- bin/{registry-ws => registry}/.gitignore | 0 bin/{registry-ws => registry}/main.go | 13 ++--- .../server/errors/auth-required.html | 0 .../server/protocol/client.go | 3 +- .../server/protocol/messages/event.go | 0 .../server/protocol/messages/hello.go | 0 .../server/protocol/messages/kinds.go | 0 .../server/server.go | 0 .../server/static.go | 0 .../server/static/index.html | 6 +- .../server/upgrade.go | 10 ++-- .../server/whoami.go | 4 ++ go.sum | 2 + 15 files changed, 22 insertions(+), 76 deletions(-) delete mode 100644 bin/registry-ws/registry.pem rename bin/{registry-ws => registry}/.gitignore (100%) rename bin/{registry-ws => registry}/main.go (82%) rename bin/{registry-ws => registry}/server/errors/auth-required.html (100%) rename bin/{registry-ws => registry}/server/protocol/client.go (97%) rename bin/{registry-ws => registry}/server/protocol/messages/event.go (100%) rename bin/{registry-ws => registry}/server/protocol/messages/hello.go (100%) rename bin/{registry-ws => registry}/server/protocol/messages/kinds.go (100%) rename bin/{registry-ws => registry}/server/server.go (100%) rename bin/{registry-ws => registry}/server/static.go (100%) rename bin/{registry-ws => registry}/server/static/index.html (55%) rename bin/{registry-ws => registry}/server/upgrade.go (76%) rename bin/{registry-ws => registry}/server/whoami.go (93%) diff --git a/bin/oriond-mock/oriond.go b/bin/oriond-mock/oriond.go index cb0c4a5..dca953e 100644 --- a/bin/oriond-mock/oriond.go +++ b/bin/oriond-mock/oriond.go @@ -11,7 +11,7 @@ import ( "os/signal" "time" - "github.com/MatthieuCoder/OrionV3/bin/registry-ws/server/protocol/messages" + "github.com/MatthieuCoder/OrionV3/bin/registry/server/protocol/messages" "github.com/MatthieuCoder/OrionV3/internal" "github.com/gorilla/websocket" "github.com/rs/zerolog" diff --git a/bin/registry-ws/registry.pem b/bin/registry-ws/registry.pem deleted file mode 100644 index 7e72efa..0000000 --- a/bin/registry-ws/registry.pem +++ /dev/null @@ -1,58 +0,0 @@ -Bag Attributes - friendlyName: Orion Registry X1 ------BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgClp+WDoXBwI2U7RH -/idtWmo2zNZ8JWs49W2I/MfN3MKgCgYIKoZIzj0DAQehRANCAAT0bHPFd7RXBFee -YmVnIMYoXnjfzSPtAnML8g1zyWNz3rjzcB7/WldHCfIABKXKhHED3KWwCMDRV4t+ -2RtUpn9c ------END PRIVATE KEY----- -Bag Attributes - friendlyName: Orion Registry X1 -subject=/CN=Orion Registry X1/O=Orion/C=FR -issuer=/CN=Orion Intermediate X2/O=Orion/C=FR ------BEGIN CERTIFICATE----- -MIICFTCCAbqgAwIBAgIUBmthVeKv65ExaUMH/qeKz1I30UcwCgYIKoZIzj0EAwIw -PTEeMBwGA1UEAwwVT3Jpb24gSW50ZXJtZWRpYXRlIFgyMQ4wDAYDVQQKDAVPcmlv -bjELMAkGA1UEBhMCRlIwHhcNMjQxMTI4MDYzNzM5WhcNMjYxMTI4MDYzNzM4WjA5 -MRowGAYDVQQDDBFPcmlvbiBSZWdpc3RyeSBYMTEOMAwGA1UECgwFT3Jpb24xCzAJ -BgNVBAYTAkZSMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9GxzxXe0VwRXnmJl -ZyDGKF54380j7QJzC/INc8ljc96483Ae/1pXRwnyAASlyoRxA9ylsAjA0VeLftkb -VKZ/XKOBmzCBmDAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFOtJd6xSSbldMrfi -NlIgEbtCn2sMMBkGA1UdEQQSMBCCDnJlZy5vcmlvbmV0LnJlMB0GA1UdJQQWMBQG -CCsGAQUFBwMEBggrBgEFBQcDATAdBgNVHQ4EFgQUKowEjlCQx7CxeTOJynBrEAPX -JNQwDgYDVR0PAQH/BAQDAgXgMAoGCCqGSM49BAMCA0kAMEYCIQCinYgPGwxnb+Et -ukVRNyyzqmZxJRCBRdn5Bxqcg7l+swIhALJnlFUbiy9RXPFnZXiWhCu/SvsZ8bT+ -MSrzxo3/dweN ------END CERTIFICATE----- -Bag Attributes - friendlyName: Unknown -subject=/CN=Orion Intermediate X2/O=Orion/C=FR -issuer=/CN=Orion Root X2/O=Orion/C=FR ------BEGIN CERTIFICATE----- -MIIB2DCCAX2gAwIBAgIUA4Nj5hLdcsQA3wioQeMKmUcKOm8wCgYIKoZIzj0EAwIw -NTEWMBQGA1UEAwwNT3Jpb24gUm9vdCBYMjEOMAwGA1UECgwFT3Jpb24xCzAJBgNV -BAYTAkZSMB4XDTI0MTAxODEyNDUzM1oXDTM0MTAxNjEyNDUzMlowPTEeMBwGA1UE -AwwVT3Jpb24gSW50ZXJtZWRpYXRlIFgyMQ4wDAYDVQQKDAVPcmlvbjELMAkGA1UE -BhMCRlIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATjdn41rcbi2A7Ekz55DRfa -zDy70fe1VtMjC7ej2VIzUdqw6KsL0Ywe6mkd2kOzwJUuPoRxQZKfe9qYoW1c7szw -o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFD5EFqFa4wRBj4hM85d7 -Tq31ZsKwMB0GA1UdDgQWBBTrSXesUkm5XTK34jZSIBG7Qp9rDDAOBgNVHQ8BAf8E -BAMCAYYwCgYIKoZIzj0EAwIDSQAwRgIhAMYrJfGBvHuouWm7ku1wbzts14qXyxrI -GVcq8dDnPMfTAiEAuQ/pdtshaGUI8+hzHDAr9+Kk4p7KBbPEiIkrRHnll8c= ------END CERTIFICATE----- -Bag Attributes - friendlyName: Unknown -subject=/CN=Orion Root X2/O=Orion/C=FR -issuer=/CN=Orion Root X2/O=Orion/C=FR ------BEGIN CERTIFICATE----- -MIIB0DCCAXWgAwIBAgIUYlSd5D84oBGQa2UtAXKi80Hwvx4wCgYIKoZIzj0EAwIw -NTEWMBQGA1UEAwwNT3Jpb24gUm9vdCBYMjEOMAwGA1UECgwFT3Jpb24xCzAJBgNV -BAYTAkZSMB4XDTI0MTAxODEyNDEzMVoXDTQ5MTAxOTEyNDEzMFowNTEWMBQGA1UE -AwwNT3Jpb24gUm9vdCBYMjEOMAwGA1UECgwFT3Jpb24xCzAJBgNVBAYTAkZSMFkw -EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5HChn5wgvzL1rPizAcJl84BdoS29HqsI -iA1xTROVlZdP5slCHRg4CqTGTT4zW0i9BBEQX4GXF2PU3uQIPpnPK6NjMGEwDwYD -VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ+RBahWuMEQY+ITPOXe06t9WbCsDAd -BgNVHQ4EFgQUPkQWoVrjBEGPiEzzl3tOrfVmwrAwDgYDVR0PAQH/BAQDAgGGMAoG -CCqGSM49BAMCA0kAMEYCIQC9hK9/R+jRtNNUT8tzJ58EWglfieUcBNPkTJqVe+Up -YwIhAI4sw3ufFskXJINmrbVnb0xd5FxjUCByuqLYtY3xYaSA ------END CERTIFICATE----- diff --git a/bin/registry-ws/.gitignore b/bin/registry/.gitignore similarity index 100% rename from bin/registry-ws/.gitignore rename to bin/registry/.gitignore diff --git a/bin/registry-ws/main.go b/bin/registry/main.go similarity index 82% rename from bin/registry-ws/main.go rename to bin/registry/main.go index 103f221..7a0bfb9 100644 --- a/bin/registry-ws/main.go +++ b/bin/registry/main.go @@ -8,7 +8,7 @@ import ( "net/http" "os" - "github.com/MatthieuCoder/OrionV3/bin/registry-ws/server" + "github.com/MatthieuCoder/OrionV3/bin/registry/server" "github.com/MatthieuCoder/OrionV3/internal" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -45,12 +45,11 @@ func main() { } tlsConfig := &tls.Config{ - Certificates: []tls.Certificate{certificateKeyPair}, - ClientCAs: authorityPool, - ClientAuth: tls.VerifyClientCertIfGiven, - MinVersion: tls.VersionTLS13, - CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, - PreferServerCipherSuites: true, + Certificates: []tls.Certificate{certificateKeyPair}, + ClientCAs: authorityPool, + ClientAuth: tls.VerifyClientCertIfGiven, + MinVersion: tls.VersionTLS13, + CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, CipherSuites: []uint16{ tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, diff --git a/bin/registry-ws/server/errors/auth-required.html b/bin/registry/server/errors/auth-required.html similarity index 100% rename from bin/registry-ws/server/errors/auth-required.html rename to bin/registry/server/errors/auth-required.html diff --git a/bin/registry-ws/server/protocol/client.go b/bin/registry/server/protocol/client.go similarity index 97% rename from bin/registry-ws/server/protocol/client.go rename to bin/registry/server/protocol/client.go index 61bfe50..e26e356 100644 --- a/bin/registry-ws/server/protocol/client.go +++ b/bin/registry/server/protocol/client.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/MatthieuCoder/OrionV3/bin/registry-ws/server/protocol/messages" + "github.com/MatthieuCoder/OrionV3/bin/registry/server/protocol/messages" "github.com/MatthieuCoder/OrionV3/internal" "github.com/MatthieuCoder/OrionV3/internal/state" "github.com/gorilla/websocket" @@ -30,7 +30,6 @@ func NewClient(ws *websocket.Conn, identity state.RouterIdentity) *Client { ctx: context.Background(), log: log.With().Uint32("router-identity", uint32(identity)).Logger(), } - c.log.Debug().Msg("starting new client connection") go c.startRoutine() return c diff --git a/bin/registry-ws/server/protocol/messages/event.go b/bin/registry/server/protocol/messages/event.go similarity index 100% rename from bin/registry-ws/server/protocol/messages/event.go rename to bin/registry/server/protocol/messages/event.go diff --git a/bin/registry-ws/server/protocol/messages/hello.go b/bin/registry/server/protocol/messages/hello.go similarity index 100% rename from bin/registry-ws/server/protocol/messages/hello.go rename to bin/registry/server/protocol/messages/hello.go diff --git a/bin/registry-ws/server/protocol/messages/kinds.go b/bin/registry/server/protocol/messages/kinds.go similarity index 100% rename from bin/registry-ws/server/protocol/messages/kinds.go rename to bin/registry/server/protocol/messages/kinds.go diff --git a/bin/registry-ws/server/server.go b/bin/registry/server/server.go similarity index 100% rename from bin/registry-ws/server/server.go rename to bin/registry/server/server.go diff --git a/bin/registry-ws/server/static.go b/bin/registry/server/static.go similarity index 100% rename from bin/registry-ws/server/static.go rename to bin/registry/server/static.go diff --git a/bin/registry-ws/server/static/index.html b/bin/registry/server/static/index.html similarity index 55% rename from bin/registry-ws/server/static/index.html rename to bin/registry/server/static/index.html index 05e7cb1..0fdbdf4 100644 --- a/bin/registry-ws/server/static/index.html +++ b/bin/registry/server/static/index.html @@ -6,6 +6,8 @@ Orion Registry - Welcome to the Orion Registry ;) + Welcome to the Orion Registry + This service is used as a server to allow clients to communicate + and initialize a peer-to-peer connection. - \ No newline at end of file + diff --git a/bin/registry-ws/server/upgrade.go b/bin/registry/server/upgrade.go similarity index 76% rename from bin/registry-ws/server/upgrade.go rename to bin/registry/server/upgrade.go index d9103f2..65057bd 100644 --- a/bin/registry-ws/server/upgrade.go +++ b/bin/registry/server/upgrade.go @@ -5,7 +5,7 @@ import ( "strconv" "strings" - "github.com/MatthieuCoder/OrionV3/bin/registry-ws/server/protocol" + "github.com/MatthieuCoder/OrionV3/bin/registry/server/protocol" "github.com/MatthieuCoder/OrionV3/internal/state" "github.com/gorilla/websocket" "github.com/rs/zerolog/log" @@ -28,23 +28,21 @@ func (c *Server) upgrade(w http.ResponseWriter, r *http.Request) { cz, err := upgrader.Upgrade(w, r, nil) if err != nil { - log.Error().Err(err).Msg("Failed to upgrade a http(s) connection to a websocket connection") + log.Error().Err(err).Msg("failed to upgrade a http(s) connection to a websocket connection") return } - // todo: close websocket connections cleanly - // defer cz.Close() leaf := r.TLS.PeerCertificates[0] cn := leaf.Subject.CommonName cnParts := strings.Split(cn, ":") if len(cnParts) != 2 || cnParts[1] != "oriond" { - log.Error().Err(err).Msg("The given certificate is not valid for logging-in into oriond") + log.Error().Err(err).Msg("the given certificate is not valid for logging-in into oriond") return } routerId, err := strconv.Atoi(cnParts[0]) if err != nil { - log.Error().Err(err).Msg("The given certificate is not valid for logging-in into oriond") + log.Error().Err(err).Msg("the given certificate is not valid for logging-in into oriond") return } identity := state.RouterIdentity(routerId) diff --git a/bin/registry-ws/server/whoami.go b/bin/registry/server/whoami.go similarity index 93% rename from bin/registry-ws/server/whoami.go rename to bin/registry/server/whoami.go index bb67230..9a502b5 100644 --- a/bin/registry-ws/server/whoami.go +++ b/bin/registry/server/whoami.go @@ -3,6 +3,8 @@ package server import ( "fmt" "net/http" + + "github.com/rs/zerolog/log" ) func (c *Server) whoami(w http.ResponseWriter, r *http.Request) { @@ -11,6 +13,8 @@ func (c *Server) whoami(w http.ResponseWriter, r *http.Request) { } state := r.TLS + log.Debug().Msg("handling a whoami request") + fmt.Fprint(w, ">>>>>>>>>>>>>>>> State <<<<<<<<<<<<<<<<\n") fmt.Fprintf(w, "Version: %x\n", state.Version) diff --git a/go.sum b/go.sum index 387a240..a41f545 100644 --- a/go.sum +++ b/go.sum @@ -46,3 +46,5 @@ golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/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= +software.sslmate.com/src/ocsputil v0.5.0 h1:mJrX5z7XbHyVFqTpDvCWy+8KuCLn1Dro+5tUoFhix7I= +software.sslmate.com/src/ocsputil v0.5.0/go.mod h1:cYsyBW9ycE4100TeKI8zqFy74W6/LIj95hZXoh0UBm4= From cd77d82c69b7df8ae0345ebffbc834aeceecea3f Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Mon, 2 Dec 2024 17:05:01 +0400 Subject: [PATCH 03/13] session recovery protocol using session IDs --- bin/oriond-mock/oriond.go | 13 ---- bin/registry/server/protocol/client.go | 68 +++++++++++-------- .../server/protocol/messages/hello.go | 1 + bin/registry/server/upgrade.go | 4 +- go.mod | 16 +++-- go.sum | 6 +- internal/state/dispatch.go | 8 +-- internal/state/router.go | 54 ++++++++++++--- 8 files changed, 105 insertions(+), 65 deletions(-) diff --git a/bin/oriond-mock/oriond.go b/bin/oriond-mock/oriond.go index dca953e..e9a4990 100644 --- a/bin/oriond-mock/oriond.go +++ b/bin/oriond-mock/oriond.go @@ -2,7 +2,6 @@ package main import ( "crypto/tls" - "encoding/json" "flag" "fmt" "net/http" @@ -11,7 +10,6 @@ import ( "os/signal" "time" - "github.com/MatthieuCoder/OrionV3/bin/registry/server/protocol/messages" "github.com/MatthieuCoder/OrionV3/internal" "github.com/gorilla/websocket" "github.com/rs/zerolog" @@ -88,17 +86,6 @@ func main() { } log.Printf("recv: %s", message) - msg := messages.Event{} - json.Unmarshal(message, &msg) - - log.Printf("received %s... handling", msg.Kind) - - switch msg.Content { - case messages.MessageKindHello: - hello := msg.Content.(*messages.Hello) - log.Printf("Hello message: %s", hello.Message) - } - } }() diff --git a/bin/registry/server/protocol/client.go b/bin/registry/server/protocol/client.go index e26e356..3eabc8d 100644 --- a/bin/registry/server/protocol/client.go +++ b/bin/registry/server/protocol/client.go @@ -23,7 +23,7 @@ type Client struct { log zerolog.Logger } -func NewClient(ws *websocket.Conn, identity state.RouterIdentity) *Client { +func NewClient(ws *websocket.Conn, identity state.RouterIdentity, sessionId string) *Client { c := &Client{ ws: ws, identity: identity, @@ -31,7 +31,7 @@ func NewClient(ws *websocket.Conn, identity state.RouterIdentity) *Client { log: log.With().Uint32("router-identity", uint32(identity)).Logger(), } c.log.Debug().Msg("starting new client connection") - go c.startRoutine() + go c.startRoutine(sessionId) return c } @@ -46,14 +46,9 @@ func (c *Client) send(k string, msg state.Event) error { return err } -func (c *Client) startRoutine() { +func (c *Client) startRoutine(sessionId string) { + defer c.ws.Close() c.log.Debug().Msg("connection handling routine started") - c.send(messages.MessageKindHello, messages.Hello{ - Message: "Hi. This is orion-registry.", - Identity: c.identity, - Version: internal.Version, - Commit: internal.Commit, - }) // check if the router exists rtrs := orionRegistryState.GetRouters() @@ -65,22 +60,43 @@ func (c *Client) startRoutine() { orionRegistryState.DispatchNewRouterEvent( rtr, ) - c.router = rtr } else { - c.log.Debug().Msg("re-using an existing router object system") - // we inform the router object, in the registry state - // that the connection is still ongoing and should not - // be idle-disposed. - c.router = rtr + if rtr.SessionId() == sessionId { + c.log.Debug().Msg("re-using an existing router object system") + // we inform the router object, in the registry state + // that the connection is still ongoing and should not + // be idle-disposed. + c.router = rtr + } else { + c.log.Debug().Msg("deleted old session, initializing new session") + rtr.Dispose() + rtr = state.NewRouter(context.Background(), c.identity, orionRegistryState) + // dispatch new router if the given router doesn't exist + orionRegistryState.DispatchNewRouterEvent( + rtr, + ) + } } + c.router = rtr + + // we send the hello message + c.send(messages.MessageKindHello, messages.Hello{ + Message: "Hi. This is orion-registry.", + Identity: c.router.Identity, + Version: internal.Version, + Commit: internal.Commit, + Session: c.router.SessionId(), + }) - sub := c.router.Subscribe() - channel := sub.Ch() ctx, cancel := context.WithCancelCause(c.ctx) - defer sub.Close() go func() { - // listening for events + // subscribe to the client events from the state + sub := c.router.Subscribe() + channel := sub.Ch() + defer sub.Close() + + // listening for events on the stream for { select { case event := <-channel: @@ -92,19 +108,18 @@ func (c *Client) startRoutine() { c.log.Debug().Msg("sending a new disconnect event") c.send(messages.MessageKindRouterDisconnect, event) } - case <-c.ctx.Done(): - goto end + case <-ctx.Done(): + c.log.Debug().Msg("server state listening routine is done") + return } } - - end: - cancel(fmt.Errorf("the state-internal event listener is finished")) }() // We start listening for events once the listener go-routine is setup // this is because the increment connection count trigers a recovery // of a lost connection rtr.IncrementConnectionCount() + defer c.router.DecrementConnectionCount() go func() { for { @@ -123,8 +138,5 @@ func (c *Client) startRoutine() { // wait for the context to be finished <-ctx.Done() - c.log.Info().Msg("connection ended") - c.router.DecrementConnectionCount() - - c.ws.Close() + c.log.Info().Err(context.Cause(ctx)).Msg("connection routine ended") } diff --git a/bin/registry/server/protocol/messages/hello.go b/bin/registry/server/protocol/messages/hello.go index 084dfab..bcb0ed4 100644 --- a/bin/registry/server/protocol/messages/hello.go +++ b/bin/registry/server/protocol/messages/hello.go @@ -9,4 +9,5 @@ type Hello struct { Identity state.RouterIdentity `json:"identity"` Version string `json:"version"` Commit string `json:"commit"` + Session string `json:"session"` } diff --git a/bin/registry/server/upgrade.go b/bin/registry/server/upgrade.go index 65057bd..f2e65a9 100644 --- a/bin/registry/server/upgrade.go +++ b/bin/registry/server/upgrade.go @@ -47,5 +47,7 @@ func (c *Server) upgrade(w http.ResponseWriter, r *http.Request) { } identity := state.RouterIdentity(routerId) - protocol.NewClient(cz, identity) + sessionId := r.Header.Get("X-SessionId") + + protocol.NewClient(cz, identity, sessionId) } diff --git a/go.mod b/go.mod index 7a0269a..7475e46 100644 --- a/go.mod +++ b/go.mod @@ -3,22 +3,26 @@ module github.com/MatthieuCoder/OrionV3 go 1.22.5 require ( - github.com/google/go-cmp v0.6.0 // indirect github.com/gorilla/websocket v1.5.3 + github.com/rs/zerolog v1.33.0 + github.com/teivah/broadcast v0.1.0 + github.com/vishvananda/netlink v1.1.0 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 +) + +require ( + github.com/google/go-cmp v0.6.0 // indirect github.com/josharian/native v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect - github.com/rs/zerolog v1.33.0 - github.com/teivah/broadcast v0.1.0 - github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect golang.org/x/crypto v0.27.0 // indirect + golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect golang.org/x/net v0.29.0 // indirect - golang.org/x/sync v0.8.0 // indirect + golang.org/x/sync v0.9.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect - golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 ) diff --git a/go.sum b/go.sum index a41f545..1d8fbcd 100644 --- a/go.sum +++ b/go.sum @@ -32,10 +32,14 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7Zo github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= +golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -46,5 +50,3 @@ golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/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= -software.sslmate.com/src/ocsputil v0.5.0 h1:mJrX5z7XbHyVFqTpDvCWy+8KuCLn1Dro+5tUoFhix7I= -software.sslmate.com/src/ocsputil v0.5.0/go.mod h1:cYsyBW9ycE4100TeKI8zqFy74W6/LIj95hZXoh0UBm4= diff --git a/internal/state/dispatch.go b/internal/state/dispatch.go index d29a41b..8b7ad75 100644 --- a/internal/state/dispatch.go +++ b/internal/state/dispatch.go @@ -19,9 +19,7 @@ func (c *OrionRegistryState) DispatchNewRouterEvent( for _, router := range c.routers { if router.Identity != newRouter.Identity { - router.DispatchNewRouterEvent( - router, - ) + router.DispatchNewRouterEvent(newRouter) } } } @@ -41,11 +39,11 @@ func (c *OrionRegistryState) DispatchRouterRemovedEvent( // todo: send event to other peers if router.Identity != deletedRouter.Identity { // todo: send event - // router.DeletedRouterEvent() + router.DispatchRouterRemovedEvent(deletedRouter) } } - c.routers[deletedRouter.Identity].Dispose() + c.routers[deletedRouter.Identity].dispose() c.routers[deletedRouter.Identity] = nil } diff --git a/internal/state/router.go b/internal/state/router.go index 7216a98..47063aa 100644 --- a/internal/state/router.go +++ b/internal/state/router.go @@ -9,6 +9,7 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/teivah/broadcast" + "golang.org/x/exp/rand" ) type RouterIdentity uint32 @@ -22,16 +23,31 @@ type Router struct { connectionsCount atomic.Int32 connectionTimeoutContextCancel context.CancelCauseFunc + session string + globalState *OrionRegistryState log zerolog.Logger } +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +func randStringBytes(n int) string { + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] + } + return string(b) +} + func NewRouter( globalContext context.Context, identity RouterIdentity, globalState *OrionRegistryState, ) *Router { ctx, cancel := context.WithCancelCause(globalContext) + session := randStringBytes(128) + logger := log.With().Uint32("router-identity", uint32(identity)).Logger() + logger.Debug().Str("session", session).Msg("new router session initiated") return &Router{ Identity: identity, connectionsCount: atomic.Int32{}, @@ -39,10 +55,15 @@ func NewRouter( routerObjectContext: ctx, routerObjectContextCancel: cancel, globalState: globalState, - log: log.With().Uint32("router-identity", uint32(identity)).Logger(), + session: session, + log: logger, } } +func (c *Router) SessionId() string { + return c.session +} + func (c *Router) Subscribe() *broadcast.Listener[Event] { return c.sending.Listener(1) } @@ -60,7 +81,6 @@ func (c *Router) updateConnectionsCountRoutine() { current := c.connectionsCount.Load() c.log.Debug(). - Int32("connections-count", current). Msg("connection count ended, updating") if c.connectionTimeoutContextCancel != nil { @@ -81,14 +101,16 @@ func (c *Router) updateConnectionsCountRoutine() { c.log.Debug().Msg("ticking a minute before session expiration") subscribe := c.Subscribe() - replayPending := make([]*Event, 1000) + defer subscribe.Close() + + replayPending := make([]Event, 1000) replayEventsCount := 0 for { select { case message := <-subscribe.Ch(): log.Debug().Msg("appending to replay pending messages") - replayPending[replayEventsCount] = &message + replayPending[replayEventsCount] = message replayEventsCount += 1 case <-ctx.Done(): subscribe.Close() @@ -107,8 +129,9 @@ func (c *Router) updateConnectionsCountRoutine() { goto end case <-timeout.C: log.Debug().Msg("session expired") - subscribe.Close() - c.globalState.DispatchRouterRemovedEvent(c) + c.Dispose() + goto end + case <-c.routerObjectContext.Done(): goto end } } @@ -120,12 +143,23 @@ func (c *Router) updateConnectionsCountRoutine() { } func (c *Router) DispatchNewRouterEvent(router *Router) { - newRouterEvent := RouterConnect{ + c.sending.Broadcast(RouterConnect{ Router: router, - } - c.sending.Broadcast(newRouterEvent) + }) +} + +func (c *Router) DispatchRouterRemovedEvent(router *Router) { + c.sending.Broadcast(RouterDisconnect{ + Router: router, + }) +} + +func (c *Router) dispose() { + c.log.Info().Msg("disposing of router") + c.routerObjectContextCancel(fmt.Errorf("router is disposed")) + c.log.Debug().Msg("context canceled") } func (c *Router) Dispose() { - log.Info().Msg("disposing of router") + c.globalState.DispatchRouterRemovedEvent(c) } From c81ff270dc72dd10bc940a4258a56c7d258705f7 Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Mon, 2 Dec 2024 18:57:21 +0400 Subject: [PATCH 04/13] base edge state handling --- bin/oriond-mock/oriond.go | 48 ++++++++ bin/registry/main.go | 2 +- bin/registry/server/protocol/client.go | 4 +- .../server/protocol/messages/event.go | 11 ++ .../server/protocol/messages/hello.go | 13 --- .../server/protocol/messages/kinds.go | 4 +- internal/state/dispatch.go | 76 ------------ internal/state/edge.go | 58 +++++++++- internal/state/edge_events.go | 9 ++ internal/state/event.go | 1 + internal/state/orion_registry.go | 28 ----- internal/state/registry.go | 109 ++++++++++++++++++ internal/state/router.go | 12 +- internal/state/router_connect.go | 5 - internal/state/router_disconnect.go | 5 - internal/state/router_events.go | 9 ++ 16 files changed, 256 insertions(+), 138 deletions(-) delete mode 100644 bin/registry/server/protocol/messages/hello.go delete mode 100644 internal/state/dispatch.go create mode 100644 internal/state/edge_events.go delete mode 100644 internal/state/orion_registry.go create mode 100644 internal/state/registry.go delete mode 100644 internal/state/router_connect.go delete mode 100644 internal/state/router_disconnect.go create mode 100644 internal/state/router_events.go diff --git a/bin/oriond-mock/oriond.go b/bin/oriond-mock/oriond.go index e9a4990..da0f5cd 100644 --- a/bin/oriond-mock/oriond.go +++ b/bin/oriond-mock/oriond.go @@ -2,6 +2,7 @@ package main import ( "crypto/tls" + "encoding/json" "flag" "fmt" "net/http" @@ -10,7 +11,9 @@ import ( "os/signal" "time" + "github.com/MatthieuCoder/OrionV3/bin/registry/server/protocol/messages" "github.com/MatthieuCoder/OrionV3/internal" + "github.com/MatthieuCoder/OrionV3/internal/state" "github.com/gorilla/websocket" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -24,6 +27,11 @@ var ( registryPort = flag.Uint("registry-port", 6443, "the port used by the registry") ) +type Event struct { + Kind string `json:"k"` + Content json.RawMessage `json:"e"` +} + func main() { interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) @@ -86,6 +94,46 @@ func main() { } log.Printf("recv: %s", message) + msg := Event{} + json.Unmarshal(message, &msg) + + log.Printf("received %s... handling", msg.Kind) + + switch msg.Kind { + case messages.MessageKindHello: + hello := messages.Hello{} + if err := json.Unmarshal(msg.Content, &hello); err != nil { + panic("invalid json") + } + log.Printf("Hello message: %s", hello.Message) + continue + case messages.MessageKindRouterConnect: + router_connect := state.RouterConnectEvent{} + if err := json.Unmarshal(msg.Content, &router_connect); err != nil { + panic("invalid json") + } + log.Printf("Router connected: %d", router_connect.Router.Identity) + + // todo: send request after provisionning the wireguard request + + continue + case messages.MessageKindRouterDisconnect: + router_connect := state.RouterDisconnectEvent{} + if err := json.Unmarshal(msg.Content, &router_connect); err != nil { + panic("invalid json") + } + log.Printf("Router disconnected: %d", router_connect.Router.Identity) + continue + case messages.MessageKindRouterEdgeInitConnectRequest: + log.Printf("connect request received") + case messages.MessageKindRouterEdgeInitConnectRequestResponse: + log.Printf("connect request ack received") + continue + default: + log.Printf("unroceverable error") + panic("invalid kind") + } + } }() diff --git a/bin/registry/main.go b/bin/registry/main.go index 7a0bfb9..a48f569 100644 --- a/bin/registry/main.go +++ b/bin/registry/main.go @@ -15,7 +15,7 @@ import ( ) var ( - pprof = flag.String("debug-pprof", ":6060", "") + pprof = flag.String("debug-pprof", "127.0.0.1:6060", "") enable_prof = flag.Bool("enable-pprof", false, "enable pprof for debugging") debug = flag.Bool("debug", false, "change the log level to debug") listeningHost = flag.String("listen-host", "127.0.0.1:6443", "the port the server will listen on") diff --git a/bin/registry/server/protocol/client.go b/bin/registry/server/protocol/client.go index 3eabc8d..e1dccfc 100644 --- a/bin/registry/server/protocol/client.go +++ b/bin/registry/server/protocol/client.go @@ -101,10 +101,10 @@ func (c *Client) startRoutine(sessionId string) { select { case event := <-channel: switch event := event.(type) { - case state.RouterConnect: + case state.RouterConnectEvent: c.log.Debug().Msg("sending a new router connect event") c.send(messages.MessageKindRouterConnect, event) - case state.RouterDisconnect: + case state.RouterDisconnectEvent: c.log.Debug().Msg("sending a new disconnect event") c.send(messages.MessageKindRouterDisconnect, event) } diff --git a/bin/registry/server/protocol/messages/event.go b/bin/registry/server/protocol/messages/event.go index eee83c4..bf33042 100644 --- a/bin/registry/server/protocol/messages/event.go +++ b/bin/registry/server/protocol/messages/event.go @@ -6,3 +6,14 @@ type Event struct { Kind string `json:"k"` Content state.Event `json:"e"` } + +type Hello struct { + Message string `json:"message"` + Identity state.RouterIdentity `json:"identity"` + Version string `json:"version"` + Commit string `json:"commit"` + Session string `json:"session"` +} + +type RouterConnectedEvent state.RouterConnectEvent +type RouterDisconnectedEvent state.RouterDisconnectEvent diff --git a/bin/registry/server/protocol/messages/hello.go b/bin/registry/server/protocol/messages/hello.go deleted file mode 100644 index bcb0ed4..0000000 --- a/bin/registry/server/protocol/messages/hello.go +++ /dev/null @@ -1,13 +0,0 @@ -package messages - -import ( - "github.com/MatthieuCoder/OrionV3/internal/state" -) - -type Hello struct { - Message string `json:"message"` - Identity state.RouterIdentity `json:"identity"` - Version string `json:"version"` - Commit string `json:"commit"` - Session string `json:"session"` -} diff --git a/bin/registry/server/protocol/messages/kinds.go b/bin/registry/server/protocol/messages/kinds.go index 97d5d79..7746064 100644 --- a/bin/registry/server/protocol/messages/kinds.go +++ b/bin/registry/server/protocol/messages/kinds.go @@ -16,8 +16,8 @@ const ( // A message sent by a router wanting to connect // to another one. // step1. (peer1) ---> (registry) ---> (peer2) - MessageKindRouterEdgeInitStep1 = "edge_initiate" + MessageKindRouterEdgeInitConnectRequest = "edge_create_request" // A message considered as a response of stage1. // step2. (peer2) ---> (registry) ---> (peer1) - MessageKindRouterEdgeInitStep2 = "edge_create_request" + MessageKindRouterEdgeInitConnectRequestResponse = "edge_create_request_ack" ) diff --git a/internal/state/dispatch.go b/internal/state/dispatch.go deleted file mode 100644 index 8b7ad75..0000000 --- a/internal/state/dispatch.go +++ /dev/null @@ -1,76 +0,0 @@ -package state - -import ( - "slices" -) - -func (c *OrionRegistryState) GetRouters() OrionRegistryRoutersState { - return c.routers -} - -// Called once a new member is joining the network -func (c *OrionRegistryState) DispatchNewRouterEvent( - newRouter *Router, -) { - c.routersLock.Lock() - defer c.routersLock.Unlock() - - c.routers[RouterIdentity(newRouter.Identity)] = newRouter - - for _, router := range c.routers { - if router.Identity != newRouter.Identity { - router.DispatchNewRouterEvent(newRouter) - } - } -} - -// Called once a member is removed -func (c *OrionRegistryState) DispatchRouterRemovedEvent( - deletedRouter *Router, -) { - if c.routers[deletedRouter.Identity] == nil { - return - } - - c.routersLock.Lock() - defer c.routersLock.Unlock() - - for _, router := range c.routers { - // todo: send event to other peers - if router.Identity != deletedRouter.Identity { - // todo: send event - router.DispatchRouterRemovedEvent(deletedRouter) - } - } - - c.routers[deletedRouter.Identity].dispose() - c.routers[deletedRouter.Identity] = nil -} - -// Dispatch new connection -func (c *OrionRegistryState) DispatchNewEdge( - edge *Edge, -) { - c.edgesLock.Lock() - defer c.edgesLock.Unlock() - - edgeA := edge.RouterA - edgeB := edge.RouterB - - // check that the routers are existing - if edgeA == nil || edgeB == nil { - // todo: report error - return - } - - ids := []uint32{uint32(edgeA.Identity), uint32(edgeB.Identity)} - slices.Sort(ids) - - // concatenate the bits - edgeId := uint64(ids[0]) << 32 & uint64(ids[1]) - - c.edges[edgeId] = edge - //edgeA.NewEdge(edge) - //edgeB.NewEdge(edge) - -} diff --git a/internal/state/edge.go b/internal/state/edge.go index 15a810c..aebcaca 100644 --- a/internal/state/edge.go +++ b/internal/state/edge.go @@ -1,22 +1,78 @@ package state +import ( + "context" + "fmt" + "slices" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +type EdgeIdentity uint64 type Edge struct { RouterA *Router RouterB *Router + + edgeObjectContext context.Context + edgeObjectContextCancel context.CancelCauseFunc + + globalState *OrionRegistryState + log zerolog.Logger +} + +func NewEdge( + globalContext context.Context, + routerA *Router, + routerB *Router, + globalState *OrionRegistryState, +) *Edge { + ctx, cancel := context.WithCancelCause(context.Background()) + edge := &Edge{ + RouterA: routerA, + RouterB: routerB, + + edgeObjectContext: ctx, + edgeObjectContextCancel: cancel, + + globalState: globalState, + } + identity := edge.EdgeId() + + logger := log.With().Uint32("edge-identity", uint32(identity)).Logger() + logger.Debug().Msg("new router session initiated") + edge.log = logger + + return edge +} + +func (c *Edge) EdgeId() EdgeIdentity { + ids := []uint32{uint32(c.RouterA.Identity), uint32(c.RouterB.Identity)} + slices.Sort(ids) + return EdgeIdentity(uint64(ids[0]) << 32 & uint64(ids[1])) } // Sends a new initialization step to both the peers // asking for a random one to choose a pre-shared key // The hole-punching logic is done locally by the peers func (c *Edge) Initialize() { - go func() { select { case <-c.RouterA.routerObjectContext.Done(): case <-c.RouterB.routerObjectContext.Done(): + case <-c.edgeObjectContext.Done(): } // the edge lifetime is finished // todo: teardown edge + c.globalState.DispatchEdgeRemovedEvent(c) }() + +} + +func (c *Edge) Dispose() { + c.globalState.DispatchEdgeRemovedEvent(c) +} +func (c *Edge) dispose() { + c.edgeObjectContextCancel(fmt.Errorf("edge is finished")) } diff --git a/internal/state/edge_events.go b/internal/state/edge_events.go new file mode 100644 index 0000000..4a3e56a --- /dev/null +++ b/internal/state/edge_events.go @@ -0,0 +1,9 @@ +package state + +type NewEdgeEvent struct { + Router *Edge +} + +type AskForNewEdge struct { + OtherNode *Router +} diff --git a/internal/state/event.go b/internal/state/event.go index 50deeb5..8158454 100644 --- a/internal/state/event.go +++ b/internal/state/event.go @@ -1,3 +1,4 @@ package state +// Meta interface holding the different events type Event interface{} diff --git a/internal/state/orion_registry.go b/internal/state/orion_registry.go deleted file mode 100644 index 07ad8fb..0000000 --- a/internal/state/orion_registry.go +++ /dev/null @@ -1,28 +0,0 @@ -package state - -import ( - "sync" -) - -type OrionRegistryRoutersState map[RouterIdentity]*Router -type OrionRegistryEdgesState map[uint64]*Edge - -// State related to the Orion-Registry -// component, that handles all the connection -// initialization system. -type OrionRegistryState struct { - routers OrionRegistryRoutersState // List of routers - routersLock sync.Mutex - - edges OrionRegistryEdgesState // List of edges in the orion graph - edgesLock sync.Mutex -} - -func NewOrionRegistryState() *OrionRegistryState { - return &OrionRegistryState{ - routers: make(OrionRegistryRoutersState), - routersLock: sync.Mutex{}, - edges: make(OrionRegistryEdgesState), - edgesLock: sync.Mutex{}, - } -} diff --git a/internal/state/registry.go b/internal/state/registry.go new file mode 100644 index 0000000..52fd898 --- /dev/null +++ b/internal/state/registry.go @@ -0,0 +1,109 @@ +package state + +import ( + "sync" + + "github.com/rs/zerolog/log" +) + +type OrionRegistryRoutersState map[RouterIdentity]*Router +type OrionRegistryEdgesState map[EdgeIdentity]*Edge + +// State related to the Orion-Registry +// component, that handles all the connection +// initialization system. +type OrionRegistryState struct { + routers OrionRegistryRoutersState // List of routers + routersLock sync.Mutex + + edges OrionRegistryEdgesState // List of edges in the orion graph + edgesLock sync.Mutex +} + +func NewOrionRegistryState() *OrionRegistryState { + return &OrionRegistryState{ + routers: make(OrionRegistryRoutersState), + routersLock: sync.Mutex{}, + edges: make(OrionRegistryEdgesState), + edgesLock: sync.Mutex{}, + } +} + +func (c *OrionRegistryState) GetRouters() OrionRegistryRoutersState { + return c.routers +} + +// Called once a new member is joining the network +func (c *OrionRegistryState) DispatchNewRouterEvent( + newRouter *Router, +) { + c.routersLock.Lock() + defer c.routersLock.Unlock() + + c.routers[RouterIdentity(newRouter.Identity)] = newRouter + + for _, router := range c.routers { + if router.Identity != newRouter.Identity { + router.DispatchNewRouterEvent(newRouter) + } + } +} + +// Called once a member is removed +func (c *OrionRegistryState) DispatchRouterRemovedEvent( + deletedRouter *Router, +) { + if c.routers[deletedRouter.Identity] == nil { + return + } + + c.routersLock.Lock() + defer c.routersLock.Unlock() + + for _, router := range c.routers { + if router.Identity != deletedRouter.Identity { + router.DispatchRouterRemovedEvent(deletedRouter) + } + } + + c.routers[deletedRouter.Identity].dispose() + c.routers[deletedRouter.Identity] = nil +} + +// Dispatch new connection +func (c *OrionRegistryState) DispatchNewEdge( + edge *Edge, +) { + c.edgesLock.Lock() + defer c.edgesLock.Unlock() + + routerA := edge.RouterA + routerB := edge.RouterB + + // check that the routers are existing + if routerA == nil || routerB == nil { + log.Fatal().Msg("one of the edge nodes is nil") + return + } + + // concatenate the bits + edgeId := edge.EdgeId() + c.edges[edgeId] = edge + routerA.DispatchNewEdgeEvent(edge) + routerB.DispatchNewEdgeEvent(edge) +} + +func (c *OrionRegistryState) DispatchEdgeRemovedEvent(edge *Edge) { + if c.routers[RouterIdentity(edge.EdgeId())] == nil { + return + } + + c.routersLock.Lock() + defer c.routersLock.Unlock() + + edge.RouterA.DispatchEdgeRemovedEvent(edge) + edge.RouterB.DispatchEdgeRemovedEvent(edge) + + c.edges[edge.EdgeId()].dispose() + c.edges[edge.EdgeId()] = nil +} diff --git a/internal/state/router.go b/internal/state/router.go index 47063aa..84a867e 100644 --- a/internal/state/router.go +++ b/internal/state/router.go @@ -91,8 +91,6 @@ func (c *Router) updateConnectionsCountRoutine() { ctx, e := context.WithCancelCause(context.Background()) c.connectionTimeoutContextCancel = e - // TODO: we must implement a way to deal with not-sent messages - // we launch a background task ticking for either // 1. the session timeout mechanism // 2. a new connection @@ -143,19 +141,23 @@ func (c *Router) updateConnectionsCountRoutine() { } func (c *Router) DispatchNewRouterEvent(router *Router) { - c.sending.Broadcast(RouterConnect{ + c.sending.Broadcast(RouterConnectEvent{ Router: router, }) } func (c *Router) DispatchRouterRemovedEvent(router *Router) { - c.sending.Broadcast(RouterDisconnect{ + c.sending.Broadcast(RouterDisconnectEvent{ Router: router, }) } +func (c *Router) DispatchNewEdgeEvent(edge *Edge) { + +} +func (c *Router) DispatchEdgeRemovedEvent(edge *Edge) {} + func (c *Router) dispose() { - c.log.Info().Msg("disposing of router") c.routerObjectContextCancel(fmt.Errorf("router is disposed")) c.log.Debug().Msg("context canceled") } diff --git a/internal/state/router_connect.go b/internal/state/router_connect.go deleted file mode 100644 index 20d399d..0000000 --- a/internal/state/router_connect.go +++ /dev/null @@ -1,5 +0,0 @@ -package state - -type RouterConnect struct { - Router *Router -} diff --git a/internal/state/router_disconnect.go b/internal/state/router_disconnect.go deleted file mode 100644 index 1dead8d..0000000 --- a/internal/state/router_disconnect.go +++ /dev/null @@ -1,5 +0,0 @@ -package state - -type RouterDisconnect struct { - Router *Router -} diff --git a/internal/state/router_events.go b/internal/state/router_events.go new file mode 100644 index 0000000..d01e6f4 --- /dev/null +++ b/internal/state/router_events.go @@ -0,0 +1,9 @@ +package state + +type RouterConnectEvent struct { + Router *Router +} + +type RouterDisconnectEvent struct { + Router *Router +} From 9b93269750e917f42b1127b9e2fd653417a48209 Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Fri, 6 Dec 2024 16:24:05 +0400 Subject: [PATCH 05/13] base for event handling --- bin/oriond-mock/oriond.go | 25 +++++-------------- bin/registry/server/protocol/client.go | 17 +++++++++---- .../server/protocol/messages/event.go | 3 --- .../server/protocol/messages/kinds.go | 18 +++++-------- internal/state/event.go | 7 ++++++ internal/state/registry.go | 6 ----- internal/state/router.go | 6 ----- internal/state/router_events.go | 4 --- 8 files changed, 31 insertions(+), 55 deletions(-) diff --git a/bin/oriond-mock/oriond.go b/bin/oriond-mock/oriond.go index da0f5cd..51f4b3f 100644 --- a/bin/oriond-mock/oriond.go +++ b/bin/oriond-mock/oriond.go @@ -22,16 +22,10 @@ import ( var ( enable_prof = flag.Bool("enable-pprof", false, "enable pprof for debugging") debug = flag.Bool("debug", false, "change the log level to debug") - registryServer = flag.String("registry-server", "reg.orionet.re", "the address of the registry server") + registryServer = flag.String("registry-server", "reg.orionet.re:6443", "the address of the registry server") pprof = flag.String("debug-pprof", "0.0.0.0:6061", "") - registryPort = flag.Uint("registry-port", 6443, "the port used by the registry") ) -type Event struct { - Kind string `json:"k"` - Content json.RawMessage `json:"e"` -} - func main() { interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) @@ -53,7 +47,7 @@ func main() { url := url.URL{ Scheme: "wss", - Host: "reg.orionet.re:6443", + Host: *registryServer, Path: "/ws", } @@ -94,7 +88,7 @@ func main() { } log.Printf("recv: %s", message) - msg := Event{} + msg := state.JsonEvent{} json.Unmarshal(message, &msg) log.Printf("received %s... handling", msg.Kind) @@ -117,16 +111,9 @@ func main() { // todo: send request after provisionning the wireguard request continue - case messages.MessageKindRouterDisconnect: - router_connect := state.RouterDisconnectEvent{} - if err := json.Unmarshal(msg.Content, &router_connect); err != nil { - panic("invalid json") - } - log.Printf("Router disconnected: %d", router_connect.Router.Identity) - continue - case messages.MessageKindRouterEdgeInitConnectRequest: - log.Printf("connect request received") - case messages.MessageKindRouterEdgeInitConnectRequestResponse: + case messages.MessageKindRouterEdgeConnectInitializeResponse: + case messages.MessageKindRouterEdgeConnectInitializeRequest: + case messages.MessageKindRouterEdgeTeardown: log.Printf("connect request ack received") continue default: diff --git a/bin/registry/server/protocol/client.go b/bin/registry/server/protocol/client.go index e1dccfc..40e2354 100644 --- a/bin/registry/server/protocol/client.go +++ b/bin/registry/server/protocol/client.go @@ -2,6 +2,7 @@ package protocol import ( "context" + "encoding/json" "fmt" "github.com/MatthieuCoder/OrionV3/bin/registry/server/protocol/messages" @@ -104,9 +105,6 @@ func (c *Client) startRoutine(sessionId string) { case state.RouterConnectEvent: c.log.Debug().Msg("sending a new router connect event") c.send(messages.MessageKindRouterConnect, event) - case state.RouterDisconnectEvent: - c.log.Debug().Msg("sending a new disconnect event") - c.send(messages.MessageKindRouterDisconnect, event) } case <-ctx.Done(): c.log.Debug().Msg("server state listening routine is done") @@ -123,12 +121,21 @@ func (c *Client) startRoutine(sessionId string) { go func() { for { - _, _, err := c.ws.ReadMessage() + _, data, err := c.ws.ReadMessage() if err != nil { goto end } - // todo: handle clients events + event := state.JsonEvent{} + if err := json.Unmarshal(data, &event); err != nil { + goto end + } + + switch event.Kind { + case messages.MessageKindRouterEdgeConnectInitializeRequest: + case messages.MessageKindRouterConnect: + case messages.MessageKindRouterEdgeTeardown: + } } end: diff --git a/bin/registry/server/protocol/messages/event.go b/bin/registry/server/protocol/messages/event.go index bf33042..9d9974d 100644 --- a/bin/registry/server/protocol/messages/event.go +++ b/bin/registry/server/protocol/messages/event.go @@ -14,6 +14,3 @@ type Hello struct { Commit string `json:"commit"` Session string `json:"session"` } - -type RouterConnectedEvent state.RouterConnectEvent -type RouterDisconnectedEvent state.RouterDisconnectEvent diff --git a/bin/registry/server/protocol/messages/kinds.go b/bin/registry/server/protocol/messages/kinds.go index 7746064..a4a5d2f 100644 --- a/bin/registry/server/protocol/messages/kinds.go +++ b/bin/registry/server/protocol/messages/kinds.go @@ -8,16 +8,10 @@ const ( // this is so that a user, can choose to initiate // a new connection to this new router. MessageKindRouterConnect = "new_router" - // Sent when a router session ended meaning - // a disconnection from the orion registry - // this will triger a teardown of the client - // and thus a end of all wireguard tunnels - MessageKindRouterDisconnect = "router_disconnect" - // A message sent by a router wanting to connect - // to another one. - // step1. (peer1) ---> (registry) ---> (peer2) - MessageKindRouterEdgeInitConnectRequest = "edge_create_request" - // A message considered as a response of stage1. - // step2. (peer2) ---> (registry) ---> (peer1) - MessageKindRouterEdgeInitConnectRequestResponse = "edge_create_request_ack" + // Sent by a peer that wants to initialize a new peer-to-peer link + MessageKindRouterEdgeConnectInitializeRequest = "edge_initialize_request" + MessageKindRouterEdgeConnectInitializeResponse = "edge_initialize_response" + + // Event emitted once an edge is destroyed + MessageKindRouterEdgeTeardown = "edge_teardown" ) diff --git a/internal/state/event.go b/internal/state/event.go index 8158454..81dee97 100644 --- a/internal/state/event.go +++ b/internal/state/event.go @@ -1,4 +1,11 @@ package state +import "encoding/json" + // Meta interface holding the different events type Event interface{} + +type JsonEvent struct { + Kind string `json:"k"` + Content json.RawMessage `json:"e"` +} diff --git a/internal/state/registry.go b/internal/state/registry.go index 52fd898..b11e734 100644 --- a/internal/state/registry.go +++ b/internal/state/registry.go @@ -60,12 +60,6 @@ func (c *OrionRegistryState) DispatchRouterRemovedEvent( c.routersLock.Lock() defer c.routersLock.Unlock() - for _, router := range c.routers { - if router.Identity != deletedRouter.Identity { - router.DispatchRouterRemovedEvent(deletedRouter) - } - } - c.routers[deletedRouter.Identity].dispose() c.routers[deletedRouter.Identity] = nil } diff --git a/internal/state/router.go b/internal/state/router.go index 84a867e..6f6c7ac 100644 --- a/internal/state/router.go +++ b/internal/state/router.go @@ -146,12 +146,6 @@ func (c *Router) DispatchNewRouterEvent(router *Router) { }) } -func (c *Router) DispatchRouterRemovedEvent(router *Router) { - c.sending.Broadcast(RouterDisconnectEvent{ - Router: router, - }) -} - func (c *Router) DispatchNewEdgeEvent(edge *Edge) { } diff --git a/internal/state/router_events.go b/internal/state/router_events.go index d01e6f4..6c0a517 100644 --- a/internal/state/router_events.go +++ b/internal/state/router_events.go @@ -3,7 +3,3 @@ package state type RouterConnectEvent struct { Router *Router } - -type RouterDisconnectEvent struct { - Router *Router -} From 1eccfe2f758cc076dc45b250ac069dbe00d67f0f Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Thu, 12 Dec 2024 13:58:19 +0400 Subject: [PATCH 06/13] beginning of the initialization for edges --- bin/oriond-mock/oriond.go | 35 ++++----- bin/registry/main.go | 2 +- bin/registry/server/protocol/client.go | 48 +++++++----- .../server/protocol/messages/event.go | 16 ---- grpc_build.sh | 5 -- install.sh | 36 --------- internal/state/edge.go | 9 ++- internal/state/event.go | 75 ++++++++++++++++++- .../messages => internal/state}/kinds.go | 2 +- internal/state/registry.go | 26 ++++--- internal/state/router.go | 36 +++++---- internal/state/router_events.go | 12 +++ packaging/daemons | 2 +- 13 files changed, 174 insertions(+), 130 deletions(-) delete mode 100644 bin/registry/server/protocol/messages/event.go delete mode 100755 grpc_build.sh delete mode 100755 install.sh rename {bin/registry/server/protocol/messages => internal/state}/kinds.go (97%) diff --git a/bin/oriond-mock/oriond.go b/bin/oriond-mock/oriond.go index 51f4b3f..0b6473b 100644 --- a/bin/oriond-mock/oriond.go +++ b/bin/oriond-mock/oriond.go @@ -11,7 +11,6 @@ import ( "os/signal" "time" - "github.com/MatthieuCoder/OrionV3/bin/registry/server/protocol/messages" "github.com/MatthieuCoder/OrionV3/internal" "github.com/MatthieuCoder/OrionV3/internal/state" "github.com/gorilla/websocket" @@ -93,28 +92,24 @@ func main() { log.Printf("received %s... handling", msg.Kind) - switch msg.Kind { - case messages.MessageKindHello: - hello := messages.Hello{} - if err := json.Unmarshal(msg.Content, &hello); err != nil { - panic("invalid json") - } - log.Printf("Hello message: %s", hello.Message) + out, err := state.UnmarshalEvent(msg) + if err != nil { + log.Print("read:", err) + return + } + + switch message := out.(type) { + case state.Hello: + log.Printf("Hello message: %s", message.Message) continue - case messages.MessageKindRouterConnect: - router_connect := state.RouterConnectEvent{} - if err := json.Unmarshal(msg.Content, &router_connect); err != nil { - panic("invalid json") - } - log.Printf("Router connected: %d", router_connect.Router.Identity) + case state.RouterConnectEvent: + log.Printf("router joined: %d", message.Router.Identity) - // todo: send request after provisionning the wireguard request + ev, _ := state.MarshalEvent(state.RouterInitiateRequest{ + Identity: &message.Router.Identity, + }) + c.WriteJSON(ev) - continue - case messages.MessageKindRouterEdgeConnectInitializeResponse: - case messages.MessageKindRouterEdgeConnectInitializeRequest: - case messages.MessageKindRouterEdgeTeardown: - log.Printf("connect request ack received") continue default: log.Printf("unroceverable error") diff --git a/bin/registry/main.go b/bin/registry/main.go index a48f569..5c3f2f8 100644 --- a/bin/registry/main.go +++ b/bin/registry/main.go @@ -47,7 +47,7 @@ func main() { tlsConfig := &tls.Config{ Certificates: []tls.Certificate{certificateKeyPair}, ClientCAs: authorityPool, - ClientAuth: tls.VerifyClientCertIfGiven, + ClientAuth: tls.RequestClientCert, MinVersion: tls.VersionTLS13, CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, CipherSuites: []uint16{ diff --git a/bin/registry/server/protocol/client.go b/bin/registry/server/protocol/client.go index 40e2354..ff4671c 100644 --- a/bin/registry/server/protocol/client.go +++ b/bin/registry/server/protocol/client.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" - "github.com/MatthieuCoder/OrionV3/bin/registry/server/protocol/messages" "github.com/MatthieuCoder/OrionV3/internal" "github.com/MatthieuCoder/OrionV3/internal/state" "github.com/gorilla/websocket" @@ -36,11 +35,8 @@ func NewClient(ws *websocket.Conn, identity state.RouterIdentity, sessionId stri return c } -func (c *Client) send(k string, msg state.Event) error { - err := c.ws.WriteJSON(messages.Event{ - Kind: k, - Content: msg, - }) +func (c *Client) send(event *state.JsonEvent) error { + err := c.ws.WriteJSON(event) if err != nil { c.log.Error().Err(err).Msg("failed to send message") } @@ -79,15 +75,15 @@ func (c *Client) startRoutine(sessionId string) { } } c.router = rtr - - // we send the hello message - c.send(messages.MessageKindHello, messages.Hello{ + event, _ := state.MarshalEvent(state.Hello{ Message: "Hi. This is orion-registry.", Identity: c.router.Identity, Version: internal.Version, Commit: internal.Commit, Session: c.router.SessionId(), }) + // we send the hello message + c.send(event) ctx, cancel := context.WithCancelCause(c.ctx) @@ -101,11 +97,7 @@ func (c *Client) startRoutine(sessionId string) { for { select { case event := <-channel: - switch event := event.(type) { - case state.RouterConnectEvent: - c.log.Debug().Msg("sending a new router connect event") - c.send(messages.MessageKindRouterConnect, event) - } + c.send(event) case <-ctx.Done(): c.log.Debug().Msg("server state listening routine is done") return @@ -128,13 +120,33 @@ func (c *Client) startRoutine(sessionId string) { event := state.JsonEvent{} if err := json.Unmarshal(data, &event); err != nil { + c.log.Error().Err(err).Msg("failed to parse jsonevent") goto end } + out, err := state.UnmarshalEvent(event) + if err != nil { + c.log.Error().Err(err).Msg("failed to parse event") + goto end + } + + switch message := out.(type) { + // sent once a router wants to connect to another one + case state.RouterInitiateRequest: + c.log.Info().Msgf("received a router connect event to %d", *message.Identity) + + routers := orionRegistryState.GetRouters() + if routers[*message.Identity] == nil || routers[c.identity] == nil { + goto end + } + + orionRegistryState.DispatchNewEdge( + state.NewEdge(context.Background(), routers[*message.Identity], routers[c.identity], orionRegistryState), + ) - switch event.Kind { - case messages.MessageKindRouterEdgeConnectInitializeRequest: - case messages.MessageKindRouterConnect: - case messages.MessageKindRouterEdgeTeardown: + continue + default: + c.log.Error().Str("event", event.Kind).Msg("unknown event type") + goto end } } diff --git a/bin/registry/server/protocol/messages/event.go b/bin/registry/server/protocol/messages/event.go deleted file mode 100644 index 9d9974d..0000000 --- a/bin/registry/server/protocol/messages/event.go +++ /dev/null @@ -1,16 +0,0 @@ -package messages - -import "github.com/MatthieuCoder/OrionV3/internal/state" - -type Event struct { - Kind string `json:"k"` - Content state.Event `json:"e"` -} - -type Hello struct { - Message string `json:"message"` - Identity state.RouterIdentity `json:"identity"` - Version string `json:"version"` - Commit string `json:"commit"` - Session string `json:"session"` -} diff --git a/grpc_build.sh b/grpc_build.sh deleted file mode 100755 index 56b6edc..0000000 --- a/grpc_build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -for f in $(find proto -name 'orion_*.proto'); do - protoc --go_out=internal --go_opt=paths=source_relative --go-grpc_out=internal --go-grpc_opt=paths=source_relative "$f" -done diff --git a/install.sh b/install.sh deleted file mode 100755 index 9f4aa99..0000000 --- a/install.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -# Enable error handling -set -e - -echo -e "Running apt-get update for accurate packages." -apt-get update -q &> /dev/null - -# Check for the `jq` command to be available. -if ! command -v jq &> /dev/null -then - echo "Ths jq command couldn't be found in your current $PATH... Trying to install it." - apt-get install -yq jq &> /dev/null -fi - -# Check for the `curl` command to be available. -if ! command -v curl &> /dev/null -then - echo "Ths curl command couldn't be found in your current $PATH... Trying to install it." - apt-get install -yq curl &> /dev/null -fi - -JSON=$(curl -s https://api.github.com/repos/MatthieuCoder/OrionV3/releases/latest) -VERSION=$(echo $JSON | jq -r '.name') -NAME_PREDICATE="contains(\"$(dpkg --print-architecture).deb\")" -URL=$(echo $JSON | jq -r ".assets[] | select(.name | $NAME_PREDICATE) | .browser_download_url") - -echo "Downloading version $VERSION for $(dpkg --print-architecture)..." -curl "$URL" -s -L -o "/tmp/orion.deb" -echo "Downloaded version $VERSION... Installing using APT" -apt install -q --allow-downgrades -y /tmp/orion.deb &> /dev/null -echo "Done. Cleaning up." -rm /tmp/orion.deb - -echo "Reloading sevices" -systemctl restart oriond \ No newline at end of file diff --git a/internal/state/edge.go b/internal/state/edge.go index aebcaca..d451a57 100644 --- a/internal/state/edge.go +++ b/internal/state/edge.go @@ -61,13 +61,14 @@ func (c *Edge) Initialize() { case <-c.RouterA.routerObjectContext.Done(): case <-c.RouterB.routerObjectContext.Done(): case <-c.edgeObjectContext.Done(): + c.log.Debug().Err(c.edgeObjectContext.Err()).Msg("edge context is finished") + return } - - // the edge lifetime is finished - // todo: teardown edge - c.globalState.DispatchEdgeRemovedEvent(c) + c.Dispose() + c.log.Debug().Msg("starting edge disposal") }() + c.log.Debug().Msg("edge instance started") } func (c *Edge) Dispose() { diff --git a/internal/state/event.go b/internal/state/event.go index 81dee97..213f476 100644 --- a/internal/state/event.go +++ b/internal/state/event.go @@ -1,6 +1,9 @@ package state -import "encoding/json" +import ( + "encoding/json" + "fmt" +) // Meta interface holding the different events type Event interface{} @@ -9,3 +12,73 @@ type JsonEvent struct { Kind string `json:"k"` Content json.RawMessage `json:"e"` } + +func UnmarshalEvent( + event JsonEvent, +) (Event, error) { + switch event.Kind { + case MessageKindHello: + hello := Hello{} + if err := json.Unmarshal(event.Content, &hello); err != nil { + return nil, err + } + return hello, nil + case MessageKindRouterConnect: + hello := RouterConnectEvent{} + if err := json.Unmarshal(event.Content, &hello); err != nil { + return nil, err + } + return hello, nil + case MessageKindRouterEdgeConnectInitializeRequest: + hello := RouterInitiateRequest{} + if err := json.Unmarshal(event.Content, &hello); err != nil { + return nil, err + } + return hello, nil + case MessageKindRouterEdgeConnectInitializeResponse: + case MessageKindRouterEdgeTeardown: + + return nil, fmt.Errorf("not implemented") + default: + return nil, fmt.Errorf("unknown event for deserialize") + } + + return nil, fmt.Errorf("not implemented") +} + +func MarshalEvent( + event Event, +) (*JsonEvent, error) { + switch event := event.(type) { + case Hello: + bytes, err := json.Marshal(event) + if err != nil { + return nil, err + } + return &JsonEvent{ + Kind: MessageKindHello, + Content: bytes, + }, nil + case RouterConnectEvent: + bytes, err := json.Marshal(event) + if err != nil { + return nil, err + } + return &JsonEvent{ + Kind: MessageKindRouterConnect, + Content: bytes, + }, nil + case RouterInitiateRequest: + bytes, err := json.Marshal(event) + if err != nil { + return nil, err + } + return &JsonEvent{ + Kind: MessageKindRouterEdgeConnectInitializeRequest, + Content: bytes, + }, nil + + } + + return nil, fmt.Errorf("event serialization not supported") +} diff --git a/bin/registry/server/protocol/messages/kinds.go b/internal/state/kinds.go similarity index 97% rename from bin/registry/server/protocol/messages/kinds.go rename to internal/state/kinds.go index a4a5d2f..63fd2ba 100644 --- a/bin/registry/server/protocol/messages/kinds.go +++ b/internal/state/kinds.go @@ -1,4 +1,4 @@ -package messages +package state const ( // Event sent at the beginning for a new connection diff --git a/internal/state/registry.go b/internal/state/registry.go index b11e734..d94767e 100644 --- a/internal/state/registry.go +++ b/internal/state/registry.go @@ -44,7 +44,9 @@ func (c *OrionRegistryState) DispatchNewRouterEvent( for _, router := range c.routers { if router.Identity != newRouter.Identity { - router.DispatchNewRouterEvent(newRouter) + router.Disatch(RouterConnectEvent{ + Router: newRouter, + }) } } } @@ -68,9 +70,6 @@ func (c *OrionRegistryState) DispatchRouterRemovedEvent( func (c *OrionRegistryState) DispatchNewEdge( edge *Edge, ) { - c.edgesLock.Lock() - defer c.edgesLock.Unlock() - routerA := edge.RouterA routerB := edge.RouterB @@ -80,23 +79,28 @@ func (c *OrionRegistryState) DispatchNewEdge( return } + c.edgesLock.Lock() + defer c.edgesLock.Unlock() + // concatenate the bits edgeId := edge.EdgeId() c.edges[edgeId] = edge - routerA.DispatchNewEdgeEvent(edge) - routerB.DispatchNewEdgeEvent(edge) + + edge.Initialize() } func (c *OrionRegistryState) DispatchEdgeRemovedEvent(edge *Edge) { - if c.routers[RouterIdentity(edge.EdgeId())] == nil { + log.Debug().Msg("edge got removed") + + if c.edges[edge.EdgeId()] == nil { return } - c.routersLock.Lock() - defer c.routersLock.Unlock() + c.edgesLock.Lock() + defer c.edgesLock.Unlock() - edge.RouterA.DispatchEdgeRemovedEvent(edge) - edge.RouterB.DispatchEdgeRemovedEvent(edge) + // edge.RouterA.DispatchEdgeRemovedEvent(edge) + // edge.RouterB.DispatchEdgeRemovedEvent(edge) c.edges[edge.EdgeId()].dispose() c.edges[edge.EdgeId()] = nil diff --git a/internal/state/router.go b/internal/state/router.go index 6f6c7ac..be690b1 100644 --- a/internal/state/router.go +++ b/internal/state/router.go @@ -16,14 +16,14 @@ type RouterIdentity uint32 type Router struct { Identity RouterIdentity - sending *broadcast.Relay[Event] + sending *broadcast.Relay[*JsonEvent] routerObjectContext context.Context routerObjectContextCancel context.CancelCauseFunc connectionsCount atomic.Int32 connectionTimeoutContextCancel context.CancelCauseFunc - - session string + pendingTeardown bool + session string globalState *OrionRegistryState log zerolog.Logger @@ -51,12 +51,13 @@ func NewRouter( return &Router{ Identity: identity, connectionsCount: atomic.Int32{}, - sending: broadcast.NewRelay[Event](), + sending: broadcast.NewRelay[*JsonEvent](), routerObjectContext: ctx, routerObjectContextCancel: cancel, globalState: globalState, session: session, log: logger, + pendingTeardown: false, } } @@ -64,7 +65,7 @@ func (c *Router) SessionId() string { return c.session } -func (c *Router) Subscribe() *broadcast.Listener[Event] { +func (c *Router) Subscribe() *broadcast.Listener[*JsonEvent] { return c.sending.Listener(1) } @@ -78,6 +79,9 @@ func (c *Router) DecrementConnectionCount() { } func (c *Router) updateConnectionsCountRoutine() { + if c.pendingTeardown { + return + } current := c.connectionsCount.Load() c.log.Debug(). @@ -95,13 +99,13 @@ func (c *Router) updateConnectionsCountRoutine() { // 1. the session timeout mechanism // 2. a new connection go func() { - timeout := time.NewTimer(time.Minute) + timeout := time.NewTimer(time.Second * 10) c.log.Debug().Msg("ticking a minute before session expiration") subscribe := c.Subscribe() defer subscribe.Close() - replayPending := make([]Event, 1000) + replayPending := make([]*JsonEvent, 1000) replayEventsCount := 0 for { @@ -140,20 +144,20 @@ func (c *Router) updateConnectionsCountRoutine() { } -func (c *Router) DispatchNewRouterEvent(router *Router) { - c.sending.Broadcast(RouterConnectEvent{ - Router: router, - }) -} - -func (c *Router) DispatchNewEdgeEvent(edge *Edge) { - +func (c *Router) Disatch(router Event) { + value, err := MarshalEvent(router) + if err != nil { + log.Error().Err(err).Msg("couldn't dispatch new event") + return + } + c.sending.Broadcast(value) } -func (c *Router) DispatchEdgeRemovedEvent(edge *Edge) {} func (c *Router) dispose() { + c.pendingTeardown = true c.routerObjectContextCancel(fmt.Errorf("router is disposed")) c.log.Debug().Msg("context canceled") + c.sending.Close() } func (c *Router) Dispose() { diff --git a/internal/state/router_events.go b/internal/state/router_events.go index 6c0a517..ce2cf6f 100644 --- a/internal/state/router_events.go +++ b/internal/state/router_events.go @@ -3,3 +3,15 @@ package state type RouterConnectEvent struct { Router *Router } + +type RouterInitiateRequest struct { + Identity *RouterIdentity +} + +type Hello struct { + Message string `json:"message"` + Identity RouterIdentity `json:"identity"` + Version string `json:"version"` + Commit string `json:"commit"` + Session string `json:"session"` +} diff --git a/packaging/daemons b/packaging/daemons index f657473..3b19492 100644 --- a/packaging/daemons +++ b/packaging/daemons @@ -41,7 +41,7 @@ pathd=no vtysh_enable=yes zebra_options=" -A 127.0.0.1 -s 90000000" mgmtd_options=" -A 127.0.0.1" -bgpd_options=" -A 127.0.0.1 -M snmp" +bgpd_options=" -A 127.0.0.1" ospfd_options=" -A 127.0.0.1" ospf6d_options=" -A ::1" ripd_options=" -A 127.0.0.1" From 50849544ef4ed1fda9e8fe44b437d4a61df9c673 Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Sun, 12 Jan 2025 11:39:23 +0400 Subject: [PATCH 07/13] base edge creation --- bin/oriond-mock/oriond.go | 4 +--- internal/state/edge.go | 25 +++++++++++++++++++++++++ internal/state/edge_events.go | 13 +++++++++++++ internal/state/event.go | 5 +++-- internal/state/kinds.go | 3 +-- internal/state/registry.go | 2 +- internal/state/router.go | 2 +- 7 files changed, 45 insertions(+), 9 deletions(-) diff --git a/bin/oriond-mock/oriond.go b/bin/oriond-mock/oriond.go index 0b6473b..a587f51 100644 --- a/bin/oriond-mock/oriond.go +++ b/bin/oriond-mock/oriond.go @@ -95,7 +95,6 @@ func main() { out, err := state.UnmarshalEvent(msg) if err != nil { log.Print("read:", err) - return } switch message := out.(type) { @@ -112,8 +111,7 @@ func main() { continue default: - log.Printf("unroceverable error") - panic("invalid kind") + log.Printf("invalid kind error") } } diff --git a/internal/state/edge.go b/internal/state/edge.go index d451a57..16e8066 100644 --- a/internal/state/edge.go +++ b/internal/state/edge.go @@ -16,6 +16,7 @@ type Edge struct { edgeObjectContext context.Context edgeObjectContextCancel context.CancelCauseFunc + seeded chan struct{} globalState *OrionRegistryState log zerolog.Logger @@ -69,6 +70,30 @@ func (c *Edge) Initialize() { }() c.log.Debug().Msg("edge instance started") + + c.seeded = make(chan struct{}) + + // send a message to the routerA, requesting a new tunnel connection. + c.RouterA.Dispatch(CreateEdgeRequest{}) + + // wait for routerA to seed his tunnel information + <-c.seeded + c.seeded = make(chan struct{}) + + // send a message to the routerB, requesting a new tunnel connection. + c.RouterB.Dispatch(CreateEdgeRequest{}) + + // wait for routerB to seed his tunnel information + <-c.seeded + + c.seeded = make(chan struct{}) + c.RouterA.Dispatch(SeedEdgeRequest{}) + <-c.seeded + + c.seeded = make(chan struct{}) + c.RouterB.Dispatch(SeedEdgeRequest{}) + <-c.seeded + c.seeded = nil } func (c *Edge) Dispose() { diff --git a/internal/state/edge_events.go b/internal/state/edge_events.go index 4a3e56a..cd47078 100644 --- a/internal/state/edge_events.go +++ b/internal/state/edge_events.go @@ -7,3 +7,16 @@ type NewEdgeEvent struct { type AskForNewEdge struct { OtherNode *Router } + +type CreateEdgeRequest struct{} +type CreateEdgeResponse struct{} + +type SeedEdgePeer struct { + PublicKey string + PresharedKey string + DefaultRoute bool +} + +type SeedEdgeRequest struct { + Peers []SeedEdgePeer +} diff --git a/internal/state/event.go b/internal/state/event.go index 213f476..64fe3c2 100644 --- a/internal/state/event.go +++ b/internal/state/event.go @@ -35,7 +35,6 @@ func UnmarshalEvent( return nil, err } return hello, nil - case MessageKindRouterEdgeConnectInitializeResponse: case MessageKindRouterEdgeTeardown: return nil, fmt.Errorf("not implemented") @@ -77,7 +76,9 @@ func MarshalEvent( Kind: MessageKindRouterEdgeConnectInitializeRequest, Content: bytes, }, nil - + case CreateEdgeRequest: + case CreateEdgeResponse: + case SeedEdgeRequest: } return nil, fmt.Errorf("event serialization not supported") diff --git a/internal/state/kinds.go b/internal/state/kinds.go index 63fd2ba..4d6ac61 100644 --- a/internal/state/kinds.go +++ b/internal/state/kinds.go @@ -9,8 +9,7 @@ const ( // a new connection to this new router. MessageKindRouterConnect = "new_router" // Sent by a peer that wants to initialize a new peer-to-peer link - MessageKindRouterEdgeConnectInitializeRequest = "edge_initialize_request" - MessageKindRouterEdgeConnectInitializeResponse = "edge_initialize_response" + MessageKindRouterEdgeConnectInitializeRequest = "edge_initialize_request" // Event emitted once an edge is destroyed MessageKindRouterEdgeTeardown = "edge_teardown" diff --git a/internal/state/registry.go b/internal/state/registry.go index d94767e..ca5ff68 100644 --- a/internal/state/registry.go +++ b/internal/state/registry.go @@ -44,7 +44,7 @@ func (c *OrionRegistryState) DispatchNewRouterEvent( for _, router := range c.routers { if router.Identity != newRouter.Identity { - router.Disatch(RouterConnectEvent{ + router.Dispatch(RouterConnectEvent{ Router: newRouter, }) } diff --git a/internal/state/router.go b/internal/state/router.go index be690b1..63da839 100644 --- a/internal/state/router.go +++ b/internal/state/router.go @@ -144,7 +144,7 @@ func (c *Router) updateConnectionsCountRoutine() { } -func (c *Router) Disatch(router Event) { +func (c *Router) Dispatch(router Event) { value, err := MarshalEvent(router) if err != nil { log.Error().Err(err).Msg("couldn't dispatch new event") From cba25abc938f1f9944445365d199a2bc4a083b88 Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Sat, 1 Feb 2025 18:31:38 +0400 Subject: [PATCH 08/13] fix packaging --- .goreleaser.yaml | 4 -- packaging/daemons | 126 ---------------------------------------- packaging/preinstall.sh | 4 -- 3 files changed, 134 deletions(-) delete mode 100644 packaging/daemons delete mode 100755 packaging/preinstall.sh diff --git a/.goreleaser.yaml b/.goreleaser.yaml index c072186..e13d4f2 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -68,7 +68,6 @@ nfpms: bindir: /usr/bin scripts: - preinstall: ./packaging/preinstall.sh postinstall: ./packaging/postinstall.sh # Version Release. @@ -105,9 +104,6 @@ nfpms: - src: packaging/ca.crt dst: /etc/oriond/ type: "config" - - src: packaging/daemons - dst: /etc/frr/daemons - type: "config" - src: packaging/sysctl.conf dst: /etc/sysctl.d/00-orion-routing.conf type: "config" diff --git a/packaging/daemons b/packaging/daemons deleted file mode 100644 index 3b19492..0000000 --- a/packaging/daemons +++ /dev/null @@ -1,126 +0,0 @@ -# This file tells the frr package which daemons to start. -# -# Sample configurations for these daemons can be found in -# /usr/share/doc/frr/examples/. -# -# ATTENTION: -# -# When activating a daemon for the first time, a config file, even if it is -# empty, has to be present *and* be owned by the user and group "frr", else -# the daemon will not be started by /etc/init.d/frr. The permissions should -# be u=rw,g=r,o=. -# When using "vtysh" such a config file is also needed. It should be owned by -# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too. -# -# The watchfrr, zebra and staticd daemons are always started. -# -bgpd=yes -ospfd=no -ospf6d=no -ripd=no -ripngd=no -isisd=no -pimd=yes -pim6d=yes -ldpd=no -nhrpd=no -eigrpd=no -babeld=no -sharpd=no -pbrd=no -bfdd=yes -fabricd=no -vrrpd=no -pathd=no - -# -# If this option is set the /etc/init.d/frr script automatically loads -# the config via "vtysh -b" when the servers are started. -# Check /etc/pam.d/frr if you intend to use "vtysh"! -# -vtysh_enable=yes -zebra_options=" -A 127.0.0.1 -s 90000000" -mgmtd_options=" -A 127.0.0.1" -bgpd_options=" -A 127.0.0.1" -ospfd_options=" -A 127.0.0.1" -ospf6d_options=" -A ::1" -ripd_options=" -A 127.0.0.1" -ripngd_options=" -A ::1" -isisd_options=" -A 127.0.0.1" -pimd_options=" -A 127.0.0.1" -pim6d_options=" -A ::1" -ldpd_options=" -A 127.0.0.1" -nhrpd_options=" -A 127.0.0.1" -eigrpd_options=" -A 127.0.0.1" -babeld_options=" -A 127.0.0.1" -sharpd_options=" -A 127.0.0.1" -pbrd_options=" -A 127.0.0.1" -staticd_options="-A 127.0.0.1" -bfdd_options=" -A 127.0.0.1" -fabricd_options="-A 127.0.0.1" -vrrpd_options=" -A 127.0.0.1" -pathd_options=" -A 127.0.0.1" - - -# If you want to pass a common option to all daemons, you can use the -# "frr_global_options" variable. -# -#frr_global_options="" - - -# The list of daemons to watch is automatically generated by the init script. -# This variable can be used to pass options to watchfrr that will be passed -# prior to the daemon list. -# -# To make watchfrr create/join the specified netns, add the the "--netns" -# option here. It will only have an effect in /etc/frr//daemons, and -# you need to start FRR with "/usr/lib/frr/frrinit.sh start ". -# -#watchfrr_options="" - - -# configuration profile -# -#frr_profile="traditional" -#frr_profile="datacenter" - - -# This is the maximum number of FD's that will be available. Upon startup this -# is read by the control files and ulimit is called. Uncomment and use a -# reasonable value for your setup if you are expecting a large number of peers -# in say BGP. -# -#MAX_FDS=1024 - -# Uncomment this option if you want to run FRR as a non-root user. Note that -# you should know what you are doing since most of the daemons need root -# to work. This could be useful if you want to run FRR in a container -# for instance. -# FRR_NO_ROOT="yes" - -# For any daemon, you can specify a "wrap" command to start instead of starting -# the daemon directly. This will simply be prepended to the daemon invocation. -# These variables have the form daemon_wrap, where 'daemon' is the name of the -# daemon (the same pattern as the daemon_options variables). -# -# Note that when daemons are started, they are told to daemonize with the `-d` -# option. This has several implications. For one, the init script expects that -# when it invokes a daemon, the invocation returns immediately. If you add a -# wrap command here, it must comply with this expectation and daemonize as -# well, or the init script will never return. Furthermore, because daemons are -# themselves daemonized with -d, you must ensure that your wrapper command is -# capable of following child processes after a fork() if you need it to do so. -# -# If your desired wrapper does not support daemonization, you can wrap it with -# a utility program that daemonizes programs, such as 'daemonize'. An example -# of this might look like: -# -# bgpd_wrap="/usr/bin/daemonize /usr/bin/mywrapper" -# -# This is particularly useful for programs which record processes but lack -# daemonization options, such as perf and rr. -# -# If you wish to wrap all daemons in the same way, you may set the "all_wrap" -# variable. -# -#all_wrap="" diff --git a/packaging/preinstall.sh b/packaging/preinstall.sh deleted file mode 100755 index b18add2..0000000 --- a/packaging/preinstall.sh +++ /dev/null @@ -1,4 +0,0 @@ -#/bin/sh - -dpkg-divert --package orion-backbone --add --rename \ - --divert /etc/frr/daemons.original /etc/frr/daemons From 41a135b23eca0808870eb29439458629d51c2f46 Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Sun, 2 Feb 2025 16:34:16 +0400 Subject: [PATCH 09/13] add vagrant configuration files for simulation --- .gitignore | 1 + .goreleaser.yaml | 2 +- Makefile | 3 +++ Vagrantfile | 42 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 Makefile create mode 100644 Vagrantfile diff --git a/.gitignore b/.gitignore index f752f81..a94c6cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ target/ .idea/ dist/ +.vagrant \ No newline at end of file diff --git a/.goreleaser.yaml b/.goreleaser.yaml index e13d4f2..d56ea3a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -71,7 +71,7 @@ nfpms: postinstall: ./packaging/postinstall.sh # Version Release. - release: 1 + release: "1" # Section. section: default diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6ccf0ad --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +build-apk: + goreleaser release --snapshot --clean +.PHONY: build-apk \ No newline at end of file diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..e2c3e92 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,42 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + config.vm.box = "debian/bookworm64" + + config.vm.provision "shell", inline: <<-SHELL + apt-get update && apt-get install -y curl + curl -s https://deb.frrouting.org/frr/keys.gpg | tee /usr/share/keyrings/frrouting.gpg > /dev/null + echo deb '[signed-by=/usr/share/keyrings/frrouting.gpg]' https://deb.frrouting.org/frr $(lsb_release -s -c) frr-stable | tee -a /etc/apt/sources.list.d/frr.list + apt-get update && apt-get install --allow-downgrades -y /vagrant/dist/orion-backbone_*_amd64.deb + SHELL + + config.vm.define "registry" do |registry| + registry.vm.network "private_network", ip: "192.168.50.200" + registry.vm.hostname = "registry" + + registry.vm.provision "shell", inline: <<-SHELL + cp /vagrant/secret/registry/registry.pem /etc/oriond/identity.pem + systemctl enable --now orion-registry + SHELL + registry.vm.network "forwarded_port", guest: 64431, host: 64431 + end + + # Provision two orion node VMs + (0..1).each do |n| + config.vm.define "node#{n}" do |node| + node.vm.network "private_network", ip: "192.168.50.1#{n}" + node.vm.hostname = "node#{n}" + + node.vm.provision "shell", inline: %{ + sed -i "s/bgpd=no/bgpd=yes/g" /etc/frr/daemons + sed -i "s/pimd=no/pimd=yes/g" /etc/frr/daemons + sed -i "s/pim6d=no/pim6d=yes/g" /etc/frr/daemons + systemctl restart frr + cp /vagrant/secret/node#{n}/identity.pem /etc/oriond/identity.pem + echo "192.168.50.200 reg.orionet.re" \> /etc/hosts + systemctl enable --now oriond + } + end + end +end From edbb96500368d62f1b50312e3719c2907b69f68b Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Sun, 2 Feb 2025 16:34:36 +0400 Subject: [PATCH 10/13] enable debug mode by default --- packaging/orion-registry | 2 +- packaging/oriond | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/orion-registry b/packaging/orion-registry index ab91f28..0978f05 100644 --- a/packaging/orion-registry +++ b/packaging/orion-registry @@ -1 +1 @@ -TERM="" +TERM="-debug" diff --git a/packaging/oriond b/packaging/oriond index ab91f28..0978f05 100644 --- a/packaging/oriond +++ b/packaging/oriond @@ -1 +1 @@ -TERM="" +TERM="-debug" From a572477e662bf37aecf24ca8d95511c911a0bc61 Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Sun, 2 Feb 2025 16:35:58 +0400 Subject: [PATCH 11/13] add state dump endpoint --- bin/oriond-mock/.gitignore | 1 - bin/{oriond-mock => oriond}/oriond.go | 2 +- bin/registry/main.go | 6 +--- bin/registry/server/protocol/client.go | 18 ++++++------ bin/registry/server/server.go | 7 +++-- bin/registry/server/upgrade.go | 7 +++++ go.mod | 2 +- go.sum | 2 -- internal/state/edge.go | 39 ++++++++++++++++++-------- internal/state/event.go | 22 +++++++++++++-- internal/state/kinds.go | 3 ++ internal/state/registry.go | 36 ++++++++++++------------ internal/state/router.go | 15 +++++----- 13 files changed, 100 insertions(+), 60 deletions(-) delete mode 100644 bin/oriond-mock/.gitignore rename bin/{oriond-mock => oriond}/oriond.go (98%) diff --git a/bin/oriond-mock/.gitignore b/bin/oriond-mock/.gitignore deleted file mode 100644 index 612424a..0000000 --- a/bin/oriond-mock/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.pem \ No newline at end of file diff --git a/bin/oriond-mock/oriond.go b/bin/oriond/oriond.go similarity index 98% rename from bin/oriond-mock/oriond.go rename to bin/oriond/oriond.go index a587f51..8f5b76e 100644 --- a/bin/oriond-mock/oriond.go +++ b/bin/oriond/oriond.go @@ -21,7 +21,7 @@ import ( var ( enable_prof = flag.Bool("enable-pprof", false, "enable pprof for debugging") debug = flag.Bool("debug", false, "change the log level to debug") - registryServer = flag.String("registry-server", "reg.orionet.re:6443", "the address of the registry server") + registryServer = flag.String("registry-server", "reg.orionet.re:64431", "the address of the registry server") pprof = flag.String("debug-pprof", "0.0.0.0:6061", "") ) diff --git a/bin/registry/main.go b/bin/registry/main.go index 5c3f2f8..006441f 100644 --- a/bin/registry/main.go +++ b/bin/registry/main.go @@ -18,7 +18,7 @@ var ( pprof = flag.String("debug-pprof", "127.0.0.1:6060", "") enable_prof = flag.Bool("enable-pprof", false, "enable pprof for debugging") debug = flag.Bool("debug", false, "change the log level to debug") - listeningHost = flag.String("listen-host", "127.0.0.1:6443", "the port the server will listen on") + listeningHost = flag.String("listen-host", "0.0.0.0:64431", "the port the server will listen on") ) func main() { @@ -51,10 +51,6 @@ func main() { MinVersion: tls.VersionTLS13, CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256}, CipherSuites: []uint16{ - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - tls.TLS_RSA_WITH_AES_256_GCM_SHA384, - tls.TLS_RSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, }, diff --git a/bin/registry/server/protocol/client.go b/bin/registry/server/protocol/client.go index ff4671c..3315c77 100644 --- a/bin/registry/server/protocol/client.go +++ b/bin/registry/server/protocol/client.go @@ -12,7 +12,7 @@ import ( "github.com/rs/zerolog/log" ) -var orionRegistryState *state.OrionRegistryState = state.NewOrionRegistryState() +var OrionRegistryState *state.OrionRegistryState = state.NewOrionRegistryState() type Client struct { ctx context.Context @@ -48,13 +48,13 @@ func (c *Client) startRoutine(sessionId string) { c.log.Debug().Msg("connection handling routine started") // check if the router exists - rtrs := orionRegistryState.GetRouters() + rtrs := OrionRegistryState.GetRouters() rtr := rtrs[c.identity] if rtr == nil { c.log.Debug().Msg("initialized a new state plane router object") - rtr = state.NewRouter(context.Background(), c.identity, orionRegistryState) + rtr = state.NewRouter(context.Background(), c.identity, OrionRegistryState) // dispatch new router if the given router doesn't exist - orionRegistryState.DispatchNewRouterEvent( + OrionRegistryState.DispatchNewRouterEvent( rtr, ) } else { @@ -67,9 +67,9 @@ func (c *Client) startRoutine(sessionId string) { } else { c.log.Debug().Msg("deleted old session, initializing new session") rtr.Dispose() - rtr = state.NewRouter(context.Background(), c.identity, orionRegistryState) + rtr = state.NewRouter(context.Background(), c.identity, OrionRegistryState) // dispatch new router if the given router doesn't exist - orionRegistryState.DispatchNewRouterEvent( + OrionRegistryState.DispatchNewRouterEvent( rtr, ) } @@ -134,13 +134,13 @@ func (c *Client) startRoutine(sessionId string) { case state.RouterInitiateRequest: c.log.Info().Msgf("received a router connect event to %d", *message.Identity) - routers := orionRegistryState.GetRouters() + routers := OrionRegistryState.GetRouters() if routers[*message.Identity] == nil || routers[c.identity] == nil { goto end } - orionRegistryState.DispatchNewEdge( - state.NewEdge(context.Background(), routers[*message.Identity], routers[c.identity], orionRegistryState), + OrionRegistryState.DispatchNewEdge( + state.NewEdge(context.Background(), routers[*message.Identity], routers[c.identity], OrionRegistryState), ) continue diff --git a/bin/registry/server/server.go b/bin/registry/server/server.go index 1d7280d..8a26d34 100644 --- a/bin/registry/server/server.go +++ b/bin/registry/server/server.go @@ -1,6 +1,7 @@ package server import ( + "io/fs" "net/http" ) @@ -10,10 +11,12 @@ func (c *Server) Handler() *http.ServeMux { mux := http.NewServeMux() // Serve the static files - fs := http.FileServer(http.FS(assets)) - mux.Handle("/", http.StripPrefix("/static", fs)) + fSys, _ := fs.Sub(fs.FS(assets), "static") + fs := http.FileServer(http.FS(fSys)) + mux.Handle("/", fs) mux.HandleFunc("/whoami", c.whoami) mux.HandleFunc("/ws", c.upgrade) + mux.HandleFunc("/state", c.state) return mux } diff --git a/bin/registry/server/upgrade.go b/bin/registry/server/upgrade.go index f2e65a9..19cb17a 100644 --- a/bin/registry/server/upgrade.go +++ b/bin/registry/server/upgrade.go @@ -1,6 +1,7 @@ package server import ( + "encoding/json" "net/http" "strconv" "strings" @@ -20,6 +21,12 @@ func upgradeErrorPage(w http.ResponseWriter) { w.Write(file) } +func (c *Server) state(w http.ResponseWriter, r *http.Request) { + s, _ := json.Marshal(protocol.OrionRegistryState) + w.Header().Add("Content-Type", "application/json") + w.Write(s) +} + func (c *Server) upgrade(w http.ResponseWriter, r *http.Request) { if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 { upgradeErrorPage(w) diff --git a/go.mod b/go.mod index 7475e46..1c4d0f4 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/teivah/broadcast v0.1.0 github.com/vishvananda/netlink v1.1.0 + golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 ) @@ -20,7 +21,6 @@ require ( github.com/mdlayher/socket v0.4.1 // indirect github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect golang.org/x/crypto v0.27.0 // indirect - golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/sync v0.9.0 // indirect golang.org/x/sys v0.25.0 // indirect diff --git a/go.sum b/go.sum index 1d8fbcd..c6c6927 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,6 @@ golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+h golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/state/edge.go b/internal/state/edge.go index 16e8066..e382ca1 100644 --- a/internal/state/edge.go +++ b/internal/state/edge.go @@ -41,7 +41,7 @@ func NewEdge( identity := edge.EdgeId() logger := log.With().Uint32("edge-identity", uint32(identity)).Logger() - logger.Debug().Msg("new router session initiated") + logger.Debug().Msg("new edge session initiated") edge.log = logger return edge @@ -50,7 +50,24 @@ func NewEdge( func (c *Edge) EdgeId() EdgeIdentity { ids := []uint32{uint32(c.RouterA.Identity), uint32(c.RouterB.Identity)} slices.Sort(ids) - return EdgeIdentity(uint64(ids[0]) << 32 & uint64(ids[1])) + return EdgeIdentity((uint64(ids[0])+1)<<32 + (uint64(ids[1]) + 1)) +} + +func (c *Edge) waitForSeed(token string) (*struct{}, error) { + for { + select { + case <-c.RouterA.routerObjectContext.Done(): + case <-c.RouterB.routerObjectContext.Done(): + case <-c.edgeObjectContext.Done(): + c.seeded = nil + c.log.Debug().Err(c.edgeObjectContext.Err()).Msg("edge context is finished") + return nil, c.edgeObjectContext.Err() + case data := <-c.seeded: + c.seeded = nil + return &data, nil + } + } + } // Sends a new initialization step to both the peers @@ -72,28 +89,28 @@ func (c *Edge) Initialize() { c.log.Debug().Msg("edge instance started") c.seeded = make(chan struct{}) - // send a message to the routerA, requesting a new tunnel connection. c.RouterA.Dispatch(CreateEdgeRequest{}) + if _, err := c.waitForSeed("token!"); err == nil { - // wait for routerA to seed his tunnel information - <-c.seeded - c.seeded = make(chan struct{}) + } else { + return + } + c.seeded = make(chan struct{}) // send a message to the routerB, requesting a new tunnel connection. c.RouterB.Dispatch(CreateEdgeRequest{}) + if _, err := c.waitForSeed("token!"); err == nil { - // wait for routerB to seed his tunnel information - <-c.seeded + } else { + return + } c.seeded = make(chan struct{}) c.RouterA.Dispatch(SeedEdgeRequest{}) - <-c.seeded c.seeded = make(chan struct{}) c.RouterB.Dispatch(SeedEdgeRequest{}) - <-c.seeded - c.seeded = nil } func (c *Edge) Dispose() { diff --git a/internal/state/event.go b/internal/state/event.go index 64fe3c2..fcdfa09 100644 --- a/internal/state/event.go +++ b/internal/state/event.go @@ -3,6 +3,7 @@ package state import ( "encoding/json" "fmt" + "reflect" ) // Meta interface holding the different events @@ -41,8 +42,6 @@ func UnmarshalEvent( default: return nil, fmt.Errorf("unknown event for deserialize") } - - return nil, fmt.Errorf("not implemented") } func MarshalEvent( @@ -77,9 +76,26 @@ func MarshalEvent( Content: bytes, }, nil case CreateEdgeRequest: + bytes, err := json.Marshal(event) + if err != nil { + return nil, err + } + return &JsonEvent{ + Kind: MessageKindCreateEdgeRequest, + Content: bytes, + }, nil case CreateEdgeResponse: + bytes, err := json.Marshal(event) + if err != nil { + return nil, err + } + return &JsonEvent{ + Kind: MessageKindCreateEdgeResponse, + Content: bytes, + }, nil case SeedEdgeRequest: + } - return nil, fmt.Errorf("event serialization not supported") + return nil, fmt.Errorf("event serialization not supported %s", reflect.TypeOf(event)) } diff --git a/internal/state/kinds.go b/internal/state/kinds.go index 4d6ac61..eda07df 100644 --- a/internal/state/kinds.go +++ b/internal/state/kinds.go @@ -10,6 +10,9 @@ const ( MessageKindRouterConnect = "new_router" // Sent by a peer that wants to initialize a new peer-to-peer link MessageKindRouterEdgeConnectInitializeRequest = "edge_initialize_request" + MessageKindCreateEdgeRequest = "edge_create_edge_request" + MessageKindCreateEdgeResponse = "edge_create_edge_response" + MessageKindSeedEdgeRequest = "edge_seed_request" // Event emitted once an edge is destroyed MessageKindRouterEdgeTeardown = "edge_teardown" diff --git a/internal/state/registry.go b/internal/state/registry.go index ca5ff68..e9aa458 100644 --- a/internal/state/registry.go +++ b/internal/state/registry.go @@ -13,24 +13,24 @@ type OrionRegistryEdgesState map[EdgeIdentity]*Edge // component, that handles all the connection // initialization system. type OrionRegistryState struct { - routers OrionRegistryRoutersState // List of routers + Routers OrionRegistryRoutersState `json:"routers"` // List of routers routersLock sync.Mutex - edges OrionRegistryEdgesState // List of edges in the orion graph + Edges OrionRegistryEdgesState `json:"edges"` // List of edges in the orion graph edgesLock sync.Mutex } func NewOrionRegistryState() *OrionRegistryState { return &OrionRegistryState{ - routers: make(OrionRegistryRoutersState), + Routers: make(OrionRegistryRoutersState), routersLock: sync.Mutex{}, - edges: make(OrionRegistryEdgesState), + Edges: make(OrionRegistryEdgesState), edgesLock: sync.Mutex{}, } } func (c *OrionRegistryState) GetRouters() OrionRegistryRoutersState { - return c.routers + return c.Routers } // Called once a new member is joining the network @@ -40,9 +40,9 @@ func (c *OrionRegistryState) DispatchNewRouterEvent( c.routersLock.Lock() defer c.routersLock.Unlock() - c.routers[RouterIdentity(newRouter.Identity)] = newRouter + c.Routers[RouterIdentity(newRouter.Identity)] = newRouter - for _, router := range c.routers { + for _, router := range c.Routers { if router.Identity != newRouter.Identity { router.Dispatch(RouterConnectEvent{ Router: newRouter, @@ -55,15 +55,15 @@ func (c *OrionRegistryState) DispatchNewRouterEvent( func (c *OrionRegistryState) DispatchRouterRemovedEvent( deletedRouter *Router, ) { - if c.routers[deletedRouter.Identity] == nil { + if c.Routers[deletedRouter.Identity] == nil { return } c.routersLock.Lock() defer c.routersLock.Unlock() - c.routers[deletedRouter.Identity].dispose() - c.routers[deletedRouter.Identity] = nil + c.Routers[deletedRouter.Identity].dispose() + delete(c.Routers, deletedRouter.Identity) } // Dispatch new connection @@ -80,28 +80,28 @@ func (c *OrionRegistryState) DispatchNewEdge( } c.edgesLock.Lock() - defer c.edgesLock.Unlock() - // concatenate the bits edgeId := edge.EdgeId() - c.edges[edgeId] = edge + c.Edges[edgeId] = edge + + c.edgesLock.Unlock() edge.Initialize() } func (c *OrionRegistryState) DispatchEdgeRemovedEvent(edge *Edge) { - log.Debug().Msg("edge got removed") - - if c.edges[edge.EdgeId()] == nil { + if c.Edges[edge.EdgeId()] == nil { return } + log.Debug().Int32("edge-id", int32(edge.EdgeId())).Msg("edge got removed") c.edgesLock.Lock() defer c.edgesLock.Unlock() + log.Debug().Int32("edge-id", int32(edge.EdgeId())).Msg("edge got removed") // edge.RouterA.DispatchEdgeRemovedEvent(edge) // edge.RouterB.DispatchEdgeRemovedEvent(edge) - c.edges[edge.EdgeId()].dispose() - c.edges[edge.EdgeId()] = nil + c.Edges[edge.EdgeId()].dispose() + delete(c.Edges, edge.EdgeId()) } diff --git a/internal/state/router.go b/internal/state/router.go index 63da839..e9b03f4 100644 --- a/internal/state/router.go +++ b/internal/state/router.go @@ -22,8 +22,8 @@ type Router struct { routerObjectContextCancel context.CancelCauseFunc connectionsCount atomic.Int32 connectionTimeoutContextCancel context.CancelCauseFunc - pendingTeardown bool - session string + PendingTeardown bool `json:"pendingTeardown"` + Session string `json:"_session"` globalState *OrionRegistryState log zerolog.Logger @@ -55,14 +55,14 @@ func NewRouter( routerObjectContext: ctx, routerObjectContextCancel: cancel, globalState: globalState, - session: session, + Session: session, log: logger, - pendingTeardown: false, + PendingTeardown: false, } } func (c *Router) SessionId() string { - return c.session + return c.Session } func (c *Router) Subscribe() *broadcast.Listener[*JsonEvent] { @@ -79,7 +79,7 @@ func (c *Router) DecrementConnectionCount() { } func (c *Router) updateConnectionsCountRoutine() { - if c.pendingTeardown { + if c.PendingTeardown { return } current := c.connectionsCount.Load() @@ -94,6 +94,7 @@ func (c *Router) updateConnectionsCountRoutine() { if current == 0 { ctx, e := context.WithCancelCause(context.Background()) c.connectionTimeoutContextCancel = e + c.PendingTeardown = true // we launch a background task ticking for either // 1. the session timeout mechanism @@ -128,6 +129,7 @@ func (c *Router) updateConnectionsCountRoutine() { break } } + c.PendingTeardown = false goto end case <-timeout.C: log.Debug().Msg("session expired") @@ -154,7 +156,6 @@ func (c *Router) Dispatch(router Event) { } func (c *Router) dispose() { - c.pendingTeardown = true c.routerObjectContextCancel(fmt.Errorf("router is disposed")) c.log.Debug().Msg("context canceled") c.sending.Close() From 5e0752cf2e52b3527b26984fe70cd290448093a2 Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Sun, 2 Feb 2025 20:54:13 +0400 Subject: [PATCH 12/13] basic vagrant and edge creation infrastructure --- Vagrantfile | 2 +- bin/oriond/oriond.go | 21 ++++- bin/registry/server/protocol/client.go | 7 +- internal/state/edge.go | 102 ++++++++++++++++------ internal/state/edge_events.go | 23 +++-- internal/state/event.go | 114 +++++++++---------------- internal/state/registry.go | 12 +-- internal/state/router.go | 16 +++- internal/state/router_events.go | 4 + 9 files changed, 175 insertions(+), 126 deletions(-) diff --git a/Vagrantfile b/Vagrantfile index e2c3e92..e7eeaf5 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -33,7 +33,7 @@ Vagrant.configure("2") do |config| sed -i "s/pimd=no/pimd=yes/g" /etc/frr/daemons sed -i "s/pim6d=no/pim6d=yes/g" /etc/frr/daemons systemctl restart frr - cp /vagrant/secret/node#{n}/identity.pem /etc/oriond/identity.pem + cp /vagrant/secret/node#{n}/oriond/identity.pem /etc/oriond/identity.pem echo "192.168.50.200 reg.orionet.re" \> /etc/hosts systemctl enable --now oriond } diff --git a/bin/oriond/oriond.go b/bin/oriond/oriond.go index 8f5b76e..2c1b8d0 100644 --- a/bin/oriond/oriond.go +++ b/bin/oriond/oriond.go @@ -98,20 +98,35 @@ func main() { } switch message := out.(type) { - case state.Hello: + case *state.Hello: log.Printf("Hello message: %s", message.Message) continue - case state.RouterConnectEvent: + case *state.RouterConnectEvent: log.Printf("router joined: %d", message.Router.Identity) ev, _ := state.MarshalEvent(state.RouterInitiateRequest{ Identity: &message.Router.Identity, }) c.WriteJSON(ev) + continue + case *state.CreateEdgeRequest: + log.Printf("create edge request received") + + ev, err := state.MarshalEvent(state.CreateEdgeResponse{ + PublicEndpoint: state.Endpoint{ + Address: "localhost", + PublicPort: 9999, + }, + PresharedKeybB4: "Z3LBJMtWxoqPyR/XkGJkbdVUnzLZRkv215El6XuGpLc=", + }) + if err != nil { + panic(err) + } + c.WriteJSON(ev) continue default: - log.Printf("invalid kind error") + log.Printf("invalid kind error: %s %T", msg.Kind, out) } } diff --git a/bin/registry/server/protocol/client.go b/bin/registry/server/protocol/client.go index 3315c77..c164060 100644 --- a/bin/registry/server/protocol/client.go +++ b/bin/registry/server/protocol/client.go @@ -131,7 +131,7 @@ func (c *Client) startRoutine(sessionId string) { switch message := out.(type) { // sent once a router wants to connect to another one - case state.RouterInitiateRequest: + case *state.RouterInitiateRequest: c.log.Info().Msgf("received a router connect event to %d", *message.Identity) routers := OrionRegistryState.GetRouters() @@ -143,6 +143,10 @@ func (c *Client) startRoutine(sessionId string) { state.NewEdge(context.Background(), routers[*message.Identity], routers[c.identity], OrionRegistryState), ) + continue + case *state.CreateEdgeResponse: + c.log.Info().Msgf("got create edge response") + c.router.EdgeResponseCallback(*message) continue default: c.log.Error().Str("event", event.Kind).Msg("unknown event type") @@ -152,6 +156,7 @@ func (c *Client) startRoutine(sessionId string) { end: cancel(fmt.Errorf("the websocket listening is finished")) + c.log.Error().Msg("event handler is finished") }() // wait for the context to be finished diff --git a/internal/state/edge.go b/internal/state/edge.go index e382ca1..09449b1 100644 --- a/internal/state/edge.go +++ b/internal/state/edge.go @@ -2,8 +2,11 @@ package state import ( "context" + "crypto/rand" + "encoding/base64" "fmt" "slices" + "time" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -16,7 +19,6 @@ type Edge struct { edgeObjectContext context.Context edgeObjectContextCancel context.CancelCauseFunc - seeded chan struct{} globalState *OrionRegistryState log zerolog.Logger @@ -53,21 +55,38 @@ func (c *Edge) EdgeId() EdgeIdentity { return EdgeIdentity((uint64(ids[0])+1)<<32 + (uint64(ids[1]) + 1)) } -func (c *Edge) waitForSeed(token string) (*struct{}, error) { - for { - select { - case <-c.RouterA.routerObjectContext.Done(): - case <-c.RouterB.routerObjectContext.Done(): - case <-c.edgeObjectContext.Done(): - c.seeded = nil - c.log.Debug().Err(c.edgeObjectContext.Err()).Msg("edge context is finished") - return nil, c.edgeObjectContext.Err() - case data := <-c.seeded: - c.seeded = nil - return &data, nil - } +func (c *Edge) seedEdgeAndWait( + router *Router, + othrIdentity RouterIdentity, +) (*CreateEdgeResponse, error) { + chanCallback := make(chan CreateEdgeResponse) + router.edgeResponseCallback = &chanCallback + // send a message to the routerA, requesting a new tunnel connection. + router.Dispatch(CreateEdgeRequest{ + PeerID: othrIdentity, + EdgeID: c.EdgeId(), + }) + + ticker := time.NewTimer(time.Second * 60) + select { + case <-c.RouterA.routerObjectContext.Done(): + goto end + case <-c.RouterB.routerObjectContext.Done(): + goto end + case <-ticker.C: + goto end + case <-c.edgeObjectContext.Done(): + goto end + case data := <-chanCallback: + router.edgeResponseCallback = nil + return &data, nil } +end: + router.edgeResponseCallback = nil + err := fmt.Errorf("timeout reached while waiting for seeding") + c.log.Debug().Err(err).Msg("timeout reached while waiting") + return nil, err } // Sends a new initialization step to both the peers @@ -88,34 +107,61 @@ func (c *Edge) Initialize() { c.log.Debug().Msg("edge instance started") - c.seeded = make(chan struct{}) - // send a message to the routerA, requesting a new tunnel connection. - c.RouterA.Dispatch(CreateEdgeRequest{}) - if _, err := c.waitForSeed("token!"); err == nil { + seedRouterA, err := c.seedEdgeAndWait(c.RouterA, c.RouterB.Identity) + if err != nil { + c.log.Err(err) + c.Dispose() + return + } + c.log.Debug().Msg("edge seeding (1/2)") - } else { + seedRouterB, err := c.seedEdgeAndWait(c.RouterB, c.RouterA.Identity) + if err != nil { + c.log.Err(err) + c.Dispose() return } - c.seeded = make(chan struct{}) - // send a message to the routerB, requesting a new tunnel connection. - c.RouterB.Dispatch(CreateEdgeRequest{}) - if _, err := c.waitForSeed("token!"); err == nil { + c.log.Debug().Msg("got initialzation data, seeding edges") - } else { + bytesA, err := base64.StdEncoding.DecodeString(seedRouterA.PresharedKeybB4) + if err != nil { + c.log.Err(err) + c.Dispose() + return + } + bytesB, err := base64.StdEncoding.DecodeString(seedRouterB.PresharedKeybB4) + if err != nil { + c.log.Err(err) + c.Dispose() return } - c.seeded = make(chan struct{}) - c.RouterA.Dispatch(SeedEdgeRequest{}) + var random [32]byte + for i := range 32 { + token := make([]byte, 1) + rand.Read(token) + random[i] = bytesA[i] ^ bytesB[i] ^ token[0] + } - c.seeded = make(chan struct{}) - c.RouterB.Dispatch(SeedEdgeRequest{}) + presharedKey := base64.StdEncoding.EncodeToString(random[:]) + + c.log.Debug().Msg("seeding edges") + c.RouterA.Dispatch(SeedEdgeRequest{ + OtherPeer: seedRouterB.PublicEndpoint, + PresharedKey: presharedKey, + }) + c.RouterB.Dispatch(SeedEdgeRequest{ + OtherPeer: seedRouterB.PublicEndpoint, + PresharedKey: presharedKey, + }) } func (c *Edge) Dispose() { + c.log.Debug().Msg("dispose") c.globalState.DispatchEdgeRemovedEvent(c) } func (c *Edge) dispose() { + c.log.Debug().Msg("internal: disposing") c.edgeObjectContextCancel(fmt.Errorf("edge is finished")) } diff --git a/internal/state/edge_events.go b/internal/state/edge_events.go index cd47078..74f89e4 100644 --- a/internal/state/edge_events.go +++ b/internal/state/edge_events.go @@ -1,22 +1,21 @@ package state -type NewEdgeEvent struct { - Router *Edge +type CreateEdgeRequest struct { + PeerID RouterIdentity // other user id + EdgeID EdgeIdentity // edge object id } -type AskForNewEdge struct { - OtherNode *Router +type Endpoint struct { + Address string // v4 address + PublicPort uint16 } -type CreateEdgeRequest struct{} -type CreateEdgeResponse struct{} - -type SeedEdgePeer struct { - PublicKey string - PresharedKey string - DefaultRoute bool +type CreateEdgeResponse struct { + PublicEndpoint Endpoint + PresharedKeybB4 string } type SeedEdgeRequest struct { - Peers []SeedEdgePeer + OtherPeer Endpoint + PresharedKey string } diff --git a/internal/state/event.go b/internal/state/event.go index fcdfa09..065ad7a 100644 --- a/internal/state/event.go +++ b/internal/state/event.go @@ -14,88 +14,54 @@ type JsonEvent struct { Content json.RawMessage `json:"e"` } +func reverseMap[M ~map[K]V, K comparable, V comparable](m M) map[V]K { + reversedMap := make(map[V]K) + for key, value := range m { + reversedMap[value] = key + } + return reversedMap +} + +var ( + TypesEvents = map[string]reflect.Type{ + MessageKindHello: reflect.TypeOf(Hello{}), + MessageKindRouterConnect: reflect.TypeOf(RouterConnectEvent{}), + MessageKindRouterEdgeConnectInitializeRequest: reflect.TypeOf(RouterInitiateRequest{}), + MessageKindCreateEdgeRequest: reflect.TypeOf(CreateEdgeRequest{}), + MessageKindCreateEdgeResponse: reflect.TypeOf(CreateEdgeResponse{}), + MessageKindSeedEdgeRequest: reflect.TypeOf(SeedEdgeRequest{}), + MessageKindRouterEdgeTeardown: reflect.TypeOf(RouterEdgeRemovedEvent{}), + } + TypesEventsReverse = reverseMap(TypesEvents) +) + func UnmarshalEvent( event JsonEvent, ) (Event, error) { - switch event.Kind { - case MessageKindHello: - hello := Hello{} - if err := json.Unmarshal(event.Content, &hello); err != nil { - return nil, err - } - return hello, nil - case MessageKindRouterConnect: - hello := RouterConnectEvent{} - if err := json.Unmarshal(event.Content, &hello); err != nil { - return nil, err - } - return hello, nil - case MessageKindRouterEdgeConnectInitializeRequest: - hello := RouterInitiateRequest{} - if err := json.Unmarshal(event.Content, &hello); err != nil { - return nil, err - } - return hello, nil - case MessageKindRouterEdgeTeardown: - - return nil, fmt.Errorf("not implemented") - default: - return nil, fmt.Errorf("unknown event for deserialize") + type_ := TypesEvents[event.Kind] + if type_ == nil { + return nil, fmt.Errorf("cannot unmarshal type: unknown message kind") + } + data := reflect.New(type_).Interface() + if err := json.Unmarshal(event.Content, &data); err != nil { + return nil, err } + return data, nil } func MarshalEvent( event Event, ) (*JsonEvent, error) { - switch event := event.(type) { - case Hello: - bytes, err := json.Marshal(event) - if err != nil { - return nil, err - } - return &JsonEvent{ - Kind: MessageKindHello, - Content: bytes, - }, nil - case RouterConnectEvent: - bytes, err := json.Marshal(event) - if err != nil { - return nil, err - } - return &JsonEvent{ - Kind: MessageKindRouterConnect, - Content: bytes, - }, nil - case RouterInitiateRequest: - bytes, err := json.Marshal(event) - if err != nil { - return nil, err - } - return &JsonEvent{ - Kind: MessageKindRouterEdgeConnectInitializeRequest, - Content: bytes, - }, nil - case CreateEdgeRequest: - bytes, err := json.Marshal(event) - if err != nil { - return nil, err - } - return &JsonEvent{ - Kind: MessageKindCreateEdgeRequest, - Content: bytes, - }, nil - case CreateEdgeResponse: - bytes, err := json.Marshal(event) - if err != nil { - return nil, err - } - return &JsonEvent{ - Kind: MessageKindCreateEdgeResponse, - Content: bytes, - }, nil - case SeedEdgeRequest: - + type_ := TypesEventsReverse[reflect.TypeOf(event)] + if type_ == "" { + return nil, fmt.Errorf("cannot marshal type: unknown message kind %T", event) } - - return nil, fmt.Errorf("event serialization not supported %s", reflect.TypeOf(event)) + bytes, err := json.Marshal(event) + if err != nil { + return nil, err + } + return &JsonEvent{ + Kind: type_, + Content: bytes, + }, nil } diff --git a/internal/state/registry.go b/internal/state/registry.go index e9aa458..2a4b343 100644 --- a/internal/state/registry.go +++ b/internal/state/registry.go @@ -80,13 +80,11 @@ func (c *OrionRegistryState) DispatchNewEdge( } c.edgesLock.Lock() - // concatenate the bits edgeId := edge.EdgeId() c.Edges[edgeId] = edge - c.edgesLock.Unlock() - edge.Initialize() + go edge.Initialize() } func (c *OrionRegistryState) DispatchEdgeRemovedEvent(edge *Edge) { @@ -97,10 +95,12 @@ func (c *OrionRegistryState) DispatchEdgeRemovedEvent(edge *Edge) { c.edgesLock.Lock() defer c.edgesLock.Unlock() - log.Debug().Int32("edge-id", int32(edge.EdgeId())).Msg("edge got removed") - // edge.RouterA.DispatchEdgeRemovedEvent(edge) - // edge.RouterB.DispatchEdgeRemovedEvent(edge) + edgeRemovedEvent := RouterEdgeRemovedEvent{ + Edge: edge, + } + edge.RouterA.Dispatch(edgeRemovedEvent) + edge.RouterB.Dispatch(edgeRemovedEvent) c.Edges[edge.EdgeId()].dispose() delete(c.Edges, edge.EdgeId()) diff --git a/internal/state/router.go b/internal/state/router.go index e9b03f4..3f888e1 100644 --- a/internal/state/router.go +++ b/internal/state/router.go @@ -23,7 +23,9 @@ type Router struct { connectionsCount atomic.Int32 connectionTimeoutContextCancel context.CancelCauseFunc PendingTeardown bool `json:"pendingTeardown"` - Session string `json:"_session"` + Session string `json:"-"` + + edgeResponseCallback *chan CreateEdgeResponse globalState *OrionRegistryState log zerolog.Logger @@ -164,3 +166,15 @@ func (c *Router) dispose() { func (c *Router) Dispose() { c.globalState.DispatchRouterRemovedEvent(c) } + +func (c *Router) EdgeResponseCallback( + response CreateEdgeResponse, +) { + fmt.Println("got edge response callback") + if c.edgeResponseCallback != nil { + (*c.edgeResponseCallback) <- response + } else { + + fmt.Println("ignored because no handler") + } +} diff --git a/internal/state/router_events.go b/internal/state/router_events.go index ce2cf6f..c55173e 100644 --- a/internal/state/router_events.go +++ b/internal/state/router_events.go @@ -8,6 +8,10 @@ type RouterInitiateRequest struct { Identity *RouterIdentity } +type RouterEdgeRemovedEvent struct { + Edge *Edge +} + type Hello struct { Message string `json:"message"` Identity RouterIdentity `json:"identity"` From ff1d1633dd3dc9c303187e43d451e3222a13646b Mon Sep 17 00:00:00 2001 From: Matthieu Pignolet Date: Tue, 4 Feb 2025 08:40:31 +0400 Subject: [PATCH 13/13] change namespace --- Vagrantfile | 6 +- bin/oriond/implementation/frr/frr_manager.go | 170 +++++++++++++++++++ bin/oriond/implementation/handler.go | 9 + bin/oriond/implementation/identity.go | 43 +++++ bin/oriond/implementation/link/background.go | 70 ++++++++ bin/oriond/implementation/link/dispose.go | 17 ++ bin/oriond/implementation/link/handler.go | 1 + bin/oriond/implementation/link/holepunch.go | 65 +++++++ bin/oriond/implementation/link/initialize.go | 79 +++++++++ bin/oriond/implementation/link/link.go | 102 +++++++++++ bin/oriond/implementation/oriond.go | 87 ++++++++++ bin/oriond/oriond.go | 149 +++++----------- bin/registry/main.go | 4 +- bin/registry/server/holepunch.go | 168 ++++++++++++++++++ bin/registry/server/protocol/client.go | 4 +- bin/registry/server/server.go | 7 +- bin/registry/server/upgrade.go | 4 +- go.mod | 24 ++- go.sum | 33 ++++ internal/address_plan.go | 12 +- internal/lockable_tasks.go | 1 + internal/state/edge.go | 2 +- internal/state/edge_events.go | 1 + internal/version.go | 16 ++ internal/wg_interface.go | 8 +- 25 files changed, 944 insertions(+), 138 deletions(-) create mode 100644 bin/oriond/implementation/frr/frr_manager.go create mode 100644 bin/oriond/implementation/handler.go create mode 100644 bin/oriond/implementation/identity.go create mode 100644 bin/oriond/implementation/link/background.go create mode 100644 bin/oriond/implementation/link/dispose.go create mode 100644 bin/oriond/implementation/link/handler.go create mode 100644 bin/oriond/implementation/link/holepunch.go create mode 100644 bin/oriond/implementation/link/initialize.go create mode 100644 bin/oriond/implementation/link/link.go create mode 100644 bin/oriond/implementation/oriond.go create mode 100644 bin/registry/server/holepunch.go diff --git a/Vagrantfile b/Vagrantfile index e7eeaf5..40ebf3d 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -12,7 +12,7 @@ Vagrant.configure("2") do |config| SHELL config.vm.define "registry" do |registry| - registry.vm.network "private_network", ip: "192.168.50.200" + registry.vm.network "private_network", ip: "192.168.10.200" registry.vm.hostname = "registry" registry.vm.provision "shell", inline: <<-SHELL @@ -25,7 +25,7 @@ Vagrant.configure("2") do |config| # Provision two orion node VMs (0..1).each do |n| config.vm.define "node#{n}" do |node| - node.vm.network "private_network", ip: "192.168.50.1#{n}" + node.vm.network "private_network", ip: "192.168.10.1#{n}" node.vm.hostname = "node#{n}" node.vm.provision "shell", inline: %{ @@ -34,7 +34,7 @@ Vagrant.configure("2") do |config| sed -i "s/pim6d=no/pim6d=yes/g" /etc/frr/daemons systemctl restart frr cp /vagrant/secret/node#{n}/oriond/identity.pem /etc/oriond/identity.pem - echo "192.168.50.200 reg.orionet.re" \> /etc/hosts + echo "192.168.10.200 reg.orionet.re" \> /etc/hosts systemctl enable --now oriond } end diff --git a/bin/oriond/implementation/frr/frr_manager.go b/bin/oriond/implementation/frr/frr_manager.go new file mode 100644 index 0000000..459b9e9 --- /dev/null +++ b/bin/oriond/implementation/frr/frr_manager.go @@ -0,0 +1,170 @@ +package frr + +import ( + "flag" + "fmt" + "os" + "os/exec" + "sync" + "text/template" + + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +var ( + frrTmplPath = flag.String("frr-config-template", "/etc/oriond/frr.conf.tmpl", "Configuration template for configuring FRR") + frrReloadBinary = flag.String("frr-reload-script", "/usr/lib/frr/frr-reload.py", "Path to the frr-reload.py utility executable") +) + +// Struct containing the information regarding someone ASN on the network. +type group struct { + ASN uint32 + Weight uint32 +} + +// Struct containing a peer in the orion network, this is typically +// on-per-connection. +type Peer struct { + Address string + OrionId uint32 + ASN uint32 + Weight uint32 +} + +// Contest representing th entire state of the frr config file. +type tmplContext struct { + ASN uint32 + OrionId uint32 + Groups []group + Peers []Peer +} + +// Struct used to interact and issue the FRR configuration file updates. +type FrrConfigManager struct { + peers map[uint32]*Peer + selfASN uint32 + OrionId uint32 + template *template.Template + peersLock *sync.RWMutex +} + +// Function used to load the template files. +func loadTmpl() (*template.Template, error) { + content, err := os.ReadFile(*frrTmplPath) + if err != nil { + return nil, err + } + return template.New(*frrTmplPath).Parse(string(content)) +} + +// Function used to create a config-manager instance. +func NewFrrConfigManager(ASN uint32, OrionId uint32) (*FrrConfigManager, error) { + tmpl, err := loadTmpl() + if err != nil { + return nil, err + } + config := &FrrConfigManager{ + peers: map[uint32]*Peer{}, + selfASN: ASN, + OrionId: OrionId, + template: tmpl, + peersLock: &sync.RWMutex{}, + } + + if err = config.Update(); err != nil { + return nil, err + } + + return config, nil +} + +// This functions takes the simplified BGP configuration stored in memory +// and renders a new configuration for the `frr` daemon used to implement +// `bgpd` which is the BGP daemon used through the Orion network. +func (c *FrrConfigManager) Update() error { + log.Debug().Msg("applying a FRR configuration update") + peers := []Peer{} + + c.peersLock.RLock() + defer c.peersLock.RUnlock() + for _, value := range c.peers { + if value != nil { + peers = append(peers, *value) + } + } + + // We initialize some basic information regarding the BGP sessions + // configured for FRR's bgpd. + context := tmplContext{ + ASN: c.selfASN, + OrionId: c.OrionId, + Peers: peers, + Groups: []group{}, + } + + // From the list of peers we infer the list of bgp groups to connect to. + for _, peer := range context.Peers { + if peer.ASN != 0 { + log.Debug().Uint32("asn", peer.ASN).Msg("new group computed") + context.Groups = append(context.Groups, group{ + ASN: peer.ASN, + }) + } + } + + // In order to call the frr-reload.py script, we must render the configuration + // to a file, we choosed to use a temporary file for this purpose. + tempConfig, err := os.CreateTemp("/tmp", "orion-conf-update*.conf") + if err != nil { + log.Error().Err(err).Msg("failed to create the new frr configuration temporary file") + return err + } + // Since all temporary files are in the /tmp directory, we can simply infer the full path. + absolutePath := tempConfig.Name() + + defer func() { + log.Debug().Msg("cleaning up temporary files") + // We do not delete the temporary files when running in debug mode. + if zerolog.GlobalLevel() != zerolog.DebugLevel { + os.Remove(absolutePath) + } + tempConfig.Close() + }() + + // We execute the template with the current context. + err = c.template.Execute(tempConfig, context) + if err != nil { + log.Debug().Err(err).Msg("failed to template the config file") + return err + } + + log.Debug().Str("config-file", absolutePath).Msg("running frr-reload.py") + execReload := exec.Command(*frrReloadBinary, "--reload", absolutePath) + // For debug purposes, we might want to link the frr-reload.py script stdout and stderr to + // the current process ones. + if zerolog.GlobalLevel() == zerolog.DebugLevel { + execReload.Stdout = os.Stdout + execReload.Stderr = os.Stderr + } + + if err := execReload.Run(); err != nil { + // In case of an errornous error code. + if exitError, ok := err.(*exec.ExitError); ok { + return fmt.Errorf("the frr-reload.py script exited with the code %s", exitError) + } + } + + return nil +} + +func (c *FrrConfigManager) UpdatePeer(id uint32, peer *Peer) { + // Locks the peer + c.peersLock.Lock() + defer c.peersLock.Unlock() + c.peers[id] = peer +} + +func (c *FrrConfigManager) GetPeer(id uint32) *Peer { + return c.peers[id] +} diff --git a/bin/oriond/implementation/handler.go b/bin/oriond/implementation/handler.go new file mode 100644 index 0000000..d68e771 --- /dev/null +++ b/bin/oriond/implementation/handler.go @@ -0,0 +1,9 @@ +package implementation + +import "github.com/gorilla/websocket" + +func (c *OrionClientDaemon) ListenOnWS( + connection *websocket.Conn, +) { + +} diff --git a/bin/oriond/implementation/identity.go b/bin/oriond/implementation/identity.go new file mode 100644 index 0000000..27b1c18 --- /dev/null +++ b/bin/oriond/implementation/identity.go @@ -0,0 +1,43 @@ +package implementation + +import ( + "flag" + "strconv" + "strings" + + "github.com/rs/zerolog/log" +) + +var ( + memberIdOverride = flag.Uint("override-member-id", 0, "An override of the memberID of this instance") + asn = flag.Uint("override-asn", 0, "An override of the ASN number used by this instance") +) + +func (c *OrionClientDaemon) resolveIdentity() error { + // If we have a memver-id override + if *memberIdOverride != 0 { + c.memberId = uint32(*memberIdOverride) + } else { + name := c.chain[0].Subject.CommonName + nameParts := strings.Split(name, ":") + + number, err := strconv.ParseInt(nameParts[0], 10, 32) + if err != nil { + log.Error(). + Err(err). + Msg("the member_id field in the certificate couldn't be parsed, please use -override-member-id to specify the member-id") + return err + } + c.memberId = uint32(number) + } + + // We check if we have a asn number override + if *asn != 0 { + c.asn = uint32(*asn) + } else { + // The regular orion as allocation + c.asn = 64511 + c.memberId + } + + return nil +} diff --git a/bin/oriond/implementation/link/background.go b/bin/oriond/implementation/link/background.go new file mode 100644 index 0000000..d6ed025 --- /dev/null +++ b/bin/oriond/implementation/link/background.go @@ -0,0 +1,70 @@ +package link + +import ( + "math" + "time" + + probing "github.com/prometheus-community/pro-bing" + "github.com/rs/zerolog/log" +) + +func (c *PeerLink) updateWeights() error { + log.Debug().Msg("starting to ping") + pinger, err := probing.NewPinger(c.otherIP.IP.String()) + if err != nil { + return err + } + pinger.SetPrivileged(true) + + // Ping one time + pinger.Count = 1 + pinger.Timeout = time.Second * 5 + pinger.InterfaceName = c.wireguardTunnel.WgLink.InterfaceAttrs.Name + + err = pinger.Run() // Blocks until finished. + if err != nil { + return err + } + stats := pinger.Statistics() // get send/receive/duplicate/rtt stats + + latency := stats.AvgRtt + if stats.PacketLoss > 0 { + log.Debug().Msg("ping failed") + latency = time.Hour * 24 * 7 + } + + log.Debug().Dur("ping-reponse", latency).Msg("ping(ed) peer") + + // max( 0, latency ), more when less latency & less with more latency + metric := math.Max(float64(0), float64(int64(500)-latency.Milliseconds())) + peer := c.frrManager.GetPeer(c.otherID) + peer.Weight = uint32(metric) + c.frrManager.UpdatePeer(c.otherID, peer) + c.frrManager.Update() + + return nil +} + +func (c *PeerLink) backgroundTask() { + // We check the status every 60 seconds + timer := time.NewTicker(time.Second * 60) + + for { + select { + case <-timer.C: + if err := c.updateWeights(); err != nil { + log.Error(). + Err(err). + Uint32("peer-id", c.otherID). + Msgf("failed to adjust the weight") + } + + case <-c.ctx.Done(): + log.Error(). + Err(c.ctx.Err()). + Uint32("peer-id", c.otherID). + Msgf("ending the background task") + return + } + } +} diff --git a/bin/oriond/implementation/link/dispose.go b/bin/oriond/implementation/link/dispose.go new file mode 100644 index 0000000..3bbb059 --- /dev/null +++ b/bin/oriond/implementation/link/dispose.go @@ -0,0 +1,17 @@ +package link + +func (c *PeerLink) Dispose() error { + // cancel all the running tasks with the peer's context + c.cancel() + // we remove the frr peer + c.frrManager.UpdatePeer(c.otherID, nil) + err := c.frrManager.Update() + if err != nil { + return err + } + + // we dispose the vpn tunnel + c.wireguardTunnel.Dispose() + + return nil +} diff --git a/bin/oriond/implementation/link/handler.go b/bin/oriond/implementation/link/handler.go new file mode 100644 index 0000000..cf8e7d5 --- /dev/null +++ b/bin/oriond/implementation/link/handler.go @@ -0,0 +1 @@ +package link diff --git a/bin/oriond/implementation/link/holepunch.go b/bin/oriond/implementation/link/holepunch.go new file mode 100644 index 0000000..bc86efb --- /dev/null +++ b/bin/oriond/implementation/link/holepunch.go @@ -0,0 +1,65 @@ +package link + +import ( + "context" + "flag" + "fmt" + + "github.com/orion-network-dev/orion-backbone/internal" + "github.com/orion-network-dev/orion-backbone/internal/state" + "github.com/rs/zerolog/log" + "gitlab.com/NebulousLabs/go-upnp" +) + +var ( + holePunchOverrideAddress = flag.String("override-hole-punch-address", "", "Override the public port for this instance") + holePunchUPNPEnable = flag.Bool("hole-punch-upnp", true, "Specify is uPNP should be enabled") +) + +func (c *PeerLink) upnpInit() { + if *holePunchUPNPEnable { + digd, err := upnp.Discover() + if err != nil { + log.Err(err).Msg("failed to intitialize upnp") + return + } + + ip, err := digd.ExternalIP() + if err != nil { + log.Err(err).Msg("failed to intitialize upnp") + return + } + + log.Info().Msgf("upnp status initialized") + c.externalIP = &ip + c.igd = digd + } +} + +func (c *PeerLink) HolePunchTunnel( + parentCtx context.Context, + tunnel *internal.WireguardInterface, +) *state.Endpoint { + if c.igd != nil { + log.Debug().Msg("trying to open port using upnp") + forwarded, err := c.igd.IsForwardedUDP(uint16(*tunnel.WgConfig.ListenPort)) + if err != nil { + log.Err(err).Msg("failed to open port using upnp") + } else { + if forwarded { + log.Debug().Msg("port already openned using upnp") + return &state.Endpoint{ + Address: *c.externalIP, + PublicPort: uint16(*tunnel.WgConfig.ListenPort), + PublicKey: tunnel.WgConfig.PrivateKey.PublicKey().String(), + } + } + + if err := c.igd.ForwardUDP(uint16(*tunnel.WgConfig.ListenPort), fmt.Sprintf("Used by orion to peer %d", c.otherID)); err != nil { + log.Debug().Msg("failed to pen port using upnp") + } + } + } + + return nil +} diff --git a/bin/oriond/implementation/link/initialize.go b/bin/oriond/implementation/link/initialize.go new file mode 100644 index 0000000..68cc297 --- /dev/null +++ b/bin/oriond/implementation/link/initialize.go @@ -0,0 +1,79 @@ +package link + +import ( + "flag" + "net" + "time" + + "github.com/orion-network-dev/orion-backbone/bin/oriond/implementation/frr" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +var ( + keepAlive = flag.Duration("wireguard-keepalive", time.Minute, "") + + allIP4Ranges = net.IPNet{ + IP: net.IPv4zero, + Mask: net.CIDRMask(0, 32), + } + allIP6Ranges = net.IPNet{ + IP: net.IPv6zero, + Mask: net.CIDRMask(0, 128), + } +) + +func (c *PeerLink) InitializePeerConnection( + Endpoint *net.UDPAddr, + PublicKey wgtypes.Key, + PresharedKey wgtypes.Key, +) error { + c.initialized = true + + // We update our wireguard tunnel to finalize the connection request + err := c.wireguardTunnel.SetPeers( + c.wgClient, + []wgtypes.PeerConfig{ + { + Endpoint: &net.UDPAddr{ + IP: Endpoint.IP, + Port: Endpoint.Port, + }, + PresharedKey: &PresharedKey, + PublicKey: PublicKey, + PersistentKeepaliveInterval: keepAlive, + AllowedIPs: []net.IPNet{ + allIP4Ranges, + allIP6Ranges, + }, + }, + }, + ) + if err != nil { + return err + } + + err = c.wireguardTunnel.SetAddress(c.selfIP) + if err != nil { + return err + } + + // We register our peering to frr + c.frrManager.UpdatePeer(c.otherID, &frr.Peer{ + ASN: c.otherID + 64511, + Address: c.otherIP.IP.String(), + OrionId: c.otherID, + Weight: 0, + }) + err = c.frrManager.Update() + if err != nil { + return err + } + + // We launch our monitoring task + go func() { + time.Sleep(time.Second * 5) + c.backgroundTask() + }() + + return nil +} diff --git a/bin/oriond/implementation/link/link.go b/bin/oriond/implementation/link/link.go new file mode 100644 index 0000000..82595c2 --- /dev/null +++ b/bin/oriond/implementation/link/link.go @@ -0,0 +1,102 @@ +package link + +import ( + "context" + "flag" + "fmt" + "net" + + "github.com/orion-network-dev/orion-backbone/bin/oriond/implementation/frr" + "github.com/orion-network-dev/orion-backbone/internal" + "github.com/vishvananda/netlink" + "gitlab.com/NebulousLabs/go-upnp" + "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +var ( + basePort = flag.Uint("override-base-port", 65000, "Override the public port for this instance") +) + +type PeerLink struct { + ctx context.Context + frrManager *frr.FrrConfigManager + wireguardTunnel *internal.WireguardInterface + wgClient *wgctrl.Client + + publicKey wgtypes.Key + selfIP *net.IPNet + otherIP *net.IPNet + selfID uint32 + otherID uint32 + cancel context.CancelFunc + initialized bool + externalIP *string + igd *upnp.IGD +} + +func NewPeerLink( + parentCtx context.Context, + selfID uint32, + otherID uint32, + wgClient *wgctrl.Client, + frrManager *frr.FrrConfigManager, +) (*PeerLink, error) { + // we get our link-local address according to the adressing plan + ipAddress := internal.GetAddress(selfID) + + // we generate the unique tunnel wireguard privateKey + privateKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return nil, err + } + + port := int(*basePort + uint(otherID)) + tunnel, err := internal.NewWireguardInterface(wgClient, &netlink.LinkAttrs{ + Name: fmt.Sprintf("orion%d", otherID), + Group: 30, + }, wgtypes.Config{ + PrivateKey: &privateKey, + ReplacePeers: true, + Peers: []wgtypes.PeerConfig{}, + ListenPort: &port, + }) + if err != nil { + return nil, err + } + + err = tunnel.SetAddress(ipAddress) + if err != nil { + defer tunnel.Dispose() + return nil, err + } + + ctx, cancel := context.WithCancel(parentCtx) + link := &PeerLink{ + ctx: ctx, + frrManager: frrManager, + wireguardTunnel: tunnel, + wgClient: wgClient, + selfID: selfID, + otherID: otherID, + selfIP: ipAddress, + publicKey: privateKey.PublicKey(), + cancel: cancel, + initialized: false, + } + link.upnpInit() + + return link, nil +} + +func (c *PeerLink) PublicKey() wgtypes.Key { + return c.publicKey +} + +func (c *PeerLink) Initialized() bool { + return c.initialized +} + +func (c *PeerLink) RemoteID() uint32 { + return c.otherID +} diff --git a/bin/oriond/implementation/oriond.go b/bin/oriond/implementation/oriond.go new file mode 100644 index 0000000..d3f2ffd --- /dev/null +++ b/bin/oriond/implementation/oriond.go @@ -0,0 +1,87 @@ +package implementation + +import ( + "context" + "crypto/x509" + "flag" + "sync" + + "github.com/orion-network-dev/orion-backbone/bin/oriond/implementation/frr" + "github.com/orion-network-dev/orion-backbone/bin/oriond/implementation/link" + "github.com/rs/zerolog/log" + "github.com/teivah/broadcast" + "golang.zx2c4.com/wireguard/wgctrl" +) + +var ( + friendlyName = flag.String("friendly-name", "Standard OrionD Instance", "The name of the software connecting to Orion") +) + +type OrionClientDaemon struct { + // Metadata regarding the client + memberId uint32 + friendlyName string + asn uint32 + + // Structs used to manage the state of OrionD + frrManager *frr.FrrConfigManager + wgClient *wgctrl.Client + + tunnels map[uint32]*link.PeerLink + tunnelsLock *sync.RWMutex + + // Runtime information + Context context.Context + ParentCtx context.Context + establishedStream *broadcast.Relay[uint32] + + chain []*x509.Certificate +} + +// Creates and initializes a new Orion client +func NewOrionClientDaemon( + parentContext context.Context, +) (*OrionClientDaemon, error) { + orionClient := OrionClientDaemon{ + friendlyName: *friendlyName, + ParentCtx: parentContext, + establishedStream: broadcast.NewRelay[uint32](), + tunnels: map[uint32]*link.PeerLink{}, + tunnelsLock: &sync.RWMutex{}, + } + + wgClient, err := wgctrl.New() + if err != nil { + return nil, err + } + orionClient.wgClient = wgClient + + // Resolve our current identity using the data from the certificates, + // taking the overrides into acocunt + if err := orionClient.resolveIdentity(); err != nil { + return nil, err + } + + // Initializing the FRR config manager, which is used to change the bgp configuration + if frrManager, err := frr.NewFrrConfigManager(orionClient.asn, orionClient.memberId); err == nil { + orionClient.frrManager = frrManager + } else { + return nil, err + } + + return &orionClient, nil +} + +// Disposing interfaces and frr peers +func (c *OrionClientDaemon) Dispose() { + log.Info().Msg("Disposing all the client") + for _, tunnel := range c.tunnels { + err := tunnel.Dispose() + if err != nil { + log.Error(). + Err(err). + Uint32("peer-id", tunnel.RemoteID()). + Msg("failed to dispose the client") + } + } +} diff --git a/bin/oriond/oriond.go b/bin/oriond/oriond.go index 2c1b8d0..3700845 100644 --- a/bin/oriond/oriond.go +++ b/bin/oriond/oriond.go @@ -1,8 +1,8 @@ package main import ( + "context" "crypto/tls" - "encoding/json" "flag" "fmt" "net/http" @@ -11,52 +11,54 @@ import ( "os/signal" "time" - "github.com/MatthieuCoder/OrionV3/internal" - "github.com/MatthieuCoder/OrionV3/internal/state" "github.com/gorilla/websocket" + "github.com/orion-network-dev/orion-backbone/bin/oriond/implementation" + "github.com/orion-network-dev/orion-backbone/internal" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) var ( - enable_prof = flag.Bool("enable-pprof", false, "enable pprof for debugging") debug = flag.Bool("debug", false, "change the log level to debug") registryServer = flag.String("registry-server", "reg.orionet.re:64431", "the address of the registry server") - pprof = flag.String("debug-pprof", "0.0.0.0:6061", "") ) func main() { + ctx, cancel := context.WithCancel(context.Background()) + + // listen for interrupts interrupt := make(chan os.Signal, 1) signal.Notify(interrupt, os.Interrupt) - // Setup logging - zerolog.TimeFieldFormat = zerolog.TimeFormatUnix + + // parse all command flags flag.Parse() - // Default level for this example is info, unless debug flag is present + // setup the time format used by the logger + zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) zerolog.SetGlobalLevel(zerolog.InfoLevel) - if *enable_prof { - go func() { - fmt.Println(http.ListenAndServe(*pprof, nil)) - }() - } + + // if the debug lag is used, we set the logging level to debug if *debug { zerolog.SetGlobalLevel(zerolog.DebugLevel) } - url := url.URL{ - Scheme: "wss", - Host: *registryServer, - Path: "/ws", - } + // we print the version information + internal.PrintVersionHeader() + + oriond, err := implementation.NewOrionClientDaemon(ctx) + defer oriond.Dispose() + // We load the required certificates privateKey, chain := internal.LoadPemFile() certificateKeyPair := internal.LoadX509KeyPair(privateKey, chain) authorityPool, err := internal.LoadAuthorityPool() if err != nil { - panic(err) + log.Fatal().Err(err).Msg("failed to load the required certificates") + return } + // information required to connect to the registry over websocket dialer := &websocket.Dialer{ Proxy: http.ProxyFromEnvironment, HandshakeTimeout: 45 * time.Second, @@ -66,97 +68,30 @@ func main() { MinVersion: tls.VersionTLS13, MaxVersion: tls.VersionTLS13, }, - Subprotocols: []string{"orion-reg-rpc"}, + Subprotocols: []string{fmt.Sprintf("orion-registry-%s", internal.Commit)}, + } + url := url.URL{ + Scheme: "wss", + Host: *registryServer, + Path: "/ws", } - c, _, err := dialer.Dial(url.String(), nil) + // we dial the registry server, initializing the tls1.3 connection + connection, _, err := dialer.Dial(url.String(), nil) if err != nil { - log.Fatal().Msgf("dial: %s", err) + log.Fatal().Err(err).Msgf("unsable to dial") } - defer c.Close() - - done := make(chan struct{}) - - go func() { - defer close(done) - for { - _, message, err := c.ReadMessage() - if err != nil { - log.Print("read:", err) - return - } - log.Printf("recv: %s", message) - - msg := state.JsonEvent{} - json.Unmarshal(message, &msg) - - log.Printf("received %s... handling", msg.Kind) - - out, err := state.UnmarshalEvent(msg) - if err != nil { - log.Print("read:", err) - } - - switch message := out.(type) { - case *state.Hello: - log.Printf("Hello message: %s", message.Message) - continue - case *state.RouterConnectEvent: - log.Printf("router joined: %d", message.Router.Identity) - - ev, _ := state.MarshalEvent(state.RouterInitiateRequest{ - Identity: &message.Router.Identity, - }) - c.WriteJSON(ev) - continue - case *state.CreateEdgeRequest: - log.Printf("create edge request received") - - ev, err := state.MarshalEvent(state.CreateEdgeResponse{ - PublicEndpoint: state.Endpoint{ - Address: "localhost", - PublicPort: 9999, - }, - PresharedKeybB4: "Z3LBJMtWxoqPyR/XkGJkbdVUnzLZRkv215El6XuGpLc=", - }) - if err != nil { - panic(err) - } - - c.WriteJSON(ev) - continue - default: - log.Printf("invalid kind error: %s %T", msg.Kind, out) - } - - } - }() - - ticker := time.NewTicker(time.Second) - defer ticker.Stop() - - for { - select { - case <-ticker.C: - - case <-done: - return - case <-interrupt: - log.Print("interrupt") - - // Cleanly close the connection by sending a close message and then - // waiting (with timeout) for the server to close the connection. - err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) - if err != nil { - log.Print("write close:", err) - return - } - select { - case <-done: - case <-time.After(time.Second): - } - return - } + defer connection.Close() + + // we initialize the oriond daemon to handle the websocket messages + oriond.ListenOnWS(connection) + + select { + case <-ctx.Done(): + return + case <-interrupt: + cancel() + <-ctx.Done() + return } - } diff --git a/bin/registry/main.go b/bin/registry/main.go index 006441f..f3ffb83 100644 --- a/bin/registry/main.go +++ b/bin/registry/main.go @@ -8,8 +8,8 @@ import ( "net/http" "os" - "github.com/MatthieuCoder/OrionV3/bin/registry/server" - "github.com/MatthieuCoder/OrionV3/internal" + "github.com/orion-network-dev/orion-backbone/bin/registry/server" + "github.com/orion-network-dev/orion-backbone/internal" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) diff --git a/bin/registry/server/holepunch.go b/bin/registry/server/holepunch.go new file mode 100644 index 0000000..193f9af --- /dev/null +++ b/bin/registry/server/holepunch.go @@ -0,0 +1,168 @@ +package server + +import ( + "context" + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "github.com/orion-network-dev/orion-backbone/internal" + "github.com/orion-network-dev/orion-backbone/internal/state" + "github.com/rs/zerolog/log" + "github.com/vishvananda/netlink" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +const ( + holePunchQueryPublicKey = "public_key" +) + +func (c *Server) upgradeHolepunch(w http.ResponseWriter, r *http.Request) { + if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 { + upgradeErrorPage(w) + return + } + + if !r.URL.Query().Has(holePunchQueryPublicKey) { + log.Error().Msg("the hole-punch request failed") + return + } + publicKey := r.URL.Query().Get(holePunchQueryPublicKey) + + cz, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Error().Err(err).Msg("failed to upgrade a http(s) connection to a websocket connection") + return + } + + leaf := r.TLS.PeerCertificates[0] + cn := leaf.Subject.CommonName + cnParts := strings.Split(cn, ":") + if len(cnParts) != 2 || cnParts[1] != "oriond" { + log.Error().Err(err).Msg("the given certificate is not valid for logging-in into oriond") + return + } + + routerId, err := strconv.Atoi(cnParts[0]) + if err != nil { + log.Error().Err(err).Msg("the given certificate is not valid for logging-in into oriond") + return + } + + identity := state.RouterIdentity(routerId) + + log.Debug().Uint32("identity", uint32(identity)).Msg("handling a hole-punching request") + + task, err := c.tasksAssigner.AssignSessionId(sessionServer.Context()) + if err != nil { + return err + } + defer task.Release() + + // Parameters for the new wireguard tunnel instance used for hole-punching. + device := wgtypes.Config{} + port := *holePunchingBasePort + task.Id + device.ListenPort = &port + + // Generate a preshared-key for the wireguard peer + presharedKey, err := wgtypes.GenerateKey() + if err != nil { + return err + } + + // Add a new peer for this client + device.Peers = append(device.Peers, wgtypes.PeerConfig{ + PublicKey: wgtypes.Key(sessionInit.PublicKey), + PresharedKey: &presharedKey, + }) + + // Generate a private-key for this wireguard instance + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + return err + } + device.PrivateKey = &key + + // Create a new wireguard interface + interfaceName := fmt.Sprintf("%s%d", *holePunchingInterfacePrefix, task.Id) + log.Info().Str("interface-name", interfaceName).Msg("creating interface") + + wgInt, err := internal.NewWireguardInterface( + r.wgClient, + &netlink.LinkAttrs{ + Name: interfaceName, + }, + device, + ) + if err != nil { + return err + } + defer wgInt.Dispose() + + log.Debug().Msg("sending the connection information to the client") + + public_key_bytes := [wgtypes.KeyLen]byte(device.PrivateKey.PublicKey()) + preshared_key_bytes := [wgtypes.KeyLen]byte(presharedKey) + + // Send the login information the the client + sessionServer.Send(&proto.HolePunchingEvent{ + Event: &proto.HolePunchingEvent_InitializationResponse{ + InitializationResponse: &proto.HolePunchingInitializationResponse{ + EndpointAddr: *holePunchingHost, + EndpointPort: uint32(port), + PublicKey: public_key_bytes[:], + PresharedKey: preshared_key_bytes[:], + }, + }, + }) + + // Create a new context for waiting for the first handshake from the client + timeoutTime := time.Second * time.Duration(*holePunchingHandshakeTimeout) + waitingCtx, ctxCancel := context.WithTimeout(sessionServer.Context(), timeoutTime) + defer ctxCancel() + // We're checking the status every second + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-ticker.C: + // We verify if an handshake was made + log.Debug().Str("interface", interfaceName).Msg("checking the wireguard interface for handshakes") + dev, err := r.wgClient.Device(interfaceName) + if err != nil { + log.Error().Err(err).Msg("error while reading the interface information") + return err + } + + if len(dev.Peers) != 1 { + err = fmt.Errorf("more than one peer is connected to the hole-punching instance") + log.Error().Err(err).Msg("this should be not possible") + return err + } + + peer := dev.Peers[0] + // We check if an endpoint was recorded + if peer.Endpoint != nil { + log.Debug().Int("task-id", task.Id).IPAddr("address", peer.Endpoint.IP).Int("port", peer.Endpoint.Port).Msg("got a connection to the wireguard instance") + + sessionServer.Send(&proto.HolePunchingEvent{ + Event: &proto.HolePunchingEvent_Complete{ + Complete: &proto.HolePunchingCompleteResponse{ + ClientEndpointAddr: peer.Endpoint.IP.String(), + ClientEndpointPort: uint32(peer.Endpoint.Port), + }, + }, + }) + + return nil + } + + case <-waitingCtx.Done(): + return waitingCtx.Err() + } + } + +} diff --git a/bin/registry/server/protocol/client.go b/bin/registry/server/protocol/client.go index c164060..c329510 100644 --- a/bin/registry/server/protocol/client.go +++ b/bin/registry/server/protocol/client.go @@ -5,9 +5,9 @@ import ( "encoding/json" "fmt" - "github.com/MatthieuCoder/OrionV3/internal" - "github.com/MatthieuCoder/OrionV3/internal/state" "github.com/gorilla/websocket" + "github.com/orion-network-dev/orion-backbone/internal" + "github.com/orion-network-dev/orion-backbone/internal/state" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) diff --git a/bin/registry/server/server.go b/bin/registry/server/server.go index 8a26d34..d513487 100644 --- a/bin/registry/server/server.go +++ b/bin/registry/server/server.go @@ -3,9 +3,13 @@ package server import ( "io/fs" "net/http" + + "github.com/orion-network-dev/orion-backbone/internal" ) -type Server struct{} +type Server struct { + tasksAssigner internal.LockableTasks +} func (c *Server) Handler() *http.ServeMux { mux := http.NewServeMux() @@ -17,6 +21,7 @@ func (c *Server) Handler() *http.ServeMux { mux.HandleFunc("/whoami", c.whoami) mux.HandleFunc("/ws", c.upgrade) mux.HandleFunc("/state", c.state) + mux.HandleFunc("/holepunch", c.upgradeHolepunch) return mux } diff --git a/bin/registry/server/upgrade.go b/bin/registry/server/upgrade.go index 19cb17a..89344c7 100644 --- a/bin/registry/server/upgrade.go +++ b/bin/registry/server/upgrade.go @@ -6,9 +6,9 @@ import ( "strconv" "strings" - "github.com/MatthieuCoder/OrionV3/bin/registry/server/protocol" - "github.com/MatthieuCoder/OrionV3/internal/state" "github.com/gorilla/websocket" + "github.com/orion-network-dev/orion-backbone/bin/registry/server/protocol" + "github.com/orion-network-dev/orion-backbone/internal/state" "github.com/rs/zerolog/log" ) diff --git a/go.mod b/go.mod index 1c4d0f4..f145c72 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/MatthieuCoder/OrionV3 +module github.com/orion-network-dev/orion-backbone go 1.22.5 @@ -8,7 +8,13 @@ require ( github.com/teivah/broadcast v0.1.0 github.com/vishvananda/netlink v1.1.0 golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f - golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 +) + +require ( + github.com/google/uuid v1.6.0 // indirect + gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 // indirect + golang.org/x/text v0.21.0 // indirect ) require ( @@ -18,11 +24,13 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.2 // indirect - github.com/mdlayher/socket v0.4.1 // indirect + github.com/mdlayher/socket v0.5.1 // indirect + github.com/prometheus-community/pro-bing v0.6.0 github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b // indirect + gitlab.com/NebulousLabs/go-upnp v0.0.0-20211002182029-11da932010b6 + golang.org/x/crypto v0.32.0 // indirect + golang.org/x/net v0.34.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect ) diff --git a/go.sum b/go.sum index c6c6927..84fb252 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= @@ -18,9 +20,13 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= +github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= 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/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/prometheus-community/pro-bing v0.6.0 h1:04SZ/092gONTE1XUFzYFWqgB4mKwcdkqNChLMFedwhg= +github.com/prometheus-community/pro-bing v0.6.0/go.mod h1:jNCOI3D7pmTCeaoF41cNS6uaxeFY/Gmc3ffwbuJVzAQ= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -30,21 +36,48 @@ github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJ github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40 h1:dizWJqTWjwyD8KGcMOwgrkqu1JIkofYgKkmDeNE7oAs= +gitlab.com/NebulousLabs/fastrand v0.0.0-20181126182046-603482d69e40/go.mod h1:rOnSnoRyxMI3fe/7KIbVcsHRGxe30OONv8dEgo+vCfA= +gitlab.com/NebulousLabs/go-upnp v0.0.0-20211002182029-11da932010b6 h1:WKij6HF8ECp9E7K0E44dew9NrRDGiNR5u4EFsXnJUx4= +gitlab.com/NebulousLabs/go-upnp v0.0.0-20211002182029-11da932010b6/go.mod h1:vhrHTGDh4YR7wK8Z+kRJ+x8SF/6RUM3Vb64Si5FD0L8= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo= golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b h1:J1CaxgLerRR5lgx3wnr6L04cJFbWoceSK9JWBdglINo= golang.zx2c4.com/wireguard v0.0.0-20230325221338-052af4a8072b/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4= +golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= +golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= 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= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdIg1ozBNLgPy4SLT84nfcBjr6rhGtXYtrkWLU= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ= diff --git a/internal/address_plan.go b/internal/address_plan.go index cf4284f..58488e8 100644 --- a/internal/address_plan.go +++ b/internal/address_plan.go @@ -5,16 +5,12 @@ import ( "net" ) -func GetSelfAddress(self uint32, other uint32) (*net.IPNet, *net.IPNet, error) { +func GetAddress(self uint32) *net.IPNet { mask := net.CIDRMask(64, 128) selfAddress := net.ParseIP(fmt.Sprintf("fe80:babe::cafe:ffff:%d", self)) - otherAddress := net.ParseIP(fmt.Sprintf("fe80:babe::cafe:ffff:%d", other)) return &net.IPNet{ - IP: selfAddress, - Mask: mask, - }, &net.IPNet{ - IP: otherAddress, - Mask: mask, - }, nil + IP: selfAddress, + Mask: mask, + } } diff --git a/internal/lockable_tasks.go b/internal/lockable_tasks.go index 1aed9a5..edafc89 100644 --- a/internal/lockable_tasks.go +++ b/internal/lockable_tasks.go @@ -28,6 +28,7 @@ func NewLockableTasks(tasksCount int) LockableTasks { concurrentTaskCount: tasksCount, } } + func (r *LockableTasks) AssignSessionId(ctx context.Context) (*Task, error) { ticker := time.NewTicker(time.Millisecond) counter := 0 diff --git a/internal/state/edge.go b/internal/state/edge.go index 09449b1..cef28d3 100644 --- a/internal/state/edge.go +++ b/internal/state/edge.go @@ -141,7 +141,7 @@ func (c *Edge) Initialize() { for i := range 32 { token := make([]byte, 1) rand.Read(token) - random[i] = bytesA[i] ^ bytesB[i] ^ token[0] + random[i] = (bytesA[i] ^ bytesB[i]) | token[0] } presharedKey := base64.StdEncoding.EncodeToString(random[:]) diff --git a/internal/state/edge_events.go b/internal/state/edge_events.go index 74f89e4..ce39bd9 100644 --- a/internal/state/edge_events.go +++ b/internal/state/edge_events.go @@ -8,6 +8,7 @@ type CreateEdgeRequest struct { type Endpoint struct { Address string // v4 address PublicPort uint16 + PublicKey string } type CreateEdgeResponse struct { diff --git a/internal/version.go b/internal/version.go index ff31bb3..0315a84 100644 --- a/internal/version.go +++ b/internal/version.go @@ -1,8 +1,24 @@ package internal +import ( + "fmt" + + "github.com/rs/zerolog/log" +) + var ( Version = "dev" Commit = "none" Date = "unknown" BuiltBy = "go" ) + +func PrintVersionHeader() { + log.Info().MsgFunc(func() string { + message := ("********************************************\n") + message += fmt.Sprintf(" Orion Version %s \n", Version) + message += fmt.Sprintf(" Commit: %s Build time: %s \n", Commit, Date) + message += ("********************************************\n") + return message + }) +} diff --git a/internal/wg_interface.go b/internal/wg_interface.go index 56b849f..02e2056 100644 --- a/internal/wg_interface.go +++ b/internal/wg_interface.go @@ -12,7 +12,7 @@ import ( type WireguardInterface struct { WgLink WireguardNetLink - wgconfig wgtypes.Config + WgConfig wgtypes.Config lock sync.Mutex } @@ -57,10 +57,10 @@ func (c *WireguardInterface) SetPeers(wg *wgctrl.Client, peers []wgtypes.PeerCon defer c.lock.Unlock() log.Debug().Str("interface", c.WgLink.InterfaceAttrs.Name).Msg("updating peers on interface") - c.wgconfig.Peers = peers - c.wgconfig.ReplacePeers = true + c.WgConfig.Peers = peers + c.WgConfig.ReplacePeers = true - if err := wg.ConfigureDevice(c.WgLink.InterfaceAttrs.Name, c.wgconfig); err != nil { + if err := wg.ConfigureDevice(c.WgLink.InterfaceAttrs.Name, c.WgConfig); err != nil { log.Error().Err(err).Msg("failed to apply the wireguard configuration") netlink.LinkDel(c.WgLink) return err