From d67f766b2e52114233cfad69c9146d44f09564c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Papp?= Date: Fri, 12 Apr 2024 17:38:31 +0200 Subject: [PATCH] Initial code --- client/internal/engine.go | 57 +++++++-- client/internal/peer/conn.go | 124 +++++++++---------- client/internal/relay/turn.go | 129 ++++++++++++++++++++ client/internal/relay/turn_test.go | 36 ++++++ signal/client/client.go | 6 +- signal/proto/signalexchange.pb.go | 185 ++++++++++++++++++++--------- signal/proto/signalexchange.proto | 13 +- 7 files changed, 418 insertions(+), 132 deletions(-) create mode 100644 client/internal/relay/turn.go create mode 100644 client/internal/relay/turn_test.go diff --git a/client/internal/engine.go b/client/internal/engine.go index ba7074672..a9003f85d 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -138,6 +138,7 @@ type Engine struct { signalProbe *Probe relayProbe *Probe wgProbe *Probe + turnRelay *relay.PermanentTurn } // Peer is an instance of the Connection Peer @@ -452,10 +453,19 @@ func SignalOfferAnswer(offerAnswer peer.OfferAnswer, myKey wgtypes.Key, remoteKe t = sProto.Body_OFFER } - msg, err := signal.MarshalCredential(myKey, offerAnswer.WgListenPort, remoteKey, &signal.Credential{ - UFrag: offerAnswer.IceCredentials.UFrag, - Pwd: offerAnswer.IceCredentials.Pwd, - }, t, offerAnswer.RosenpassPubKey, offerAnswer.RosenpassAddr) + msg, err := signal.MarshalCredential( + myKey, + offerAnswer.WgListenPort, + remoteKey, &signal.Credential{ + UFrag: offerAnswer.IceCredentials.UFrag, + Pwd: offerAnswer.IceCredentials.Pwd, + }, + t, + offerAnswer.RosenpassPubKey, + offerAnswer.RosenpassAddr, + offerAnswer.RelayedAddr.String(), + offerAnswer.RemoteAddr.String(), + ) if err != nil { return err } @@ -483,6 +493,13 @@ func (e *Engine) handleSync(update *mgmProto.SyncResponse) error { return err } + turnRelay := relay.NewPermanentTurn(e.STUNs[0], e.TURNs[0]) + err = turnRelay.Open() + if err != nil { + return fmt.Errorf("faile to open turn relay: %w", err) + } + e.turnRelay = turnRelay + // todo update signal } @@ -603,6 +620,7 @@ func (e *Engine) updateSTUNs(stuns []*mgmProto.HostConfig) error { var newSTUNs []*stun.URI log.Debugf("got STUNs update from Management Service, updating") for _, s := range stuns { + log.Debugf("-----updated TURN: %s", s.Uri) url, err := stun.ParseURI(s.Uri) if err != nil { return err @@ -621,6 +639,7 @@ func (e *Engine) updateTURNs(turns []*mgmProto.ProtectedHostConfig) error { var newTURNs []*stun.URI log.Debugf("got TURNs update from Management Service, updating") for _, turn := range turns { + log.Debugf("-----updated Turn %v, %s, %s", turn.HostConfig.Uri, turn.User, turn.Password) url, err := stun.ParseURI(turn.HostConfig.Uri) if err != nil { return err @@ -630,7 +649,6 @@ func (e *Engine) updateTURNs(turns []*mgmProto.ProtectedHostConfig) error { newTURNs = append(newTURNs, url) } e.TURNs = newTURNs - return nil } @@ -934,7 +952,7 @@ func (e *Engine) createPeerConn(pubKey string, allowedIPs string) (*peer.Conn, e RosenpassAddr: e.getRosenpassAddr(), } - peerConn, err := peer.NewConn(config, e.statusRecorder, e.wgProxyFactory, e.mobileDep.TunAdapter, e.mobileDep.IFaceDiscover) + peerConn, err := peer.NewConn(config, e.statusRecorder, e.wgProxyFactory, e.mobileDep.TunAdapter, e.mobileDep.IFaceDiscover, e.turnRelay) if err != nil { return nil, err } @@ -1000,6 +1018,17 @@ func (e *Engine) receiveSignalEvents() { rosenpassPubKey = msg.GetBody().GetRosenpassConfig().GetRosenpassPubKey() rosenpassAddr = msg.GetBody().GetRosenpassConfig().GetRosenpassServerAddr() } + + relayedAddr, err := net.ResolveUDPAddr("udp", msg.GetBody().GetRelay().GetRelayedAddress()) + if err != nil { + return err + } + + remoteAddr, err := net.ResolveUDPAddr("udp", msg.GetBody().GetRelay().GetSrvRefAddress()) + if err != nil { + return err + } + conn.OnRemoteOffer(peer.OfferAnswer{ IceCredentials: peer.IceCredentials{ UFrag: remoteCred.UFrag, @@ -1009,6 +1038,8 @@ func (e *Engine) receiveSignalEvents() { Version: msg.GetBody().GetNetBirdVersion(), RosenpassPubKey: rosenpassPubKey, RosenpassAddr: rosenpassAddr, + RelayedAddr: relayedAddr, + RemoteAddr: remoteAddr, }) case sProto.Body_ANSWER: remoteCred, err := signal.UnMarshalCredential(msg) @@ -1024,6 +1055,17 @@ func (e *Engine) receiveSignalEvents() { rosenpassPubKey = msg.GetBody().GetRosenpassConfig().GetRosenpassPubKey() rosenpassAddr = msg.GetBody().GetRosenpassConfig().GetRosenpassServerAddr() } + + relayedAddr, err := net.ResolveUDPAddr("udp", msg.GetBody().GetRelay().GetRelayedAddress()) + if err != nil { + return err + } + + remoteAddr, err := net.ResolveUDPAddr("udp", msg.GetBody().GetRelay().GetSrvRefAddress()) + if err != nil { + return err + } + conn.OnRemoteAnswer(peer.OfferAnswer{ IceCredentials: peer.IceCredentials{ UFrag: remoteCred.UFrag, @@ -1033,6 +1075,8 @@ func (e *Engine) receiveSignalEvents() { Version: msg.GetBody().GetNetBirdVersion(), RosenpassPubKey: rosenpassPubKey, RosenpassAddr: rosenpassAddr, + RelayedAddr: relayedAddr, + RemoteAddr: remoteAddr, }) case sProto.Body_CANDIDATE: candidate, err := ice.UnmarshalCandidate(msg.GetBody().Payload) @@ -1043,7 +1087,6 @@ func (e *Engine) receiveSignalEvents() { conn.OnRemoteCandidate(candidate) case sProto.Body_MODE: } - return nil }) if err != nil { diff --git a/client/internal/peer/conn.go b/client/internal/peer/conn.go index 9e7ee6959..45f970538 100644 --- a/client/internal/peer/conn.go +++ b/client/internal/peer/conn.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net" - "runtime" "strings" "sync" "time" @@ -14,6 +13,7 @@ import ( log "github.com/sirupsen/logrus" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "github.com/netbirdio/netbird/client/internal/relay" "github.com/netbirdio/netbird/client/internal/stdnet" "github.com/netbirdio/netbird/client/internal/wgproxy" "github.com/netbirdio/netbird/iface" @@ -93,6 +93,10 @@ type OfferAnswer struct { // RosenpassAddr is the Rosenpass server address (IP:port) of the remote peer when receiving this message // This value is the local Rosenpass server address when sending the message RosenpassAddr string + + // Turn Relay + RelayedAddr net.Addr + RemoteAddr net.Addr } // IceCredentials ICE protocol credentials struct @@ -141,11 +145,11 @@ type Conn struct { sentExtraSrflx bool remoteEndpoint *net.UDPAddr - remoteConn *ice.Conn connID nbnet.ConnectionID beforeAddPeerHooks []BeforeAddPeerHookFunc afterRemovePeerHooks []AfterRemovePeerHookFunc + turnRelay *relay.PermanentTurn } // meta holds meta information about a connection @@ -176,7 +180,7 @@ func (conn *Conn) UpdateStunTurn(turnStun []*stun.URI) { // NewConn creates a new not opened Conn to the remote peer. // To establish a connection run Conn.Open -func NewConn(config ConnConfig, statusRecorder *Status, wgProxyFactory *wgproxy.Factory, adapter iface.TunAdapter, iFaceDiscover stdnet.ExternalIFaceDiscover) (*Conn, error) { +func NewConn(config ConnConfig, statusRecorder *Status, wgProxyFactory *wgproxy.Factory, adapter iface.TunAdapter, iFaceDiscover stdnet.ExternalIFaceDiscover, turnRelay *relay.PermanentTurn) (*Conn, error) { return &Conn{ config: config, mu: sync.Mutex{}, @@ -189,6 +193,7 @@ func NewConn(config ConnConfig, statusRecorder *Status, wgProxyFactory *wgproxy. wgProxyFactory: wgProxyFactory, adapter: adapter, iFaceDiscover: iFaceDiscover, + turnRelay: turnRelay, }, nil } @@ -212,7 +217,7 @@ func (conn *Conn) reCreateAgent() error { MulticastDNSMode: ice.MulticastDNSModeDisabled, NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4, ice.NetworkTypeUDP6}, Urls: conn.config.StunTurn, - CandidateTypes: conn.candidateTypes(), + CandidateTypes: []ice.CandidateType{}, FailedTimeout: &failedTimeout, InterfaceFilter: stdnet.InterfaceFilter(conn.config.InterfaceBlackList), UDPMux: conn.config.UDPMux, @@ -262,17 +267,6 @@ func (conn *Conn) reCreateAgent() error { return nil } -func (conn *Conn) candidateTypes() []ice.CandidateType { - if hasICEForceRelayConn() { - return []ice.CandidateType{ice.CandidateTypeRelay} - } - // TODO: remove this once we have refactored userspace proxy into the bind package - if runtime.GOOS == "ios" { - return []ice.CandidateType{ice.CandidateTypeHost, ice.CandidateTypeServerReflexive} - } - return []ice.CandidateType{ice.CandidateTypeHost, ice.CandidateTypeServerReflexive, ice.CandidateTypeRelay} -} - // Open opens connection to the remote peer starting ICE candidate gathering process. // Blocks until connection has been closed or connection timeout. // ConnStatus will be set accordingly @@ -351,23 +345,12 @@ func (conn *Conn) Open() error { log.Warnf("error while updating the state of peer %s,err: %v", conn.config.Key, err) } - err = conn.agent.GatherCandidates() - if err != nil { - return err - } - - // will block until connection succeeded - // but it won't release if ICE Agent went into Disconnected or Failed state, - // so we have to cancel it with the provided context once agent detected a broken connection isControlling := conn.config.LocalKey > conn.config.Key - var remoteConn *ice.Conn if isControlling { - remoteConn, err = conn.agent.Dial(conn.ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd) - } else { - remoteConn, err = conn.agent.Accept(conn.ctx, remoteOfferAnswer.IceCredentials.UFrag, remoteOfferAnswer.IceCredentials.Pwd) - } - if err != nil { - return err + err = conn.turnRelay.PunchHole(remoteOfferAnswer.RemoteAddr) + if err != nil { + log.Errorf("failed to punch hole: %v", err) + } } // dynamically set remote WireGuard port is other side specified a different one from the default one @@ -376,7 +359,11 @@ func (conn *Conn) Open() error { remoteWgPort = remoteOfferAnswer.WgListenPort } - conn.remoteConn = remoteConn + // todo configure the wg with proper address + remoteConn, err := net.Dial("udp", remoteOfferAnswer.RemoteAddr.String()) + if err != nil { + log.Errorf("failed to dial remote peer %s: %v", conn.config.Key, err) + } // the ice connection has been established successfully so we are ready to start the proxy remoteAddr, err := conn.configureConnection(remoteConn, remoteWgPort, remoteOfferAnswer.RosenpassPubKey, @@ -415,25 +402,14 @@ func (conn *Conn) configureConnection(remoteConn net.Conn, remoteWgPort int, rem conn.mu.Lock() defer conn.mu.Unlock() - pair, err := conn.agent.GetSelectedCandidatePair() + var endpoint net.Addr + log.Debugf("setup relay connection") + conn.wgProxy = conn.wgProxyFactory.GetProxy() + endpoint, err := conn.wgProxy.AddTurnConn(remoteConn) if err != nil { return nil, err } - var endpoint net.Addr - if isRelayCandidate(pair.Local) { - log.Debugf("setup relay connection") - conn.wgProxy = conn.wgProxyFactory.GetProxy() - endpoint, err = conn.wgProxy.AddTurnConn(remoteConn) - if err != nil { - return nil, err - } - } else { - // To support old version's with direct mode we attempt to punch an additional role with the remote WireGuard port - go conn.punchRemoteWGPort(pair, remoteWgPort) - endpoint = remoteConn.RemoteAddr() - } - endpointUdpAddr, _ := net.ResolveUDPAddr(endpoint.Network(), endpoint.String()) conn.remoteEndpoint = endpointUdpAddr log.Debugf("Conn resolved IP for %s: %s", endpoint, endpointUdpAddr.IP) @@ -454,31 +430,33 @@ func (conn *Conn) configureConnection(remoteConn net.Conn, remoteWgPort int, rem } conn.status = StatusConnected - rosenpassEnabled := false - if remoteRosenpassPubKey != nil { - rosenpassEnabled = true - } + /* + rosenpassEnabled := false + if remoteRosenpassPubKey != nil { + rosenpassEnabled = true + } - peerState := State{ - PubKey: conn.config.Key, - ConnStatus: conn.status, - ConnStatusUpdate: time.Now(), - LocalIceCandidateType: pair.Local.Type().String(), - RemoteIceCandidateType: pair.Remote.Type().String(), - LocalIceCandidateEndpoint: fmt.Sprintf("%s:%d", pair.Local.Address(), pair.Local.Port()), - RemoteIceCandidateEndpoint: fmt.Sprintf("%s:%d", pair.Remote.Address(), pair.Local.Port()), - Direct: !isRelayCandidate(pair.Local), - RosenpassEnabled: rosenpassEnabled, - Mux: new(sync.RWMutex), - } - if pair.Local.Type() == ice.CandidateTypeRelay || pair.Remote.Type() == ice.CandidateTypeRelay { - peerState.Relayed = true - } + peerState := State{ + PubKey: conn.config.Key, + ConnStatus: conn.status, + ConnStatusUpdate: time.Now(), + LocalIceCandidateType: pair.Local.Type().String(), + RemoteIceCandidateType: pair.Remote.Type().String(), + LocalIceCandidateEndpoint: fmt.Sprintf("%s:%d", pair.Local.Address(), pair.Local.Port()), + RemoteIceCandidateEndpoint: fmt.Sprintf("%s:%d", pair.Remote.Address(), pair.Local.Port()), + Direct: !isRelayCandidate(pair.Local), + RosenpassEnabled: rosenpassEnabled, + Mux: new(sync.RWMutex), + } + if pair.Local.Type() == ice.CandidateTypeRelay || pair.Remote.Type() == ice.CandidateTypeRelay { + peerState.Relayed = true + } - err = conn.statusRecorder.UpdatePeerState(peerState) - if err != nil { - log.Warnf("unable to save peer's state, got error: %v", err) - } + err = conn.statusRecorder.UpdatePeerState(peerState) + if err != nil { + log.Warnf("unable to save peer's state, got error: %v", err) + } + */ _, ipNet, err := net.ParseCIDR(conn.config.WgConfig.AllowedIps) if err != nil { @@ -680,6 +658,8 @@ func (conn *Conn) sendAnswer() error { Version: version.NetbirdVersion(), RosenpassPubKey: conn.config.RosenpassPubKey, RosenpassAddr: conn.config.RosenpassAddr, + RelayedAddr: conn.turnRelay.RelayedAddress(), + RemoteAddr: conn.turnRelay.SrvRefAddr(), }) if err != nil { return err @@ -703,6 +683,8 @@ func (conn *Conn) sendOffer() error { Version: version.NetbirdVersion(), RosenpassPubKey: conn.config.RosenpassPubKey, RosenpassAddr: conn.config.RosenpassAddr, + RelayedAddr: conn.turnRelay.RelayedAddress(), + RemoteAddr: conn.turnRelay.SrvRefAddr(), }) if err != nil { return err @@ -742,6 +724,10 @@ func (conn *Conn) Status() ConnStatus { return conn.status } +func (conn *Conn) OnRemoteRelayRequest(relayedAddr string, remoteIP string) { + +} + // OnRemoteOffer handles an offer from the remote peer and returns true if the message was accepted, false otherwise // doesn't block, discards the message if connection wasn't ready func (conn *Conn) OnRemoteOffer(offer OfferAnswer) bool { diff --git a/client/internal/relay/turn.go b/client/internal/relay/turn.go new file mode 100644 index 000000000..75b53135d --- /dev/null +++ b/client/internal/relay/turn.go @@ -0,0 +1,129 @@ +package relay + +import ( + "fmt" + "math" + "net" + "sync" + + "github.com/pion/logging" + "github.com/pion/stun/v2" + "github.com/pion/turn/v3" + log "github.com/sirupsen/logrus" +) + +type PermanentTurn struct { + stunURI *stun.URI + turnURI *stun.URI + + stunConn net.PacketConn + turnClient *turn.Client + turnClientListenLock sync.Mutex + relayConn net.PacketConn // represents the remote socket. + srvReflexiveAddress *net.UDPAddr +} + +func NewPermanentTurn(stunURL, turnURL *stun.URI) *PermanentTurn { + return &PermanentTurn{ + stunURI: stunURL, + turnURI: turnURL, + } +} + +func (r *PermanentTurn) Open() error { + stunConn, err := net.ListenPacket("udp4", "0.0.0.0:0") + if err != nil { + return err + } + r.stunConn = stunConn + + cfg := &turn.ClientConfig{ + STUNServerAddr: toURL(r.stunURI), + TURNServerAddr: toURL(r.turnURI), + Conn: stunConn, + Username: r.turnURI.Username, + Password: r.turnURI.Password, + LoggerFactory: logging.NewDefaultLoggerFactory(), + } + + client, err := turn.NewClient(cfg) + if err != nil { + log.Errorf("failed to create turn client: %v", err) + return err + } + r.turnClient = client + r.listen() + + relayConn, err := client.Allocate() + if err != nil { + log.Errorf("failed to allocate relay connection: %v", err) + return err + } + r.relayConn = relayConn + + srvReflexiveAddress, err := r.discoverPublicIP() + if err != nil { + log.Errorf("failed to discover public IP: %v", err) + return err + } + r.srvReflexiveAddress = srvReflexiveAddress + return nil +} + +func (r *PermanentTurn) RelayedAddress() net.Addr { + return r.relayConn.LocalAddr() +} + +func (r *PermanentTurn) SrvRefAddr() net.Addr { + return r.srvReflexiveAddress +} + +func (r *PermanentTurn) discoverPublicIP() (*net.UDPAddr, error) { + addr, err := r.turnClient.SendBindingRequest() + if err != nil { + log.Errorf("failed to send binding request: %v", err) + return nil, err + + } + + udpAddr, ok := addr.(*net.UDPAddr) + if !ok { + return nil, fmt.Errorf("failed to cast addr to udp addr") + } + + return udpAddr, nil +} + +func (r *PermanentTurn) listen() { + if !r.turnClientListenLock.TryLock() { + return + } + + go func() { + defer r.turnClientListenLock.Unlock() + + buf := make([]byte, math.MaxUint16) + for { + n, from, err := r.stunConn.ReadFrom(buf) + if err != nil { + log.Errorf("Failed to read from stun conn. Exiting loop %v", err) + break + } + + _, err = r.turnClient.HandleInbound(buf[:n], from) + if err != nil { + log.Errorf("Failed to handle inbound turn message: %s. Exiting loop", err) + break + } + } + }() +} + +func (r *PermanentTurn) PunchHole(mappedAddr net.Addr) error { + _, err := r.relayConn.WriteTo([]byte("Hello"), mappedAddr) + return err +} + +func toURL(uri *stun.URI) string { + return fmt.Sprintf("%s:%d", uri.Host, uri.Port) +} diff --git a/client/internal/relay/turn_test.go b/client/internal/relay/turn_test.go new file mode 100644 index 000000000..7752b8edd --- /dev/null +++ b/client/internal/relay/turn_test.go @@ -0,0 +1,36 @@ +package relay + +import ( + "os" + "testing" + + "github.com/pion/stun/v2" + + "github.com/netbirdio/netbird/util" +) + +func TestMain(m *testing.M) { + _ = util.InitLog("trace", "console") + code := m.Run() + os.Exit(code) +} + +func TestNewPermanentTurn(t *testing.T) { + turnURI, err := stun.ParseURI("turns:turn.netbird.io:443?transport=tcp") + if err != nil { + t.Errorf("failed to parse stun url: %v", err) + } + turnURI.Username = "1713006060" + turnURI.Password = "pO5Pfx15luZ92mW+FHPa6/LtJ7Y=" + + stunURI, err := stun.ParseURI("stun:stun.netbird.io:5555") + if err != nil { + t.Errorf("failed to parse stun url: %v", err) + } + turnRelay := NewPermanentTurn(stunURI, turnURI) + err = turnRelay.Open() + if err != nil { + t.Errorf("failed to open turn relay: %v", err) + } + +} diff --git a/signal/client/client.go b/signal/client/client.go index dc73b2ce5..13a916101 100644 --- a/signal/client/client.go +++ b/signal/client/client.go @@ -56,7 +56,7 @@ func UnMarshalCredential(msg *proto.Message) (*Credential, error) { // MarshalCredential marshal a Credential instance and returns a Message object func MarshalCredential(myKey wgtypes.Key, myPort int, remoteKey wgtypes.Key, credential *Credential, t proto.Body_Type, - rosenpassPubKey []byte, rosenpassAddr string) (*proto.Message, error) { + rosenpassPubKey []byte, rosenpassAddr, relayedAddress, serverRefIP string) (*proto.Message, error) { return &proto.Message{ Key: myKey.PublicKey().String(), RemoteKey: remoteKey.String(), @@ -69,6 +69,10 @@ func MarshalCredential(myKey wgtypes.Key, myPort int, remoteKey wgtypes.Key, cre RosenpassPubKey: rosenpassPubKey, RosenpassServerAddr: rosenpassAddr, }, + Relay: &proto.Relay{ + RelayedAddress: relayedAddress, + SrvRefAddress: serverRefIP, + }, }, }, nil } diff --git a/signal/proto/signalexchange.pb.go b/signal/proto/signalexchange.pb.go index 782c45da1..92c3d5ecc 100644 --- a/signal/proto/signalexchange.pb.go +++ b/signal/proto/signalexchange.pb.go @@ -215,16 +215,21 @@ type Body struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Type Body_Type `protobuf:"varint,1,opt,name=type,proto3,enum=signalexchange.Body_Type" json:"type,omitempty"` - Payload string `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` + Type Body_Type `protobuf:"varint,1,opt,name=type,proto3,enum=signalexchange.Body_Type" json:"type,omitempty"` + // these will be set in OFFER, ANSWER, CANDIDATE only + Payload string `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` // wgListenPort is an actual WireGuard listen port - WgListenPort uint32 `protobuf:"varint,3,opt,name=wgListenPort,proto3" json:"wgListenPort,omitempty"` + // these will be set in OFFER, ANSWER, CANDIDATE only + WgListenPort uint32 `protobuf:"varint,3,opt,name=wgListenPort,proto3" json:"wgListenPort,omitempty"` + // these will be set in OFFER, ANSWER, CANDIDATE only NetBirdVersion string `protobuf:"bytes,4,opt,name=netBirdVersion,proto3" json:"netBirdVersion,omitempty"` Mode *Mode `protobuf:"bytes,5,opt,name=mode,proto3" json:"mode,omitempty"` // featuresSupported list of supported features by the client of this protocol FeaturesSupported []uint32 `protobuf:"varint,6,rep,packed,name=featuresSupported,proto3" json:"featuresSupported,omitempty"` // RosenpassConfig is a Rosenpass config of the remote peer our peer tries to connect to + // is this optional or mandatory? RosenpassConfig *RosenpassConfig `protobuf:"bytes,7,opt,name=rosenpassConfig,proto3" json:"rosenpassConfig,omitempty"` + Relay *Relay `protobuf:"bytes,8,opt,name=relay,proto3" json:"relay,omitempty"` } func (x *Body) Reset() { @@ -308,13 +313,18 @@ func (x *Body) GetRosenpassConfig() *RosenpassConfig { return nil } +func (x *Body) GetRelay() *Relay { + if x != nil { + return x.Relay + } + return nil +} + // Mode indicates a connection mode type Mode struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - - Direct *bool `protobuf:"varint,1,opt,name=direct,proto3,oneof" json:"direct,omitempty"` } func (x *Mode) Reset() { @@ -349,11 +359,59 @@ func (*Mode) Descriptor() ([]byte, []int) { return file_signalexchange_proto_rawDescGZIP(), []int{3} } -func (x *Mode) GetDirect() bool { - if x != nil && x.Direct != nil { - return *x.Direct +type Relay struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RelayedAddress string `protobuf:"bytes,1,opt,name=relayedAddress,proto3" json:"relayedAddress,omitempty"` + SrvRefAddress string `protobuf:"bytes,2,opt,name=srvRefAddress,proto3" json:"srvRefAddress,omitempty"` +} + +func (x *Relay) Reset() { + *x = Relay{} + if protoimpl.UnsafeEnabled { + mi := &file_signalexchange_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } - return false +} + +func (x *Relay) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Relay) ProtoMessage() {} + +func (x *Relay) ProtoReflect() protoreflect.Message { + mi := &file_signalexchange_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 Relay.ProtoReflect.Descriptor instead. +func (*Relay) Descriptor() ([]byte, []int) { + return file_signalexchange_proto_rawDescGZIP(), []int{4} +} + +func (x *Relay) GetRelayedAddress() string { + if x != nil { + return x.RelayedAddress + } + return "" +} + +func (x *Relay) GetSrvRefAddress() string { + if x != nil { + return x.SrvRefAddress + } + return "" } type RosenpassConfig struct { @@ -369,7 +427,7 @@ type RosenpassConfig struct { func (x *RosenpassConfig) Reset() { *x = RosenpassConfig{} if protoimpl.UnsafeEnabled { - mi := &file_signalexchange_proto_msgTypes[4] + mi := &file_signalexchange_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -382,7 +440,7 @@ func (x *RosenpassConfig) String() string { func (*RosenpassConfig) ProtoMessage() {} func (x *RosenpassConfig) ProtoReflect() protoreflect.Message { - mi := &file_signalexchange_proto_msgTypes[4] + mi := &file_signalexchange_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -395,7 +453,7 @@ func (x *RosenpassConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use RosenpassConfig.ProtoReflect.Descriptor instead. func (*RosenpassConfig) Descriptor() ([]byte, []int) { - return file_signalexchange_proto_rawDescGZIP(), []int{4} + return file_signalexchange_proto_rawDescGZIP(), []int{5} } func (x *RosenpassConfig) GetRosenpassPubKey() []byte { @@ -431,7 +489,7 @@ var file_signalexchange_proto_rawDesc = []byte{ 0x52, 0x09, 0x72, 0x65, 0x6d, 0x6f, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x52, - 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0xf6, 0x02, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2d, + 0x04, 0x62, 0x6f, 0x64, 0x79, 0x22, 0xa3, 0x03, 0x0a, 0x04, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x42, 0x6f, 0x64, 0x79, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, @@ -451,33 +509,39 @@ var file_signalexchange_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x36, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, - 0x0a, 0x05, 0x4f, 0x46, 0x46, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x53, - 0x57, 0x45, 0x52, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x44, 0x49, 0x44, 0x41, - 0x54, 0x45, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4f, 0x44, 0x45, 0x10, 0x04, 0x22, 0x2e, - 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x06, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x22, 0x6d, - 0x0a, 0x0f, 0x52, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x50, 0x75, - 0x62, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x6f, 0x73, 0x65, - 0x6e, 0x70, 0x61, 0x73, 0x73, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x13, 0x72, - 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, - 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, - 0x61, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x32, 0xb9, 0x01, - 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x12, 0x4c, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, - 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, - 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x2e, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x59, - 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, - 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x1a, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, - 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2b, 0x0a, 0x05, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x52, 0x05, 0x72, 0x65, + 0x6c, 0x61, 0x79, 0x22, 0x36, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x4f, + 0x46, 0x46, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x4e, 0x53, 0x57, 0x45, 0x52, + 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x44, 0x49, 0x44, 0x41, 0x54, 0x45, 0x10, + 0x02, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x4f, 0x44, 0x45, 0x10, 0x04, 0x22, 0x06, 0x0a, 0x04, 0x4d, + 0x6f, 0x64, 0x65, 0x22, 0x55, 0x0a, 0x05, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x26, 0x0a, 0x0e, + 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x64, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x72, 0x76, 0x52, 0x65, 0x66, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x72, 0x76, + 0x52, 0x65, 0x66, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x6d, 0x0a, 0x0f, 0x52, 0x6f, + 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x28, 0x0a, + 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, + 0x73, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x13, 0x72, 0x6f, 0x73, 0x65, 0x6e, + 0x70, 0x61, 0x73, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x72, 0x6f, 0x73, 0x65, 0x6e, 0x70, 0x61, 0x73, 0x73, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x32, 0xb9, 0x01, 0x0a, 0x0e, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x04, + 0x53, 0x65, 0x6e, 0x64, 0x12, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, + 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, + 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x0d, 0x43, 0x6f, + 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x20, 0x2e, 0x73, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, 0x6e, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x65, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x45, + 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -493,29 +557,31 @@ func file_signalexchange_proto_rawDescGZIP() []byte { } var file_signalexchange_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_signalexchange_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_signalexchange_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_signalexchange_proto_goTypes = []interface{}{ (Body_Type)(0), // 0: signalexchange.Body.Type (*EncryptedMessage)(nil), // 1: signalexchange.EncryptedMessage (*Message)(nil), // 2: signalexchange.Message (*Body)(nil), // 3: signalexchange.Body (*Mode)(nil), // 4: signalexchange.Mode - (*RosenpassConfig)(nil), // 5: signalexchange.RosenpassConfig + (*Relay)(nil), // 5: signalexchange.Relay + (*RosenpassConfig)(nil), // 6: signalexchange.RosenpassConfig } var file_signalexchange_proto_depIdxs = []int32{ 3, // 0: signalexchange.Message.body:type_name -> signalexchange.Body 0, // 1: signalexchange.Body.type:type_name -> signalexchange.Body.Type 4, // 2: signalexchange.Body.mode:type_name -> signalexchange.Mode - 5, // 3: signalexchange.Body.rosenpassConfig:type_name -> signalexchange.RosenpassConfig - 1, // 4: signalexchange.SignalExchange.Send:input_type -> signalexchange.EncryptedMessage - 1, // 5: signalexchange.SignalExchange.ConnectStream:input_type -> signalexchange.EncryptedMessage - 1, // 6: signalexchange.SignalExchange.Send:output_type -> signalexchange.EncryptedMessage - 1, // 7: signalexchange.SignalExchange.ConnectStream:output_type -> signalexchange.EncryptedMessage - 6, // [6:8] is the sub-list for method output_type - 4, // [4:6] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 6, // 3: signalexchange.Body.rosenpassConfig:type_name -> signalexchange.RosenpassConfig + 5, // 4: signalexchange.Body.relay:type_name -> signalexchange.Relay + 1, // 5: signalexchange.SignalExchange.Send:input_type -> signalexchange.EncryptedMessage + 1, // 6: signalexchange.SignalExchange.ConnectStream:input_type -> signalexchange.EncryptedMessage + 1, // 7: signalexchange.SignalExchange.Send:output_type -> signalexchange.EncryptedMessage + 1, // 8: signalexchange.SignalExchange.ConnectStream:output_type -> signalexchange.EncryptedMessage + 7, // [7:9] is the sub-list for method output_type + 5, // [5:7] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_signalexchange_proto_init() } @@ -573,6 +639,18 @@ func file_signalexchange_proto_init() { } } file_signalexchange_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Relay); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_signalexchange_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*RosenpassConfig); i { case 0: return &v.state @@ -585,14 +663,13 @@ func file_signalexchange_proto_init() { } } } - file_signalexchange_proto_msgTypes[3].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_signalexchange_proto_rawDesc, NumEnums: 1, - NumMessages: 5, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/signal/proto/signalexchange.proto b/signal/proto/signalexchange.proto index a8c4c309c..9cf75f348 100644 --- a/signal/proto/signalexchange.proto +++ b/signal/proto/signalexchange.proto @@ -49,22 +49,33 @@ message Body { MODE = 4; } Type type = 1; + // these will be set in OFFER, ANSWER, CANDIDATE only string payload = 2; // wgListenPort is an actual WireGuard listen port + // these will be set in OFFER, ANSWER, CANDIDATE only uint32 wgListenPort = 3; + // these will be set in OFFER, ANSWER, CANDIDATE only string netBirdVersion = 4; + Mode mode = 5; // featuresSupported list of supported features by the client of this protocol repeated uint32 featuresSupported = 6; // RosenpassConfig is a Rosenpass config of the remote peer our peer tries to connect to + // is this optional or mandatory? RosenpassConfig rosenpassConfig = 7; + + Relay relay = 8; } // Mode indicates a connection mode message Mode { - optional bool direct = 1; +} + +message Relay { + string relayedAddress = 1; + string srvRefAddress = 2; } message RosenpassConfig {