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:
Ivan Kozlovic
2019-05-22 12:31:16 -06:00
parent 698d9e642c
commit 97ee89cc67
4 changed files with 57 additions and 3 deletions

View File

@@ -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

View File

@@ -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
}

View File

@@ -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':

View File

@@ -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)
}