mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 03:38:42 -07:00
Check inbound GW connection connected state in parser
If the first protocol for an inbound gateway connection is not CONNECT, reject with auth violation. Fixes #1006 Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
This commit is contained in:
@@ -40,7 +40,7 @@ var (
|
||||
|
||||
const (
|
||||
// VERSION is the current version for the server.
|
||||
VERSION = "2.0.0-RC12"
|
||||
VERSION = "2.0.0-RC14"
|
||||
|
||||
// PROTO is the currently supported protocol.
|
||||
// 0 was the original
|
||||
|
||||
@@ -149,6 +149,9 @@ type gateway struct {
|
||||
infoJSON []byte // Needed when sending INFO after receiving INFO from remote
|
||||
outsim *sync.Map // Per-account subject interest (or no-interest) (outbound conn)
|
||||
insim map[string]*insie // Per-account subject no-interest sent or modeInterestOnly mode (inbound conn)
|
||||
|
||||
// Set/check in readLoop without lock. This is to know that an inbound has sent the CONNECT protocol first
|
||||
connected bool
|
||||
}
|
||||
|
||||
// Outbound subject interest entry.
|
||||
@@ -809,6 +812,15 @@ func (c *client) processGatewayConnect(arg []byte) error {
|
||||
return ErrWrongGateway
|
||||
}
|
||||
|
||||
// For a gateway connection, c.gw is guaranteed not to be nil here
|
||||
// (created in createGateway() and never set to nil).
|
||||
// For inbound connections, it is important to know in the parser
|
||||
// if the CONNECT was received first, so we use this boolean (as
|
||||
// opposed to client.flags that require locking) to indicate that
|
||||
// CONNECT was processed. Again, this boolean is set/read in the
|
||||
// readLoop without locking.
|
||||
c.gw.connected = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -127,8 +127,17 @@ func (c *client) parse(buf []byte) error {
|
||||
|
||||
switch c.state {
|
||||
case OP_START:
|
||||
if b != 'C' && b != 'c' && authSet {
|
||||
goto authErr
|
||||
if b != 'C' && b != 'c' {
|
||||
if authSet {
|
||||
goto authErr
|
||||
}
|
||||
// If the connection is a gateway connection, make sure that
|
||||
// if this is an inbound, it starts with a CONNECT.
|
||||
if c.kind == GATEWAY && !c.gw.outbound && !c.gw.connected {
|
||||
// Use auth violation since no CONNECT was sent.
|
||||
// It could be a parseErr too.
|
||||
goto authErr
|
||||
}
|
||||
}
|
||||
switch b {
|
||||
case 'P', 'p':
|
||||
|
||||
@@ -446,3 +446,36 @@ func TestGatewaySendAllSubs(t *testing.T) {
|
||||
clientSend("UNSUB 1\r\n")
|
||||
gAExpect(runsubRe)
|
||||
}
|
||||
|
||||
func TestGatewayNoPanicOnBadProtocol(t *testing.T) {
|
||||
ob := testDefaultOptionsForGateway("B")
|
||||
sb := runGatewayServer(ob)
|
||||
defer sb.Shutdown()
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
proto string
|
||||
}{
|
||||
{"sub", "SUB > 1\r\n"},
|
||||
{"unsub", "UNSUB 1\r\n"},
|
||||
{"rsub", "RS+ $foo foo 2\r\n"},
|
||||
{"runsub", "RS- $foo foo 2\r\n"},
|
||||
{"pub", "PUB foo 2\r\nok\r\n"},
|
||||
{"anything", "xxxx\r\n"},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
// Create raw tcp connection to gateway port
|
||||
client := createClientConn(t, ob.Gateway.Host, ob.Gateway.Port)
|
||||
defer client.Close()
|
||||
clientSend := sendCommand(t, client)
|
||||
clientSend(test.proto)
|
||||
})
|
||||
}
|
||||
|
||||
// Server should not have crashed.
|
||||
client := createClientConn(t, ob.Host, ob.Port)
|
||||
defer client.Close()
|
||||
clientSend, clientExpect := setupConn(t, client)
|
||||
clientSend("PING\r\n")
|
||||
clientExpect(pongRe)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user