[tor-commits] [flashproxy/master] Resurrect websocket-client.
dcf at torproject.org
dcf at torproject.org
Thu May 30 23:40:11 UTC 2013
commit 5a7fa6ef4b2593531188f043421ec48f731b1a04
Author: David Fifield <david at bamsoftware.com>
Date: Thu May 30 14:27:30 2013 -0700
Resurrect websocket-client.
---
.gitignore | 1 +
websocket-transport/Makefile | 3 +-
websocket-transport/websocket-client.go | 220 +++++++++++++++++++++++++++++++
3 files changed, 223 insertions(+), 1 deletion(-)
diff --git a/.gitignore b/.gitignore
index b8833f8..cc97752 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.pyc
/dist
/py2exe-tmp
+/websocket-transport/websocket-client
/websocket-transport/websocket-server
diff --git a/websocket-transport/Makefile b/websocket-transport/Makefile
index 5cdba65..ac6fa08 100644
--- a/websocket-transport/Makefile
+++ b/websocket-transport/Makefile
@@ -1,7 +1,7 @@
PREFIX = /usr/local
BINDIR = $(PREFIX)/bin
-PROGRAMS = websocket-server
+PROGRAMS = websocket-client websocket-server
GOBUILDFLAGS =
# Alternate flags to use gccgo, allowing cross-compiling for x86 from
@@ -11,6 +11,7 @@ GOBUILDFLAGS =
all: websocket-server
+websocket-client: websocket-client.go socks.go pt.go
websocket-server: websocket-server.go pt.go websocket.go
%: %.go
diff --git a/websocket-transport/websocket-client.go b/websocket-transport/websocket-client.go
new file mode 100644
index 0000000..129e90a
--- /dev/null
+++ b/websocket-transport/websocket-client.go
@@ -0,0 +1,220 @@
+// Tor websocket client transport plugin.
+//
+// Usage:
+// ClientTransportPlugin websocket exec ./websocket-client
+
+package main
+
+import (
+ "code.google.com/p/go.net/websocket"
+ "flag"
+ "fmt"
+ "io"
+ "net"
+ "net/url"
+ "os"
+ "os/signal"
+ "sync"
+ "time"
+)
+
+const socksTimeout = 2
+const bufSiz = 1500
+
+// When a connection handler starts, +1 is written to this channel; when it
+// ends, -1 is written.
+var handlerChan = make(chan int)
+
+func logDebug(format string, v ...interface{}) {
+ fmt.Fprintf(os.Stderr, format+"\n", v...)
+}
+
+func proxy(local *net.TCPConn, ws *websocket.Conn) {
+ var wg sync.WaitGroup
+
+ wg.Add(2)
+
+ // Local-to-WebSocket read loop.
+ go func() {
+ buf := make([]byte, bufSiz)
+ var err error
+ for {
+ n, er := local.Read(buf[:])
+ if n > 0 {
+ ew := websocket.Message.Send(ws, buf[:n])
+ if ew != nil {
+ err = ew
+ break
+ }
+ }
+ if er != nil {
+ err = er
+ break
+ }
+ }
+ if err != nil && err != io.EOF {
+ logDebug("%s", err)
+ }
+ local.CloseRead()
+ ws.Close()
+
+ wg.Done()
+ }()
+
+ // WebSocket-to-local read loop.
+ go func() {
+ var buf []byte
+ var err error
+ for {
+ er := websocket.Message.Receive(ws, &buf)
+ if er != nil {
+ err = er
+ break
+ }
+ n, ew := local.Write(buf)
+ if ew != nil {
+ err = ew
+ break
+ }
+ if n != len(buf) {
+ err = io.ErrShortWrite
+ break
+ }
+ }
+ if err != nil && err != io.EOF {
+ logDebug("%s", err)
+ }
+ local.CloseWrite()
+ ws.Close()
+
+ wg.Done()
+ }()
+
+ wg.Wait()
+}
+
+func handleConnection(conn *net.TCPConn) error {
+ defer conn.Close()
+
+ handlerChan <- 1
+ defer func() {
+ handlerChan <- -1
+ }()
+
+ var ws *websocket.Conn
+
+ conn.SetDeadline(time.Now().Add(socksTimeout * time.Second))
+ err := AwaitSocks4aConnect(conn, func(dest string) (*net.TCPAddr, error) {
+ // Disable deadline.
+ conn.SetDeadline(time.Time{})
+ logDebug("SOCKS request for %s", dest)
+ destAddr, err := net.ResolveTCPAddr("tcp", dest)
+ if err != nil {
+ return nil, err
+ }
+ wsUrl := url.URL{Scheme: "ws", Host: dest}
+ ws, err = websocket.Dial(wsUrl.String(), "", wsUrl.String())
+ if err != nil {
+ return nil, err
+ }
+ logDebug("WebSocket connection to %s", ws.Config().Location.String())
+ return destAddr, nil
+ })
+ if err != nil {
+ return err
+ }
+ defer ws.Close()
+ proxy(conn, ws)
+ return nil
+}
+
+func socksAcceptLoop(ln *net.TCPListener) error {
+ for {
+ socks, err := ln.AcceptTCP()
+ if err != nil {
+ return err
+ }
+ go func() {
+ err := handleConnection(socks)
+ if err != nil {
+ logDebug("SOCKS from %s: %s", socks.RemoteAddr(), err)
+ }
+ }()
+ }
+ return nil
+}
+
+func startListener(addrStr string) (*net.TCPListener, error) {
+ addr, err := net.ResolveTCPAddr("tcp", addrStr)
+ if err != nil {
+ return nil, err
+ }
+ ln, err := net.ListenTCP("tcp", addr)
+ if err != nil {
+ return nil, err
+ }
+ go func() {
+ err := socksAcceptLoop(ln)
+ if err != nil {
+ logDebug("accept: %s", err)
+ }
+ }()
+ return ln, nil
+}
+
+func main() {
+ const ptMethodName = "websocket"
+ var defaultSocksAddrStrs = []string{"127.0.0.1:0"}
+ var socksAddrStrs []string
+
+ var socksArg = flag.String("socks", "", "address on which to listen for SOCKS connections")
+ flag.Parse()
+ if *socksArg != "" {
+ socksAddrStrs = []string{*socksArg}
+ } else {
+ socksAddrStrs = defaultSocksAddrStrs
+ }
+
+ PtClientSetup([]string{ptMethodName})
+
+ listeners := make([]*net.TCPListener, 0)
+ for _, socksAddrStr := range socksAddrStrs {
+ ln, err := startListener(socksAddrStr)
+ if err != nil {
+ PtCmethodError(ptMethodName, err.Error())
+ }
+ PtCmethod(ptMethodName, "socks4", ln.Addr())
+ listeners = append(listeners, ln)
+ }
+ PtCmethodsDone()
+
+ var numHandlers int = 0
+
+ signalChan := make(chan os.Signal, 1)
+ signal.Notify(signalChan, os.Interrupt)
+ var sigint bool = false
+ for !sigint {
+ select {
+ case n := <-handlerChan:
+ numHandlers += n
+ case <-signalChan:
+ logDebug("SIGINT")
+ sigint = true
+ }
+ }
+
+ for _, ln := range listeners {
+ ln.Close()
+ }
+
+ sigint = false
+ for numHandlers != 0 && !sigint {
+ select {
+ case n := <-handlerChan:
+ numHandlers += n
+ case <-signalChan:
+ logDebug("SIGINT")
+ sigint = true
+ }
+ }
+}
More information about the tor-commits
mailing list