commit daab1193f4234bd23e26f7a525356b67630c6ba2 Author: David Fifield david@bamsoftware.com Date: Sat May 24 20:25:49 2014 -0700
Add some proxy support functions.
These are candidates to move to goptlib for proposal 232 support.
I assumed that you should be able to give a proxy host as a domain name, but it turns out that proposal 232 doesn't actually say that (https://trac.torproject.org/projects/tor/ticket/12125#comment:3). Some of the tests use IP addresses and some use host names. --- meek-client/proxy.go | 53 ++++++++++++++++++++++++++++++++++ meek-client/proxy_test.go | 69 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+)
diff --git a/meek-client/proxy.go b/meek-client/proxy.go new file mode 100644 index 0000000..56717a3 --- /dev/null +++ b/meek-client/proxy.go @@ -0,0 +1,53 @@ +package main + +import ( + "errors" + "fmt" + "net/url" + "os" +) + +import "git.torproject.org/pluggable-transports/goptlib.git" + +// The code in this file has to do with configuring an upstream proxy, whether +// through the command line or the managed interface of proposal 232 +// (TOR_PT_PROXY). +// +// https://gitweb.torproject.org/torspec.git/blob/HEAD:/proposals/232-pluggable... + +// Get the upstream proxy URL. Returns nil if no proxy is requested. The +// function ensures that the Scheme and Host fields are set; i.e., that the URL +// is absolute. This function reads the environment variable TOR_PT_PROXY. +// +// This function doesn't check that the scheme is one of Tor's supported proxy +// schemes; that is, one of "http", "socks5", or "socks4a". The caller must be +// able to handle any returned scheme (which may be by calling PtProxyError if +// it doesn't know how to handle the scheme). +func PtGetProxyURL() (*url.URL, error) { + rawurl := os.Getenv("TOR_PT_PROXY") + if rawurl == "" { + return nil, nil + } + u, err := url.Parse(rawurl) + if err != nil { + return nil, err + } + if u.Scheme == "" { + return nil, errors.New("missing scheme") + } + if u.Host == "" { + return nil, errors.New("missing host") + } + return u, nil +} + +// Emit a PROXY-ERROR line with explanation text. +func PtProxyError(msg string) { + fmt.Fprintf(pt.Stdout, "PROXY-ERROR %s\n", msg) +} + +// Emit a PROXY DONE line. Call this after parsing the return value of +// PtGetProxyURL. +func PtProxyDone() { + fmt.Fprintf(pt.Stdout, "PROXY DONE\n") +} diff --git a/meek-client/proxy_test.go b/meek-client/proxy_test.go new file mode 100644 index 0000000..9565101 --- /dev/null +++ b/meek-client/proxy_test.go @@ -0,0 +1,69 @@ +package main + +import ( + "os" + "testing" +) + +func TestGetProxyURL(t *testing.T) { + badTests := [...]string{ + "bogus", + "http:", + "://127.0.0.1", + "//127.0.0.1", + "http:127.0.0.1", + "://[::1]", + "//[::1]", + "http:[::1]", + "://localhost", + "//localhost", + "http:localhost", + } + goodTests := [...]struct { + input, expected string + }{ + {"http://127.0.0.1", "http://127.0.0.1%22%7D, + {"http://127.0.0.1:8080", "http://127.0.0.1:8080%22%7D, + {"http://127.0.0.1:8080/", "http://127.0.0.1:8080/%22%7D, + {"http://127.0.0.1:8080/path", "http://127.0.0.1:8080/path%22%7D, + {"http://%5B::1]", "http://%5B::1%5D%22%7D, + {"http://%5B::1%5D:8080", "http://%5B::1%5D:8080%22%7D, + {"http://%5B::1%5D:8080/", "http://%5B::1%5D:8080/%22%7D, + {"http://%5B::1%5D:8080/path", "http://%5B::1%5D:8080/path%22%7D, + {"http://localhost", "http://localhost%22%7D, + {"http://localhost:8080", "http://localhost:8080%22%7D, + {"http://localhost:8080/", "http://localhost:8080/%22%7D, + {"http://localhost:8080/path", "http://localhost:8080/path%22%7D, + {"http://user@localhost:8080", "http://user@localhost:8080%22%7D, + {"http://user:password@localhost:8080", "http://user:password@localhost:8080%22%7D, + {"unknown://localhost/whatever", "unknown://localhost/whatever"}, + } + + os.Clearenv() + u, err := PtGetProxyURL() + if err != nil { + t.Errorf("empty environment unexpectedly returned an error: %s", err) + } + if u != nil { + t.Errorf("empty environment returned %q", u) + } + + for _, input := range badTests { + os.Setenv("TOR_PT_PROXY", input) + u, err = PtGetProxyURL() + if err == nil { + t.Errorf("TOR_PT_PROXY=%q unexpectedly succeeded and returned %q", input, u) + } + } + + for _, test := range goodTests { + os.Setenv("TOR_PT_PROXY", test.input) + u, err := PtGetProxyURL() + if err != nil { + t.Errorf("TOR_PT_PROXY=%q unexpectedly returned an error: %s", test.input, err) + } + if u == nil || u.String() != test.expected { + t.Errorf("TOR_PT_PROXY=%q → %q (expected %q)", test.input, u, test.expected) + } + } +}
tor-commits@lists.torproject.org