From ed4022c5b21e91dfe6a7d922729db055e4c0d829 Mon Sep 17 00:00:00 2001 From: Alim Shapiev Date: Sun, 3 Nov 2024 10:28:51 +0100 Subject: [PATCH] Refactoring and fixes --- x/configurl/fake.go | 66 ++----------------- x/fake/settings.go | 57 ++++++++++++++++ x/fake/stream_dialer.go | 57 +++++++++++++--- x/fake/writer.go | 43 +++++++----- x/fake/writer_test.go | 52 +++++++-------- .../md5signature.go} | 2 +- x/packet/type.go | 34 ++++++++++ 7 files changed, 198 insertions(+), 113 deletions(-) create mode 100644 x/fake/settings.go rename x/{fake/signature/signature.go => md5signature/md5signature.go} (98%) create mode 100644 x/packet/type.go diff --git a/x/configurl/fake.go b/x/configurl/fake.go index 66077a87..55b9bb9c 100644 --- a/x/configurl/fake.go +++ b/x/configurl/fake.go @@ -1,80 +1,22 @@ -// Copyright 2024 The Outline Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package configurl import ( "context" "fmt" - "github.com/Jigsaw-Code/outline-sdk/x/fake" - "strconv" - "github.com/Jigsaw-Code/outline-sdk/transport" + "github.com/Jigsaw-Code/outline-sdk/x/fake" ) -// tls wikipedia request -var tlsData = [517]byte{ - 0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0xfc, 0x03, 0x03, 0x03, 0x5f, - 0x6f, 0x2c, 0xed, 0x13, 0x22, 0xf8, 0xdc, 0xb2, 0xf2, 0x60, 0x48, 0x2d, 0x72, - 0x66, 0x6f, 0x57, 0xdd, 0x13, 0x9d, 0x1b, 0x37, 0xdc, 0xfa, 0x36, 0x2e, 0xba, - 0xf9, 0x92, 0x99, 0x3a, 0x20, 0xf9, 0xdf, 0x0c, 0x2e, 0x8a, 0x55, 0x89, 0x82, - 0x31, 0x63, 0x1a, 0xef, 0xa8, 0xbe, 0x08, 0x58, 0xa7, 0xa3, 0x5a, 0x18, 0xd3, - 0x96, 0x5f, 0x04, 0x5c, 0xb4, 0x62, 0xaf, 0x89, 0xd7, 0x0f, 0x8b, 0x00, 0x3e, - 0x13, 0x02, 0x13, 0x03, 0x13, 0x01, 0xc0, 0x2c, 0xc0, 0x30, 0x00, 0x9f, 0xcc, - 0xa9, 0xcc, 0xa8, 0xcc, 0xaa, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e, 0xc0, 0x24, - 0xc0, 0x28, 0x00, 0x6b, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x67, 0xc0, 0x0a, 0xc0, - 0x14, 0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0x00, 0x9d, 0x00, 0x9c, - 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0xff, 0x01, 0x00, 0x01, - 0x75, 0x00, 0x00, 0x00, 0x16, 0x00, 0x14, 0x00, 0x00, 0x11, 0x77, 0x77, 0x77, - 0x2e, 0x77, 0x69, 0x6b, 0x69, 0x70, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x6f, 0x72, - 0x67, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x16, - 0x00, 0x14, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x19, 0x00, 0x18, 0x01, - 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04, 0x00, 0x10, 0x00, 0x0e, - 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, - 0x31, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, - 0x00, 0x0d, 0x00, 0x2a, 0x00, 0x28, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, - 0x07, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0a, 0x08, 0x0b, 0x08, 0x04, 0x08, 0x05, - 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x03, 0x03, 0x03, 0x01, 0x03, - 0x02, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x00, 0x2b, 0x00, 0x09, 0x08, 0x03, - 0x04, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, - 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x11, 0x8c, 0xb8, - 0x8c, 0xe8, 0x8a, 0x08, 0x90, 0x1e, 0xee, 0x19, 0xd9, 0xdd, 0xe8, 0xd4, 0x06, - 0xb1, 0xd1, 0xe2, 0xab, 0xe0, 0x16, 0x63, 0xd6, 0xdc, 0xda, 0x84, 0xa4, 0xb8, - 0x4b, 0xfb, 0x0e, 0x00, 0x15, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -} -var httpData = []byte("GET / HTTP/1.1\r\nHost: www.wikipedia.org\r\n\r\n") -var udpData [64]byte - func registerFakeStreamDialer(r TypeRegistry[transport.StreamDialer], typeID string, newSD BuildFunc[transport.StreamDialer]) { r.RegisterType(typeID, func(ctx context.Context, config *Config) (transport.StreamDialer, error) { sd, err := newSD(ctx, config.BaseConfig) if err != nil { return nil, err } - prefixBytesStr := config.URL.Opaque - prefixBytes, err := strconv.Atoi(prefixBytesStr) + settings, err := fake.ParseSettings(config.URL.Opaque) if err != nil { - return nil, fmt.Errorf("prefixBytes is not a number: %v. Fake config should be in fake: format", prefixBytesStr) + return nil, fmt.Errorf("failed to parse settings: %w", err) } - // TODO: Read fake data from the CLI or use a default value (depending on the protocol). - var fakeData []byte - // TODO: Read fake offset from the CLI - var fakeOffset int64 = 0 - // TODO: Read fake TTL from the CLI or use a default value (8) - var fakeTtl int = 8 - // TODO: Read md5 signature from the CLI or use a default value (false). - var md5Sig bool = false - return fake.NewStreamDialer(sd, int64(prefixBytes), fakeData, fakeOffset, fakeTtl, md5Sig) + return fake.NewStreamDialer(sd, settings.FakeData, settings.FakeOffset, settings.FakeBytes, settings.FakeTtl, settings.Md5Sig) }) } diff --git a/x/fake/settings.go b/x/fake/settings.go new file mode 100644 index 00000000..193cf2cb --- /dev/null +++ b/x/fake/settings.go @@ -0,0 +1,57 @@ +package fake + +import ( + "fmt" + "strconv" + "strings" +) + +const defaultTtl = 8 + +type Settings struct { + FakeData []byte + FakeOffset int64 + FakeBytes int64 + FakeTtl int + Md5Sig bool +} + +// ParseSettings expects the settings to be in the format "[data(str)]::::" +func ParseSettings(raw string) (*Settings, error) { + result := Settings{ + FakeTtl: defaultTtl, + } + parts := strings.Split(raw, ":") + if len(parts) > 0 && parts[0] != "" { + result.FakeData = []byte(parts[0]) + } + if len(parts) > 1 && parts[1] != "" { + offset, err := strconv.ParseInt(parts[1], 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse offset: %w", err) + } + result.FakeOffset = offset + } + if len(parts) > 2 && parts[2] != "" { + bytes, err := strconv.ParseInt(parts[2], 10, 64) + if err != nil { + return nil, fmt.Errorf("failed to parse bytes: %w", err) + } + result.FakeBytes = bytes + } + if len(parts) > 3 && parts[3] != "" { + ttl, err := strconv.Atoi(parts[3]) + if err != nil { + return nil, fmt.Errorf("failed to parse TTL: %w", err) + } + result.FakeTtl = ttl + } + if len(parts) > 4 && parts[4] != "" { + md5Sig, err := strconv.ParseBool(parts[4]) + if err != nil { + return nil, fmt.Errorf("failed to parse MD5 signature flag: %w", err) + } + result.Md5Sig = md5Sig + } + return &result, nil +} diff --git a/x/fake/stream_dialer.go b/x/fake/stream_dialer.go index e3ceb81c..f2752881 100644 --- a/x/fake/stream_dialer.go +++ b/x/fake/stream_dialer.go @@ -18,30 +18,64 @@ import ( "context" "errors" "fmt" - "github.com/Jigsaw-Code/outline-sdk/x/fake/signature" + "github.com/Jigsaw-Code/outline-sdk/x/md5signature" "net" "github.com/Jigsaw-Code/outline-sdk/transport" ) +// Example of fake data for TLS +var defaultTlsFakeData = [517]byte{ + 0x16, 0x03, 0x01, 0x02, 0x00, 0x01, 0x00, 0x01, 0xfc, 0x03, 0x03, 0x03, 0x5f, + 0x6f, 0x2c, 0xed, 0x13, 0x22, 0xf8, 0xdc, 0xb2, 0xf2, 0x60, 0x48, 0x2d, 0x72, + 0x66, 0x6f, 0x57, 0xdd, 0x13, 0x9d, 0x1b, 0x37, 0xdc, 0xfa, 0x36, 0x2e, 0xba, + 0xf9, 0x92, 0x99, 0x3a, 0x20, 0xf9, 0xdf, 0x0c, 0x2e, 0x8a, 0x55, 0x89, 0x82, + 0x31, 0x63, 0x1a, 0xef, 0xa8, 0xbe, 0x08, 0x58, 0xa7, 0xa3, 0x5a, 0x18, 0xd3, + 0x96, 0x5f, 0x04, 0x5c, 0xb4, 0x62, 0xaf, 0x89, 0xd7, 0x0f, 0x8b, 0x00, 0x3e, + 0x13, 0x02, 0x13, 0x03, 0x13, 0x01, 0xc0, 0x2c, 0xc0, 0x30, 0x00, 0x9f, 0xcc, + 0xa9, 0xcc, 0xa8, 0xcc, 0xaa, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e, 0xc0, 0x24, + 0xc0, 0x28, 0x00, 0x6b, 0xc0, 0x23, 0xc0, 0x27, 0x00, 0x67, 0xc0, 0x0a, 0xc0, + 0x14, 0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0x00, 0x9d, 0x00, 0x9c, + 0x00, 0x3d, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x2f, 0x00, 0xff, 0x01, 0x00, 0x01, + 0x75, 0x00, 0x00, 0x00, 0x16, 0x00, 0x14, 0x00, 0x00, 0x11, 0x77, 0x77, 0x77, + 0x2e, 0x77, 0x69, 0x6b, 0x69, 0x70, 0x65, 0x64, 0x69, 0x61, 0x2e, 0x6f, 0x72, + 0x67, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, 0x16, + 0x00, 0x14, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x19, 0x00, 0x18, 0x01, + 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, 0x01, 0x04, 0x00, 0x10, 0x00, 0x0e, + 0x00, 0x0c, 0x02, 0x68, 0x32, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, + 0x31, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, + 0x00, 0x0d, 0x00, 0x2a, 0x00, 0x28, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x08, + 0x07, 0x08, 0x08, 0x08, 0x09, 0x08, 0x0a, 0x08, 0x0b, 0x08, 0x04, 0x08, 0x05, + 0x08, 0x06, 0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x03, 0x03, 0x03, 0x01, 0x03, + 0x02, 0x04, 0x02, 0x05, 0x02, 0x06, 0x02, 0x00, 0x2b, 0x00, 0x09, 0x08, 0x03, + 0x04, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, + 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x11, 0x8c, 0xb8, + 0x8c, 0xe8, 0x8a, 0x08, 0x90, 0x1e, 0xee, 0x19, 0xd9, 0xdd, 0xe8, 0xd4, 0x06, + 0xb1, 0xd1, 0xe2, 0xab, 0xe0, 0x16, 0x63, 0xd6, 0xdc, 0xda, 0x84, 0xa4, 0xb8, + 0x4b, 0xfb, 0x0e, 0x00, 0x15, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +} + +// Example of fake data for HTTP +var defaultHttpFakeData = []byte("GET / HTTP/1.1\r\nHost: www.wikipedia.org\r\n\r\n") + type fakeDialer struct { dialer transport.StreamDialer - splitPoint int64 fakeData []byte fakeOffset int64 + fakeBytes int64 fakeTtl int md5Sig bool } var _ transport.StreamDialer = (*fakeDialer)(nil) -// NewStreamDialer creates a [transport.StreamDialer] that writes "fakeData" in the beginning of the stream and -// then splits the outgoing stream after writing "fakeBytes" bytes using [FakeWriter]. +// NewStreamDialer creates a [transport.StreamDialer] that writes "FakeData" in the beginning of the stream and +// then splits the outgoing stream after writing "FakeBytes" bytes using [FakeWriter]. func NewStreamDialer( dialer transport.StreamDialer, - prefixBytes int64, fakeData []byte, fakeOffset int64, + fakeBytes int64, fakeTtl int, md5Sig bool, ) (transport.StreamDialer, error) { @@ -50,9 +84,9 @@ func NewStreamDialer( } return &fakeDialer{ dialer: dialer, - splitPoint: prefixBytes, fakeData: fakeData, fakeOffset: fakeOffset, + fakeBytes: fakeBytes, fakeTtl: fakeTtl, md5Sig: md5Sig, }, nil @@ -65,10 +99,17 @@ func (d *fakeDialer) DialStream(ctx context.Context, remoteAddr string) (transpo return nil, err } if tcpInnerConn, isTcp := innerConn.(*net.TCPConn); isTcp && d.md5Sig { - err := signature.Add(tcpInnerConn, remoteAddr, tcpInnerConn.RemoteAddr().String()) + err := md5signature.Add(tcpInnerConn, remoteAddr, tcpInnerConn.RemoteAddr().String()) if err != nil { return nil, fmt.Errorf("failed to add MD5 signature: %w", err) } } - return transport.WrapConn(innerConn, innerConn, NewWriter(innerConn, d.splitPoint, d.fakeData, d.fakeOffset, d.fakeTtl)), nil + return transport.WrapConn(innerConn, innerConn, NewWriter(innerConn, d.fakeData, d.fakeOffset, d.fakeBytes, d.fakeTtl)), nil +} + +func getDefaultFakeData(isHttp bool) []byte { + if isHttp { + return defaultHttpFakeData + } + return defaultTlsFakeData[:] } diff --git a/x/fake/writer.go b/x/fake/writer.go index d72539bb..10b9428e 100644 --- a/x/fake/writer.go +++ b/x/fake/writer.go @@ -1,8 +1,10 @@ package fake import ( + "bufio" "bytes" "fmt" + "github.com/Jigsaw-Code/outline-sdk/x/packet" "github.com/Jigsaw-Code/outline-sdk/x/ttl" "io" "net" @@ -10,9 +12,9 @@ import ( type fakeWriter struct { writer io.Writer - fakeBytes int64 fakeData []byte fakeOffset int64 + fakeBytes int64 ttl int } @@ -26,11 +28,11 @@ type fakeWriterReaderFrom struct { var _ io.ReaderFrom = (*fakeWriterReaderFrom)(nil) // NewWriter creates a [io.Writer] that ensures the fake data is written before the real data. -// A write will end right after byte index fakeBytes - 1, before a write starting at byte index fakeBytes. -// For example, if you have a write of [0123456789], fakeData = [abc], fakeOffset = 1, and fakeBytes = 3, +// A write will end right after byte index FakeBytes - 1, before a write starting at byte index FakeBytes. +// For example, if you have a write of [0123456789], FakeData = [abc], FakeOffset = 1, and FakeBytes = 3, // you will get writes [bc] and [0123456789]. If the input writer is a [io.ReaderFrom], the output writer will be too. -func NewWriter(writer io.Writer, fakeBytes int64, fakeData []byte, fakeOffset int64, fakeTtl int) io.Writer { - sw := &fakeWriter{writer, fakeBytes, fakeData, fakeOffset, fakeTtl} +func NewWriter(writer io.Writer, fakeData []byte, fakeOffset int64, fakeBytes int64, fakeTtl int) io.Writer { + sw := &fakeWriter{writer, fakeData, fakeOffset, fakeBytes, fakeTtl} if rf, ok := writer.(io.ReaderFrom); ok { return &fakeWriterReaderFrom{sw, rf} } @@ -39,7 +41,8 @@ func NewWriter(writer io.Writer, fakeBytes int64, fakeData []byte, fakeOffset in func (w *fakeWriterReaderFrom) ReadFrom(source io.Reader) (written int64, err error) { conn, isNetConn := w.writer.(net.Conn) - fakeData := w.getFakeData() + bufioReader := bufio.NewReader(source) + fakeData := w.getFakeData(bufioReader) if fakeData != nil { if isNetConn { oldTtl, err := ttl.Set(conn, w.ttl) @@ -66,7 +69,7 @@ func (w *fakeWriterReaderFrom) ReadFrom(source io.Reader) (written int64, err er func (w *fakeWriter) Write(data []byte) (written int, err error) { conn, isNetConn := w.writer.(net.Conn) - fakeData := w.getFakeData() + fakeData := w.getFakeData(bufio.NewReader(bytes.NewReader(data))) if fakeData != nil { if isNetConn { oldTtl, err := ttl.Set(conn, w.ttl) @@ -79,27 +82,35 @@ func (w *fakeWriter) Write(data []byte) (written int, err error) { } }() } + fmt.Printf("Writing fake data with TTL %d:\n---\n%s\n---\n", w.ttl, fakeData) + fakeData = append(fakeData, make([]byte, len(data)-len(fakeData))...) fakeN, err := w.writer.Write(fakeData) written += fakeN if err != nil { return written, err } } - n, err := w.writer.Write(data) - written += n + fmt.Printf("Writing real data:\n---\n%s\n---\n", data) + //n, err := w.writer.Write(data) + //written += n return written, err } -func (w *fakeWriter) getFakeData() []byte { - if w.fakeOffset >= int64(len(w.fakeData)) { +func (w *fakeWriter) getFakeData(dataReader *bufio.Reader) []byte { + fakeData := w.fakeData + if fakeData == nil { + isHttp := packet.IsHTTP(dataReader) + fakeData = getDefaultFakeData(isHttp) + } + if w.fakeOffset >= int64(len(fakeData)) { return nil } - data := w.fakeData[w.fakeOffset:] - if w.fakeBytes < int64(len(data)) { - data = data[:w.fakeBytes] + fakeData = fakeData[w.fakeOffset:] + if w.fakeBytes < int64(len(fakeData)) { + fakeData = fakeData[:w.fakeBytes] } - if len(data) == 0 { + if len(fakeData) == 0 { return nil } - return data + return fakeData } diff --git a/x/fake/writer_test.go b/x/fake/writer_test.go index 8d048e11..5134dfc1 100644 --- a/x/fake/writer_test.go +++ b/x/fake/writer_test.go @@ -44,7 +44,7 @@ func TestWrite_FullFake(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(len(fakeData)) // 9 fakeOffset := int64(0) - fakeWriter := NewWriter(&innerWriter, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&innerWriter, fakeData, fakeOffset, fakeBytes, 0) n, err := fakeWriter.Write([]byte("Request")) // 7 bytes require.NoError(t, err) require.Equal(t, 16, n) // 9 fake + 7 real @@ -56,7 +56,7 @@ func TestWrite_PartialFake(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(5) // Inject first 5 bytes: "Fake " fakeOffset := int64(0) - fakeWriter := NewWriter(&innerWriter, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&innerWriter, fakeData, fakeOffset, fakeBytes, 0) n, err := fakeWriter.Write([]byte("Request")) // 7 bytes require.NoError(t, err) require.Equal(t, 12, n) // 5 fake + 7 real @@ -68,7 +68,7 @@ func TestWrite_NoFake(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(0) // No fake data fakeOffset := int64(0) - fakeWriter := NewWriter(&innerWriter, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&innerWriter, fakeData, fakeOffset, fakeBytes, 0) n, err := fakeWriter.Write([]byte("Request")) // 7 bytes require.NoError(t, err) require.Equal(t, 7, n) // 0 fake + 7 real @@ -79,8 +79,8 @@ func TestWrite_WithOffset(t *testing.T) { var innerWriter collectWrites fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(4) // Inject 4 bytes starting from offset - fakeOffset := int64(5) // fakeData[5:] = "data" - fakeWriter := NewWriter(&innerWriter, fakeBytes, fakeData, fakeOffset, 0) + fakeOffset := int64(5) // FakeData[5:] = "data" + fakeWriter := NewWriter(&innerWriter, fakeData, fakeOffset, fakeBytes, 0) n, err := fakeWriter.Write([]byte("Request")) // 7 bytes require.NoError(t, err) require.Equal(t, 11, n) // 4 fake + 7 real @@ -92,7 +92,7 @@ func TestWrite_NeedsTwoWrites(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(6) // Inject first 6 bytes: "Fake d" fakeOffset := int64(0) - fakeWriter := NewWriter(&innerWriter, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&innerWriter, fakeData, fakeOffset, fakeBytes, 0) n, err := fakeWriter.Write([]byte("Request")) // 7 bytes require.NoError(t, err) require.Equal(t, 13, n) // 6 fake + 7 real @@ -101,19 +101,19 @@ func TestWrite_NeedsTwoWrites(t *testing.T) { func TestWrite_Compound(t *testing.T) { var innerWriter collectWrites - // First fakeWriter: fakeBytes=1, fakeData="F" + // First fakeWriter: FakeBytes=1, FakeData="F" fakeData1 := []byte("F") fakeBytes1 := int64(1) fakeOffset1 := int64(0) fakeTtl1 := 0 - writer1 := NewWriter(&innerWriter, fakeBytes1, fakeData1, fakeOffset1, fakeTtl1) + writer1 := NewWriter(&innerWriter, fakeData1, fakeOffset1, fakeBytes1, fakeTtl1) - // Second fakeWriter: fakeBytes=3, fakeData="ake d", fakeOffset=0 - fakeData2 := []byte("ake") // Total fakeData now: "Fake d" + // Second fakeWriter: FakeBytes=3, FakeData="ake d", FakeOffset=0 + fakeData2 := []byte("ake") // Total FakeData now: "Fake d" fakeBytes2 := int64(3) fakeOffset2 := int64(0) fakeTtl2 := 0 - fakeWriter := NewWriter(writer1, fakeBytes2, fakeData2, fakeOffset2, fakeTtl2) + fakeWriter := NewWriter(writer1, fakeData2, fakeOffset2, fakeBytes2, fakeTtl2) // Write "Request" n, err := fakeWriter.Write([]byte("Request")) // 7 bytes @@ -126,7 +126,7 @@ func TestReadFrom_FullFake(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(9) // Inject all fake data fakeOffset := int64(0) - fakeWriter := NewWriter(&bytes.Buffer{}, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&bytes.Buffer{}, fakeData, fakeOffset, fakeBytes, 0) rf, ok := fakeWriter.(io.ReaderFrom) require.True(t, ok) @@ -140,7 +140,7 @@ func TestReadFrom_PartialFake(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(5) // Inject first 5 bytes: "Fake " fakeOffset := int64(0) - fakeWriter := NewWriter(&bytes.Buffer{}, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&bytes.Buffer{}, fakeData, fakeOffset, fakeBytes, 0) rf, ok := fakeWriter.(io.ReaderFrom) require.True(t, ok) @@ -154,7 +154,7 @@ func TestReadFrom_NoFake(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(0) // No fake data fakeOffset := int64(0) - fakeWriter := NewWriter(&bytes.Buffer{}, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&bytes.Buffer{}, fakeData, fakeOffset, fakeBytes, 0) rf, ok := fakeWriter.(io.ReaderFrom) require.True(t, ok) @@ -167,8 +167,8 @@ func TestReadFrom_NoFake(t *testing.T) { func TestReadFrom_WithOffset(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(4) // Inject 4 bytes starting from offset - fakeOffset := int64(5) // fakeData[5:] = "data" - fakeWriter := NewWriter(&bytes.Buffer{}, fakeBytes, fakeData, fakeOffset, 0) + fakeOffset := int64(5) // FakeData[5:] = "data" + fakeWriter := NewWriter(&bytes.Buffer{}, fakeData, fakeOffset, fakeBytes, 0) rf, ok := fakeWriter.(io.ReaderFrom) require.True(t, ok) @@ -182,7 +182,7 @@ func TestReadFrom_NeedsTwoReads(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(6) // Inject first 6 bytes: "Fake d" fakeOffset := int64(0) - fakeWriter := NewWriter(&bytes.Buffer{}, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&bytes.Buffer{}, fakeData, fakeOffset, fakeBytes, 0) rf, ok := fakeWriter.(io.ReaderFrom) require.True(t, ok) @@ -201,19 +201,19 @@ func TestReadFrom_NeedsTwoReads(t *testing.T) { func TestReadFrom_Compound(t *testing.T) { var innerWriter collectWrites - // First fakeWriter: fakeBytes=3, fakeData="Fake " + // First fakeWriter: FakeBytes=3, FakeData="Fake " fakeData1 := []byte("Fake ") fakeBytes1 := int64(3) fakeOffset1 := int64(0) fakeTtl1 := 0 - writer1 := NewWriter(&innerWriter, fakeBytes1, fakeData1, fakeOffset1, fakeTtl1) + writer1 := NewWriter(&innerWriter, fakeData1, fakeOffset1, fakeBytes1, fakeTtl1) - // Second fakeWriter: fakeBytes=5, fakeData="data", fakeOffset=0 + // Second fakeWriter: FakeBytes=5, FakeData="data", FakeOffset=0 fakeData2 := []byte("data") fakeBytes2 := int64(5) fakeOffset2 := int64(0) fakeTtl2 := 0 - writer2 := NewWriter(writer1, fakeBytes2, fakeData2, fakeOffset2, fakeTtl2) + writer2 := NewWriter(writer1, fakeData2, fakeOffset2, fakeBytes2, fakeTtl2) n, err := writer2.Write([]byte("Request")) require.NoError(t, err) @@ -225,8 +225,8 @@ func TestWrite_WithOffsetBeyondFakeData(t *testing.T) { var innerWriter collectWrites fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(4) // Attempt to inject 4 bytes - fakeOffset := int64(10) // Offset beyond fakeData length - fakeWriter := NewWriter(&innerWriter, fakeBytes, fakeData, fakeOffset, 0) + fakeOffset := int64(10) // Offset beyond FakeData length + fakeWriter := NewWriter(&innerWriter, fakeData, fakeOffset, fakeBytes, 0) n, err := fakeWriter.Write([]byte("Request")) // 7 bytes require.NoError(t, err) require.Equal(t, 7, n) // 0 fake + 7 real @@ -236,9 +236,9 @@ func TestWrite_WithOffsetBeyondFakeData(t *testing.T) { func TestReadFrom_WithOffsetBeyondFakeData(t *testing.T) { fakeData := []byte("Fake data") // 9 bytes fakeBytes := int64(5) // Attempt to inject 5 bytes - fakeOffset := int64(10) // Offset beyond fakeData length + fakeOffset := int64(10) // Offset beyond FakeData length var buffer bytes.Buffer - fakeWriter := NewWriter(&buffer, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&buffer, fakeData, fakeOffset, fakeBytes, 0) rf, ok := fakeWriter.(io.ReaderFrom) require.True(t, ok) @@ -255,7 +255,7 @@ func BenchmarkReadFrom(b *testing.B) { for n := 0; n < b.N; n++ { reader := bytes.NewReader([]byte("Request")) var buffer bytes.Buffer - fakeWriter := NewWriter(&buffer, fakeBytes, fakeData, fakeOffset, 0) + fakeWriter := NewWriter(&buffer, fakeData, fakeOffset, fakeBytes, 0) rf, ok := fakeWriter.(io.ReaderFrom) if !ok { b.Fatalf("Writer does not implement io.ReaderFrom") diff --git a/x/fake/signature/signature.go b/x/md5signature/md5signature.go similarity index 98% rename from x/fake/signature/signature.go rename to x/md5signature/md5signature.go index 0abc3166..366823c7 100644 --- a/x/fake/signature/signature.go +++ b/x/md5signature/md5signature.go @@ -1,4 +1,4 @@ -package signature +package md5signature import ( "fmt" diff --git a/x/packet/type.go b/x/packet/type.go new file mode 100644 index 00000000..435a0cb2 --- /dev/null +++ b/x/packet/type.go @@ -0,0 +1,34 @@ +package packet + +import ( + "bufio" + "bytes" +) + +var ( + httpMethods = []string{ + "HEAD", + "GET", + "POST", + "PUT", + "DELETE", + "OPTIONS", + "CONNECT", + "TRACE", + "PATCH", + } +) + +// IsHTTP returns true if the data starts with an HTTP method. +func IsHTTP(r *bufio.Reader) bool { + peek, err := r.Peek(4) + if err != nil { + return false + } + for _, method := range httpMethods { + if bytes.HasPrefix(peek, []byte(method)) { + return true + } + } + return false +}