diff options
author | entity0xfe <109791748+entity0xfe@users.noreply.github.com> | 2022-10-01 21:41:02 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-01 20:41:02 +0100 |
commit | ad986f372d3fac82137d406f9bf8bd2a1a74fbcd (patch) | |
tree | 585ff485276820ff3019db92817fd9d03cdc030a | |
parent | 0935886045bce20ed648e27e72b9faf5e5803130 (diff) |
cmd/strelaysrv: Add optional auth token (fixes #3987) (#8561)
* implement authentication via token for relaysrv
Make replaysrv check for a token before allowing clients to
join. The token can be set via the replay-uri.
* fix formatting
* key composite literal
* do not error out if auth material is provided but not needed
* remove unused method receiver
* clean up unused parameter in functions
* cleaner token handling, disable joining the pool if token is set.
* Keep backwards compatibility with older clients.
In prior versions of the protocol JoinRelayRequest did not have a
token field. Trying to unmarshal such a request will result in
an error. Return an empty JoinRelayRequest, that is a request
without token, instead.
Co-authored-by: entity0xfe <entity0xfe@my.domain>
-rw-r--r-- | cmd/strelaysrv/listener.go | 15 | ||||
-rw-r--r-- | cmd/strelaysrv/main.go | 8 | ||||
-rw-r--r-- | lib/relay/client/static.go | 7 | ||||
-rw-r--r-- | lib/relay/protocol/packets.go | 5 | ||||
-rw-r--r-- | lib/relay/protocol/packets_xdr.go | 65 | ||||
-rw-r--r-- | lib/relay/protocol/protocol.go | 9 |
6 files changed, 78 insertions, 31 deletions
diff --git a/cmd/strelaysrv/listener.go b/cmd/strelaysrv/listener.go index d9df57b128..d31f9b84a8 100644 --- a/cmd/strelaysrv/listener.go +++ b/cmd/strelaysrv/listener.go @@ -23,7 +23,7 @@ var ( numConnections int64 ) -func listener(_, addr string, config *tls.Config) { +func listener(_, addr string, config *tls.Config, token string) { tcpListener, err := net.Listen("tcp", addr) if err != nil { log.Fatalln(err) @@ -49,7 +49,7 @@ func listener(_, addr string, config *tls.Config) { } if isTLS { - go protocolConnectionHandler(conn, config) + go protocolConnectionHandler(conn, config, token) } else { go sessionConnectionHandler(conn) } @@ -57,7 +57,7 @@ func listener(_, addr string, config *tls.Config) { } } -func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) { +func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config, token string) { conn := tls.Server(tcpConn, config) if err := conn.SetDeadline(time.Now().Add(messageTimeout)); err != nil { if debug { @@ -119,6 +119,15 @@ func protocolConnectionHandler(tcpConn net.Conn, config *tls.Config) { switch msg := message.(type) { case protocol.JoinRelayRequest: + if token != "" && msg.Token != token { + if debug { + log.Printf("invalid token %s\n", msg.Token) + } + protocol.WriteMessage(conn, protocol.ResponseWrongToken) + conn.Close() + continue + } + if atomic.LoadInt32(&overLimit) > 0 { protocol.WriteMessage(conn, protocol.RelayFull{}) if debug { diff --git a/cmd/strelaysrv/main.go b/cmd/strelaysrv/main.go index 4633cd2ea6..bdf317875c 100644 --- a/cmd/strelaysrv/main.go +++ b/cmd/strelaysrv/main.go @@ -56,6 +56,7 @@ var ( networkBufferSize int statusAddr string + token string poolAddrs string pools []string providedBy string @@ -89,6 +90,7 @@ func main() { flag.IntVar(&globalLimitBps, "global-rate", globalLimitBps, "Global rate limit, in bytes/s") flag.BoolVar(&debug, "debug", debug, "Enable debug output") flag.StringVar(&statusAddr, "status-srv", ":22070", "Listen address for status service (blank to disable)") + flag.StringVar(&token, "token", "", "Token to restrict access to the relay (optional). Disables joining any pools.") flag.StringVar(&poolAddrs, "pools", defaultPoolAddrs, "Comma separated list of relay pool addresses to join") flag.StringVar(&providedBy, "provided-by", "", "An optional description about who provides the relay") flag.StringVar(&extAddress, "ext-address", "", "An optional address to advertise as being available on.\n\tAllows listening on an unprivileged port with port forwarding from e.g. 443, and be connected to on port 443.") @@ -256,6 +258,10 @@ func main() { log.Println("URI:", uri.String()) + if token != "" { + poolAddrs = "" + } + if poolAddrs == defaultPoolAddrs { log.Println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") log.Println("!! Joining default relay pools, this relay will be available for public use. !!") @@ -271,7 +277,7 @@ func main() { } } - go listener(proto, listen, tlsCfg) + go listener(proto, listen, tlsCfg, token) sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) diff --git a/lib/relay/client/static.go b/lib/relay/client/static.go index 1be039fbeb..11f50083bb 100644 --- a/lib/relay/client/static.go +++ b/lib/relay/client/static.go @@ -27,7 +27,8 @@ type staticClient struct { messageTimeout time.Duration connectTimeout time.Duration - conn *tls.Conn + conn *tls.Conn + token string } func newStaticClient(uri *url.URL, certs []tls.Certificate, invitations chan protocol.SessionInvitation, timeout time.Duration) *staticClient { @@ -38,6 +39,8 @@ func newStaticClient(uri *url.URL, certs []tls.Certificate, invitations chan pro messageTimeout: time.Minute * 2, connectTimeout: timeout, + + token: uri.Query().Get("token"), } c.commonClient = newCommonClient(invitations, c.serve, c.String()) return c @@ -173,7 +176,7 @@ func (c *staticClient) disconnect() { } func (c *staticClient) join() error { - if err := protocol.WriteMessage(c.conn, protocol.JoinRelayRequest{}); err != nil { + if err := protocol.WriteMessage(c.conn, protocol.JoinRelayRequest{Token: c.token}); err != nil { return err } diff --git a/lib/relay/protocol/packets.go b/lib/relay/protocol/packets.go index 7f06dca864..1e85e2da6a 100644 --- a/lib/relay/protocol/packets.go +++ b/lib/relay/protocol/packets.go @@ -31,9 +31,12 @@ type header struct { type Ping struct{} type Pong struct{} -type JoinRelayRequest struct{} type RelayFull struct{} +type JoinRelayRequest struct { + Token string +} + type JoinSessionRequest struct { Key []byte // max:32 } diff --git a/lib/relay/protocol/packets_xdr.go b/lib/relay/protocol/packets_xdr.go index 51c20350c8..81200aa05f 100644 --- a/lib/relay/protocol/packets_xdr.go +++ b/lib/relay/protocol/packets_xdr.go @@ -137,70 +137,87 @@ func (*Pong) UnmarshalXDRFrom(_ *xdr.Unmarshaller) error { /* -JoinRelayRequest Structure: +RelayFull Structure: (contains no fields) -struct JoinRelayRequest { +struct RelayFull { } */ -func (JoinRelayRequest) XDRSize() int { +func (RelayFull) XDRSize() int { return 0 } -func (JoinRelayRequest) MarshalXDR() ([]byte, error) { +func (RelayFull) MarshalXDR() ([]byte, error) { return nil, nil } -func (JoinRelayRequest) MustMarshalXDR() []byte { +func (RelayFull) MustMarshalXDR() []byte { return nil } -func (JoinRelayRequest) MarshalXDRInto(_ *xdr.Marshaller) error { +func (RelayFull) MarshalXDRInto(_ *xdr.Marshaller) error { return nil } -func (*JoinRelayRequest) UnmarshalXDR(_ []byte) error { +func (*RelayFull) UnmarshalXDR(_ []byte) error { return nil } -func (*JoinRelayRequest) UnmarshalXDRFrom(_ *xdr.Unmarshaller) error { +func (*RelayFull) UnmarshalXDRFrom(_ *xdr.Unmarshaller) error { return nil } /* -RelayFull Structure: -(contains no fields) +JoinRelayRequest Structure: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/ / +\ Token (length + padded data) \ +/ / ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -struct RelayFull { +struct JoinRelayRequest { + string Token<>; } */ -func (RelayFull) XDRSize() int { - return 0 -} -func (RelayFull) MarshalXDR() ([]byte, error) { - return nil, nil +func (o JoinRelayRequest) XDRSize() int { + return 4 + len(o.Token) + xdr.Padding(len(o.Token)) } -func (RelayFull) MustMarshalXDR() []byte { - return nil +func (o JoinRelayRequest) MarshalXDR() ([]byte, error) { + buf := make([]byte, o.XDRSize()) + m := &xdr.Marshaller{Data: buf} + return buf, o.MarshalXDRInto(m) } -func (RelayFull) MarshalXDRInto(_ *xdr.Marshaller) error { - return nil +func (o JoinRelayRequest) MustMarshalXDR() []byte { + bs, err := o.MarshalXDR() + if err != nil { + panic(err) + } + return bs } -func (*RelayFull) UnmarshalXDR(_ []byte) error { - return nil +func (o JoinRelayRequest) MarshalXDRInto(m *xdr.Marshaller) error { + m.MarshalString(o.Token) + return m.Error } -func (*RelayFull) UnmarshalXDRFrom(_ *xdr.Unmarshaller) error { - return nil +func (o *JoinRelayRequest) UnmarshalXDR(bs []byte) error { + u := &xdr.Unmarshaller{Data: bs} + return o.UnmarshalXDRFrom(u) +} +func (o *JoinRelayRequest) UnmarshalXDRFrom(u *xdr.Unmarshaller) error { + o.Token = u.UnmarshalString() + return u.Error } /* diff --git a/lib/relay/protocol/protocol.go b/lib/relay/protocol/protocol.go index 0bc079ab65..a4eb4d8d5f 100644 --- a/lib/relay/protocol/protocol.go +++ b/lib/relay/protocol/protocol.go @@ -17,6 +17,7 @@ var ( ResponseSuccess = Response{0, "success"} ResponseNotFound = Response{1, "not found"} ResponseAlreadyConnected = Response{2, "already connected"} + ResponseWrongToken = Response{3, "wrong token"} ResponseUnexpectedMessage = Response{100, "unexpected message"} ) @@ -107,6 +108,14 @@ func ReadMessage(r io.Reader) (interface{}, error) { return msg, err case messageTypeJoinRelayRequest: var msg JoinRelayRequest + + // In prior versions of the protocol JoinRelayRequest did not have a + // token field. Trying to unmarshal such a request will result in + // an error, return msg with an empty token instead. + if header.messageLength == 0 { + return msg, nil + } + err := msg.UnmarshalXDR(buf) return msg, err case messageTypeJoinSessionRequest: |