[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [goptlib/master] Bug 28940: add support for LOG.
commit 350ea810838a99d9fc9bf7e3523fcc5635691eed
Author: David Fifield <david@xxxxxxxxxxxxxxx>
Date: Thu Feb 7 19:56:13 2019 -0700
Bug 28940: add support for LOG.
---
pt.go | 65 +++++++++++++++++++++++++++++++
pt_test.go | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 193 insertions(+)
diff --git a/pt.go b/pt.go
index f7929e6..23893f4 100644
--- a/pt.go
+++ b/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
@@ -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)
@@ -347,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.
diff --git a/pt_test.go b/pt_test.go
index 70f5533..d74d6d7 100644
--- a/pt_test.go
+++ b/pt_test.go
@@ -959,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)
+ }
+ }
+}
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits