This commit is contained in:
2026-08-16 19:02:48 -03:00
parent 96fe00eb2b
commit c8e3011f21
31 changed files with 3457 additions and 351 deletions
+93 -9
View File
@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
"net"
)
const (
@@ -72,12 +73,36 @@ func MaskInPlace(data []byte, sid SessionID, mode byte, seq uint64, response boo
}
func WriteRequest(w io.Writer, mode byte, sid SessionID, seq uint64, plaintext []byte) error {
return WriteRequestProfile(w, mode, sid, seq, plaintext, 0)
}
// WriteRequestProfile writes a binary request whose first byte is XORed with
// headerMask. The remaining framing and payload encoding stay unchanged.
// Masks are selected once at client startup and then remain fixed.
func WriteRequestProfile(w io.Writer, mode byte, sid SessionID, seq uint64, plaintext []byte, headerMask byte) error {
return WriteRequestProfileEncoding(w, mode, sid, seq, plaintext, headerMask, false)
}
// WriteRequestProfileEncoding optionally leaves the payload clear. Clear mode
// is signalled by the connection cover preface, so legacy peers continue to use
// the SHA-256 compatibility mask unchanged.
func WriteRequestProfileEncoding(w io.Writer, mode byte, sid SessionID, seq uint64, plaintext []byte, headerMask byte, clear bool) error {
if len(plaintext) > MaxPayload {
return fmt.Errorf("request payload too large: %d", len(plaintext))
}
if clear {
var header [RequestHeaderSize]byte
header[0] = mode ^ headerMask
copy(header[1:17], sid[:])
binary.BigEndian.PutUint64(header[17:25], seq)
binary.BigEndian.PutUint32(header[25:29], uint32(len(plaintext)))
buffers := net.Buffers{header[:], plaintext}
_, err := buffers.WriteTo(w)
return err
}
packet := make([]byte, RequestHeaderSize+len(plaintext))
packet[0] = mode
packet[0] = mode ^ headerMask
copy(packet[1:17], sid[:])
binary.BigEndian.PutUint64(packet[17:25], seq)
binary.BigEndian.PutUint32(packet[25:29], uint32(len(plaintext)))
@@ -87,13 +112,25 @@ func WriteRequest(w io.Writer, mode byte, sid SessionID, seq uint64, plaintext [
}
func ReadRequest(r io.Reader) (Request, error) {
return ReadRequestProfile(r, 0)
}
// ReadRequestProfile decodes a request written with WriteRequestProfile.
func ReadRequestProfile(r io.Reader, headerMask byte) (Request, error) {
return ReadRequestProfileEncoding(r, headerMask, false)
}
func ReadRequestProfileEncoding(r io.Reader, headerMask byte, clear bool) (Request, error) {
var req Request
var header [RequestHeaderSize]byte
if _, err := io.ReadFull(r, header[:]); err != nil {
return req, err
}
req.Mode = header[0]
req.Mode = header[0] ^ headerMask
if req.Mode > ModeClose {
return req, errors.New("unknown request mode")
}
copy(req.Session[:], header[1:17])
req.Seq = binary.BigEndian.Uint64(header[17:25])
n := binary.BigEndian.Uint32(header[25:29])
@@ -106,28 +143,53 @@ func ReadRequest(r io.Reader) (Request, error) {
if _, err := io.ReadFull(r, req.Payload); err != nil {
return req, err
}
MaskInPlace(req.Payload, req.Session, req.Mode, req.Seq, false)
if !clear {
MaskInPlace(req.Payload, req.Session, req.Mode, req.Seq, false)
}
}
return req, nil
}
func WriteResponse(w io.Writer, status byte, body []byte) error {
return WriteResponseProfile(w, status, body, writerHeaderMask(w))
}
// WriteResponseProfile writes a response using the selected first-byte mask.
func WriteResponseProfile(w io.Writer, status byte, body []byte, headerMask byte) error {
if len(body) > MaxPayload {
return fmt.Errorf("response body too large: %d", len(body))
}
packet := make([]byte, ResponseHeaderSize+len(body))
packet[0] = status
packet[0] = status ^ headerMask
binary.BigEndian.PutUint32(packet[1:5], uint32(len(body)))
copy(packet[5:], body)
return writeAll(w, packet)
}
func WriteMaskedResponse(w io.Writer, status byte, body []byte, sid SessionID, mode byte, seq uint64) error {
return WriteMaskedResponseProfileEncoding(w, status, body, sid, mode, seq, writerHeaderMask(w), writerClearPayload(w))
}
// WriteMaskedResponseProfile combines the normal payload mask with the
// selected first-byte header mask.
func WriteMaskedResponseProfile(w io.Writer, status byte, body []byte, sid SessionID, mode byte, seq uint64, headerMask byte) error {
return WriteMaskedResponseProfileEncoding(w, status, body, sid, mode, seq, headerMask, false)
}
func WriteMaskedResponseProfileEncoding(w io.Writer, status byte, body []byte, sid SessionID, mode byte, seq uint64, headerMask byte, clear bool) error {
if len(body) > MaxPayload {
return fmt.Errorf("response body too large: %d", len(body))
}
if clear {
var header [ResponseHeaderSize]byte
header[0] = status ^ headerMask
binary.BigEndian.PutUint32(header[1:5], uint32(len(body)))
buffers := net.Buffers{header[:], body}
_, err := buffers.WriteTo(w)
return err
}
packet := make([]byte, ResponseHeaderSize+len(body))
packet[0] = status
packet[0] = status ^ headerMask
binary.BigEndian.PutUint32(packet[1:5], uint32(len(body)))
copy(packet[5:], body)
MaskInPlace(packet[5:], sid, mode, seq, true)
@@ -135,6 +197,11 @@ func WriteMaskedResponse(w io.Writer, status byte, body []byte, sid SessionID, m
}
func ReadResponse(r io.Reader) (byte, []byte, error) {
return ReadResponseProfile(r, 0)
}
// ReadResponseProfile decodes a response written with a header profile.
func ReadResponseProfile(r io.Reader, headerMask byte) (byte, []byte, error) {
var header [ResponseHeaderSize]byte
if _, err := io.ReadFull(r, header[:]); err != nil {
return 0, nil, err
@@ -150,16 +217,19 @@ func ReadResponse(r io.Reader) (byte, []byte, error) {
return 0, nil, err
}
}
return header[0], body, nil
status := header[0] ^ headerMask
if status > StatusEOF {
return 0, nil, errors.New("unknown response status")
}
return status, body, nil
}
func DecodeMaskedResponse(status byte, body []byte, sid SessionID, mode byte, seq uint64) []byte {
if len(body) == 0 || status == StatusError {
return body
}
out := append([]byte(nil), body...)
MaskInPlace(out, sid, mode, seq, true)
return out
MaskInPlace(body, sid, mode, seq, true)
return body
}
func writeAll(w io.Writer, b []byte) error {
@@ -175,3 +245,17 @@ func writeAll(w io.Writer, b []byte) error {
}
return nil
}
func writerHeaderMask(w io.Writer) byte {
if profiled, ok := w.(interface{ HeaderMask() byte }); ok {
return profiled.HeaderMask()
}
return 0
}
func writerClearPayload(w io.Writer) bool {
if profiled, ok := w.(interface{ ClearPayload() bool }); ok {
return profiled.ClearPayload()
}
return false
}
+95 -19
View File
@@ -1,29 +1,105 @@
package wire
import (
"bytes"
"testing"
"bytes"
"io"
"testing"
)
func TestMaskChangesWithSequenceAndRoundTrips(t *testing.T) {
var sid SessionID
for i := range sid { sid[i] = byte(i+1) }
plain := bytes.Repeat([]byte("DragonTCP"), 100)
a := append([]byte(nil), plain...)
b := append([]byte(nil), plain...)
MaskInPlace(a, sid, ModeUpload, 1, false)
MaskInPlace(b, sid, ModeUpload, 2, false)
if bytes.Equal(a, b) { t.Fatal("different sequences produced identical wire bytes") }
MaskInPlace(a, sid, ModeUpload, 1, false)
if !bytes.Equal(a, plain) { t.Fatal("mask did not round-trip") }
var sid SessionID
for i := range sid {
sid[i] = byte(i + 1)
}
plain := bytes.Repeat([]byte("DragonTCP"), 100)
a := append([]byte(nil), plain...)
b := append([]byte(nil), plain...)
MaskInPlace(a, sid, ModeUpload, 1, false)
MaskInPlace(b, sid, ModeUpload, 2, false)
if bytes.Equal(a, b) {
t.Fatal("different sequences produced identical wire bytes")
}
MaskInPlace(a, sid, ModeUpload, 1, false)
if !bytes.Equal(a, plain) {
t.Fatal("mask did not round-trip")
}
}
func TestBinaryHeaderProfilesRoundTrip(t *testing.T) {
var sid SessionID
for i := range sid {
sid[i] = byte(i + 1)
}
for n := 0; n < 256; n += 8 {
mask := byte(n)
var request bytes.Buffer
if err := WriteRequestProfile(&request, ModeUpload, sid, 42, []byte("payload"), mask); err != nil {
t.Fatal(err)
}
if got := request.Bytes()[0]; got != ModeUpload^mask {
t.Fatalf("mask %02x first byte=%02x", mask, got)
}
req, err := ReadRequestProfile(&request, mask)
if err != nil {
t.Fatalf("mask %02x: %v", mask, err)
}
if req.Mode != ModeUpload || req.Seq != 42 || !bytes.Equal(req.Payload, []byte("payload")) {
t.Fatalf("mask %02x request did not round-trip", mask)
}
var response bytes.Buffer
if err := WriteResponseProfile(&response, StatusOK, []byte("ok"), mask); err != nil {
t.Fatal(err)
}
status, body, err := ReadResponseProfile(&response, mask)
if err != nil || status != StatusOK || !bytes.Equal(body, []byte("ok")) {
t.Fatalf("mask %02x response did not round-trip: status=%d body=%q err=%v", mask, status, body, err)
}
}
}
type profiledBuffer struct {
bytes.Buffer
mask byte
}
func (b *profiledBuffer) HeaderMask() byte { return b.mask }
func TestServerResponseUsesConnectionProfile(t *testing.T) {
profiled := &profiledBuffer{mask: 0xa0}
if err := WriteResponse(profiled, StatusOK, []byte("ok")); err != nil {
t.Fatal(err)
}
if got := profiled.Bytes()[0]; got != StatusOK^profiled.mask {
t.Fatalf("first byte=%02x, want %02x", got, StatusOK^profiled.mask)
}
}
func BenchmarkMask1MiB(b *testing.B) {
var sid SessionID
data := make([]byte, 1024*1024)
b.SetBytes(int64(len(data)))
b.ResetTimer()
for i:=0;i<b.N;i++ {
MaskInPlace(data,sid,ModeUpload,uint64(i),false)
}
var sid SessionID
data := make([]byte, 1024*1024)
b.SetBytes(int64(len(data)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
MaskInPlace(data, sid, ModeUpload, uint64(i), false)
}
}
func BenchmarkWriteRequest1MiB(b *testing.B) {
var sid SessionID
data := make([]byte, 1024*1024)
for _, tc := range []struct {
name string
clear bool
}{{"sha256-compat", false}, {"clear", true}} {
b.Run(tc.name, func(b *testing.B) {
b.SetBytes(int64(len(data)))
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if err := WriteRequestProfileEncoding(io.Discard, ModeUpload, sid, uint64(i), data, 0, tc.clear); err != nil {
b.Fatal(err)
}
}
})
}
}