Ticket #28940: 0001-Bug-28940-add-support-for-LOG.patch

File 0001-Bug-28940-add-support-for-LOG.patch, 6.3 KB (added by dcf, 14 months ago)
  • pt.go

    From c1a3d0b9da13921cc1921e7859243777d94ce762 Mon Sep 17 00:00:00 2001
    From: David Fifield <david@bamsoftware.com>
    Date: Thu, 7 Feb 2019 19:56:13 -0700
    Subject: [PATCH] Bug 28940: add support for LOG.
    
    ---
     pt.go      |  52 +++++++++++++++++++++++++
     pt_test.go | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
     2 files changed, 180 insertions(+)
    
    diff --git a/pt.go b/pt.go
    index cc0ed8c..4a65a09 100644
    a b  
    2424//                      conn, err := ln.AcceptSocks()
    2525//                      if err != nil {
    2626//                              if e, ok := err.(net.Error); ok && e.Temporary() {
     27//                                      pt.Log(pt.LogLevelError, "accept error: " + err.Error())
    2728//                                      continue
    2829//                              }
    2930//                              return err
     
    8384//                              if e, ok := err.(net.Error); ok && e.Temporary() {
    8485//                                      continue
    8586//                              }
     87//                              pt.Log(pt.LogLevelError, "accept error: " + err.Error())
    8688//                              return err
    8789//                      }
    8890//                      go handler(conn)
    func ProxyDone() { 
    347349        fmt.Fprintf(Stdout, "PROXY DONE\n")
    348350}
    349351
     352// Severity levels for the Log function.
     353const (
     354        LogLevelError   = "error"
     355        LogLevelWarning = "warning"
     356        LogLevelNotice  = "notice"
     357        LogLevelInfo    = "info"
     358        LogLevelDebug   = "debug"
     359)
     360
     361// Encode a string according to the CString rules of section 2.1.1 in
     362// control-spec.txt.
     363//      CString = DQUOTE *qcontent DQUOTE
     364// "...in a CString, the escapes '\n', '\t', '\r', and the octal escapes '\0'
     365// ... '\377' represent newline, tab, carriage return, and the 256 possible
     366// octet values respectively."
     367// RFC 2822 section 3.2.5 in turn defines the minimum byte values we need to
     368// escape: everything but
     369//      NO-WS-CTL /     ; Non white space controls
     370//      %d33 /          ; The rest of the US-ASCII
     371//      %d35-91 /       ;  characters not including "\"
     372//      %d93-126        ;  or the quote character
     373// Technically control-spec.txt requires us to escape the space character (32),
     374// but the code doesn't do that and it seems to be an error in the spec:
     375// https://bugs.torproject.org/29432.
     376//
     377// We additionally need to ensure that whatever we return passes argIsSafe,
     378// because strings encoded by this function are printed verbatim by Log.
     379func encodeCString(s string) string {
     380        result := bytes.NewBuffer([]byte{})
     381        result.WriteByte('"')
     382        for _, c := range []byte(s) {
     383                if c == 32 || c == 33 || (35 <= c && c <= 91) || (93 <= c && c <= 126) {
     384                        result.WriteByte(c)
     385                } else {
     386                        fmt.Fprintf(result, "\\%03o", c)
     387                }
     388        }
     389        result.WriteByte('"')
     390        return result.String()
     391}
     392
     393// Emit a LOG message with the given severity (one of LogLevelError,
     394// LogLevelWarning, LogLevelNotice, LogLevelInfo, or LogLevelDebug).
     395func Log(severity, message string) {
     396        // "<Message> contains the log message which can be a String or CString..."
     397        // encodeCString always makes the string safe to emit; i.e., it
     398        // satisfies argIsSafe.
     399        line("LOG", "SEVERITY="+encodeCString(severity), "MESSAGE="+encodeCString(message))
     400}
     401
    350402// Get a pluggable transports version offered by Tor and understood by us, if
    351403// any. The only version we understand is "1". This function reads the
    352404// environment variable TOR_PT_MANAGED_TRANSPORT_VER.
  • pt_test.go

    diff --git a/pt_test.go b/pt_test.go
    index f9f4790..8507cdc 100644
    a b func TestMakeStateDir(t *testing.T) { 
    817817                t.Errorf("MakeStateDir with a subdirectory of a file unexpectedly succeeded")
    818818        }
    819819}
     820
     821// Compare with unescape_string in src/lib/encoding/cstring.c. That function
     822// additionally allows hex escapes, but control-spec.txt's CString doesn't say
     823// anything about that.
     824func decodeCString(enc string) (string, error) {
     825        var result bytes.Buffer
     826        b := []byte(enc)
     827        state := "^"
     828        number := 0
     829        i := 0
     830        for i < len(b) {
     831                c := b[i]
     832                switch state {
     833                case "^":
     834                        if c != '"' {
     835                                return "", fmt.Errorf("missing start quote")
     836                        }
     837                        state = "."
     838                case ".":
     839                        switch c {
     840                        case '\\':
     841                                state = "\\"
     842                        case '"':
     843                                state = "$"
     844                        default:
     845                                result.WriteByte(c)
     846                        }
     847                case "\\":
     848                        switch c {
     849                        case 'n':
     850                                result.WriteByte('\n')
     851                                state = "."
     852                        case 't':
     853                                result.WriteByte('\t')
     854                                state = "."
     855                        case 'r':
     856                                result.WriteByte('\r')
     857                                state = "."
     858                        case '\\':
     859                                result.WriteByte('\\')
     860                                state = "."
     861                        case '0', '1', '2', '3', '4', '5', '6', '7':
     862                                number = int(c - '0')
     863                                state = "o1"
     864                        default:
     865                                return "", fmt.Errorf("unknown escape \\%c", c)
     866                        }
     867                case "o1": // 1 octal digit read
     868                        switch c {
     869                        case '0', '1', '2', '3', '4', '5', '6', '7':
     870                                number = number*8 + int(c-'0')
     871                                state = "o2"
     872                        default:
     873                                if number > 255 {
     874                                        return "", fmt.Errorf("invalid octal escape")
     875                                }
     876                                result.WriteByte(byte(number))
     877                                state = "."
     878                                continue // process the current byte again
     879                        }
     880                case "o2": // 2 octal digits read
     881                        switch c {
     882                        case '0', '1', '2', '3', '4', '5', '6', '7':
     883                                number = number*8 + int(c-'0')
     884                                if number > 255 {
     885                                        return "", fmt.Errorf("invalid octal escape")
     886                                }
     887                                result.WriteByte(byte(number))
     888                                state = "."
     889                        default:
     890                                if number > 255 {
     891                                        return "", fmt.Errorf("invalid octal escape")
     892                                }
     893                                result.WriteByte(byte(number))
     894                                state = "."
     895                                continue // process the current byte again
     896                        }
     897                case "$":
     898                        return "", fmt.Errorf("trailing garbage")
     899                }
     900                i++
     901        }
     902        if state != "$" {
     903                return "", fmt.Errorf("unexpected end of string")
     904        }
     905        return result.String(), nil
     906}
     907
     908func roundtripCString(src string) (string, error) {
     909        enc := encodeCString(src)
     910        dec, err := decodeCString(enc)
     911        if err != nil {
     912                return enc, fmt.Errorf("failed to decode: %+q → %+q: %v", src, enc, err)
     913        }
     914        if dec != src {
     915                return enc, fmt.Errorf("roundtrip failed: %+q → %+q → %+q", src, enc, dec)
     916        }
     917        return enc, nil
     918}
     919
     920func TestEncodeCString(t *testing.T) {
     921        tests := []string{
     922                "",
     923                "\"",
     924                "\"\"",
     925                "abc\"def",
     926                "\\",
     927                "\\\\",
     928                "\x0123abc", // trap here is if you encode '\x01' as "\\1"; it would join with the following digits: "\\123abc".
     929                "\n\r\t\x7f",
     930                "\\377",
     931        }
     932        allBytes := make([]byte, 256)
     933        for i := 0; i < len(allBytes); i++ {
     934                allBytes[i] = byte(i)
     935        }
     936        tests = append(tests, string(allBytes))
     937
     938        for _, test := range tests {
     939                enc, err := roundtripCString(test)
     940                if err != nil {
     941                        t.Error(err)
     942                }
     943                if !argIsSafe(enc) {
     944                        t.Errorf("escaping %+q resulted in non-safe %+q", test, enc)
     945                }
     946        }
     947}