read DNS RDLENGTH as an unsigned 16-bit value - #9548
Conversation
| val `class` = readShort().toInt() | ||
| val timeToLive = readInt() | ||
| val recordDataLength = readShort().toLong() | ||
| val recordDataLength = readShort().toUShort().toLong() |
There was a problem hiding this comment.
| val recordDataLength = readShort().toUShort().toLong() | |
| val recordDataLength = readUShort().toLong() |
(also needs an import)
There was a problem hiding this comment.
Tried this and it doesn't compile, readUShort isn't in okio yet. I checked 3.17.0 (what this repo is on) and 3.18.0, and neither has it on BufferedSource or as an extension in the okio package. I've kept readShort().toUShort().toLong() for now since it matches the count fields and SvcParam lengths above; happy to switch all the call sites over once okio grows readUShort.
There was a problem hiding this comment.
Done. The DNS code moved to okhttp3/internal/dns on master since I opened this, so I rebased and carried the change and the regression test over to the new location. That file already imports okio.readUShort for the counts and the SvcParam lengths, so it comes out as just the one-line swap to readUShort().toLong(). Test and spotless pass on the rebased branch.
| import okio.IOException | ||
| import okio.ProtocolException | ||
| import okio.Source | ||
| import okio.buffer |
There was a problem hiding this comment.
| import okio.buffer | |
| import okio.readUShort |
1c8949c to
db2a1c4
Compare
readResourceRecord pulls the record data length out of the RDLENGTH field, which RFC 1035 defines as an unsigned 16-bit integer, but it decodes that field with readShort().toLong(), so any length with the high bit set comes back negative. Every other 16-bit field in this reader already goes through toUShort(), so this one is the odd one out. For an A or AAAA record the wrong sign is caught by the exact-length check, but for a record type we don't decode the code falls into skip(recordDataLength), and okio's skip treats a negative count as a no-op rather than an error. That means a record legitimately carrying 32768 or more bytes never gets consumed, the reader stays parked in the middle of the message, and the leftover bytes either trip the trailing-data check or get read as the next record. I hit it while feeding the reader a response with a large unknown record sitting in front of an A record. Decoding the field as unsigned, the same way the counts and the HTTPS parameter lengths already are, keeps the stream in sync, and I added a regression test that reads a message with an oversized unsupported record.