[tor-commits] [flashproxy/master] Do USERADDR and DONE commands.

dcf at torproject.org dcf at torproject.org
Sun Feb 3 03:40:13 UTC 2013


commit 866e8d58b32eb4472d05905db7a0d4ac0c193e80
Author: David Fifield <david at bamsoftware.com>
Date:   Wed Jan 30 13:46:41 2013 -0800

    Do USERADDR and DONE commands.
---
 websocket-transport/pt.go |  103 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 103 insertions(+), 0 deletions(-)

diff --git a/websocket-transport/pt.go b/websocket-transport/pt.go
index 2b4a759..f39e177 100644
--- a/websocket-transport/pt.go
+++ b/websocket-transport/pt.go
@@ -31,6 +31,7 @@ import (
 	"crypto/rand"
 	"crypto/sha256"
 	"crypto/subtle"
+	"encoding/binary"
 	"errors"
 	"fmt"
 	"io"
@@ -455,6 +456,103 @@ func extOrPortAuthenticate(s *net.TCPConn, info *PtServerInfo) error {
 	return nil
 }
 
+// See section 3.1 of 196-transport-control-ports.txt.
+const (
+	extOrCmdDone     = 0x0000
+	extOrCmdUserAddr = 0x0001
+	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 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 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 a USERADDR command 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 extOrPortDoUserAddr(s *net.TCPConn, conn net.Conn) error {
+	var err error
+
+	err = extOrPortSendUserAddr(s, conn)
+	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
@@ -474,6 +572,11 @@ func PtConnectOr(info *PtServerInfo, conn net.Conn) (*net.TCPConn, error) {
 		s.Close()
 		return nil, err
 	}
+	err = extOrPortDoUserAddr(s, conn)
+	if err != nil {
+		s.Close()
+		return nil, err
+	}
 	s.SetDeadline(time.Time{})
 
 	return s, nil





More information about the tor-commits mailing list