[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