mirror of
https://github.com/hackdiaz-dev/free-turn-proxy.git
synced 2026-10-12 09:41:53 +02:00
74241de764
убраны флаги -mode и -bond: остался только udp-релей для wireguard. удалены tcpfwd, tcpfwdserver, bondclient, bondserver, bondframe, kcptun, wire/relay; proxy/common переехал в udprelay/dial. BREAKING CHANGE: флаги -mode и -bond удалены; конфиги и ссылки freeturn:// с tcp-режимом больше не принимаются.
247 lines
5.8 KiB
Go
247 lines
5.8 KiB
Go
package rtpopus3
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/binary"
|
|
"testing"
|
|
)
|
|
|
|
func newKey(t *testing.T) []byte {
|
|
t.Helper()
|
|
k := make([]byte, KeyLen)
|
|
if _, err := rand.Read(k); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return k
|
|
}
|
|
|
|
func TestWrapInPlaceRoundTrip(t *testing.T) {
|
|
t.Parallel()
|
|
key := newKey(t)
|
|
cli, err := NewConn(key, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
srv, err := NewConn(key, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
payload := []byte("wireguard-ish payload 0123456789abcdef")
|
|
buf := make([]byte, MaxWire(len(payload)))
|
|
copy(buf[headerLen:], payload)
|
|
n, err := cli.WrapInPlace(buf, len(payload))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != overhead+len(payload) {
|
|
t.Fatalf("wire len = %d, want %d", n, overhead+len(payload))
|
|
}
|
|
plain, err := srv.UnwrapInPlace(buf[:n])
|
|
if err != nil {
|
|
t.Fatalf("unwrap: %v", err)
|
|
}
|
|
if !bytes.Equal(plain, payload) {
|
|
t.Fatalf("plaintext mismatch: %q", plain)
|
|
}
|
|
}
|
|
|
|
func TestWrapIntoRoundTrip(t *testing.T) {
|
|
t.Parallel()
|
|
key := newKey(t)
|
|
cli, _ := NewConn(key, false)
|
|
srv, _ := NewConn(key, true)
|
|
|
|
payload := []byte("wireguard bytes over relay")
|
|
dst := make([]byte, MaxWire(len(payload)))
|
|
n, err := cli.WrapInto(dst, payload)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out := make([]byte, len(payload))
|
|
m, err := srv.Unwrap(dst[:n], out)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if m != len(payload) || !bytes.Equal(out[:m], payload) {
|
|
t.Fatalf("mismatch: got %q", out[:m])
|
|
}
|
|
}
|
|
|
|
func TestHeaderShape(t *testing.T) {
|
|
t.Parallel()
|
|
key := newKey(t)
|
|
cli, _ := NewConn(key, false)
|
|
|
|
payload := []byte("abc")
|
|
buf := make([]byte, MaxWire(len(payload)))
|
|
copy(buf[headerLen:], payload)
|
|
if _, err := cli.WrapInPlace(buf, len(payload)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if buf[0] != rtpVerExt {
|
|
t.Errorf("byte0 = 0x%02x, want 0x%02x (V=2, X=1)", buf[0], rtpVerExt)
|
|
}
|
|
if buf[12] != 0xBE || buf[13] != 0xDE {
|
|
t.Errorf("ext profile = 0x%02x%02x, want 0xBEDE", buf[12], buf[13])
|
|
}
|
|
if w := binary.BigEndian.Uint16(buf[14:16]); w != 3 {
|
|
t.Errorf("ext length = %d words, want 3", w)
|
|
}
|
|
if buf[16] != extAudioLevelHdr || buf[18] != extTransportHdr || buf[21] != extAbsSendTimeHdr {
|
|
t.Errorf("ext element headers = 0x%02x 0x%02x 0x%02x, want 0x10 0x21 0x32",
|
|
buf[16], buf[18], buf[21])
|
|
}
|
|
if buf[28]&0x80 != 0 {
|
|
t.Errorf("client nonce sessionID MSB set, want clear (direction bit)")
|
|
}
|
|
}
|
|
|
|
func TestServerDirectionBit(t *testing.T) {
|
|
t.Parallel()
|
|
key := newKey(t)
|
|
srv, _ := NewConn(key, true)
|
|
payload := []byte("x")
|
|
buf := make([]byte, MaxWire(len(payload)))
|
|
copy(buf[headerLen:], payload)
|
|
if _, err := srv.WrapInPlace(buf, len(payload)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if buf[28]&0x80 == 0 {
|
|
t.Errorf("server nonce sessionID MSB clear, want set (direction bit)")
|
|
}
|
|
}
|
|
|
|
func TestSeqGaps(t *testing.T) {
|
|
t.Parallel()
|
|
key := newKey(t)
|
|
conn, _ := NewConn(key, false)
|
|
|
|
conn.nextGapAt = 3
|
|
conn.gapSize = 2
|
|
|
|
payload := []byte("test")
|
|
seqs := make([]uint16, 10)
|
|
for i := range seqs {
|
|
buf := make([]byte, MaxWire(len(payload)))
|
|
copy(buf[headerLen:], payload)
|
|
if _, err := conn.WrapInPlace(buf, len(payload)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
seqs[i] = binary.BigEndian.Uint16(buf[2:4])
|
|
}
|
|
|
|
got := int(seqs[3]) - int(seqs[2])
|
|
if got != 3 {
|
|
t.Logf("seq progression: %v", seqs)
|
|
}
|
|
}
|
|
|
|
func TestAudioStateMachine(t *testing.T) {
|
|
t.Parallel()
|
|
key := newKey(t)
|
|
conn, _ := NewConn(key, false)
|
|
|
|
conn.audioState = stateSilence
|
|
conn.pktsInState = 0
|
|
conn.nextStateSwitch = 2
|
|
|
|
payload := []byte("pkt")
|
|
markers := make([]bool, 10)
|
|
for i := range markers {
|
|
buf := make([]byte, MaxWire(len(payload)))
|
|
copy(buf[headerLen:], payload)
|
|
if _, err := conn.WrapInPlace(buf, len(payload)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
markers[i] = buf[1]&rtpMarker != 0
|
|
}
|
|
|
|
t.Logf("markers: %v", markers)
|
|
if !markers[1] {
|
|
t.Error("expected M=1 on silence->speech transition at packet index 1")
|
|
}
|
|
}
|
|
|
|
func TestAbsSendTimeValidFormat(t *testing.T) {
|
|
t.Parallel()
|
|
key := newKey(t)
|
|
conn, _ := NewConn(key, false)
|
|
|
|
payload := []byte("timecheck")
|
|
buf := make([]byte, MaxWire(len(payload)))
|
|
copy(buf[headerLen:], payload)
|
|
if _, err := conn.WrapInPlace(buf, len(payload)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ast := (uint32(buf[22]) << 16) | (uint32(buf[23]) << 8) | uint32(buf[24])
|
|
if ast>>24 != 0 {
|
|
t.Errorf("abs-send-time exceeds 24 bits: 0x%06x", ast)
|
|
}
|
|
sec := ast >> 18
|
|
if sec >= 64 {
|
|
t.Errorf("abs-send-time seconds >= 64: %d", sec)
|
|
}
|
|
}
|
|
|
|
func TestVariableTsStep(t *testing.T) {
|
|
t.Parallel()
|
|
key := newKey(t)
|
|
conn, _ := NewConn(key, false)
|
|
|
|
payload := []byte("varstep")
|
|
tsValues := make([]uint32, 100)
|
|
for i := range tsValues {
|
|
buf := make([]byte, MaxWire(len(payload)))
|
|
copy(buf[headerLen:], payload)
|
|
if _, err := conn.WrapInPlace(buf, len(payload)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tsValues[i] = binary.BigEndian.Uint32(buf[4:8])
|
|
}
|
|
|
|
diffs := make(map[uint32]int)
|
|
for i := 1; i < len(tsValues); i++ {
|
|
diff := tsValues[i] - tsValues[i-1]
|
|
diffs[diff]++
|
|
}
|
|
t.Logf("timestamp step distribution: %v", diffs)
|
|
if len(diffs) < 2 {
|
|
t.Log("all timestamp steps are identical; expected some variation (may be rare)")
|
|
}
|
|
}
|
|
|
|
func TestTamperDetected(t *testing.T) {
|
|
t.Parallel()
|
|
key := newKey(t)
|
|
cli, _ := NewConn(key, false)
|
|
srv, _ := NewConn(key, true)
|
|
|
|
payload := []byte("integrity matters")
|
|
buf := make([]byte, MaxWire(len(payload)))
|
|
copy(buf[headerLen:], payload)
|
|
n, _ := cli.WrapInPlace(buf, len(payload))
|
|
|
|
buf[n-1] ^= 0xFF
|
|
if _, err := srv.UnwrapInPlace(buf[:n]); err == nil {
|
|
t.Fatal("expected AEAD open failure on tampered tag")
|
|
}
|
|
}
|
|
|
|
func TestWrongKeyFails(t *testing.T) {
|
|
t.Parallel()
|
|
cli, _ := NewConn(newKey(t), false)
|
|
srv, _ := NewConn(newKey(t), true)
|
|
|
|
payload := []byte("secret")
|
|
buf := make([]byte, MaxWire(len(payload)))
|
|
copy(buf[headerLen:], payload)
|
|
n, _ := cli.WrapInPlace(buf, len(payload))
|
|
if _, err := srv.UnwrapInPlace(buf[:n]); err == nil {
|
|
t.Fatal("expected failure decrypting with wrong key")
|
|
}
|
|
}
|