[tor-commits] [goptlib/master] Implement socks as a Listener.
dcf at torproject.org
dcf at torproject.org
Mon Dec 9 02:49:51 UTC 2013
commit a0eeefa02086248e7253ba3c1cf4780c1cfe69da
Author: David Fifield <david at bamsoftware.com>
Date: Sat Dec 7 01:21:04 2013 -0800
Implement socks as a Listener.
---
examples/dummy-client/dummy-client.go | 25 ++++----
socks/socks.go | 102 ++++++++++++++++++++++++---------
2 files changed, 85 insertions(+), 42 deletions(-)
diff --git a/examples/dummy-client/dummy-client.go b/examples/dummy-client/dummy-client.go
index 783788a..10f7b8b 100644
--- a/examples/dummy-client/dummy-client.go
+++ b/examples/dummy-client/dummy-client.go
@@ -44,7 +44,7 @@ func copyLoop(a, b net.Conn) {
wg.Wait()
}
-func handleConnection(local net.Conn) error {
+func handleConnection(local *socks.Conn) error {
defer local.Close()
handlerChan <- 1
@@ -52,28 +52,25 @@ func handleConnection(local net.Conn) error {
handlerChan <- -1
}()
- var remote net.Conn
- err := socks.AwaitSocks4aConnect(local.(*net.TCPConn), func(dest string) (*net.TCPAddr, error) {
- var err error
- // set remote in outer function environment
- remote, err = net.Dial("tcp", dest)
- if err != nil {
- return nil, err
- }
- return remote.RemoteAddr().(*net.TCPAddr), nil
- })
+ 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
}
+
defer remote.Close()
copyLoop(local, remote)
return nil
}
-func acceptLoop(ln net.Listener) error {
+func acceptLoop(ln *socks.Listener) error {
for {
- conn, err := ln.Accept()
+ conn, err := ln.AcceptSocks()
if err != nil {
return err
}
@@ -83,7 +80,7 @@ func acceptLoop(ln net.Listener) error {
}
func startListener(addr string) (net.Listener, error) {
- ln, err := net.Listen("tcp", addr)
+ ln, err := socks.Listen("tcp", addr)
if err != nil {
return nil, err
}
diff --git a/socks/socks.go b/socks/socks.go
index 0cbbba8..04b7ccd 100644
--- a/socks/socks.go
+++ b/socks/socks.go
@@ -1,6 +1,25 @@
// 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
@@ -25,38 +44,65 @@ type Request struct {
Target string
}
-// Read a SOCKS4a connect request, and call the given connect callback with the
-// requested destination string. If the callback returns an error, sends a SOCKS
-// request failed message. Otherwise, sends a SOCKS request granted message for
-// the destination address returned by the callback.
-// var remote net.Conn
-// err := socks.AwaitSocks4aConnect(local.(*net.TCPConn), func(dest string) (*net.TCPAddr, error) {
-// var err error
-// // set remote in outer function environment
-// remote, err = net.Dial("tcp", dest)
-// if err != nil {
-// return nil, err
-// }
-// return remote.RemoteAddr().(*net.TCPAddr), nil
-// })
-// if err != nil {
-// return err
-// }
-// defer remote.Close()
-// copyLoop(local, remote)
-func AwaitSocks4aConnect(conn *net.TCPConn, connect func(string) (*net.TCPAddr, error)) error {
- req, err := readSocks4aConnect(conn)
+// 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 {
- sendSocks4aResponseRejected(conn)
- return err
+ return nil, err
}
- destAddr, err := connect(req.Target)
+ conn := new(Conn)
+ conn.Conn = c
+ conn.Req, err = readSocks4aConnect(conn)
if err != nil {
- sendSocks4aResponseRejected(conn)
- return err
+ conn.Close()
+ return nil, err
}
- sendSocks4aResponseGranted(conn, destAddr)
- return nil
+ return conn, nil
}
// Read a SOCKS4a connect request. Returns a Request.
More information about the tor-commits
mailing list