[Pkg-privacy-commits] [golang-goptlib] 12/20: Imported Upstream version 0.4
Ximin Luo
infinity0 at moszumanska.debian.org
Sat Aug 22 10:04:07 UTC 2015
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch master
in repository golang-goptlib.
commit cada8f9564c27145b0e257de44572f241ec86cce
Author: Ximin Luo <infinity0 at pwned.gg>
Date: Mon Mar 30 04:54:31 2015 +0200
Imported Upstream version 0.4
---
README | 8 ++---
args.go | 19 +++++-----
args_test.go | 22 ++++++------
pt.go | 112 +++++++++++++++++++++++++++++++++++------------------------
pt_test.go | 80 ++++++++++++++++++++++++++----------------
socks.go | 7 ++--
6 files changed, 144 insertions(+), 104 deletions(-)
diff --git a/README b/README
index f3ce5b3..c4ca377 100644
--- a/README
+++ b/README
@@ -1,8 +1,8 @@
goptlib is a library for writing Tor pluggable transports in Go.
-https://gitweb.torproject.org/torspec.git/blob/HEAD:/pt-spec.txt
-https://gitweb.torproject.org/torspec.git/blob/HEAD:/proposals/196-transport-control-ports.txt
-https://gitweb.torproject.org/torspec.git/blob/HEAD:/proposals/217-ext-orport-auth.txt
+https://gitweb.torproject.org/torspec.git/tree/pt-spec.txt
+https://gitweb.torproject.org/torspec.git/tree/proposals/196-transport-control-ports.txt
+https://gitweb.torproject.org/torspec.git/tree/proposals/217-ext-orport-auth.txt
To download a copy of the library into $GOPATH:
go get git.torproject.org/pluggable-transports/goptlib.git
@@ -15,7 +15,7 @@ The recommended way to start writing a new transport plugin is to copy
dummy-client or dummy-server and make changes to it.
There is browseable documentation here:
-http://godoc.org/git.torproject.org/pluggable-transports/goptlib.git
+https://godoc.org/git.torproject.org/pluggable-transports/goptlib.git
Report bugs to the tor-dev at lists.torproject.org mailing list or to the
bug tracker at https://trac.torproject.org/projects/tor.
diff --git a/args.go b/args.go
index 5e96589..7672a35 100644
--- a/args.go
+++ b/args.go
@@ -2,7 +2,6 @@ package pt
import (
"bytes"
- "errors"
"fmt"
"sort"
"strings"
@@ -34,7 +33,7 @@ func (args Args) Add(key, value string) {
}
// Return the index of the next unescaped byte in s that is in the term set, or
-// else the length of the string if not terminators appear. Additionally return
+// else the length of the string if no terminators appear. Additionally return
// the unescaped string up to the returned index.
func indexUnescaped(s string, term []byte) (int, string, error) {
var i int
@@ -48,7 +47,7 @@ func indexUnescaped(s string, term []byte) (int, string, error) {
if b == '\\' {
i++
if i >= len(s) {
- return 0, "", errors.New(fmt.Sprintf("nothing following final escape in %q", s))
+ return 0, "", fmt.Errorf("nothing following final escape in %q", s)
}
b = s[i]
}
@@ -82,7 +81,7 @@ func parseClientParameters(s string) (args Args, err error) {
i += offset
// End of string or no equals sign?
if i >= len(s) || s[i] != '=' {
- err = errors.New(fmt.Sprintf("no equals sign in %q", s[begin:i]))
+ err = fmt.Errorf("no equals sign in %q", s[begin:i])
return
}
// Skip the equals sign.
@@ -94,7 +93,7 @@ func parseClientParameters(s string) (args Args, err error) {
}
i += offset
if len(key) == 0 {
- err = errors.New(fmt.Sprintf("empty key in %q", s[begin:i]))
+ err = fmt.Errorf("empty key in %q", s[begin:i])
return
}
args.Add(key, value)
@@ -132,7 +131,7 @@ func parseServerTransportOptions(s string) (opts map[string]Args, err error) {
i += offset
// End of string or no colon?
if i >= len(s) || s[i] != ':' {
- err = errors.New(fmt.Sprintf("no colon in %q", s[begin:i]))
+ err = fmt.Errorf("no colon in %q", s[begin:i])
return
}
// Skip the colon.
@@ -145,7 +144,7 @@ func parseServerTransportOptions(s string) (opts map[string]Args, err error) {
i += offset
// End of string or no equals sign?
if i >= len(s) || s[i] != '=' {
- err = errors.New(fmt.Sprintf("no equals sign in %q", s[begin:i]))
+ err = fmt.Errorf("no equals sign in %q", s[begin:i])
return
}
// Skip the equals sign.
@@ -157,11 +156,11 @@ func parseServerTransportOptions(s string) (opts map[string]Args, err error) {
}
i += offset
if len(methodName) == 0 {
- err = errors.New(fmt.Sprintf("empty method name in %q", s[begin:i]))
+ err = fmt.Errorf("empty method name in %q", s[begin:i])
return
}
if len(key) == 0 {
- err = errors.New(fmt.Sprintf("empty key in %q", s[begin:i]))
+ err = fmt.Errorf("empty key in %q", s[begin:i])
return
}
if opts[methodName] == nil {
@@ -200,7 +199,7 @@ func encodeSmethodArgs(args Args) string {
}
keys := make([]string, 0, len(args))
- for key, _ := range args {
+ for key := range args {
keys = append(keys, key)
}
sort.Strings(keys)
diff --git a/args_test.go b/args_test.go
index 8a77251..134ac31 100644
--- a/args_test.go
+++ b/args_test.go
@@ -255,29 +255,29 @@ func TestParseServerTransportOptions(t *testing.T) {
{
"t:k=v",
map[string]Args{
- "t": Args{"k": []string{"v"}},
+ "t": {"k": []string{"v"}},
},
},
{
"t1:k=v1;t2:k=v2;t1:k=v3",
map[string]Args{
- "t1": Args{"k": []string{"v1", "v3"}},
- "t2": Args{"k": []string{"v2"}},
+ "t1": {"k": []string{"v1", "v3"}},
+ "t2": {"k": []string{"v2"}},
},
},
{
"t\\:1:k=v;t\\=2:k=v;t\\;3:k=v;t\\\\4:k=v",
map[string]Args{
- "t:1": Args{"k": []string{"v"}},
- "t=2": Args{"k": []string{"v"}},
- "t;3": Args{"k": []string{"v"}},
- "t\\4": Args{"k": []string{"v"}},
+ "t:1": {"k": []string{"v"}},
+ "t=2": {"k": []string{"v"}},
+ "t;3": {"k": []string{"v"}},
+ "t\\4": {"k": []string{"v"}},
},
},
{
"t:k\\:1=v;t:k\\=2=v;t:k\\;3=v;t:k\\\\4=v",
map[string]Args{
- "t": Args{
+ "t": {
"k:1": []string{"v"},
"k=2": []string{"v"},
"k;3": []string{"v"},
@@ -288,14 +288,14 @@ func TestParseServerTransportOptions(t *testing.T) {
{
"t:k=v\\:1;t:k=v\\=2;t:k=v\\;3;t:k=v\\\\4",
map[string]Args{
- "t": Args{"k": []string{"v:1", "v=2", "v;3", "v\\4"}},
+ "t": {"k": []string{"v:1", "v=2", "v;3", "v\\4"}},
},
},
{
"trebuchet:secret=nou;trebuchet:cache=/tmp/cache;ballista:secret=yes",
map[string]Args{
- "trebuchet": Args{"secret": []string{"nou"}, "cache": []string{"/tmp/cache"}},
- "ballista": Args{"secret": []string{"yes"}},
+ "trebuchet": {"secret": []string{"nou"}, "cache": []string{"/tmp/cache"}},
+ "ballista": {"secret": []string{"yes"}},
},
},
}
diff --git a/pt.go b/pt.go
index 8630cae..d2e7dc1 100644
--- a/pt.go
+++ b/pt.go
@@ -111,13 +111,13 @@
// the example programs dummy-client and dummy-server.
//
// Tor pluggable transports specification:
-// https://gitweb.torproject.org/torspec.git/blob/HEAD:/pt-spec.txt.
+// https://gitweb.torproject.org/torspec.git/tree/pt-spec.txt.
//
// Extended ORPort:
-// https://gitweb.torproject.org/torspec.git/blob/HEAD:/proposals/196-transport-control-ports.txt.
+// https://gitweb.torproject.org/torspec.git/tree/proposals/196-transport-control-ports.txt.
//
// Extended ORPort Authentication:
-// https://gitweb.torproject.org/torspec.git/blob/HEAD:/proposals/217-ext-orport-auth.txt.
+// https://gitweb.torproject.org/torspec.git/tree/proposals/217-ext-orport-auth.txt.
//
// The package implements a SOCKS4a server sufficient for a Tor client transport
// plugin.
@@ -132,7 +132,6 @@ import (
"crypto/sha256"
"crypto/subtle"
"encoding/binary"
- "errors"
"fmt"
"io"
"net"
@@ -202,35 +201,57 @@ func getenvRequired(key string) (string, error) {
return value, nil
}
-// 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)
+// Returns true iff keyword contains only bytes allowed in a PT→Tor output line
+// keyword.
+// <KeywordChar> ::= <any US-ASCII alphanumeric, dash, and underscore>
+func keywordIsSafe(keyword string) bool {
+ for _, b := range []byte(keyword) {
+ if b >= '0' && b <= '9' {
+ continue
+ }
+ if b >= 'A' && b <= 'Z' {
+ continue
+ }
+ if b >= 'a' && b <= 'z' {
+ continue
}
+ if b == '-' || b == '_' {
+ continue
+ }
+ return false
}
- return buf.String()
+ return true
+}
+
+// Returns true iff arg contains only bytes allowed in a PT→Tor output line arg.
+// <ArgChar> ::= <any US-ASCII character but NUL or NL>
+func argIsSafe(arg string) bool {
+ for _, b := range []byte(arg) {
+ if b >= '\x80' || b == '\x00' || b == '\n' {
+ return false
+ }
+ }
+ return true
}
func formatline(keyword string, v ...string) string {
var buf bytes.Buffer
+ if !keywordIsSafe(keyword) {
+ panic(fmt.Sprintf("keyword %q contains forbidden bytes", keyword))
+ }
buf.WriteString(keyword)
for _, x := range v {
- buf.WriteString(" " + escape(x))
+ if !argIsSafe(x) {
+ panic(fmt.Sprintf("arg %q contains forbidden bytes", x))
+ }
+ buf.WriteString(" " + x)
}
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.
+// Print a pluggable transports protocol line to Stdout. The line consists of a
+// keyword followed by any number of space-separated arg strings. Panics if
+// there are forbidden bytes in the keyword or the args (pt-spec.txt 2.2.1).
func line(keyword string, v ...string) {
fmt.Fprintln(Stdout, formatline(keyword, v...))
}
@@ -352,7 +373,7 @@ func getClientTransports(star []string) ([]string, error) {
// This structure is returned by ClientSetup. It consists of a list of method
// names.
type ClientInfo struct {
- MethodNames []string
+ MethodNames []string
}
// Check the client pluggable transports environment, emitting an error message
@@ -513,14 +534,14 @@ func readAuthCookie(f io.Reader) ([]byte, error) {
// Check that the file ends here.
n, err = f.Read(make([]byte, 1))
if n != 0 {
- return nil, errors.New(fmt.Sprintf("file is longer than 64 bytes"))
+ return nil, fmt.Errorf("file is longer than 64 bytes")
} else if err != io.EOF {
- return nil, errors.New(fmt.Sprintf("did not find EOF at end of file"))
+ return nil, fmt.Errorf("did not find EOF at end of file")
}
header := buf[0:32]
cookie := buf[32:64]
if subtle.ConstantTimeCompare(header, authCookieHeader) != 1 {
- return nil, errors.New(fmt.Sprintf("missing auth cookie header"))
+ return nil, fmt.Errorf("missing auth cookie header")
}
return cookie, nil
@@ -545,7 +566,7 @@ type ServerInfo struct {
Bindaddrs []Bindaddr
OrAddr *net.TCPAddr
ExtendedOrAddr *net.TCPAddr
- AuthCookie []byte
+ AuthCookiePath string
}
// Check the server pluggable transports environment, emitting an error message
@@ -591,17 +612,10 @@ func ServerSetup(star []string) (info ServerInfo, err error) {
return
}
}
- authCookieFilename := getenv("TOR_PT_AUTH_COOKIE_FILE")
- if authCookieFilename != "" {
- info.AuthCookie, err = readAuthCookieFile(authCookieFilename)
- if err != nil {
- err = envError(fmt.Sprintf("error reading TOR_PT_AUTH_COOKIE_FILE %q: %s", authCookieFilename, err.Error()))
- return
- }
- }
+ info.AuthCookiePath = getenv("TOR_PT_AUTH_COOKIE_FILE")
// Need either OrAddr or ExtendedOrAddr.
- if info.OrAddr == nil && (info.ExtendedOrAddr == nil || info.AuthCookie == nil) {
+ if info.OrAddr == nil && (info.ExtendedOrAddr == nil || info.AuthCookiePath == "") {
err = envError("need TOR_PT_ORPORT or TOR_PT_EXTENDED_SERVER_PORT environment variable")
return
}
@@ -644,12 +658,12 @@ func extOrPortAuthenticate(s io.ReadWriter, info *ServerInfo) error {
authTypes[b] = true
}
if count >= 256 {
- return errors.New(fmt.Sprintf("read 256 auth types without seeing \\x00"))
+ return fmt.Errorf("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"))
+ return fmt.Errorf("server didn't offer auth type 1")
}
_, err := s.Write([]byte{1})
if err != nil {
@@ -679,12 +693,20 @@ func extOrPortAuthenticate(s io.ReadWriter, info *ServerInfo) error {
return err
}
- expectedServerHash := computeServerHash(info.AuthCookie, clientNonce, serverNonce)
+ // Work around tor bug #15240 where the auth cookie is generated after
+ // pluggable transports are launched, leading to a stale cookie getting
+ // cached forever if it is only read once as part of ServerSetup.
+ authCookie, err := readAuthCookieFile(info.AuthCookiePath)
+ if err != nil {
+ return fmt.Errorf("error reading TOR_PT_AUTH_COOKIE_FILE %q: %s", info.AuthCookiePath, err.Error())
+ }
+
+ expectedServerHash := computeServerHash(authCookie, clientNonce, serverNonce)
if subtle.ConstantTimeCompare(serverHash, expectedServerHash) != 1 {
- return errors.New(fmt.Sprintf("mismatch in server hash"))
+ return fmt.Errorf("mismatch in server hash")
}
- clientHash = computeClientHash(info.AuthCookie, clientNonce, serverNonce)
+ clientHash = computeClientHash(authCookie, clientNonce, serverNonce)
_, err = s.Write(clientHash)
if err != nil {
return err
@@ -696,7 +718,7 @@ func extOrPortAuthenticate(s io.ReadWriter, info *ServerInfo) error {
return err
}
if status[0] != 1 {
- return errors.New(fmt.Sprintf("server rejected authentication"))
+ return fmt.Errorf("server rejected authentication")
}
return nil
@@ -714,7 +736,7 @@ const (
func extOrPortSendCommand(s io.Writer, cmd uint16, body []byte) error {
var buf bytes.Buffer
if len(body) > 65535 {
- return errors.New(fmt.Sprintf("body length %d exceeds maximum of 65535", len(body)))
+ return fmt.Errorf("body length %d exceeds maximum of 65535", len(body))
}
err := binary.Write(&buf, binary.BigEndian, cmd)
if err != nil {
@@ -807,9 +829,9 @@ func extOrPortSetup(s io.ReadWriter, addr, methodName string) error {
return err
}
if cmd == extOrCmdDeny {
- return errors.New("server returned DENY after our USERADDR and DONE")
+ return fmt.Errorf("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 fmt.Errorf("server returned unknown command 0x%04x after our USERADDR and DONE", cmd)
}
return nil
@@ -824,7 +846,7 @@ func extOrPortSetup(s io.ReadWriter, addr, methodName string) error {
// commands, respectively. If either is "", the corresponding command is not
// sent.
func DialOr(info *ServerInfo, addr, methodName string) (*net.TCPConn, error) {
- if info.ExtendedOrAddr == nil || info.AuthCookie == nil {
+ if info.ExtendedOrAddr == nil || info.AuthCookiePath == "" {
return net.DialTCP("tcp", nil, info.OrAddr)
}
diff --git a/pt_test.go b/pt_test.go
index d6a53e1..8cdf6da 100644
--- a/pt_test.go
+++ b/pt_test.go
@@ -13,40 +13,60 @@ import (
"testing"
)
-func stringIsSafe(s string) bool {
- for _, c := range []byte(s) {
- if c == '\x00' || c == '\n' || c > 127 {
- return false
+func TestKeywordIsSafe(t *testing.T) {
+ tests := [...]struct {
+ keyword string
+ expected bool
+ }{
+ {"", true},
+ {"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_", true},
+ {"CMETHOD", true},
+ {"CMETHOD:", false},
+ {"a b c", false},
+ {"CMETHOD\x7f", false},
+ {"CMETHOD\x80", false},
+ {"CMETHOD\x81", false},
+ {"CMETHOD\xff", false},
+ {"CMÉTHOD", false},
+ }
+
+ for _, input := range tests {
+ isSafe := keywordIsSafe(input.keyword)
+ if isSafe != input.expected {
+ t.Errorf("keywordIsSafe(%q) → %v (expected %v)",
+ input.keyword, isSafe, input.expected)
}
}
- return true
}
-func TestEscape(t *testing.T) {
- tests := [...]string{
- "",
- "abc",
- "a\nb",
- "a\\b",
- "ab\\",
- "ab\\\n",
- "ab\n\\",
+func TestArgIsSafe(t *testing.T) {
+ tests := [...]struct {
+ arg string
+ expected bool
+ }{
+ {"", true},
+ {"abc", true},
+ {"127.0.0.1:8000", true},
+ {"étude", false},
+ {"a\nb", false},
+ {"a\\b", true},
+ {"ab\\", true},
+ {"ab\\\n", false},
+ {"ab\n\\", false},
+ {"abc\x7f", true},
+ {"abc\x80", false},
+ {"abc\x81", false},
+ {"abc\xff", false},
+ {"abc\xff", false},
+ {"var=GVsbG8\\=", true},
}
- 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))
+ isSafe := argIsSafe(input.arg)
+ if isSafe != input.expected {
+ t.Errorf("argIsSafe(%q) → %v (expected %v)",
+ input.arg, isSafe, input.expected)
+ }
}
}
@@ -755,7 +775,7 @@ func TestMakeStateDir(t *testing.T) {
}
defer os.RemoveAll(tempDir)
- goodTests := [...]string {
+ goodTests := [...]string{
// Already existing directory.
tempDir,
@@ -786,13 +806,13 @@ func TestMakeStateDir(t *testing.T) {
os.Setenv("TOR_PT_STATE_LOCATION", tempFile)
_, err = MakeStateDir()
if err == nil {
- t.Errorf("MakeStateDir with a file unexpectedly succeded")
+ t.Errorf("MakeStateDir with a file unexpectedly succeeded")
}
// Directory name that cannot be created. (Subdir of a file)
os.Setenv("TOR_PT_STATE_LOCATION", path.Join(tempFile, "subDir"))
_, err = MakeStateDir()
if err == nil {
- t.Errorf("MakeStateDir with a subdirectory of a file unexpectedly succeded")
+ t.Errorf("MakeStateDir with a subdirectory of a file unexpectedly succeeded")
}
}
diff --git a/socks.go b/socks.go
index f34f78f..6ad6542 100644
--- a/socks.go
+++ b/socks.go
@@ -2,7 +2,6 @@ package pt
import (
"bufio"
- "errors"
"fmt"
"io"
"net"
@@ -166,11 +165,11 @@ func readSocks4aConnect(s io.Reader) (req SocksRequest, err error) {
return
}
if h[0] != socksVersion {
- err = errors.New(fmt.Sprintf("SOCKS header had version 0x%02x, not 0x%02x", h[0], socksVersion))
+ err = fmt.Errorf("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))
+ err = fmt.Errorf("SOCKS header had command 0x%02x, not 0x%02x", h[1], socksCmdConnect)
return
}
@@ -202,7 +201,7 @@ func readSocks4aConnect(s io.Reader) (req SocksRequest, err error) {
}
if r.Buffered() != 0 {
- err = errors.New(fmt.Sprintf("%d bytes left after SOCKS header", r.Buffered()))
+ err = fmt.Errorf("%d bytes left after SOCKS header", r.Buffered())
return
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/golang-goptlib.git
More information about the Pkg-privacy-commits
mailing list