commit 37be077e66cbff6403e054b2351e2eab3037a292
Author: David Fifield <da...@bamsoftware.com>
Date:   Sat Dec 7 20:50:27 2013 -0800

    Move socks code into the pt package.
---
 examples/dummy-client/dummy-client.go |    7 +-
 pt.go                                 |    9 +-
 socks.go                              |  189 +++++++++++++++++++++++++++++++++
 socks/socks.go                        |  183 -------------------------------
 socks/socks_test.go                   |  113 --------------------
 socks_test.go                         |  109 +++++++++++++++++++
 6 files changed, 308 insertions(+), 302 deletions(-)

diff --git a/examples/dummy-client/dummy-client.go 
b/examples/dummy-client/dummy-client.go
index 10f7b8b..de56d99 100644
--- a/examples/dummy-client/dummy-client.go
+++ b/examples/dummy-client/dummy-client.go
@@ -20,7 +20,6 @@ import (
 )
 
 import "git.torproject.org/pluggable-transports/goptlib.git"
-import "git.torproject.org/pluggable-transports/goptlib.git/socks"
 
 var ptInfo pt.ClientInfo
 
@@ -44,7 +43,7 @@ func copyLoop(a, b net.Conn) {
        wg.Wait()
 }
 
-func handleConnection(local *socks.Conn) error {
+func handleConnection(local *pt.SocksConn) error {
        defer local.Close()
 
        handlerChan <- 1
@@ -68,7 +67,7 @@ func handleConnection(local *socks.Conn) error {
        return nil
 }
 
-func acceptLoop(ln *socks.Listener) error {
+func acceptLoop(ln *pt.SocksListener) error {
        for {
                conn, err := ln.AcceptSocks()
                if err != nil {
@@ -80,7 +79,7 @@ func acceptLoop(ln *socks.Listener) error {
 }
 
 func startListener(addr string) (net.Listener, error) {
-       ln, err := socks.Listen("tcp", addr)
+       ln, err := pt.ListenSocks("tcp", addr)
        if err != nil {
                return nil, err
        }
diff --git a/pt.go b/pt.go
index 86632d9..ddecc29 100644
--- a/pt.go
+++ b/pt.go
@@ -8,15 +8,15 @@
 //             os.Exit(1)
 //     }
 //     for _, methodName := range ptInfo.MethodNames {
-//             ln, err := startSocksListener()
+//             ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
 //             if err != nil {
 //                     pt.CmethodError(methodName, err.Error())
 //                     continue
 //             }
+//             go acceptLoop(ln)
 //             pt.Cmethod(methodName, "socks4", ln.Addr())
 //     }
 //     pt.CmethodsDone()
-// See the socks package for help with writing a SOCKS listener.
 //
 // Sample server usage:
 //     func handler(conn net.Conn) {
@@ -48,6 +48,11 @@
 //
 // Extended ORPort Authentication:
 // 
https://gitweb.torproject.org/torspec.git/blob/HEAD:/proposals/217-ext-orport-auth.txt.
+//
+// The package implements a SOCKS4a server sufficient for a Tor client 
transport
+// plugin.
+//
+// http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol
 package pt
 
 import (
diff --git a/socks.go b/socks.go
new file mode 100644
index 0000000..a5889fa
--- /dev/null
+++ b/socks.go
@@ -0,0 +1,189 @@
+package pt
+
+import (
+       "bufio"
+       "errors"
+       "fmt"
+       "io"
+       "net"
+)
+
+const (
+       socksVersion         = 0x04
+       socksCmdConnect      = 0x01
+       socksResponseVersion = 0x00
+       socksRequestGranted  = 0x5a
+       socksRequestRejected = 0x5b
+)
+
+// SocksRequest describes a SOCKS request.
+type SocksRequest struct {
+       Username string
+       Target   string
+}
+
+// SocksConn encapsulates a net.Conn and information associated with a SOCKS 
request.
+type SocksConn struct {
+       net.Conn
+       Req SocksRequest
+}
+
+// Send a message to the proxy client that access to the given address is
+// granted.
+func (conn *SocksConn) Grant(addr *net.TCPAddr) error {
+       return sendSocks4aResponseGranted(conn, addr)
+}
+
+// Send a message to the proxy client that access was rejected or failed.
+func (conn *SocksConn) Reject() error {
+       return sendSocks4aResponseRejected(conn)
+}
+
+// SocksListener wraps a net.Listener in order to read a SOCKS request on 
Accept.
+//
+//     func handleConn(conn *pt.SocksConn) error {
+//             defer conn.Close()
+//
+//             remote, err := net.Dial("tcp", conn.Req.Target)
+//             if err != nil {
+//                     conn.Reject()
+//                     return err
+//             }
+//             err = conn.Grant(remote.RemoteAddr().(*net.TCPAddr))
+//             if err != nil {
+//                     return err
+//             }
+//             defer remote.Close()
+//
+//             // do something with conn and remote
+//     }
+//     ...
+//     ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
+//     if err != nil {
+//             panic(err.Error())
+//     }
+//     for {
+//             conn, err := ln.AcceptSocks()
+//             if err != nil {
+//                     break
+//             }
+//             go handleConn(conn)
+//     }
+type SocksListener struct {
+       net.Listener
+}
+
+// Open a net.Listener according to network and laddr, and return it as a
+// SocksListener.
+func ListenSocks(network, laddr string) (*SocksListener, error) {
+       ln, err := net.Listen(network, laddr)
+       if err != nil {
+               return nil, err
+       }
+       return NewSocksListener(ln), nil
+}
+
+// Create a new SocksListener wrapping the given net.Listener.
+func NewSocksListener(ln net.Listener) *SocksListener {
+       return &SocksListener{ln}
+}
+
+// Accept is the same as AcceptSocks, except that it returns a generic 
net.Conn.
+// It is present for the sake of satisfying the net.Listener interface.
+func (ln *SocksListener) Accept() (net.Conn, error) {
+       return ln.AcceptSocks()
+}
+
+// Call Accept on the wrapped net.Listener, do SOCKS negotiation, and return a
+// SocksConn. After accepting, you must call either conn.Grant or conn.Reject
+// (presumably after trying to connect to conn.Req.Target).
+func (ln *SocksListener) AcceptSocks() (*SocksConn, error) {
+       c, err := ln.Listener.Accept()
+       if err != nil {
+               return nil, err
+       }
+       conn := new(SocksConn)
+       conn.Conn = c
+       conn.Req, err = readSocks4aConnect(conn)
+       if err != nil {
+               conn.Close()
+               return nil, err
+       }
+       return conn, nil
+}
+
+// Read a SOCKS4a connect request. Returns a SocksRequest.
+func readSocks4aConnect(s io.Reader) (req SocksRequest, err error) {
+       r := bufio.NewReader(s)
+
+       var h [8]byte
+       _, err = io.ReadFull(r, h[:])
+       if err != nil {
+               return
+       }
+       if h[0] != socksVersion {
+               err = errors.New(fmt.Sprintf("SOCKS header had version 0x%02x, 
not 0x%02x", h[0], socksVersion))
+               return
+       }
+       if h[1] != socksCmdConnect {
+               err = errors.New(fmt.Sprintf("SOCKS header had command 0x%02x, 
not 0x%02x", h[1], socksCmdConnect))
+               return
+       }
+
+       var usernameBytes []byte
+       usernameBytes, err = r.ReadBytes('\x00')
+       if err != nil {
+               return
+       }
+       req.Username = string(usernameBytes[:len(usernameBytes)-1])
+
+       var port int
+       var host string
+
+       port = int(h[2])<<8 | int(h[3])<<0
+       if h[4] == 0 && h[5] == 0 && h[6] == 0 && h[7] != 0 {
+               var hostBytes []byte
+               hostBytes, err = r.ReadBytes('\x00')
+               if err != nil {
+                       return
+               }
+               host = string(hostBytes[:len(hostBytes)-1])
+       } else {
+               host = net.IPv4(h[4], h[5], h[6], h[7]).String()
+       }
+
+       if r.Buffered() != 0 {
+               err = errors.New(fmt.Sprintf("%d bytes left after SOCKS 
header", r.Buffered()))
+               return
+       }
+
+       req.Target = fmt.Sprintf("%s:%d", host, port)
+       return
+}
+
+// Send a SOCKS4a response with the given code and address.
+func sendSocks4aResponse(w io.Writer, code byte, addr *net.TCPAddr) error {
+       var resp [8]byte
+       resp[0] = socksResponseVersion
+       resp[1] = code
+       resp[2] = byte((addr.Port >> 8) & 0xff)
+       resp[3] = byte((addr.Port >> 0) & 0xff)
+       resp[4] = addr.IP[0]
+       resp[5] = addr.IP[1]
+       resp[6] = addr.IP[2]
+       resp[7] = addr.IP[3]
+       _, err := w.Write(resp[:])
+       return err
+}
+
+var emptyAddr = net.TCPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 0}
+
+// Send a SOCKS4a response code 0x5a.
+func sendSocks4aResponseGranted(w io.Writer, addr *net.TCPAddr) error {
+       return sendSocks4aResponse(w, socksRequestGranted, addr)
+}
+
+// Send a SOCKS4a response code 0x5b (with an all-zero address).
+func sendSocks4aResponseRejected(w io.Writer) error {
+       return sendSocks4aResponse(w, socksRequestRejected, &emptyAddr)
+}
diff --git a/socks/socks.go b/socks/socks.go
deleted file mode 100644
index 450c409..0000000
--- a/socks/socks.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// Package socks implements a SOCKS4a server sufficient for a Tor client
-// transport plugin.
-//
-//     ln, err := socks.Listen("tcp", ":3128")
-//     if err != nil {
-//             return err
-//     }
-//     conn, err := ln.AcceptSocks()
-//     if err != nil {
-//             return err
-//     }
-//     defer conn.Close()
-//     remote, err := net.Dial("tcp", local.Req.Target)
-//     if err != nil {
-//             local.Reject()
-//             return err
-//     }
-//     err = local.Grant(remote.RemoteAddr().(*net.TCPAddr))
-//     if err != nil {
-//             return err
-//     }
-//
-// http://ftp.icm.edu.pl/packages/socks/socks4/SOCKS4.protocol
-package socks
-
-import (
-       "bufio"
-       "errors"
-       "fmt"
-       "io"
-       "net"
-)
-
-const (
-       socksVersion         = 0x04
-       socksCmdConnect      = 0x01
-       socksResponseVersion = 0x00
-       socksRequestGranted  = 0x5a
-       socksRequestRejected = 0x5b
-)
-
-// Request describes a SOCKS request.
-type Request struct {
-       Username string
-       Target   string
-}
-
-// Conn encapsulates a net.Conn and information associated with a SOCKS 
request.
-type Conn struct {
-       net.Conn
-       Req Request
-}
-
-// Send a message to the proxy client that access to the given address is
-// granted.
-func (conn *Conn) Grant(addr *net.TCPAddr) error {
-       return sendSocks4aResponseGranted(conn, addr)
-}
-
-// Send a message to the proxy client that access was rejected or failed.
-func (conn *Conn) Reject() error {
-       return sendSocks4aResponseRejected(conn)
-}
-
-// Listener wraps a net.Listener in order to read a SOCKS request on Accept.
-type Listener struct {
-       net.Listener
-}
-
-// Open a net.Listener according to network and laddr, and return it as a
-// Listener.
-func Listen(network, laddr string) (*Listener, error) {
-       ln, err := net.Listen(network, laddr)
-       if err != nil {
-               return nil, err
-       }
-       return NewListener(ln), nil
-}
-
-// Create a new Listener wrapping the given net.Listener.
-func NewListener(ln net.Listener) *Listener {
-       return &Listener{ln}
-}
-
-// Accept is the same as AcceptSocks, except that it returns a generic 
net.Conn.
-// It is present for the sake of satisfying the net.Listener interface.
-func (ln *Listener) Accept() (net.Conn, error) {
-       return ln.AcceptSocks()
-}
-
-// Call Accept on the wrapped net.Listener, do SOCKS negotiation, and return a
-// Conn. After accepting, you must call either conn.Grant or conn.Reject
-// (presumably after trying to connect to conn.Req.Target).
-func (ln *Listener) AcceptSocks() (*Conn, error) {
-       c, err := ln.Listener.Accept()
-       if err != nil {
-               return nil, err
-       }
-       conn := new(Conn)
-       conn.Conn = c
-       conn.Req, err = readSocks4aConnect(conn)
-       if err != nil {
-               conn.Close()
-               return nil, err
-       }
-       return conn, nil
-}
-
-// Read a SOCKS4a connect request. Returns a Request.
-func readSocks4aConnect(s io.Reader) (req Request, err error) {
-       r := bufio.NewReader(s)
-
-       var h [8]byte
-       _, err = io.ReadFull(r, h[:])
-       if err != nil {
-               return
-       }
-       if h[0] != socksVersion {
-               err = errors.New(fmt.Sprintf("SOCKS header had version 0x%02x, 
not 0x%02x", h[0], socksVersion))
-               return
-       }
-       if h[1] != socksCmdConnect {
-               err = errors.New(fmt.Sprintf("SOCKS header had command 0x%02x, 
not 0x%02x", h[1], socksCmdConnect))
-               return
-       }
-
-       var usernameBytes []byte
-       usernameBytes, err = r.ReadBytes('\x00')
-       if err != nil {
-               return
-       }
-       req.Username = string(usernameBytes[:len(usernameBytes)-1])
-
-       var port int
-       var host string
-
-       port = int(h[2])<<8 | int(h[3])<<0
-       if h[4] == 0 && h[5] == 0 && h[6] == 0 && h[7] != 0 {
-               var hostBytes []byte
-               hostBytes, err = r.ReadBytes('\x00')
-               if err != nil {
-                       return
-               }
-               host = string(hostBytes[:len(hostBytes)-1])
-       } else {
-               host = net.IPv4(h[4], h[5], h[6], h[7]).String()
-       }
-
-       if r.Buffered() != 0 {
-               err = errors.New(fmt.Sprintf("%d bytes left after SOCKS 
header", r.Buffered()))
-               return
-       }
-
-       req.Target = fmt.Sprintf("%s:%d", host, port)
-       return
-}
-
-// Send a SOCKS4a response with the given code and address.
-func sendSocks4aResponse(w io.Writer, code byte, addr *net.TCPAddr) error {
-       var resp [8]byte
-       resp[0] = socksResponseVersion
-       resp[1] = code
-       resp[2] = byte((addr.Port >> 8) & 0xff)
-       resp[3] = byte((addr.Port >> 0) & 0xff)
-       resp[4] = addr.IP[0]
-       resp[5] = addr.IP[1]
-       resp[6] = addr.IP[2]
-       resp[7] = addr.IP[3]
-       _, err := w.Write(resp[:])
-       return err
-}
-
-var emptyAddr = net.TCPAddr{IP: net.IPv4(0, 0, 0, 0), Port: 0}
-
-// Send a SOCKS4a response code 0x5a.
-func sendSocks4aResponseGranted(w io.Writer, addr *net.TCPAddr) error {
-       return sendSocks4aResponse(w, socksRequestGranted, addr)
-}
-
-// Send a SOCKS4a response code 0x5b (with an all-zero address).
-func sendSocks4aResponseRejected(w io.Writer) error {
-       return sendSocks4aResponse(w, socksRequestRejected, &emptyAddr)
-}
diff --git a/socks/socks_test.go b/socks/socks_test.go
deleted file mode 100644
index 759bf4a..0000000
--- a/socks/socks_test.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package socks
-
-import (
-       "bytes"
-       "net"
-       "testing"
-)
-
-func tcpAddrsEqual(a, b *net.TCPAddr) bool {
-       return a.IP.Equal(b.IP) && a.Port == b.Port
-}
-
-func TestReadSocks4aConnect(t *testing.T) {
-       badTests := [...][]byte{
-               []byte(""),
-               // missing userid
-               []byte("\x04\x01\x12\x34\x01\x02\x03\x04"),
-               // missing \x00 after userid
-               []byte("\x04\x01\x12\x34\x01\x02\x03\x04userid"),
-               // missing hostname
-               []byte("\x04\x01\x12\x34\x00\x00\x00\x01userid\x00"),
-               // missing \x00 after hostname
-               []byte("\x04\x01\x12\x34\x00\x00\x00\x01userid\x00hostname"),
-               // BIND request
-               []byte("\x04\x02\x12\x34\x01\x02\x03\x04userid\x00"),
-               // SOCKS5
-               []byte("\x05\x01\x00"),
-       }
-       ipTests := [...]struct {
-               input  []byte
-               userid string
-               addr   net.TCPAddr
-       }{
-               {
-                       []byte("\x04\x01\x12\x34\x01\x02\x03\x04userid\x00"),
-                       "userid", net.TCPAddr{IP: net.ParseIP("1.2.3.4"), Port: 
0x1234},
-               },
-               {
-                       []byte("\x04\x01\x12\x34\x01\x02\x03\x04\x00"),
-                       "", net.TCPAddr{IP: net.ParseIP("1.2.3.4"), Port: 
0x1234},
-               },
-       }
-       hostnameTests := [...]struct {
-               input  []byte
-               userid string
-               target string
-       }{
-               {
-                       
[]byte("\x04\x01\x12\x34\x00\x00\x00\x01userid\x00hostname\x00"),
-                       "userid", "hostname:4660",
-               },
-               {
-                       
[]byte("\x04\x01\x12\x34\x00\x00\x00\x01\x00hostname\x00"),
-                       "", "hostname:4660",
-               },
-               {
-                       
[]byte("\x04\x01\x12\x34\x00\x00\x00\x01userid\x00\x00"),
-                       "userid", ":4660",
-               },
-               {
-                       []byte("\x04\x01\x12\x34\x00\x00\x00\x01\x00\x00"),
-                       "", ":4660",
-               },
-       }
-
-       for _, input := range badTests {
-               var buf bytes.Buffer
-               buf.Write(input)
-               _, err := readSocks4aConnect(&buf)
-               if err == nil {
-                       t.Errorf("%q unexpectedly succeeded", input)
-               }
-       }
-
-       for _, test := range ipTests {
-               var buf bytes.Buffer
-               buf.Write(test.input)
-               req, err := readSocks4aConnect(&buf)
-               if err != nil {
-                       t.Errorf("%q unexpectedly returned an error: %s", 
test.input, err)
-               }
-               if req.Username != test.userid {
-                       t.Errorf("%q → username %q (expected %q)", test.input,
-                               req.Username, test.userid)
-               }
-               addr, err := net.ResolveTCPAddr("tcp", req.Target)
-               if err != nil {
-                       t.Error("%q → target %q: cannot resolve: %s", 
test.input,
-                               req.Target, err)
-               }
-               if !tcpAddrsEqual(addr, &test.addr) {
-                       t.Errorf("%q → address %s (expected %s)", test.input,
-                               req.Target, test.addr.String())
-               }
-       }
-
-       for _, test := range hostnameTests {
-               var buf bytes.Buffer
-               buf.Write(test.input)
-               req, err := readSocks4aConnect(&buf)
-               if err != nil {
-                       t.Errorf("%q unexpectedly returned an error: %s", 
test.input, err)
-               }
-               if req.Username != test.userid {
-                       t.Errorf("%q → username %q (expected %q)", test.input,
-                               req.Username, test.userid)
-               }
-               if req.Target != test.target {
-                       t.Errorf("%q → target %q (expected %q)", test.input,
-                               req.Target, test.target)
-               }
-       }
-}
diff --git a/socks_test.go b/socks_test.go
new file mode 100644
index 0000000..bb638b5
--- /dev/null
+++ b/socks_test.go
@@ -0,0 +1,109 @@
+package pt
+
+import (
+       "bytes"
+       "net"
+       "testing"
+)
+
+func TestReadSocks4aConnect(t *testing.T) {
+       badTests := [...][]byte{
+               []byte(""),
+               // missing userid
+               []byte("\x04\x01\x12\x34\x01\x02\x03\x04"),
+               // missing \x00 after userid
+               []byte("\x04\x01\x12\x34\x01\x02\x03\x04userid"),
+               // missing hostname
+               []byte("\x04\x01\x12\x34\x00\x00\x00\x01userid\x00"),
+               // missing \x00 after hostname
+               []byte("\x04\x01\x12\x34\x00\x00\x00\x01userid\x00hostname"),
+               // BIND request
+               []byte("\x04\x02\x12\x34\x01\x02\x03\x04userid\x00"),
+               // SOCKS5
+               []byte("\x05\x01\x00"),
+       }
+       ipTests := [...]struct {
+               input  []byte
+               userid string
+               addr   net.TCPAddr
+       }{
+               {
+                       []byte("\x04\x01\x12\x34\x01\x02\x03\x04userid\x00"),
+                       "userid", net.TCPAddr{IP: net.ParseIP("1.2.3.4"), Port: 
0x1234},
+               },
+               {
+                       []byte("\x04\x01\x12\x34\x01\x02\x03\x04\x00"),
+                       "", net.TCPAddr{IP: net.ParseIP("1.2.3.4"), Port: 
0x1234},
+               },
+       }
+       hostnameTests := [...]struct {
+               input  []byte
+               userid string
+               target string
+       }{
+               {
+                       
[]byte("\x04\x01\x12\x34\x00\x00\x00\x01userid\x00hostname\x00"),
+                       "userid", "hostname:4660",
+               },
+               {
+                       
[]byte("\x04\x01\x12\x34\x00\x00\x00\x01\x00hostname\x00"),
+                       "", "hostname:4660",
+               },
+               {
+                       
[]byte("\x04\x01\x12\x34\x00\x00\x00\x01userid\x00\x00"),
+                       "userid", ":4660",
+               },
+               {
+                       []byte("\x04\x01\x12\x34\x00\x00\x00\x01\x00\x00"),
+                       "", ":4660",
+               },
+       }
+
+       for _, input := range badTests {
+               var buf bytes.Buffer
+               buf.Write(input)
+               _, err := readSocks4aConnect(&buf)
+               if err == nil {
+                       t.Errorf("%q unexpectedly succeeded", input)
+               }
+       }
+
+       for _, test := range ipTests {
+               var buf bytes.Buffer
+               buf.Write(test.input)
+               req, err := readSocks4aConnect(&buf)
+               if err != nil {
+                       t.Errorf("%q unexpectedly returned an error: %s", 
test.input, err)
+               }
+               if req.Username != test.userid {
+                       t.Errorf("%q → username %q (expected %q)", test.input,
+                               req.Username, test.userid)
+               }
+               addr, err := net.ResolveTCPAddr("tcp", req.Target)
+               if err != nil {
+                       t.Error("%q → target %q: cannot resolve: %s", 
test.input,
+                               req.Target, err)
+               }
+               if !tcpAddrsEqual(addr, &test.addr) {
+                       t.Errorf("%q → address %s (expected %s)", test.input,
+                               req.Target, test.addr.String())
+               }
+       }
+
+       for _, test := range hostnameTests {
+               var buf bytes.Buffer
+               buf.Write(test.input)
+               req, err := readSocks4aConnect(&buf)
+               if err != nil {
+                       t.Errorf("%q unexpectedly returned an error: %s", 
test.input, err)
+               }
+               if req.Username != test.userid {
+                       t.Errorf("%q → username %q (expected %q)", test.input,
+                               req.Username, test.userid)
+               }
+               if req.Target != test.target {
+                       t.Errorf("%q → target %q (expected %q)", test.input,
+                               req.Target, test.target)
+               }
+       }
+}



_______________________________________________
tor-commits mailing list
tor-commits@lists.torproject.org
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits

Reply via email to