[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