[Pkg-privacy-commits] [golang-goptlib] 16/20: Imported Upstream version 0.5
Ximin Luo
infinity0 at moszumanska.debian.org
Sat Aug 22 10:04:07 UTC 2015
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch master
in repository golang-goptlib.
commit 0136c839b324f59e44c178169349592e56a9c2f0
Author: Ximin Luo <infinity0 at pwned.gg>
Date: Mon Jul 6 11:55:55 2015 +0200
Imported Upstream version 0.5
---
examples/dummy-client/dummy-client.go | 17 ++++--
examples/dummy-server/dummy-server.go | 6 +-
proxy_test.go | 80 +++++++++++++++++++++++++
pt.go | 78 ++++++++++++++++++++++---
pt_test.go | 6 +-
socks.go | 25 ++++----
socks_test.go | 107 ++++++++++++++++++++++++++++++++++
7 files changed, 289 insertions(+), 30 deletions(-)
diff --git a/examples/dummy-client/dummy-client.go b/examples/dummy-client/dummy-client.go
index 64f1ec1..045a8f2 100644
--- a/examples/dummy-client/dummy-client.go
+++ b/examples/dummy-client/dummy-client.go
@@ -5,9 +5,9 @@
// Bridge dummy X.X.X.X:YYYY
// ClientTransportPlugin dummy exec dummy-client
//
-// Because this transport doesn't do anything to the traffic, you can use any
-// ordinary relay's ORPort in the Bridge line; it doesn't have to declare
-// support for the dummy transport.
+// Because this transport doesn't do anything to the traffic, you can use the
+// ORPort of any ordinary bridge (or relay that has DirPort set) in the bridge
+// line; it doesn't have to declare support for the dummy transport.
package main
import (
@@ -71,10 +71,10 @@ func acceptLoop(ln *pt.SocksListener) error {
for {
conn, err := ln.AcceptSocks()
if err != nil {
- if e, ok := err.(net.Error); ok && !e.Temporary() {
- return err
+ if e, ok := err.(net.Error); ok && e.Temporary() {
+ continue
}
- continue
+ return err
}
go handler(conn)
}
@@ -88,6 +88,11 @@ func main() {
os.Exit(1)
}
+ if ptInfo.ProxyURL != nil {
+ pt.ProxyError("proxy is not supported")
+ os.Exit(1)
+ }
+
listeners := make([]net.Listener, 0)
for _, methodName := range ptInfo.MethodNames {
switch methodName {
diff --git a/examples/dummy-server/dummy-server.go b/examples/dummy-server/dummy-server.go
index ea91be9..70251ea 100644
--- a/examples/dummy-server/dummy-server.go
+++ b/examples/dummy-server/dummy-server.go
@@ -68,10 +68,10 @@ func acceptLoop(ln net.Listener) error {
for {
conn, err := ln.Accept()
if err != nil {
- if e, ok := err.(net.Error); ok && !e.Temporary() {
- return err
+ if e, ok := err.(net.Error); ok && e.Temporary() {
+ continue
}
- continue
+ return err
}
go handler(conn)
}
diff --git a/proxy_test.go b/proxy_test.go
new file mode 100644
index 0000000..c7a113b
--- /dev/null
+++ b/proxy_test.go
@@ -0,0 +1,80 @@
+package pt
+
+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",
+ // No port in these.
+ "http://127.0.0.1",
+ "socks4a://127.0.0.1",
+ "socks5://127.0.0.1",
+ "http://127.0.0.1:",
+ "http://[::1]",
+ "http://localhost",
+ "unknown://localhost/whatever",
+ // No host in these.
+ "http://:8080",
+ "socks4a://:1080",
+ "socks5://:1080",
+ }
+ goodTests := [...]struct {
+ input, expected string
+ }{
+ {"http://127.0.0.1:8080", "http://127.0.0.1:8080"},
+ {"http://127.0.0.1:8080/", "http://127.0.0.1:8080/"},
+ {"http://127.0.0.1:8080/path", "http://127.0.0.1:8080/path"},
+ {"http://[::1]:8080", "http://[::1]:8080"},
+ {"http://[::1]:8080/", "http://[::1]:8080/"},
+ {"http://[::1]:8080/path", "http://[::1]:8080/path"},
+ {"http://localhost:8080", "http://localhost:8080"},
+ {"http://localhost:8080/", "http://localhost:8080/"},
+ {"http://localhost:8080/path", "http://localhost:8080/path"},
+ {"http://user@localhost:8080", "http://user@localhost:8080"},
+ {"http://user:password@localhost:8080", "http://user:password@localhost:8080"},
+ {"socks5://localhost:1080", "socks5://localhost:1080"},
+ {"socks4a://localhost:1080", "socks4a://localhost:1080"},
+ {"unknown://localhost:9999/whatever", "unknown://localhost:9999/whatever"},
+ }
+
+ os.Clearenv()
+ u, err := getProxyURL()
+ 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 = getProxyURL()
+ 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 := getProxyURL()
+ 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)
+ }
+ }
+}
diff --git a/pt.go b/pt.go
index d2e7dc1..a8c815e 100644
--- a/pt.go
+++ b/pt.go
@@ -23,10 +23,10 @@
// for {
// conn, err := ln.AcceptSocks()
// if err != nil {
-// if e, ok := err.(net.Error); ok && !e.Temporary() {
-// return err
+// if e, ok := err.(net.Error); ok && e.Temporary() {
+// continue
// }
-// continue
+// return err
// }
// go handler(conn)
// }
@@ -39,6 +39,12 @@
// if err != nil {
// os.Exit(1)
// }
+// if ptInfo.ProxyURL != nil {
+// // you need to interpret the proxy URL yourself
+// // call pt.ProxyDone instead if it's a type you understand
+// pt.ProxyError("proxy %s is not supported")
+// os.Exit(1)
+// }
// for _, methodName := range ptInfo.MethodNames {
// switch methodName {
// case "foo":
@@ -74,10 +80,10 @@
// for {
// conn, err := ln.Accept()
// if err != nil {
-// if e, ok := err.(net.Error); ok && !e.Temporary() {
-// return err
+// if e, ok := err.(net.Error); ok && e.Temporary() {
+// continue
// }
-// continue
+// return err
// }
// go handler(conn)
// }
@@ -119,6 +125,9 @@
// Extended ORPort Authentication:
// https://gitweb.torproject.org/torspec.git/tree/proposals/217-ext-orport-auth.txt.
//
+// Pluggable Transport through SOCKS proxy:
+// https://gitweb.torproject.org/torspec.git/tree/proposals/232-pluggable-transports-through-proxy.txt
+//
// The package implements a SOCKS4a server sufficient for a Tor client transport
// plugin.
//
@@ -135,6 +144,7 @@ import (
"fmt"
"io"
"net"
+ "net/url"
"os"
"strconv"
"strings"
@@ -286,6 +296,12 @@ func SmethodError(methodName, msg string) error {
return doError("SMETHOD-ERROR", methodName, msg)
}
+// Emit a PROXY-ERROR line with explanation text. Returns a representation of
+// the error.
+func ProxyError(msg string) error {
+ return doError("PROXY-ERROR %s\n", msg)
+}
+
// Emit a CMETHOD line. socks must be "socks4" or "socks5". Call this once for
// each listening client SOCKS port.
func Cmethod(name string, socks string, addr net.Addr) {
@@ -326,6 +342,11 @@ func SmethodsDone() {
line("SMETHODS", "DONE")
}
+// Emit a PROXY DONE line. Call this after parsing ClientInfo.ProxyURL.
+func ProxyDone() {
+ fmt.Fprintf(Stdout, "PROXY DONE\n")
+}
+
// Get a pluggable transports version offered by Tor and understood by us, if
// any. The only version we understand is "1". This function reads the
// environment variable TOR_PT_MANAGED_TRANSPORT_VER.
@@ -370,10 +391,48 @@ func getClientTransports(star []string) ([]string, error) {
return strings.Split(clientTransports, ","), nil
}
+// 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. It additionally checks that the Host field contains both a host
+// and a port part. 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 ProxyError if
+// it doesn't know how to handle the scheme).
+func getProxyURL() (*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, fmt.Errorf("missing scheme")
+ }
+ if u.Host == "" {
+ return nil, fmt.Errorf("missing authority")
+ }
+ host, port, err := net.SplitHostPort(u.Host)
+ if err != nil {
+ return nil, err
+ }
+ if host == "" {
+ return nil, fmt.Errorf("missing host")
+ }
+ if port == "" {
+ return nil, fmt.Errorf("missing port")
+ }
+ return u, nil
+}
+
// This structure is returned by ClientSetup. It consists of a list of method
-// names.
+// names and the upstream proxy URL, if any.
type ClientInfo struct {
MethodNames []string
+ ProxyURL *url.URL
}
// Check the client pluggable transports environment, emitting an error message
@@ -401,6 +460,11 @@ func ClientSetup(star []string) (info ClientInfo, err error) {
return
}
+ info.ProxyURL, err = getProxyURL()
+ if err != nil {
+ return
+ }
+
return info, nil
}
diff --git a/pt_test.go b/pt_test.go
index 8cdf6da..c0540b5 100644
--- a/pt_test.go
+++ b/pt_test.go
@@ -704,19 +704,19 @@ func TestExtOrPortRecvCommand(t *testing.T) {
}
// set up so that extOrPortSetup can write to one buffer and read from another.
-type MockSetupBuf struct {
+type mockSetupBuf struct {
bytes.Buffer
ReadBuf bytes.Buffer
}
-func (buf *MockSetupBuf) Read(p []byte) (int, error) {
+func (buf *mockSetupBuf) Read(p []byte) (int, error) {
n, err := buf.ReadBuf.Read(p)
return n, err
}
func testExtOrPortSetupIndividual(t *testing.T, addr, methodName string) {
var err error
- var buf MockSetupBuf
+ var buf mockSetupBuf
// fake an OKAY response.
err = extOrPortSendCommand(&buf.ReadBuf, extOrCmdOkay, []byte{})
if err != nil {
diff --git a/socks.go b/socks.go
index 6ad6542..9a764b8 100644
--- a/socks.go
+++ b/socks.go
@@ -73,10 +73,10 @@ func (conn *SocksConn) Reject() error {
// conn, err := ln.AcceptSocks()
// if err != nil {
// log.Printf("accept error: %s", err)
-// if e, ok := err.(net.Error); ok && !e.Temporary() {
-// break
+// if e, ok := err.(net.Error); ok && e.Temporary() {
+// continue
// }
-// continue
+// break
// }
// go handleConn(conn)
// }
@@ -118,16 +118,17 @@ func (ln *SocksListener) Accept() (net.Conn, error) {
// for {
// conn, err := ln.AcceptSocks()
// if err != nil {
-// if e, ok := err.(net.Error); ok && !e.Temporary() {
-// log.Printf("permanent accept error; giving up: %s", err)
-// break
+// if e, ok := err.(net.Error); ok && e.Temporary() {
+// log.Printf("temporary accept error; trying again: %s", err)
+// continue
// }
-// log.Printf("temporary accept error; trying again: %s", err)
-// continue
+// log.Printf("permanent accept error; giving up: %s", err)
+// break
// }
// go handleConn(conn)
// }
func (ln *SocksListener) AcceptSocks() (*SocksConn, error) {
+retry:
c, err := ln.Listener.Accept()
if err != nil {
return nil, err
@@ -136,16 +137,18 @@ func (ln *SocksListener) AcceptSocks() (*SocksConn, error) {
conn.Conn = c
err = conn.SetDeadline(time.Now().Add(socksRequestTimeout))
if err != nil {
- return nil, err
+ conn.Close()
+ goto retry
}
conn.Req, err = readSocks4aConnect(conn)
if err != nil {
conn.Close()
- return nil, err
+ goto retry
}
err = conn.SetDeadline(time.Time{})
if err != nil {
- return nil, err
+ conn.Close()
+ goto retry
}
return conn, nil
}
diff --git a/socks_test.go b/socks_test.go
index 18d141a..7fee46a 100644
--- a/socks_test.go
+++ b/socks_test.go
@@ -2,8 +2,11 @@ package pt
import (
"bytes"
+ "errors"
+ "io"
"net"
"testing"
+ "time"
)
func TestReadSocks4aConnect(t *testing.T) {
@@ -160,3 +163,107 @@ func TestSendSocks4aResponse(t *testing.T) {
}
}
}
+
+var fakeListenerDistinguishedError = errors.New("distinguished error")
+
+// fakeListener is a fake dummy net.Listener that returns the given net.Conn and
+// error the first time Accept is called. After the first call, it returns
+// (nil, fakeListenerDistinguishedError).
+type fakeListener struct {
+ c net.Conn
+ err error
+}
+
+func (ln *fakeListener) Accept() (net.Conn, error) {
+ c := ln.c
+ err := ln.err
+ ln.c = nil
+ ln.err = fakeListenerDistinguishedError
+ return c, err
+}
+
+func (ln *fakeListener) Close() error {
+ return nil
+}
+
+func (ln *fakeListener) Addr() net.Addr {
+ return &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0, Zone: ""}
+}
+
+// A trivial net.Error that lets you control whether it is considered Temporary.
+type netError struct {
+ errString string
+ temporary bool
+}
+
+func (e *netError) Error() string {
+ return e.errString
+}
+
+func (e *netError) Temporary() bool {
+ return e.temporary
+}
+
+func (e *netError) Timeout() bool {
+ return false
+}
+
+// The purpose of ignoreDeadlineConn is to wrap net.Pipe so that the deadline
+// functions don't return an error ("net.Pipe does not support deadlines").
+type ignoreDeadlineConn struct {
+ net.Conn
+}
+
+func (c *ignoreDeadlineConn) SetDeadline(t time.Time) error {
+ return nil
+}
+
+func (c *ignoreDeadlineConn) SetReadDeadline(t time.Time) error {
+ return nil
+}
+
+func (c *ignoreDeadlineConn) SetWriteDeadline(t time.Time) error {
+ return nil
+}
+
+func TestAcceptErrors(t *testing.T) {
+ // Check that AcceptSocks accurately reflects net.Errors returned by the
+ // underlying call to Accept. This is important for the handling of
+ // Temporary and non-Temporary errors. The loop iterates over
+ // non-net.Error, non-Temporary net.Error, and Temporary net.Error.
+ for _, expectedErr := range []error{io.EOF, &netError{"non-temp", false}, &netError{"temp", true}} {
+ ln := NewSocksListener(&fakeListener{nil, expectedErr})
+ _, err := ln.AcceptSocks()
+ if expectedNerr, ok := expectedErr.(net.Error); ok {
+ nerr, ok := err.(net.Error)
+ if !ok {
+ t.Errorf("AcceptSocks returned non-net.Error %v", nerr)
+ } else {
+ if expectedNerr.Temporary() != expectedNerr.Temporary() {
+ t.Errorf("AcceptSocks did not keep Temporary status of net.Error: %v", nerr)
+ }
+ }
+ }
+ }
+
+ c1, c2 := net.Pipe()
+ go func() {
+ // Bogus request: SOCKS 5 then EOF.
+ c2.Write([]byte("\x05\x01\x00"))
+ c2.Close()
+ }()
+ ln := NewSocksListener(&fakeListener{c: &ignoreDeadlineConn{c1}, err: nil})
+ _, err := ln.AcceptSocks()
+ // The error in parsing the SOCKS request must be either silently
+ // ignored, or else must be a Temporary net.Error. I.e., it must not be
+ // the io.ErrUnexpectedEOF caused by the short request.
+ if err == fakeListenerDistinguishedError {
+ // Was silently ignored.
+ } else if nerr, ok := err.(net.Error); ok {
+ if !nerr.Temporary() {
+ t.Errorf("AcceptSocks returned non-Temporary net.Error: %v", nerr)
+ }
+ } else {
+ t.Errorf("AcceptSocks returned non-net.Error: %v", err)
+ }
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/golang-goptlib.git
More information about the Pkg-privacy-commits
mailing list