61 lines
1.5 KiB
Go
61 lines
1.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
// Reject truncated, oversized or compressed-bomb frames before slicing payloads.
|
|
func decodeVolc(data []byte) (typ, flags byte, code uint32, payload []byte, err error) {
|
|
invalid := errors.New("invalid ASR frame")
|
|
if len(data) < 8 || data[0]>>4 != 1 {
|
|
return 0, 0, 0, nil, invalid
|
|
}
|
|
typ, flags = data[1]>>4, data[1]&15
|
|
off := int(data[0]&15) * 4
|
|
if off < 4 || off > len(data) || (typ != msgFullServer && typ != msgError) {
|
|
return 0, 0, 0, nil, invalid
|
|
}
|
|
if flags&1 != 0 {
|
|
off += 4
|
|
} // Bit 1 means last packet; it does not imply a sequence field.
|
|
if off > len(data) {
|
|
return 0, 0, 0, nil, invalid
|
|
}
|
|
if typ == msgError {
|
|
if off+4 > len(data) {
|
|
return 0, 0, 0, nil, invalid
|
|
}
|
|
code = binary.BigEndian.Uint32(data[off : off+4])
|
|
off += 4
|
|
}
|
|
if off+4 > len(data) {
|
|
return 0, 0, 0, nil, invalid
|
|
}
|
|
size := uint64(binary.BigEndian.Uint32(data[off : off+4]))
|
|
off += 4
|
|
if size > 1<<20 || size != uint64(len(data)-off) {
|
|
return 0, 0, 0, nil, invalid
|
|
}
|
|
payload = data[off:]
|
|
switch data[2] & 15 {
|
|
case compNone:
|
|
case compGzip:
|
|
reader, e := gzip.NewReader(bytes.NewReader(payload))
|
|
if e != nil {
|
|
return 0, 0, 0, nil, invalid
|
|
}
|
|
payload, e = io.ReadAll(io.LimitReader(reader, (1<<20)+1))
|
|
closeErr := reader.Close()
|
|
if e != nil || closeErr != nil || len(payload) > 1<<20 {
|
|
return 0, 0, 0, nil, invalid
|
|
}
|
|
default:
|
|
return 0, 0, 0, nil, invalid
|
|
}
|
|
return typ, flags, code, payload, nil
|
|
}
|