/* SPDX-License-Identifier: MIT
*
* Phobos
*/
package cobf
import (
"bytes"
"testing"
)
const (
atypIPv4 = 0x01
atypDomain = 0x03
atypIPv6 = 0x04
)
var ipv6Addr = []byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
// Locks the wire layout of the SOCKS5 address block. The domain case carries
// the RFC 1928 length prefix, which the C builder once omitted while the C
// parser required it -- every UDP ASSOCIATE to a hostname was dropped and the
// session torn down.
var targetVectors = []struct {
name string
atyp byte
addr []byte
port uint16
wire []byte
}{
{"ipv4", atypIPv4, []byte{203, 0, 113, 7}, 51820,
[]byte{0x01, 203, 0, 113, 7, 0xCA, 0x6C}},
{"domain", atypDomain, []byte("example.com"), 53,
[]byte{0x03, 11, 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', 0, 53}},
{"ipv6", atypIPv6, ipv6Addr, 443,
append(append([]byte{0x04}, ipv6Addr...), 0x01, 0xBB)},
}
func TestBuildTargetMatchesWireLayout(t *testing.T) {
for _, tc := range targetVectors {
out := make([]byte, MaxTargetSize)
n := BuildTarget(out, tc.atyp, tc.addr, tc.port)
if n < 0 {
t.Fatalf("%s: build refused a %d byte buffer", tc.name, len(out))
}
if !bytes.Equal(out[:n], tc.wire) {
t.Errorf("%s: built %x, want %x", tc.name, out[:n], tc.wire)
}
}
}
func TestParseTargetMatchesWireLayout(t *testing.T) {
for _, tc := range targetVectors {
atyp, addr, port, consumed := ParseTarget(tc.wire)
if consumed != len(tc.wire) {
t.Fatalf("%s: consumed %d of %d bytes", tc.name, consumed, len(tc.wire))
}
if atyp != tc.atyp || port != tc.port || !bytes.Equal(addr, tc.addr) {
t.Errorf("%s: parsed atyp %d addr %x port %d, want %d, %x and %d",
tc.name, atyp, addr, port, tc.atyp, tc.addr, tc.port)
}
}
}
func TestParseTargetReportsIncompleteAndUnsupported(t *testing.T) {
for _, tc := range targetVectors {
for cut := 1; cut < len(tc.wire); cut++ {
if _, _, _, consumed := ParseTarget(tc.wire[:cut]); consumed != 0 {
t.Fatalf("%s: truncated to %d bytes returned %d, want 0", tc.name, cut, consumed)
}
}
}
if _, _, _, consumed := ParseTarget([]byte{0x02, 1, 2, 3, 4, 0, 0}); consumed >= 0 {
t.Errorf("unsupported ATYP returned %d, want a negative result", consumed)
}
}
func TestBuildTargetRejectsShortBuffer(t *testing.T) {
for _, tc := range targetVectors {
out := make([]byte, len(tc.wire)-1)
if n := BuildTarget(out, tc.atyp, tc.addr, tc.port); n >= 0 {
t.Errorf("%s: build accepted a buffer one byte too small", tc.name)
}
}
}