[tor-commits] [websocket/master] Delete the local pt library.

dcf at torproject.org dcf at torproject.org
Fri Dec 13 07:14:21 UTC 2013


commit 9ca17c7ae0c24168d1aa09dd4ad01068914386f5
Author: David Fifield <david at bamsoftware.com>
Date:   Thu Dec 12 21:04:07 2013 -0800

    Delete the local pt library.
    
    Use goptlib instead.
---
 Makefile                                 |    4 +-
 pt/.gitignore                            |    2 -
 pt/examples/dummy-client/dummy-client.go |  137 -------
 pt/examples/dummy-server/dummy-server.go |  121 ------
 pt/pt.go                                 |  611 ------------------------------
 pt/pt_test.go                            |   61 ---
 pt/socks/socks.go                        |  107 ------
 websocket-client/websocket-client.go     |   66 ++--
 websocket-server/websocket-server.go     |   22 +-
 9 files changed, 49 insertions(+), 1082 deletions(-)

diff --git a/Makefile b/Makefile
index 95aa243..28a94ad 100644
--- a/Makefile
+++ b/Makefile
@@ -10,10 +10,10 @@ GOBUILDFLAGS =
 
 all: websocket-server/websocket-server
 
-websocket-server/websocket-server: websocket-server/*.go websocket/*.go pt/*.go
+websocket-server/websocket-server: websocket-server/*.go websocket/*.go
 	cd websocket-server && go build $(GOBUILDFLAGS)
 
-websocket-client/websocket-client: websocket-client/*.go websocket/*.go pt/*.go
+websocket-client/websocket-client: websocket-client/*.go websocket/*.go
 	cd websocket-client && go build $(GOBUILDFLAGS)
 
 install: websocket-server/websocket-server
diff --git a/pt/.gitignore b/pt/.gitignore
deleted file mode 100644
index d4d5132..0000000
--- a/pt/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/examples/dummy-client/dummy-client
-/examples/dummy-server/dummy-server
diff --git a/pt/examples/dummy-client/dummy-client.go b/pt/examples/dummy-client/dummy-client.go
deleted file mode 100644
index 3cf7b45..0000000
--- a/pt/examples/dummy-client/dummy-client.go
+++ /dev/null
@@ -1,137 +0,0 @@
-// Usage (in torrc):
-//   UseBridges 1
-//   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.
-
-package main
-
-import (
-	"io"
-	"net"
-	"os"
-	"os/signal"
-	"sync"
-	"syscall"
-)
-
-import "git.torproject.org/pluggable-transports/websocket.git/src/pt"
-import "git.torproject.org/pluggable-transports/websocket.git/src/pt/socks"
-
-var ptInfo pt.ClientInfo
-
-// When a connection handler starts, +1 is written to this channel; when it
-// ends, -1 is written.
-var handlerChan = make(chan int)
-
-func copyLoop(a, b net.Conn) {
-	var wg sync.WaitGroup
-	wg.Add(2)
-
-	go func() {
-		io.Copy(b, a)
-		wg.Done()
-	}()
-	go func() {
-		io.Copy(a, b)
-		wg.Done()
-	}()
-
-	wg.Wait()
-}
-
-func handleConnection(local net.Conn) error {
-	defer local.Close()
-
-	handlerChan <- 1
-	defer func() {
-		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
-	})
-	if err != nil {
-		return err
-	}
-	defer remote.Close()
-	copyLoop(local, remote)
-
-	return nil
-}
-
-func acceptLoop(ln net.Listener) error {
-	for {
-		conn, err := ln.Accept()
-		if err != nil {
-			return err
-		}
-		go handleConnection(conn)
-	}
-	return nil
-}
-
-func startListener(addr string) (net.Listener, error) {
-	ln, err := net.Listen("tcp", addr)
-	if err != nil {
-		return nil, err
-	}
-	go acceptLoop(ln)
-	return ln, nil
-}
-
-func main() {
-	ptInfo = pt.ClientSetup([]string{"dummy"})
-
-	listeners := make([]net.Listener, 0)
-	for _, methodName := range ptInfo.MethodNames {
-		ln, err := startListener("127.0.0.1:0")
-		if err != nil {
-			pt.CmethodError(methodName, err.Error())
-			continue
-		}
-		pt.Cmethod(methodName, "socks4", ln.Addr())
-		listeners = append(listeners, ln)
-	}
-	pt.CmethodsDone()
-
-	var numHandlers int = 0
-	var sig os.Signal
-	sigChan := make(chan os.Signal, 1)
-	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
-
-	// wait for first signal
-	sig = nil
-	for sig == nil {
-		select {
-		case n := <-handlerChan:
-			numHandlers += n
-		case sig = <-sigChan:
-		}
-	}
-	for _, ln := range listeners {
-		ln.Close()
-	}
-
-	if sig == syscall.SIGTERM {
-		return
-	}
-
-	// wait for second signal or no more handlers
-	sig = nil
-	for sig == nil && numHandlers != 0 {
-		select {
-		case n := <-handlerChan:
-			numHandlers += n
-		case sig = <-sigChan:
-		}
-	}
-}
diff --git a/pt/examples/dummy-server/dummy-server.go b/pt/examples/dummy-server/dummy-server.go
deleted file mode 100644
index 26314d0..0000000
--- a/pt/examples/dummy-server/dummy-server.go
+++ /dev/null
@@ -1,121 +0,0 @@
-// Usage (in torrc):
-//   BridgeRelay 1
-//   ORPort 9001
-//   ExtORPort 6669
-//   ServerTransportPlugin dummy exec dummy-server
-
-package main
-
-import (
-	"io"
-	"net"
-	"os"
-	"os/signal"
-	"sync"
-	"syscall"
-)
-
-import "git.torproject.org/pluggable-transports/websocket.git/src/pt"
-
-var ptInfo pt.ServerInfo
-
-// When a connection handler starts, +1 is written to this channel; when it
-// ends, -1 is written.
-var handlerChan = make(chan int)
-
-func copyLoop(a, b net.Conn) {
-	var wg sync.WaitGroup
-	wg.Add(2)
-
-	go func() {
-		io.Copy(b, a)
-		wg.Done()
-	}()
-	go func() {
-		io.Copy(a, b)
-		wg.Done()
-	}()
-
-	wg.Wait()
-}
-
-func handleConnection(conn net.Conn) {
-	handlerChan <- 1
-	defer func() {
-		handlerChan <- -1
-	}()
-
-	or, err := pt.ConnectOr(&ptInfo, conn, "dummy")
-	if err != nil {
-		return
-	}
-	copyLoop(conn, or)
-}
-
-func acceptLoop(ln net.Listener) error {
-	for {
-		conn, err := ln.Accept()
-		if err != nil {
-			return err
-		}
-		go handleConnection(conn)
-	}
-	return nil
-}
-
-func startListener(addr *net.TCPAddr) (net.Listener, error) {
-	ln, err := net.ListenTCP("tcp", addr)
-	if err != nil {
-		return nil, err
-	}
-	go acceptLoop(ln)
-	return ln, nil
-}
-
-func main() {
-	ptInfo = pt.ServerSetup([]string{"dummy"})
-
-	listeners := make([]net.Listener, 0)
-	for _, bindAddr := range ptInfo.BindAddrs {
-		ln, err := startListener(bindAddr.Addr)
-		if err != nil {
-			pt.SmethodError(bindAddr.MethodName, err.Error())
-			continue
-		}
-		pt.Smethod(bindAddr.MethodName, ln.Addr())
-		listeners = append(listeners, ln)
-	}
-	pt.SmethodsDone()
-
-	var numHandlers int = 0
-	var sig os.Signal
-	sigChan := make(chan os.Signal, 1)
-	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
-
-	// wait for first signal
-	sig = nil
-	for sig == nil {
-		select {
-		case n := <-handlerChan:
-			numHandlers += n
-		case sig = <-sigChan:
-		}
-	}
-	for _, ln := range listeners {
-		ln.Close()
-	}
-
-	if sig == syscall.SIGTERM {
-		return
-	}
-
-	// wait for second signal or no more handlers
-	sig = nil
-	for sig == nil && numHandlers != 0 {
-		select {
-		case n := <-handlerChan:
-			numHandlers += n
-		case sig = <-sigChan:
-		}
-	}
-}
diff --git a/pt/pt.go b/pt/pt.go
deleted file mode 100644
index 526f3b7..0000000
--- a/pt/pt.go
+++ /dev/null
@@ -1,611 +0,0 @@
-// Tor pluggable transports library.
-//
-// Sample client usage:
-//
-// import "git.torproject.org/pluggable-transports/websocket.git/src/pt"
-// var ptInfo pt.ClientInfo
-// ptInfo = pt.ClientSetup([]string{"foo"})
-// for _, methodName := range ptInfo.MethodNames {
-// 	ln, err := startSocksListener()
-// 	if err != nil {
-// 		pt.CmethodError(methodName, err.Error())
-// 		continue
-// 	}
-// 	pt.Cmethod(methodName, "socks4", ln.Addr())
-// }
-// pt.CmethodsDone()
-//
-// Sample server usage:
-//
-// import "git.torproject.org/pluggable-transports/websocket.git/src/pt"
-// var ptInfo pt.ServerInfo
-// ptInfo = pt.ServerSetup([]string{"foo", "bar"})
-// for _, bindAddr := range ptInfo.BindAddrs {
-// 	ln, err := startListener(bindAddr.Addr, bindAddr.MethodName)
-// 	if err != nil {
-// 		pt.SmethodError(bindAddr.MethodName, err.Error())
-// 		continue
-// 	}
-// 	pt.Smethod(bindAddr.MethodName, ln.Addr())
-// }
-// pt.SmethodsDone()
-// func handler(conn net.Conn, methodName string) {
-// 	or, err := pt.ConnectOr(&ptInfo, conn, methodName)
-// 	if err != nil {
-// 		return
-// 	}
-// 	// Do something with or and conn.
-// }
-
-package pt
-
-import (
-	"bufio"
-	"bytes"
-	"crypto/hmac"
-	"crypto/rand"
-	"crypto/sha256"
-	"crypto/subtle"
-	"encoding/binary"
-	"errors"
-	"fmt"
-	"io"
-	"net"
-	"os"
-	"strings"
-	"time"
-)
-
-func getenv(key string) string {
-	return os.Getenv(key)
-}
-
-// Abort with an ENV-ERROR if the environment variable isn't set.
-func getenvRequired(key string) string {
-	value := os.Getenv(key)
-	if value == "" {
-		EnvError(fmt.Sprintf("no %s environment variable", key))
-	}
-	return value
-}
-
-// Escape a string so it contains no byte values over 127 and doesn't contain
-// any of the characters '\x00' or '\n'.
-func escape(s string) string {
-	var buf bytes.Buffer
-	for _, b := range []byte(s) {
-		if b == '\n' {
-			buf.WriteString("\\n")
-		} else if b == '\\' {
-			buf.WriteString("\\\\")
-		} else if 0 < b && b < 128 {
-			buf.WriteByte(b)
-		} else {
-			fmt.Fprintf(&buf, "\\x%02x", b)
-		}
-	}
-	return buf.String()
-}
-
-// Print a pluggable transports protocol line to stdout. The line consists of an
-// unescaped keyword, followed by any number of escaped strings.
-func Line(keyword string, v ...string) {
-	var buf bytes.Buffer
-	buf.WriteString(keyword)
-	for _, x := range v {
-		buf.WriteString(" " + escape(x))
-	}
-	fmt.Println(buf.String())
-	os.Stdout.Sync()
-}
-
-// All of the *Error functions call os.Exit(1).
-
-// Emit an ENV-ERROR with explanation text.
-func EnvError(msg string) {
-	Line("ENV-ERROR", msg)
-	os.Exit(1)
-}
-
-// Emit a VERSION-ERROR with explanation text.
-func VersionError(msg string) {
-	Line("VERSION-ERROR", msg)
-	os.Exit(1)
-}
-
-// Emit a CMETHOD-ERROR with explanation text.
-func CmethodError(methodName, msg string) {
-	Line("CMETHOD-ERROR", methodName, msg)
-	os.Exit(1)
-}
-
-// Emit an SMETHOD-ERROR with explanation text.
-func SmethodError(methodName, msg string) {
-	Line("SMETHOD-ERROR", methodName, msg)
-	os.Exit(1)
-}
-
-// 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) {
-	Line("CMETHOD", name, socks, addr.String())
-}
-
-// Emit a CMETHODS DONE line. Call this after opening all client listeners.
-func CmethodsDone() {
-	Line("CMETHODS", "DONE")
-}
-
-// Emit an SMETHOD line. Call this once for each listening server port.
-func Smethod(name string, addr net.Addr) {
-	Line("SMETHOD", name, addr.String())
-}
-
-// Emit an SMETHODS DONE line. Call this after opening all server listeners.
-func SmethodsDone() {
-	Line("SMETHODS", "DONE")
-}
-
-// 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.
-func getManagedTransportVer() string {
-	const transportVersion = "1"
-	for _, offered := range strings.Split(getenvRequired("TOR_PT_MANAGED_TRANSPORT_VER"), ",") {
-		if offered == transportVersion {
-			return offered
-		}
-	}
-	return ""
-}
-
-// Get the intersection of the method names offered by Tor and those in
-// methodNames. This function reads the environment variable
-// TOR_PT_CLIENT_TRANSPORTS.
-func getClientTransports(methodNames []string) []string {
-	clientTransports := getenvRequired("TOR_PT_CLIENT_TRANSPORTS")
-	if clientTransports == "*" {
-		return methodNames
-	}
-	result := make([]string, 0)
-	for _, requested := range strings.Split(clientTransports, ",") {
-		for _, methodName := range methodNames {
-			if requested == methodName {
-				result = append(result, methodName)
-				break
-			}
-		}
-	}
-	return result
-}
-
-// This structure is returned by ClientSetup. It consists of a list of method
-// names.
-type ClientInfo struct {
-	MethodNames []string
-}
-
-// Check the client pluggable transports environments, emitting an error message
-// and exiting the program if any error is encountered. Returns a subset of
-// methodNames requested by Tor.
-func ClientSetup(methodNames []string) ClientInfo {
-	var info ClientInfo
-
-	ver := getManagedTransportVer()
-	if ver == "" {
-		VersionError("no-version")
-	} else {
-		Line("VERSION", ver)
-	}
-
-	info.MethodNames = getClientTransports(methodNames)
-	if len(info.MethodNames) == 0 {
-		CmethodsDone()
-		os.Exit(1)
-	}
-
-	return info
-}
-
-// A combination of a method name and an address, as extracted from
-// TOR_PT_SERVER_BINDADDR.
-type BindAddr struct {
-	MethodName string
-	Addr       *net.TCPAddr
-}
-
-// Resolve an address string into a net.TCPAddr.
-func resolveBindAddr(bindAddr string) (*net.TCPAddr, error) {
-	addr, err := net.ResolveTCPAddr("tcp", bindAddr)
-	if err == nil {
-		return addr, nil
-	}
-	// Before the fixing of bug #7011, tor doesn't put brackets around IPv6
-	// addresses. Split after the last colon, assuming it is a port
-	// separator, and try adding the brackets.
-	parts := strings.Split(bindAddr, ":")
-	if len(parts) <= 2 {
-		return nil, err
-	}
-	bindAddr = "[" + strings.Join(parts[:len(parts)-1], ":") + "]:" + parts[len(parts)-1]
-	return net.ResolveTCPAddr("tcp", bindAddr)
-}
-
-// Return a new slice, the members of which are those members of addrs having a
-// MethodName in methodNames.
-func filterBindAddrs(addrs []BindAddr, methodNames []string) []BindAddr {
-	var result []BindAddr
-
-	for _, ba := range addrs {
-		for _, methodName := range methodNames {
-			if ba.MethodName == methodName {
-				result = append(result, ba)
-				break
-			}
-		}
-	}
-
-	return result
-}
-
-// Return a map from method names to bind addresses. The map is the contents of
-// TOR_PT_SERVER_BINDADDR, with keys filtered by TOR_PT_SERVER_TRANSPORTS, and
-// further filtered by the methods in methodNames.
-func getServerBindAddrs(methodNames []string) []BindAddr {
-	var result []BindAddr
-
-	// Get the list of all requested bindaddrs.
-	var serverBindAddr = getenvRequired("TOR_PT_SERVER_BINDADDR")
-	for _, spec := range strings.Split(serverBindAddr, ",") {
-		var bindAddr BindAddr
-
-		parts := strings.SplitN(spec, "-", 2)
-		if len(parts) != 2 {
-			EnvError(fmt.Sprintf("TOR_PT_SERVER_BINDADDR: %q: doesn't contain \"-\"", spec))
-		}
-		bindAddr.MethodName = parts[0]
-		addr, err := resolveBindAddr(parts[1])
-		if err != nil {
-			EnvError(fmt.Sprintf("TOR_PT_SERVER_BINDADDR: %q: %s", spec, err.Error()))
-		}
-		bindAddr.Addr = addr
-		result = append(result, bindAddr)
-	}
-
-	// Filter by TOR_PT_SERVER_TRANSPORTS.
-	serverTransports := getenvRequired("TOR_PT_SERVER_TRANSPORTS")
-	if serverTransports != "*" {
-		result = filterBindAddrs(result, strings.Split(serverTransports, ","))
-	}
-
-	// Finally filter by what we understand.
-	result = filterBindAddrs(result, methodNames)
-
-	return result
-}
-
-// Read and validate the contents of an auth cookie file. Returns the 32-byte
-// cookie. See section 4.2.1.2 of pt-spec.txt.
-func readAuthCookieFile(filename string) ([]byte, error) {
-	authCookieHeader := []byte("! Extended ORPort Auth Cookie !\x0a")
-	header := make([]byte, 32)
-	cookie := make([]byte, 32)
-
-	f, err := os.Open(filename)
-	if err != nil {
-		return cookie, err
-	}
-	defer f.Close()
-
-	n, err := io.ReadFull(f, header)
-	if err != nil {
-		return cookie, err
-	}
-	n, err = io.ReadFull(f, cookie)
-	if err != nil {
-		return cookie, err
-	}
-	// Check that the file ends here.
-	n, err = f.Read(make([]byte, 1))
-	if n != 0 {
-		return cookie, errors.New(fmt.Sprintf("file is longer than 64 bytes"))
-	} else if err != io.EOF {
-		return cookie, errors.New(fmt.Sprintf("did not find EOF at end of file"))
-	}
-
-	if !bytes.Equal(header, authCookieHeader) {
-		return cookie, errors.New(fmt.Sprintf("missing auth cookie header"))
-	}
-
-	return cookie, nil
-}
-
-// This structure is returned by ServerSetup. It consists of a list of
-// BindAddrs, an address for the ORPort, an address for the extended ORPort (if
-// any), and an authentication cookie (if any).
-type ServerInfo struct {
-	BindAddrs      []BindAddr
-	OrAddr         *net.TCPAddr
-	ExtendedOrAddr *net.TCPAddr
-	AuthCookie     []byte
-}
-
-// Check the server pluggable transports environments, emitting an error message
-// and exiting the program if any error is encountered. Resolves the various
-// requested bind addresses, the server ORPort and extended ORPort, and reads
-// the auth cookie file. Returns a ServerInfo struct.
-func ServerSetup(methodNames []string) ServerInfo {
-	var info ServerInfo
-	var err error
-
-	ver := getManagedTransportVer()
-	if ver == "" {
-		VersionError("no-version")
-	} else {
-		Line("VERSION", ver)
-	}
-
-	var orPort = getenvRequired("TOR_PT_ORPORT")
-	info.OrAddr, err = net.ResolveTCPAddr("tcp", orPort)
-	if err != nil {
-		EnvError(fmt.Sprintf("cannot resolve TOR_PT_ORPORT %q: %s", orPort, err.Error()))
-	}
-
-	info.BindAddrs = getServerBindAddrs(methodNames)
-	if len(info.BindAddrs) == 0 {
-		SmethodsDone()
-		os.Exit(1)
-	}
-
-	var extendedOrPort = getenv("TOR_PT_EXTENDED_SERVER_PORT")
-	if extendedOrPort != "" {
-		info.ExtendedOrAddr, err = net.ResolveTCPAddr("tcp", extendedOrPort)
-		if err != nil {
-			EnvError(fmt.Sprintf("cannot resolve TOR_PT_EXTENDED_SERVER_PORT %q: %s", extendedOrPort, err.Error()))
-		}
-	}
-
-	var authCookieFilename = getenv("TOR_PT_AUTH_COOKIE_FILE")
-	if authCookieFilename != "" {
-		info.AuthCookie, err = readAuthCookieFile(authCookieFilename)
-		if err != nil {
-			EnvError(fmt.Sprintf("error reading TOR_PT_AUTH_COOKIE_FILE %q: %s", authCookieFilename, err.Error()))
-		}
-	}
-
-	return info
-}
-
-// See 217-ext-orport-auth.txt section 4.2.1.3.
-func computeServerHash(info *ServerInfo, clientNonce, serverNonce []byte) []byte {
-	h := hmac.New(sha256.New, info.AuthCookie)
-	io.WriteString(h, "ExtORPort authentication server-to-client hash")
-	h.Write(clientNonce)
-	h.Write(serverNonce)
-	return h.Sum([]byte{})
-}
-
-// See 217-ext-orport-auth.txt section 4.2.1.3.
-func computeClientHash(info *ServerInfo, clientNonce, serverNonce []byte) []byte {
-	h := hmac.New(sha256.New, info.AuthCookie)
-	io.WriteString(h, "ExtORPort authentication client-to-server hash")
-	h.Write(clientNonce)
-	h.Write(serverNonce)
-	return h.Sum([]byte{})
-}
-
-func extOrPortAuthenticate(s *net.TCPConn, info *ServerInfo) error {
-	r := bufio.NewReader(s)
-
-	// Read auth types. 217-ext-orport-auth.txt section 4.1.
-	var authTypes [256]bool
-	var count int
-	for count = 0; count < 256; count++ {
-		b, err := r.ReadByte()
-		if err != nil {
-			return err
-		}
-		if b == 0 {
-			break
-		}
-		authTypes[b] = true
-	}
-	if count >= 256 {
-		return errors.New(fmt.Sprintf("read 256 auth types without seeing \\x00"))
-	}
-
-	// We support only type 1, SAFE_COOKIE.
-	if !authTypes[1] {
-		return errors.New(fmt.Sprintf("server didn't offer auth type 1"))
-	}
-	_, err := s.Write([]byte{1})
-	if err != nil {
-		return err
-	}
-
-	clientNonce := make([]byte, 32)
-	clientHash := make([]byte, 32)
-	serverNonce := make([]byte, 32)
-	serverHash := make([]byte, 32)
-
-	_, err = io.ReadFull(rand.Reader, clientNonce)
-	if err != nil {
-		return err
-	}
-	_, err = s.Write(clientNonce)
-	if err != nil {
-		return err
-	}
-
-	_, err = io.ReadFull(r, serverHash)
-	if err != nil {
-		return err
-	}
-	_, err = io.ReadFull(r, serverNonce)
-	if err != nil {
-		return err
-	}
-
-	expectedServerHash := computeServerHash(info, clientNonce, serverNonce)
-	if subtle.ConstantTimeCompare(serverHash, expectedServerHash) != 1 {
-		return errors.New(fmt.Sprintf("mismatch in server hash"))
-	}
-
-	clientHash = computeClientHash(info, clientNonce, serverNonce)
-	_, err = s.Write(clientHash)
-	if err != nil {
-		return err
-	}
-
-	status := make([]byte, 1)
-	_, err = io.ReadFull(r, status)
-	if err != nil {
-		return err
-	}
-	if status[0] != 1 {
-		return errors.New(fmt.Sprintf("server rejected authentication"))
-	}
-
-	if r.Buffered() != 0 {
-		return errors.New(fmt.Sprintf("%d bytes left after extended OR port authentication", r.Buffered()))
-	}
-
-	return nil
-}
-
-// See section 3.1 of 196-transport-control-ports.txt.
-const (
-	extOrCmdDone      = 0x0000
-	extOrCmdUserAddr  = 0x0001
-	extOrCmdTransport = 0x0002
-	extOrCmdOkay      = 0x1000
-	extOrCmdDeny      = 0x1001
-)
-
-func extOrPortWriteCommand(s *net.TCPConn, cmd uint16, body []byte) error {
-	var buf bytes.Buffer
-	if len(body) > 65535 {
-		return errors.New("command exceeds maximum length of 65535")
-	}
-	err := binary.Write(&buf, binary.BigEndian, cmd)
-	if err != nil {
-		return err
-	}
-	err = binary.Write(&buf, binary.BigEndian, uint16(len(body)))
-	if err != nil {
-		return err
-	}
-	err = binary.Write(&buf, binary.BigEndian, body)
-	if err != nil {
-		return err
-	}
-	_, err = s.Write(buf.Bytes())
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Send a USERADDR command on s. See section 3.1.2.1 of
-// 196-transport-control-ports.txt.
-func extOrPortSendUserAddr(s *net.TCPConn, conn net.Conn) error {
-	return extOrPortWriteCommand(s, extOrCmdUserAddr, []byte(conn.RemoteAddr().String()))
-}
-
-// Send a TRANSPORT command on s. See section 3.1.2.2 of
-// 196-transport-control-ports.txt.
-func extOrPortSendTransport(s *net.TCPConn, methodName string) error {
-	return extOrPortWriteCommand(s, extOrCmdTransport, []byte(methodName))
-}
-
-// Send a DONE command on s. See section 3.1 of 196-transport-control-ports.txt.
-func extOrPortSendDone(s *net.TCPConn) error {
-	return extOrPortWriteCommand(s, extOrCmdDone, []byte{})
-}
-
-func extOrPortRecvCommand(s *net.TCPConn) (cmd uint16, body []byte, err error) {
-	var bodyLen uint16
-	data := make([]byte, 4)
-
-	_, err = io.ReadFull(s, data)
-	if err != nil {
-		return
-	}
-	buf := bytes.NewBuffer(data)
-	err = binary.Read(buf, binary.BigEndian, &cmd)
-	if err != nil {
-		return
-	}
-	err = binary.Read(buf, binary.BigEndian, &bodyLen)
-	if err != nil {
-		return
-	}
-	body = make([]byte, bodyLen)
-	_, err = io.ReadFull(s, body)
-	if err != nil {
-		return
-	}
-
-	return cmd, body, err
-}
-
-// Send USERADDR and TRANSPORT commands followed by a DONE command. Wait for an
-// OKAY or DENY response command from the server. Returns nil if and only if
-// OKAY is received.
-func extOrPortSetup(s *net.TCPConn, conn net.Conn, methodName string) error {
-	var err error
-
-	err = extOrPortSendUserAddr(s, conn)
-	if err != nil {
-		return err
-	}
-	err = extOrPortSendTransport(s, methodName)
-	if err != nil {
-		return err
-	}
-	err = extOrPortSendDone(s)
-	if err != nil {
-		return err
-	}
-	cmd, _, err := extOrPortRecvCommand(s)
-	if err != nil {
-		return err
-	}
-	if cmd == extOrCmdDeny {
-		return errors.New("server returned DENY after our USERADDR and DONE")
-	} else if cmd != extOrCmdOkay {
-		return errors.New(fmt.Sprintf("server returned unknown command 0x%04x after our USERADDR and DONE", cmd))
-	}
-
-	return nil
-}
-
-// Connect to info.ExtendedOrAddr if defined, or else info.OrAddr, and return an
-// open *net.TCPConn. If connecting to the extended OR port, extended OR port
-// authentication à la 217-ext-orport-auth.txt is done before returning; an
-// error is returned if authentication fails.
-func ConnectOr(info *ServerInfo, conn net.Conn, methodName string) (*net.TCPConn, error) {
-	if info.ExtendedOrAddr == nil {
-		return net.DialTCP("tcp", nil, info.OrAddr)
-	}
-
-	s, err := net.DialTCP("tcp", nil, info.ExtendedOrAddr)
-	if err != nil {
-		return nil, err
-	}
-	s.SetDeadline(time.Now().Add(5 * time.Second))
-	err = extOrPortAuthenticate(s, info)
-	if err != nil {
-		s.Close()
-		return nil, err
-	}
-	err = extOrPortSetup(s, conn, methodName)
-	if err != nil {
-		s.Close()
-		return nil, err
-	}
-	s.SetDeadline(time.Time{})
-
-	return s, nil
-}
diff --git a/pt/pt_test.go b/pt/pt_test.go
deleted file mode 100644
index cc7924a..0000000
--- a/pt/pt_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package pt
-
-import "os"
-import "testing"
-
-func stringIsSafe(s string) bool {
-	for _, c := range []byte(s) {
-		if c == '\x00' || c == '\n' || c > 127 {
-			return false
-		}
-	}
-	return true
-}
-
-func TestEscape(t *testing.T) {
-	tests := [...]string{
-		"",
-		"abc",
-		"a\nb",
-		"a\\b",
-		"ab\\",
-		"ab\\\n",
-		"ab\n\\",
-	}
-
-	check := func(input string) {
-		output := escape(input)
-		if !stringIsSafe(output) {
-			t.Errorf("escape(%q) → %q", input, output)
-		}
-	}
-	for _, input := range tests {
-		check(input)
-	}
-	for b := 0; b < 256; b++ {
-		// check one-byte string with each byte value 0–255
-		check(string([]byte{byte(b)}))
-		// check UTF-8 encoding of each character 0–255
-		check(string(b))
-	}
-}
-
-func TestGetManagedTransportVer(t *testing.T) {
-	tests := [...]struct {
-		input, expected string
-	}{
-		{"1", "1"},
-		{"1,1", "1"},
-		{"1,2", "1"},
-		{"2,1", "1"},
-		{"2", ""},
-	}
-
-	for _, test := range tests {
-		os.Setenv("TOR_PT_MANAGED_TRANSPORT_VER", test.input)
-		output := getManagedTransportVer()
-		if output != test.expected {
-			t.Errorf("%q → %q (expected %q)", test.input, output, test.expected)
-		}
-	}
-}
diff --git a/pt/socks/socks.go b/pt/socks/socks.go
deleted file mode 100644
index 788d53c..0000000
--- a/pt/socks/socks.go
+++ /dev/null
@@ -1,107 +0,0 @@
-// SOCKS4a server library.
-
-package socks
-
-import (
-	"bufio"
-	"errors"
-	"fmt"
-	"io"
-	"net"
-)
-
-const (
-	socksVersion         = 0x04
-	socksCmdConnect      = 0x01
-	socksResponseVersion = 0x00
-	socksRequestGranted  = 0x5a
-	socksRequestFailed   = 0x5b
-)
-
-// 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.
-func AwaitSocks4aConnect(conn *net.TCPConn, connect func(string) (*net.TCPAddr, error)) error {
-	dest, err := readSocks4aConnect(conn)
-	if err != nil {
-		sendSocks4aResponseFailed(conn)
-		return err
-	}
-	destAddr, err := connect(dest)
-	if err != nil {
-		sendSocks4aResponseFailed(conn)
-		return err
-	}
-	sendSocks4aResponseGranted(conn, destAddr)
-	return nil
-}
-
-// Read a SOCKS4a connect request. Returns a "host:port" string.
-func readSocks4aConnect(s io.Reader) (string, error) {
-	r := bufio.NewReader(s)
-
-	var h [8]byte
-	n, err := io.ReadFull(r, h[:])
-	if err != nil {
-		return "", errors.New(fmt.Sprintf("after %d bytes of SOCKS header: %s", n, err))
-	}
-	if h[0] != socksVersion {
-		return "", errors.New(fmt.Sprintf("SOCKS header had version 0x%02x, not 0x%02x", h[0], socksVersion))
-	}
-	if h[1] != socksCmdConnect {
-		return "", errors.New(fmt.Sprintf("SOCKS header had command 0x%02x, not 0x%02x", h[1], socksCmdConnect))
-	}
-
-	_, err = r.ReadBytes('\x00')
-	if err != nil {
-		return "", errors.New(fmt.Sprintf("reading SOCKS userid: %s", err))
-	}
-
-	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 {
-		hostBytes, err := r.ReadBytes('\x00')
-		if err != nil {
-			return "", errors.New(fmt.Sprintf("reading SOCKS4a destination: %s", err))
-		}
-		host = string(hostBytes[:len(hostBytes)-1])
-	} else {
-		host = net.IPv4(h[4], h[5], h[6], h[7]).String()
-	}
-
-	if r.Buffered() != 0 {
-		return "", errors.New(fmt.Sprintf("%d bytes left after SOCKS header", r.Buffered()))
-	}
-
-	return fmt.Sprintf("%s:%d", host, port), nil
-}
-
-// 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 sendSocks4aResponseFailed(w io.Writer) error {
-	return sendSocks4aResponse(w, socksRequestFailed, &emptyAddr)
-}
diff --git a/websocket-client/websocket-client.go b/websocket-client/websocket-client.go
index 7f838bb..547d217 100644
--- a/websocket-client/websocket-client.go
+++ b/websocket-client/websocket-client.go
@@ -18,11 +18,11 @@ import (
 	"time"
 )
 
-import "../pt"
-import "../pt/socks"
+import "git.torproject.org/pluggable-transports/goptlib.git"
+
+var ptInfo pt.ClientInfo
 
 const ptMethodName = "websocket"
-const socksTimeout = 2 * time.Second
 const bufSiz = 1500
 
 var logFile = os.Stderr
@@ -115,7 +115,7 @@ func proxy(local *net.TCPConn, ws *websocket.Conn) {
 	wg.Wait()
 }
 
-func handleConnection(conn *net.TCPConn) error {
+func handleConnection(conn *pt.SocksConn) error {
 	defer conn.Close()
 
 	handlerChan <- 1
@@ -125,34 +125,32 @@ func handleConnection(conn *net.TCPConn) error {
 
 	var ws *websocket.Conn
 
-	conn.SetDeadline(time.Now().Add(socksTimeout))
-	err := socks.AwaitSocks4aConnect(conn, func(dest string) (*net.TCPAddr, error) {
-		// Disable deadline.
-		conn.SetDeadline(time.Time{})
-		Log("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
-		}
-		Log("WebSocket connection to %s", ws.Config().Location.String())
-		return destAddr, nil
-	})
+	Log("SOCKS request for %s", conn.Req.Target)
+	destAddr, err := net.ResolveTCPAddr("tcp", conn.Req.Target)
 	if err != nil {
+		conn.Reject()
 		return err
 	}
+	wsUrl := url.URL{Scheme: "ws", Host: conn.Req.Target}
+	ws, err = websocket.Dial(wsUrl.String(), "", wsUrl.String())
+	if err != nil {
+		err = conn.Reject()
+		return err
+	}
+	Log("WebSocket connection to %s", ws.Config().Location.String())
 	defer ws.Close()
-	proxy(conn, ws)
+	err = conn.Grant(destAddr)
+	if err != nil {
+		return err
+	}
+
+	proxy(conn.Conn.(*net.TCPConn), ws)
 	return nil
 }
 
-func socksAcceptLoop(ln *net.TCPListener) error {
+func socksAcceptLoop(ln *pt.SocksListener) error {
 	for {
-		socks, err := ln.AcceptTCP()
+		socks, err := ln.AcceptSocks()
 		if err != nil {
 			return err
 		}
@@ -166,12 +164,8 @@ func socksAcceptLoop(ln *net.TCPListener) error {
 	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)
+func startListener(addrStr string) (*pt.SocksListener, error) {
+	ln, err := pt.ListenSocks("tcp", addrStr)
 	if err != nil {
 		return nil, err
 	}
@@ -188,6 +182,7 @@ func main() {
 	var logFilename string
 	var socksAddrStrs = []string{"127.0.0.1:0"}
 	var socksArg string
+	var err error
 
 	flag.Usage = usage
 	flag.StringVar(&logFilename, "log", "", "log file to write to")
@@ -208,15 +203,20 @@ func main() {
 	}
 
 	Log("starting")
-	pt.ClientSetup([]string{ptMethodName})
+	ptInfo, err = pt.ClientSetup([]string{ptMethodName})
+	if err != nil {
+		Log("error in setup: %s", err)
+		os.Exit(1)
+	}
 
-	listeners := make([]*net.TCPListener, 0)
+	listeners := make([]net.Listener, 0)
 	for _, socksAddrStr := range socksAddrStrs {
 		ln, err := startListener(socksAddrStr)
 		if err != nil {
 			pt.CmethodError(ptMethodName, err.Error())
+			continue
 		}
-		pt.Cmethod(ptMethodName, "socks4", ln.Addr())
+		pt.Cmethod(ptMethodName, ln.Version(), ln.Addr())
 		Log("listening on %s", ln.Addr().String())
 		listeners = append(listeners, ln)
 	}
diff --git a/websocket-server/websocket-server.go b/websocket-server/websocket-server.go
index e5ed1c5..806dd51 100644
--- a/websocket-server/websocket-server.go
+++ b/websocket-server/websocket-server.go
@@ -20,9 +20,10 @@ import (
 	"time"
 )
 
-import "../pt"
 import "../websocket"
 
+import "git.torproject.org/pluggable-transports/goptlib.git"
+
 const ptMethodName = "websocket"
 const requestTimeout = 10 * time.Second
 
@@ -176,7 +177,7 @@ func webSocketHandler(ws *websocket.WebSocket) {
 		handlerChan <- -1
 	}()
 
-	s, err := pt.ConnectOr(&ptInfo, ws.Conn, ptMethodName)
+	s, err := pt.DialOr(&ptInfo, ws.Conn.RemoteAddr(), ptMethodName)
 	if err != nil {
 		log("Failed to connect to ORPort: " + err.Error())
 		return
@@ -225,23 +226,28 @@ func main() {
 	}
 
 	log("starting")
-	ptInfo = pt.ServerSetup([]string{ptMethodName})
+	var err error
+	ptInfo, err = pt.ServerSetup([]string{ptMethodName})
+	if err != nil {
+		log("error in setup: %s", err)
+		os.Exit(1)
+	}
 
 	listeners := make([]*net.TCPListener, 0)
-	for _, bindAddr := range ptInfo.BindAddrs {
+	for _, bindaddr := range ptInfo.Bindaddrs {
 		// Override tor's requested port (which is 0 if this transport
 		// has not been run before) with the one requested by the --port
 		// option.
 		if port != 0 {
-			bindAddr.Addr.Port = port
+			bindaddr.Addr.Port = port
 		}
 
-		ln, err := startListener(bindAddr.Addr)
+		ln, err := startListener(bindaddr.Addr)
 		if err != nil {
-			pt.SmethodError(bindAddr.MethodName, err.Error())
+			pt.SmethodError(bindaddr.MethodName, err.Error())
 			continue
 		}
-		pt.Smethod(bindAddr.MethodName, ln.Addr())
+		pt.Smethod(bindaddr.MethodName, ln.Addr())
 		log("listening on %s", ln.Addr().String())
 		listeners = append(listeners, ln)
 	}





More information about the tor-commits mailing list