[Pkg-privacy-commits] [Git][pkg-privacy-team/golang-goptlib][master] 7 commits: New upstream version 1.2.0

Antoine Beaupré (@anarcat) anarcat at debian.org
Thu May 26 19:36:11 BST 2022



Antoine Beaupré pushed to branch master at Privacy Maintainers / golang-goptlib


Commits:
29f0b456 by Antoine Beaupré at 2022-05-26T14:14:05-04:00
New upstream version 1.2.0
- - - - -
ddb3fede by Antoine Beaupré at 2022-05-26T14:14:06-04:00
Update upstream source from tag 'upstream/1.2.0'

Update to upstream version '1.2.0'
with Debian dir 3a06647332d503d54ed6fdbe6eeca7595eb34a42
- - - - -
b02d63fb by meskio at 2022-05-26T14:14:28-04:00
Update to 1.2.0 upstream release

- - - - -
7f4a3a18 by Antoine Beaupré at 2022-05-26T14:19:58-04:00
fix test failure because of a missing test artifact

- - - - -
553d0028 by Antoine Beaupré at 2022-05-26T14:26:22-04:00
remove lintian override

This was triggering a lintian *error*:

E: golang-goptlib-dev: malformed-override Unknown tag no-upstream-changelog in line 2

... so it doesn't quite seem worth it.

- - - - -
8a590a48 by Antoine Beaupré at 2022-05-26T14:26:48-04:00
follow salsa move

This fixes those lintian warnings:

W: golang-goptlib source: vcs-obsolete-in-debian-infrastructure Browser https://anonscm.debian.org/cgit/pkg-privacy/packages/golang-goptlib.git
W: golang-goptlib source: vcs-obsolete-in-debian-infrastructure Git https://anonscm.debian.org/git/pkg-privacy/packages/golang-goptlib.git

- - - - -
1a409203 by Antoine Beaupré at 2022-05-26T14:28:00-04:00
update changelog with latest

- - - - -


15 changed files:

- + ChangeLog
- args.go
- args_test.go
- debian/changelog
- debian/compat
- debian/control
- − debian/golang-goptlib-dev.lintian-overrides
- debian/rules
- examples/dummy-client/dummy-client.go
- examples/dummy-server/dummy-server.go
- + go.mod
- pt.go
- pt_test.go
- socks_test.go
- + test_authcookie


Changes:

=====================================
ChangeLog
=====================================
@@ -0,0 +1,75 @@
+== v1.2.0
+
+The default and development branch is now "main" rather than "master".
+The master branch will no longer be updated.
+https://lists.torproject.org/pipermail/anti-censorship-team/2021-May/000168.html
+If you have an existing clone of the master branch, run these commands
+to update it:
+	git fetch origin
+	git remote set-head origin -a
+	git branch --move master main
+	git branch --set-upstream-to=origin/main main
+
+Added a go.mod file.
+https://bugs.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/40065
+
+== v1.1.0
+
+Added the Log function.
+https://bugs.torproject.org/28940
+
+== v1.0.0
+
+Changed the tag naming scheme to work better with Go modules.
+https://github.com/golang/go/wiki/Modules#semantic-import-versioning
+
+== 0.7
+
+Fixed the ProxyError function; previously it would always panic.
+
+Repeated transport names in TOR_PT_SERVER_BINDADDR now result in an
+ENV-ERROR.
+https://bugs.torproject.org/21261
+
+== 0.6
+
+Remove all support for the "*" transport specification. The argument to
+the ClientSetup and ServerSetup functions is now unused.
+https://bugs.torproject.org/15612
+
+Replaced SOCKS4a with SOCKS5.
+https://bugs.torproject.org/12535
+
+== 0.5
+
+The AcceptSocks function no longer reports non-permanent errors, such as
+those caused by a faulty SOCKS handshake.
+
+Added support for an upstream proxy (TOR_PT_PROXY). The two new
+functions are ProxyError and ProxyDone. The ClientInfo struct has a new
+ProxyURL member.
+https://bugs.torproject.org/12125
+
+== 0.4
+
+Read the ExtORPort cookie file on every call to DialOr, instead of
+reading it once and caching the result. This is to work around a tor bug
+where tor doesn't ensure a new cookie file is written before starting
+pluggable transports.
+https://bugs.torproject.org/15240
+
+== 0.3
+
+Made output functions panic intead of backslash-escaping. Escaping of
+invalid bytes is not specified by pt-spec, and backslashes conflicted
+with the specified escaping of SMETHOD ARGS.
+https://bugs.torproject.org/13370
+
+== 0.2
+
+Added the MakeStateDir function.
+
+== 0.1
+== 0.0
+
+Initial release.


