|
1 | 1 | package protocol
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "crypto/tls" |
| 5 | + "encoding/binary" |
| 6 | + "errors" |
4 | 7 | "fmt"
|
5 | 8 | "io"
|
6 | 9 | )
|
@@ -35,6 +38,25 @@ func ReadResponse(r io.Reader, apiKey ApiKey, apiVersion int16) (correlationID i
|
35 | 38 |
|
36 | 39 | d.remain = int(size)
|
37 | 40 | correlationID = d.readInt32()
|
| 41 | + if err = d.err; err != nil { |
| 42 | + if errors.Is(err, io.ErrUnexpectedEOF) { |
| 43 | + // If a Writer/Reader is configured without TLS and connects |
| 44 | + // to a broker expecting TLS the only message we return to the |
| 45 | + // caller is io.ErrUnexpetedEOF which is opaque. This section |
| 46 | + // tries to determine if that's what has happened. |
| 47 | + // We first deconstruct the initial 4 bytes of the message |
| 48 | + // from the size which was read earlier. |
| 49 | + // Next, we examine those bytes to see if they looks like a TLS |
| 50 | + // error message. If they do we wrap the io.ErrUnexpectedEOF |
| 51 | + // with some context. |
| 52 | + if looksLikeUnexpectedTLS(size) { |
| 53 | + err = fmt.Errorf("%w: broker appears to be expecting TLS", io.ErrUnexpectedEOF) |
| 54 | + } |
| 55 | + return |
| 56 | + } |
| 57 | + err = dontExpectEOF(err) |
| 58 | + return |
| 59 | + } |
38 | 60 |
|
39 | 61 | res := &t.responses[apiVersion-minVersion]
|
40 | 62 |
|
@@ -109,3 +131,21 @@ func WriteResponse(w io.Writer, apiVersion int16, correlationID int32, msg Messa
|
109 | 131 |
|
110 | 132 | return err
|
111 | 133 | }
|
| 134 | + |
| 135 | +const ( |
| 136 | + tlsAlertByte byte = 0x15 |
| 137 | +) |
| 138 | + |
| 139 | +// looksLikeUnexpectedTLS returns true if the size passed in resemble |
| 140 | +// the TLS alert message that is returned to a client which sends |
| 141 | +// an invalid ClientHello message. |
| 142 | +func looksLikeUnexpectedTLS(size int32) bool { |
| 143 | + var sizeBytes [4]byte |
| 144 | + binary.BigEndian.PutUint32(sizeBytes[:], uint32(size)) |
| 145 | + |
| 146 | + if sizeBytes[0] != tlsAlertByte { |
| 147 | + return false |
| 148 | + } |
| 149 | + version := int(sizeBytes[1])<<8 | int(sizeBytes[2]) |
| 150 | + return version <= tls.VersionTLS13 && version >= tls.VersionTLS10 |
| 151 | +} |
0 commit comments