From 6498e0ce00329a6a652ebc85ec4d432a86404b06 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Thu, 17 Mar 2022 16:05:00 -0400 Subject: obfsproxy: add initial proxy implementation Fixes #3 Signed-off-by: Sam Whited --- obfsproxy/main_test.go | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 obfsproxy/main_test.go (limited to 'obfsproxy/main_test.go') diff --git a/obfsproxy/main_test.go b/obfsproxy/main_test.go new file mode 100644 index 0000000..d22d3af --- /dev/null +++ b/obfsproxy/main_test.go @@ -0,0 +1,92 @@ +package main + +import ( + "context" + "flag" + "net" + "os" + "os/exec" + "testing" + "time" + + "golang.org/x/net/proxy" +) + +type testWriter struct { + t *testing.T + prefix string +} + +func (w testWriter) Write(p []byte) (int, error) { + w.t.Logf("%s%s", w.prefix, p) + return len(p), nil +} + +func TestMain(m *testing.M) { + runProxy := flag.Bool("runproxy", false, "Start the command instead of running the tests") + flag.Parse() + if *runProxy { + os.Args = append(os.Args[0:1], flag.Args()...) + main() + return + } + os.Exit(m.Run()) +} + +func TestRoundTrip(t *testing.T) { + // Setup and exec the proxy: + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + // Instead of passing a listener to the command or doing IPC to get the + // address of the listener created by the command back out, which would all + // require changes to the actual binary for something that has no use outside + // of tests and is just another potential source of errors, just start and + // stop a listener to get a random port and then pass that in (for the command + // to re-open) as a string. It's not ideal, but it's simple. + ln, err := net.Listen("tcp", "[::1]:0") + if err != nil { + t.Fatalf("error listening: %v", err) + } + addr := ln.Addr() + err = ln.Close() + if err != nil { + t.Fatalf("error closing listener: %v", err) + } + cmd := exec.CommandContext(ctx, os.Args[0], "-runproxy", "--", "-addr", addr.String(), "-proxy", "37.218.241.98:4430") + cmd.Stdout = testWriter{prefix: "stdout ", t: t} + cmd.Stderr = testWriter{prefix: "stderr ", t: t} + t.Logf("running proxy command %v", cmd.Args) + err = cmd.Start() + if err != nil { + t.Fatalf("error starting proxy: %v", err) + } + + // Once the proxy is running, try to connect: + ln, err = net.Listen("tcp", "[::1]:0") + if err != nil { + t.Fatalf("error listening for connection: %v", err) + } + go func() { + conn, err := ln.Accept() + if err != nil { + t.Logf("error accepting connection: %v", err) + } + t.Logf("got conn: %v", conn) + }() + dialer, err := proxy.SOCKS5("tcp", addr.String(), nil, proxy.Direct) + if err != nil { + t.Fatalf("error creating socks dialer: %v", err) + } + + // TODO: this is slow, flakey, and generally jank. Can we watch /proc for a + // new file descriptor or just poll until the listener is open? + t.Logf("waiting 3 seconds for command to start…") + time.Sleep(3 * time.Second) + + _, err = dialer.Dial("tcp", ln.Addr().String()) + if err != nil { + t.Fatalf("error dialing: %v", err) + } + + select {} +} -- cgit v1.2.3