=====================================
args.go
=====================================
@@ -58,10 +58,9 @@ func indexUnescaped(s string, term []byte) (int, string, error) {
 
 // Parse a name–value mapping as from an encoded SOCKS username/password.
 //
-// "If any [k=v] items are provided, they are configuration parameters for the
-// proxy: Tor should separate them with semicolons ... If a key or value value
-// must contain [an equals sign or] a semicolon or a backslash, it is escaped
-// with a backslash."
+// "First the '<Key>=<Value>' formatted arguments MUST be escaped, such that all
+// backslash, equal sign, and semicolon characters are escaped with a
+// backslash."
 func parseClientParameters(s string) (args Args, err error) {
 	args = make(Args)
 	if len(s) == 0 {
@@ -108,10 +107,11 @@ func parseClientParameters(s string) (args Args, err error) {
 
 // Parse a transport–name–value mapping as from TOR_PT_SERVER_TRANSPORT_OPTIONS.
 //
-// "<value> is a k=v string value with options that are to be passed to the
-// transport. Colons, semicolons, equal signs and backslashes must be escaped
-// with a backslash."
-// Example: trebuchet:secret=nou;trebuchet:cache=/tmp/cache;ballista:secret=yes
+// "...a semicolon-separated list of <key>:<value> pairs, where <key> is a PT
+// name and <value> is a k=v string value with options that are to be passed to
+// the transport. Colons, semicolons, equal signs and backslashes must be
+// escaped with a backslash."
+// Example: scramblesuit:key=banana;automata:rule=110;automata:depth=3
 func parseServerTransportOptions(s string) (opts map[string]Args, err error) {
 	opts = make(map[string]Args)
 	if len(s) == 0 {
@@ -192,7 +192,7 @@ func backslashEscape(s string, set []byte) string {
 // of an SMETHOD line. The output is sorted by key. The "ARGS:" prefix is not
 // added.
 //
-// "Equal signs and commas [and backslashes] must be escaped with a backslash."
+// "Equal signs and commas [and backslashes] MUST be escaped with a backslash."
 func encodeSmethodArgs(args Args) string {
 	if args == nil {
 		return ""


=====================================
args_test.go
=====================================
@@ -138,6 +138,10 @@ func TestParseClientParameters(t *testing.T) {
 			"a=b=c",
 			Args{"a": []string{"b=c"}},
 		},
+		{
+			"a=bc==",
+			Args{"a": []string{"bc=="}},
+		},
 		{
 			"key=a\nb",
 			Args{"key": []string{"a\nb"}},
@@ -258,6 +262,18 @@ func TestParseServerTransportOptions(t *testing.T) {
 				"t": {"k": []string{"v"}},
 			},
 		},
+		{
+			"t:k=v=v",
+			map[string]Args{
+				"t": {"k": []string{"v=v"}},
+			},
+		},
+		{
+			"t:k=vv==",
+			map[string]Args{
+				"t": {"k": []string{"vv=="}},
+			},
+		},
 		{
 			"t1:k=v1;t2:k=v2;t1:k=v3",
 			map[string]Args{


=====================================
debian/changelog
=====================================
@@ -1,3 +1,19 @@
+golang-goptlib (1.2.0-1) unstable; urgency=medium
+
+  [ Antoine Beaupré ]
+  * Team upload
+  * fix tests with newer release
+  * fix Vcs-* URLs
+  * remove lintian override (`no-upstream-changelog`) that was
+    triggering... a lintian error!
+
+  [ Ruben Pollan ]
+  * New upstream release.
+  * Update to debhelper 13, newer policy, no change.
+  * Update to latest Standards-Version.
+
+ -- Antoine Beaupré <anarcat at debian.org>  Thu, 26 May 2022 14:27:13 -0400
+
 golang-goptlib (0.6-3) unstable; urgency=medium
 
   * Team upload.


=====================================
debian/compat
=====================================
@@ -1 +1 @@
-9
+13


=====================================
debian/control
=====================================
@@ -3,12 +3,10 @@ Section: devel
 Priority: optional
 Maintainer: Debian Privacy Tools Maintainers <pkg-privacy-maintainers at lists.alioth.debian.org>
 Uploaders: Ximin Luo <infinity0 at debian.org>
-Build-Depends: debhelper (>= 9.0.0), dh-golang, golang-go
-Standards-Version: 4.1.3
-Vcs-Git: https://anonscm.debian.org/git/pkg-privacy/packages/golang-goptlib.git
-Vcs-Browser: https://anonscm.debian.org/cgit/pkg-privacy/packages/golang-goptlib.git
-#Secondary mirror here:
-#Vcs-Browser: https://gitweb.torproject.org/debian/goptlib.git
+Build-Depends: debhelper (>= 13.0.0), dh-golang, golang-go
+Standards-Version: 4.6.1
+Vcs-Git: https://salsa.debian.org/pkg-privacy-team/golang-goptlib.git
+Vcs-Browser: https://salsa.debian.org/pkg-privacy-team/golang-goptlib/
 XS-Go-Import-Path: git.torproject.org/pluggable-transports/goptlib.git
 
 Package: golang-goptlib-dev


=====================================
debian/golang-goptlib-dev.lintian-overrides deleted
=====================================
@@ -1,2 +0,0 @@
-# these don't exist yet.
-no-upstream-changelog


=====================================
debian/rules
=====================================
@@ -17,3 +17,7 @@ BUILDDIR = obj-$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
 override_dh_auto_install:
 	cd "$(BUILDDIR)" && rm -rf bin/ src/git.torproject.org/pluggable-transports/goptlib.git/examples
 	dh_auto_install
+
+override_dh_auto_test:
+	cp test_authcookie "$(BUILDDIR)"/src/git.torproject.org/pluggable-transports/goptlib.git
+	dh_auto_test


=====================================
examples/dummy-client/dummy-client.go
=====================================
@@ -12,6 +12,7 @@ package main
 
 import (
 	"io"
+	"io/ioutil"
 	"net"
 	"os"
 	"os/signal"
@@ -23,10 +24,6 @@ import "git.torproject.org/pluggable-transports/goptlib.git"
 
 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)
@@ -44,11 +41,6 @@ func copyLoop(a, b net.Conn) {
 }
 
 func handler(conn *pt.SocksConn) error {
-	handlerChan <- 1
-	defer func() {
-		handlerChan <- -1
-	}()
-
 	defer conn.Close()
 	remote, err := net.Dial("tcp", conn.Req.Target)
 	if err != nil {
@@ -111,35 +103,23 @@ func main() {
 	}
 	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()
+	signal.Notify(sigChan, syscall.SIGTERM)
+
+	if os.Getenv("TOR_PT_EXIT_ON_STDIN_CLOSE") == "1" {
+		// This environment variable means we should treat EOF on stdin
+		// just like SIGTERM: https://bugs.torproject.org/15435.
+		go func() {
+			io.Copy(ioutil.Discard, os.Stdin)
+			sigChan <- syscall.SIGTERM
+		}()
 	}
 
-	if sig == syscall.SIGTERM {
-		return
-	}
+	// wait for a signal
+	<-sigChan
 
-	// wait for second signal or no more handlers
-	sig = nil
-	for sig == nil && numHandlers != 0 {
-		select {
-		case n := <-handlerChan:
-			numHandlers += n
-		case sig = <-sigChan:
-		}
+	// signal received, shut down
+	for _, ln := range listeners {
+		ln.Close()
 	}
 }


=====================================
examples/dummy-server/dummy-server.go
=====================================
@@ -13,6 +13,7 @@ package main
 
 import (
 	"io"
+	"io/ioutil"
 	"net"
 	"os"
 	"os/signal"
@@ -24,10 +25,6 @@ import "git.torproject.org/pluggable-transports/goptlib.git"
 
 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)
@@ -47,11 +44,6 @@ func copyLoop(a, b net.Conn) {
 func handler(conn net.Conn) error {
 	defer conn.Close()
 
-	handlerChan <- 1
-	defer func() {
-		handlerChan <- -1
-	}()
-
 	or, err := pt.DialOr(&ptInfo, conn.RemoteAddr().String(), "dummy")
 	if err != nil {
 		return err
@@ -103,35 +95,23 @@ func main() {
 	}
 	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()
+	signal.Notify(sigChan, syscall.SIGTERM)
+
+	if os.Getenv("TOR_PT_EXIT_ON_STDIN_CLOSE") == "1" {
+		// This environment variable means we should treat EOF on stdin
+		// just like SIGTERM: https://bugs.torproject.org/15435.
+		go func() {
+			io.Copy(ioutil.Discard, os.Stdin)
+			sigChan <- syscall.SIGTERM
+		}()
 	}
 
-	if sig == syscall.SIGTERM {
-		return
-	}
+	// wait for a signal
+	<-sigChan
 
-	// wait for second signal or no more handlers
-	sig = nil
-	for sig == nil && numHandlers != 0 {
-		select {
-		case n := <-handlerChan:
-			numHandlers += n
-		case sig = <-sigChan:
-		}
+	// signal received, shut down
+	for _, ln := range listeners {
+		ln.Close()
 	}
 }


=====================================
go.mod
=====================================
@@ -0,0 +1,3 @@
+module git.torproject.org/pluggable-transports/goptlib.git
+
+go 1.11


=====================================
pt.go
=====================================
@@ -24,6 +24,7 @@
 // 			conn, err := ln.AcceptSocks()
 // 			if err != nil {
 // 				if e, ok := err.(net.Error); ok && e.Temporary() {
+// 					pt.Log(pt.LogSeverityError, "accept error: " + err.Error())
 // 					continue
 // 				}
 // 				return err
@@ -42,7 +43,7 @@
 // 		if ptInfo.ProxyURL != nil {
 // 			// you need to interpret the proxy URL yourself
 // 			// call pt.ProxyDone instead if it's a type you understand
-// 			pt.ProxyError("proxy %s is not supported")
+// 			pt.ProxyError(fmt.Sprintf("proxy %s is not supported", ptInfo.ProxyURL))
 // 			os.Exit(1)
 // 		}
 // 		for _, methodName := range ptInfo.MethodNames {
@@ -83,6 +84,7 @@
 // 				if e, ok := err.(net.Error); ok && e.Temporary() {
 // 					continue
 // 				}
+// 				pt.Log(pt.LogSeverityError, "accept error: " + err.Error())
 // 				return err
 // 			}
 // 			go handler(conn)
@@ -113,17 +115,17 @@
 // 		pt.SmethodsDone()
 // 	}
 //
-// Some additional care is needed to handle SIGINT and shutdown properly. See
+// Some additional care is needed to handle signals and shutdown properly. See
 // the example programs dummy-client and dummy-server.
 //
 // Tor pluggable transports specification:
 // https://spec.torproject.org/pt-spec
 //
 // Extended ORPort:
-// https://gitweb.torproject.org/torspec.git/tree/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/tree/proposals/217-ext-orport-auth.txt.
+// https://gitweb.torproject.org/torspec.git/tree/proposals/217-ext-orport-auth.txt
 //
 // Pluggable Transport through SOCKS proxy:
 // https://gitweb.torproject.org/torspec.git/tree/proposals/232-pluggable-transports-through-proxy.txt
@@ -217,19 +219,18 @@ func getenvRequired(key string) (string, error) {
 // <KeywordChar> ::= <any US-ASCII alphanumeric, dash, and underscore>
 func keywordIsSafe(keyword string) bool {
 	for _, b := range []byte(keyword) {
-		if b >= '0' && b <= '9' {
+		switch {
+		case '0' <= b && b <= '9':
 			continue
-		}
-		if b >= 'A' && b <= 'Z' {
+		case 'A' <= b && b <= 'Z':
 			continue
-		}
-		if b >= 'a' && b <= 'z' {
+		case 'a' <= b && b <= 'z':
 			continue
-		}
-		if b == '-' || b == '_' {
+		case b == '-' || b == '_':
 			continue
+		default:
+			return false
 		}
-		return false
 	}
 	return true
 }
@@ -300,7 +301,7 @@ func SmethodError(methodName, msg string) error {
 // Emit a PROXY-ERROR line with explanation text. Returns a representation of
 // the error.
 func ProxyError(msg string) error {
-	return doError("PROXY-ERROR %s\n", msg)
+	return doError("PROXY-ERROR", msg)
 }
 
 // Emit a CMETHOD line. socks must be "socks4" or "socks5". Call this once for
@@ -348,6 +349,69 @@ func ProxyDone() {
 	fmt.Fprintf(Stdout, "PROXY DONE\n")
 }
 
+// Unexported type to represent log severities, preventing external callers from
+// inventing new severity strings that may violate quoting rules.
+//
+// pt-spec.txt section 3.3.4 specifies quoting for MESSAGE, but not for
+// SEVERITY, and the example shows an unquoted "SEVERITY=debug". While we know
+// tor's parser permits quoting of SEVERITY, it's not actually specified..
+// Therefore we we need to guard against callers passing a string that violates
+// the global protocol constraint of "any US-ASCII character but NUL or NL." So
+// here, we instantiate exactly the five supported severities, using a type that
+// cannot be constructed outside the package.
+type logSeverity struct {
+	string
+}
+
+// Severity levels for the Log function.
+var (
+	LogSeverityError   = logSeverity{"error"}
+	LogSeverityWarning = logSeverity{"warning"}
+	LogSeverityNotice  = logSeverity{"notice"}
+	LogSeverityInfo    = logSeverity{"info"}
+	LogSeverityDebug   = logSeverity{"debug"}
+)
+
+// Encode a string according to the CString rules of section 2.1.1 in
+// control-spec.txt.
+// 	CString = DQUOTE *qcontent DQUOTE
+// "...in a CString, the escapes '\n', '\t', '\r', and the octal escapes '\0'
+// ... '\377' represent newline, tab, carriage return, and the 256 possible
+// octet values respectively."
+// RFC 2822 section 3.2.5 in turn defines what byte values we need to escape:
+// everything but
+// 	NO-WS-CTL /     ; Non white space controls
+// 	%d33 /          ; The rest of the US-ASCII
+// 	%d35-91 /       ;  characters not including "\"
+// 	%d93-126        ;  or the quote character
+// Technically control-spec.txt requires us to escape the space character (32),
+// but it is an error in the spec: https://bugs.torproject.org/29432.
+//
+// We additionally need to ensure that whatever we return passes argIsSafe,
+// because strings encoded by this function are printed verbatim by Log.
+func encodeCString(s string) string {
+	result := bytes.NewBuffer([]byte{})
+	result.WriteByte('"')
+	for _, c := range []byte(s) {
+		if c == 32 || c == 33 || (35 <= c && c <= 91) || (93 <= c && c <= 126) {
+			result.WriteByte(c)
+		} else {
+			fmt.Fprintf(result, "\\%03o", c)
+		}
+	}
+	result.WriteByte('"')
+	return result.String()
+}
+
+// Emit a LOG message with the given severity (one of LogSeverityError,
+// LogSeverityWarning, LogSeverityNotice, LogSeverityInfo, or LogSeverityDebug).
+func Log(severity logSeverity, message string) {
+	// "<Message> contains the log message which can be a String or CString..."
+	// encodeCString always makes the string safe to emit; i.e., it
+	// satisfies argIsSafe.
+	line("LOG", "SEVERITY="+severity.string, "MESSAGE="+encodeCString(message))
+}
+
 // 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.
@@ -449,7 +513,7 @@ type ClientInfo struct {
 // was a list of transport names to use in case Tor requested "*". That feature
 // was never implemented and has been removed from the pluggable transports
 // specification.
-// https://trac.torproject.org/projects/tor/ticket/15612
+// https://bugs.torproject.org/15612
 func ClientSetup(_ []string) (info ClientInfo, err error) {
 	ver, err := getManagedTransportVer()
 	if err != nil {
@@ -494,6 +558,7 @@ func resolveAddr(addrStr string) (*net.TCPAddr, error) {
 		// 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.
+		// https://bugs.torproject.org/7011
 		parts := strings.Split(addrStr, ":")
 		if len(parts) <= 2 {
 			return nil, err
@@ -556,6 +621,7 @@ func getServerBindaddrs() ([]Bindaddr, error) {
 	if err != nil {
 		return nil, err
 	}
+	seenMethods := make(map[string]bool)
 	for _, spec := range strings.Split(serverBindaddr, ",") {
 		var bindaddr Bindaddr
 
@@ -564,6 +630,12 @@ func getServerBindaddrs() ([]Bindaddr, error) {
 			return nil, envError(fmt.Sprintf("TOR_PT_SERVER_BINDADDR: %q: doesn't contain \"-\"", spec))
 		}
 		bindaddr.MethodName = parts[0]
+		// Check for duplicate method names: "Applications MUST NOT set
+		// more than one <address>:<port> pair per PT name."
+		if seenMethods[bindaddr.MethodName] {
+			return nil, envError(fmt.Sprintf("TOR_PT_SERVER_BINDADDR: %q: duplicate method name %q", spec, bindaddr.MethodName))
+		}
+		seenMethods[bindaddr.MethodName] = true
 		addr, err := resolveAddr(parts[1])
 		if err != nil {
 			return nil, envError(fmt.Sprintf("TOR_PT_SERVER_BINDADDR: %q: %s", spec, err.Error()))
@@ -608,13 +680,18 @@ func readAuthCookie(f io.Reader) ([]byte, error) {
 }
 
 // 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) {
+// cookie. See section 4.2.1.2 of 217-ext-orport-auth.txt.
+func readAuthCookieFile(filename string) (cookie []byte, err error) {
 	f, err := os.Open(filename)
 	if err != nil {
 		return nil, err
 	}
-	defer f.Close()
+	defer func() {
+		closeErr := f.Close()
+		if err == nil {
+			err = closeErr
+		}
+	}()
 
 	return readAuthCookie(f)
 }
@@ -647,7 +724,7 @@ type ServerInfo struct {
 // was a list of transport names to use in case Tor requested "*". That feature
 // was never implemented and has been removed from the pluggable transports
 // specification.
-// https://trac.torproject.org/projects/tor/ticket/15612
+// https://bugs.torproject.org/15612
 func ServerSetup(_ []string) (info ServerInfo, err error) {
 	ver, err := getManagedTransportVer()
 	if err != nil {
@@ -766,6 +843,7 @@ func extOrPortAuthenticate(s io.ReadWriter, info *ServerInfo) error {
 	// 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.
+	// https://bugs.torproject.org/15240
 	authCookie, err := readAuthCookieFile(info.AuthCookiePath)
 	if err != nil {
 		return fmt.Errorf("error reading TOR_PT_AUTH_COOKIE_FILE %q: %s", info.AuthCookiePath, err.Error())
@@ -794,7 +872,7 @@ func extOrPortAuthenticate(s io.ReadWriter, info *ServerInfo) error {
 	return nil
 }
 
-// See section 3.1 of 196-transport-control-ports.txt.
+// See section 3.1.1 of 196-transport-control-ports.txt.
 const (
 	extOrCmdDone      = 0x0000
 	extOrCmdUserAddr  = 0x0001
@@ -875,7 +953,7 @@ func extOrPortRecvCommand(s io.Reader) (cmd uint16, body []byte, err error) {
 // OKAY or DENY response command from the server. If addr or methodName is "",
 // the corresponding command is not sent. Returns nil if and only if OKAY is
 // received.
-func extOrPortSetup(s io.ReadWriter, addr, methodName string) error {
+func extOrPortSetMetadata(s io.ReadWriter, addr, methodName string) error {
 	var err error
 
 	if addr != "" {
@@ -907,6 +985,27 @@ func extOrPortSetup(s io.ReadWriter, addr, methodName string) error {
 	return nil
 }
 
+func extOrPortSetup(s net.Conn, timeout time.Duration,
+	info *ServerInfo, addr, methodName string) error {
+	err := s.SetDeadline(time.Now().Add(5 * time.Second))
+	if err != nil {
+		return err
+	}
+	err = extOrPortAuthenticate(s, info)
+	if err != nil {
+		return err
+	}
+	err = extOrPortSetMetadata(s, addr, methodName)
+	if err != nil {
+		return err
+	}
+	err = s.SetDeadline(time.Time{})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
 // Dial 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
@@ -924,18 +1023,11 @@ func DialOr(info *ServerInfo, addr, methodName string) (*net.TCPConn, error) {
 	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, addr, methodName)
+	err = extOrPortSetup(s, 5*time.Second, info, addr, methodName)
 	if err != nil {
 		s.Close()
 		return nil, err
 	}
-	s.SetDeadline(time.Time{})
 
 	return s, nil
 }


=====================================
pt_test.go
=====================================
@@ -11,8 +11,37 @@ import (
 	"path"
 	"sort"
 	"testing"
+	"time"
 )
 
+const testAuthCookiePath = "test_authcookie"
+
+func TestErrors(t *testing.T) {
+	Stdout = ioutil.Discard
+
+	var err error
+	err = envError("XYZ")
+	if err.Error() != "ENV-ERROR XYZ" {
+		t.Errorf("unexpected string %q from envError", err.Error())
+	}
+	err = versionError("XYZ")
+	if err.Error() != "VERSION-ERROR XYZ" {
+		t.Errorf("unexpected string %q from versionError", err.Error())
+	}
+	err = CmethodError("method", "XYZ")
+	if err.Error() != "CMETHOD-ERROR method XYZ" {
+		t.Errorf("unexpected string %q from CmethodError", err.Error())
+	}
+	err = SmethodError("method", "XYZ")
+	if err.Error() != "SMETHOD-ERROR method XYZ" {
+		t.Errorf("unexpected string %q from SmethodError", err.Error())
+	}
+	err = ProxyError("XYZ")
+	if err.Error() != "PROXY-ERROR XYZ" {
+		t.Errorf("unexpected string %q from ProxyError", err.Error())
+	}
+}
+
 func TestKeywordIsSafe(t *testing.T) {
 	tests := [...]struct {
 		keyword  string
@@ -27,6 +56,7 @@ func TestKeywordIsSafe(t *testing.T) {
 		{"CMETHOD\x80", false},
 		{"CMETHOD\x81", false},
 		{"CMETHOD\xff", false},
+		{"\xffCMETHOD", false},
 		{"CMÉTHOD", false},
 	}
 
@@ -155,7 +185,7 @@ func TestGetClientTransports(t *testing.T) {
 		},
 		// In the past, "*" meant to return all known transport names.
 		// But now it has no special meaning.
-		// https://trac.torproject.org/projects/tor/ticket/15612
+		// https://bugs.torproject.org/15612
 		{
 			"*",
 			[]string{"*"},
@@ -302,6 +332,18 @@ func TestGetServerBindaddrs(t *testing.T) {
 			`alpha\,beta`,
 			"",
 		},
+		// duplicates in TOR_PT_SERVER_BINDADDR
+		// https://bugs.torproject.org/21261
+		{
+			`alpha-0.0.0.0:1234,alpha-[::]:1234`,
+			`alpha`,
+			"",
+		},
+		{
+			`alpha-0.0.0.0:1234,alpha-0.0.0.0:1234`,
+			`alpha`,
+			"",
+		},
 	}
 	goodTests := [...]struct {
 		ptServerBindaddr         string
@@ -343,7 +385,7 @@ func TestGetServerBindaddrs(t *testing.T) {
 		},
 		// In the past, "*" meant to return all known transport names.
 		// But now it has no special meaning.
-		// https://trac.torproject.org/projects/tor/ticket/15612
+		// https://bugs.torproject.org/15612
 		{
 			"alpha-1.2.3.4:1111,beta-[1:2::3:4]:2222",
 			"*",
@@ -665,31 +707,34 @@ func TestExtOrPortRecvCommand(t *testing.T) {
 	}
 }
 
-// set up so that extOrPortSetup can write to one buffer and read from another.
-type mockSetupBuf struct {
-	bytes.Buffer
-	ReadBuf bytes.Buffer
+// set up so that extOrPortSetMetadata can write to one buffer and read from another.
+type mockSetMetadataBuf struct {
+	ReadBuf  bytes.Buffer
+	WriteBuf bytes.Buffer
+}
+
+func (buf *mockSetMetadataBuf) Read(p []byte) (int, error) {
+	return buf.ReadBuf.Read(p)
 }
 
-func (buf *mockSetupBuf) Read(p []byte) (int, error) {
-	n, err := buf.ReadBuf.Read(p)
-	return n, err
+func (buf *mockSetMetadataBuf) Write(p []byte) (int, error) {
+	return buf.WriteBuf.Write(p)
 }
 
-func testExtOrPortSetupIndividual(t *testing.T, addr, methodName string) {
+func testExtOrPortSetMetadataIndividual(t *testing.T, addr, methodName string) {
 	var err error
-	var buf mockSetupBuf
+	var buf mockSetMetadataBuf
 	// fake an OKAY response.
 	err = extOrPortSendCommand(&buf.ReadBuf, extOrCmdOkay, []byte{})
 	if err != nil {
-		t.Fatal(err)
+		panic(err)
 	}
-	err = extOrPortSetup(&buf, addr, methodName)
+	err = extOrPortSetMetadata(&buf, addr, methodName)
 	if err != nil {
-		t.Fatalf("error in extOrPortSetup: %s", err)
+		t.Fatalf("error in extOrPortSetMetadata: %s", err)
 	}
 	for {
-		cmd, body, err := extOrPortRecvCommand(&buf.Buffer)
+		cmd, body, err := extOrPortRecvCommand(&buf.WriteBuf)
 		if err != nil {
 			t.Fatalf("error in extOrPortRecvCommand: %s", err)
 		}
@@ -712,13 +757,149 @@ func testExtOrPortSetupIndividual(t *testing.T, addr, methodName string) {
 	}
 }
 
-func TestExtOrPortSetup(t *testing.T) {
+func TestExtOrPortSetMetadata(t *testing.T) {
 	const addr = "127.0.0.1:40000"
 	const methodName = "alpha"
-	testExtOrPortSetupIndividual(t, "", "")
-	testExtOrPortSetupIndividual(t, addr, "")
-	testExtOrPortSetupIndividual(t, "", methodName)
-	testExtOrPortSetupIndividual(t, addr, methodName)
+	testExtOrPortSetMetadataIndividual(t, "", "")
+	testExtOrPortSetMetadataIndividual(t, addr, "")
+	testExtOrPortSetMetadataIndividual(t, "", methodName)
+	testExtOrPortSetMetadataIndividual(t, addr, methodName)
+}
+
+func simulateServerExtOrPortAuth(r io.Reader, w io.Writer, authCookie []byte) error {
+	// send auth types
+	_, err := w.Write([]byte{1, 0})
+	if err != nil {
+		return err
+	}
+	// read client auth type
+	buf := make([]byte, 1)
+	_, err = io.ReadFull(r, buf)
+	if err != nil {
+		return err
+	}
+	if buf[0] != 1 {
+		return fmt.Errorf("didn't get client auth type 1")
+	}
+	// read client nonce
+	clientNonce := make([]byte, 32)
+	_, err = io.ReadFull(r, clientNonce)
+	if err != nil {
+		return err
+	}
+	// send server hash and nonce
+	serverNonce := make([]byte, 32)
+	serverHash := computeServerHash(authCookie, clientNonce, serverNonce)
+	_, err = w.Write(serverHash)
+	if err != nil {
+		return err
+	}
+	_, err = w.Write(serverNonce)
+	if err != nil {
+		return err
+	}
+	// read client hash
+	clientHash := make([]byte, 32)
+	_, err = io.ReadFull(r, clientHash)
+	if err != nil {
+		return err
+	}
+	// send success status
+	_, err = w.Write([]byte{1})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+type failSetDeadlineAfter struct {
+	n   int
+	err error
+}
+
+func (c *failSetDeadlineAfter) try() error {
+	if c.n > 0 {
+		c.n--
+		return nil
+	}
+	return c.err
+}
+
+func (c *failSetDeadlineAfter) SetDeadline(_ time.Time) error {
+	return c.try()
+}
+
+func (c *failSetDeadlineAfter) SetReadDeadline(_ time.Time) error {
+	return c.try()
+}
+
+func (c *failSetDeadlineAfter) SetWriteDeadline(_ time.Time) error {
+	return c.try()
+}
+
+// a fake Conn whose Set*Deadline functions fail after a certain number of
+// calls.
+type connFailSetDeadline struct {
+	io.Reader
+	io.Writer
+	failSetDeadlineAfter
+}
+
+func (c *connFailSetDeadline) Close() error {
+	return nil
+}
+
+func (c *connFailSetDeadline) LocalAddr() net.Addr {
+	return &net.IPAddr{net.IPv4(0, 0, 0, 0), ""}
+}
+
+func (c *connFailSetDeadline) RemoteAddr() net.Addr {
+	return &net.IPAddr{net.IPv4(0, 0, 0, 0), ""}
+}
+
+// Test that a failure of SetDeadline is reported.
+func TestExtOrPortSetupFailSetDeadline(t *testing.T) {
+	authCookie, err := readAuthCookieFile(testAuthCookiePath)
+	if err != nil {
+		panic(err)
+	}
+
+	// extOrPortSetup calls SetDeadline twice, so try failing the call after
+	// differing delays.
+	expectedErr := fmt.Errorf("distinguished error")
+	for _, delay := range []int{0, 1, 2} {
+		upstreamR, upstreamW := io.Pipe()
+		downstreamR, downstreamW := io.Pipe()
+
+		// mock ExtORPort to talk to
+		go func() {
+			// handle auth
+			err := simulateServerExtOrPortAuth(upstreamR, downstreamW, authCookie)
+			if err != nil {
+				return
+			}
+			// discard succeeding client data
+			go func() {
+				io.Copy(ioutil.Discard, upstreamR)
+			}()
+			// fake an OKAY response.
+			err = extOrPortSendCommand(downstreamW, extOrCmdOkay, []byte{})
+			if err != nil {
+				return
+			}
+		}()
+
+		// make a Conn that will fail SetDeadline after a certain number
+		// of calls.
+		s := &connFailSetDeadline{downstreamR, upstreamW, failSetDeadlineAfter{delay, expectedErr}}
+		serverInfo := &ServerInfo{AuthCookiePath: testAuthCookiePath}
+		err = extOrPortSetup(s, 1*time.Second, serverInfo, "", "")
+		if delay < 2 && err != expectedErr {
+			t.Fatalf("delay %v: expected error %v, got %v", delay, expectedErr, err)
+		} else if delay >= 2 && err != nil {
+			t.Fatalf("delay %v: got error %v", delay, err)
+		}
+	}
 }
 
 func TestMakeStateDir(t *testing.T) {
@@ -778,3 +959,131 @@ func TestMakeStateDir(t *testing.T) {
 		t.Errorf("MakeStateDir with a subdirectory of a file unexpectedly succeeded")
 	}
 }
+
+// Compare with unescape_string in tor's src/lib/encoding/cstring.c. That
+// function additionally allows hex escapes, but control-spec.txt's CString
+// doesn't say anything about that.
+func decodeCString(enc string) (string, error) {
+	var result bytes.Buffer
+	b := []byte(enc)
+	state := "^"
+	number := 0
+	i := 0
+	for i < len(b) {
+		c := b[i]
+		switch state {
+		case "^":
+			if c != '"' {
+				return "", fmt.Errorf("missing start quote")
+			}
+			state = "."
+		case ".":
+			switch c {
+			case '\\':
+				state = "\\"
+			case '"':
+				state = "$"
+			default:
+				result.WriteByte(c)
+			}
+		case "\\":
+			switch c {
+			case 'n':
+				result.WriteByte('\n')
+				state = "."
+			case 't':
+				result.WriteByte('\t')
+				state = "."
+			case 'r':
+				result.WriteByte('\r')
+				state = "."
+			case '"', '\\':
+				result.WriteByte(c)
+				state = "."
+			case '0', '1', '2', '3', '4', '5', '6', '7':
+				number = int(c - '0')
+				state = "o1"
+			default:
+				return "", fmt.Errorf("unknown escape \\%c", c)
+			}
+		case "o1": // 1 octal digit read
+			switch c {
+			case '0', '1', '2', '3', '4', '5', '6', '7':
+				number = number*8 + int(c-'0')
+				state = "o2"
+			default:
+				if number > 255 {
+					return "", fmt.Errorf("invalid octal escape")
+				}
+				result.WriteByte(byte(number))
+				state = "."
+				continue // process the current byte again
+			}
+		case "o2": // 2 octal digits read
+			switch c {
+			case '0', '1', '2', '3', '4', '5', '6', '7':
+				number = number*8 + int(c-'0')
+				if number > 255 {
+					return "", fmt.Errorf("invalid octal escape")
+				}
+				result.WriteByte(byte(number))
+				state = "."
+			default:
+				if number > 255 {
+					return "", fmt.Errorf("invalid octal escape")
+				}
+				result.WriteByte(byte(number))
+				state = "."
+				continue // process the current byte again
+			}
+		case "$":
+			return "", fmt.Errorf("trailing garbage")
+		}
+		i++
+	}
+	if state != "$" {
+		return "", fmt.Errorf("unexpected end of string")
+	}
+	return result.String(), nil
+}
+
+func roundtripCString(src string) (string, error) {
+	enc := encodeCString(src)
+	dec, err := decodeCString(enc)
+	if err != nil {
+		return enc, fmt.Errorf("failed to decode: %+q → %+q: %v", src, enc, err)
+	}
+	if dec != src {
+		return enc, fmt.Errorf("roundtrip failed: %+q → %+q → %+q", src, enc, dec)
+	}
+	return enc, nil
+}
+
+func TestEncodeCString(t *testing.T) {
+	tests := []string{
+		"",
+		"\"",
+		"\"\"",
+		"abc\"def",
+		"\\",
+		"\\\\",
+		"\x0123abc", // trap here is if you encode '\x01' as "\\1"; it would join with the following digits: "\\123abc".
+		"\n\r\t\x7f",
+		"\\377",
+	}
+	allBytes := make([]byte, 256)
+	for i := 0; i < len(allBytes); i++ {
+		allBytes[i] = byte(i)
+	}
+	tests = append(tests, string(allBytes))
+
+	for _, test := range tests {
+		enc, err := roundtripCString(test)
+		if err != nil {
+			t.Error(err)
+		}
+		if !argIsSafe(enc) {
+			t.Errorf("escaping %+q resulted in non-safe %+q", test, enc)
+		}
+	}
+}


=====================================
socks_test.go
=====================================
@@ -3,8 +3,8 @@ package pt
 import (
 	"bufio"
 	"bytes"
-	"errors"
 	"encoding/hex"
+	"errors"
 	"io"
 	"net"
 	"testing"


=====================================
test_authcookie
=====================================
@@ -0,0 +1,2 @@
+! Extended ORPort Auth Cookie !
+this file is used in test code.



View it on GitLab: https://salsa.debian.org/pkg-privacy-team/golang-goptlib/-/compare/5e9998660d0f784b52a41c6873f2091764f43b3c...1a409203ccf289948fe3d04a7eb1845fb8eba125

-- 
View it on GitLab: https://salsa.debian.org/pkg-privacy-team/golang-goptlib/-/compare/5e9998660d0f784b52a41c6873f2091764f43b3c...1a409203ccf289948fe3d04a7eb1845fb8eba125
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-privacy-commits/attachments/20220526/ece62234/attachment-0001.htm>


More information about the Pkg-privacy-commits mailing list