]> Sergey Matveev's repositories - tofuproxy.git/commitdiff
Ability to remove hosts from the states, refactoring
authorSergey Matveev <stargrave@stargrave.org>
Thu, 9 Sep 2021 10:54:26 +0000 (13:54 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Thu, 9 Sep 2021 11:51:12 +0000 (14:51 +0300)
21 files changed:
caches/caches.go [new file with mode: 0644]
cert.pem.do
cmd/tofuproxy/main.go
doc/index.texi
doc/usage.texi
fifos/del.go [new file with mode: 0644]
fifos/ensure.do
fifos/list.go [new file with mode: 0644]
fifos/log.go [moved from fifos/fifos.go with 60% similarity]
fifos/multitail.sh
fifos/start.go [new file with mode: 0644]
httpauth.go [moved from auth.go with 96% similarity]
rounds/denyFonts.go
rounds/redirectHTML.go
rounds/spy.go
rounds/transcodeJXL.go
rounds/transcodeWebP.go
tls.go
tlsauth.go
trip.go
verify.go

diff --git a/caches/caches.go b/caches/caches.go
new file mode 100644 (file)
index 0000000..f451da4
--- /dev/null
@@ -0,0 +1,20 @@
+package caches
+
+import (
+       "crypto/tls"
+       "sync"
+)
+
+var (
+       Accepted  = make(map[string]string)
+       AcceptedM sync.RWMutex
+
+       Rejected  = make(map[string]string)
+       RejectedM sync.RWMutex
+
+       HTTPAuthCache  = make(map[string][2]string)
+       HTTPAuthCacheM sync.RWMutex
+
+       TLSAuthCache  = make(map[string]*tls.Certificate)
+       TLSAuthCacheM sync.RWMutex
+)
index 0110e611e9d2581136debfc362991d950a306f0a..a25ff366d19a6d1ad3ee0c6e551429d8176d7787 100644 (file)
@@ -1,2 +1,3 @@
 [ -e certgen.cmd ] || redo certgen.cmd
-./certgen.cmd
+umask 077
+./certgen.cmd > $3
index 8a0be00267f4cc17c191ecbea841c65aac0fd3bb..96dbd321a209503e527b839e2acb97cbc3d61bcd 100644 (file)
@@ -51,8 +51,7 @@ func main() {
        }
 
        fifos.NoTAI = *notai
-       fifos.FIFOs = *fifosDir
-       fifos.Init()
+       fifos.Start(*fifosDir)
        tofuproxy.Certs = *certs
        tofuproxy.CCerts = *ccerts
        tofuproxy.DNSSrv = *dnsSrv
index 10c8582d248cc85b118ceafdadca16a6d7fb4acb..3958d312b5a87a0f009401532dd49c6bc34bfdcc 100644 (file)
@@ -111,7 +111,7 @@ to forcefully trust the domain.
 @item
 @strong{HTTP-based authorization} requests are intercepted and
 user/password input dialogue is shown. It automatically loads
-@strong{initial form} values from @file{.netrc}.
+@strong{initial form} values from @strong{@file{.netrc}}.
 
 @item
 TLS @strong{client certificates} supported: separate dialogue window for
index 064d57eb11b262e899a9d6d12561e253991df63c..8942839df9863b2fc6b8bd443ce15760651a5d75 100644 (file)
@@ -48,6 +48,10 @@ main.go:70: listening: [::1]:8080 dns: [::1]:53 certs: ./certs ccerts: ./ccerts
 
 @item Point you HTTP/HTTPS clients to @code{http://localhost:8080}.
 
+@item
+If you want to use TLS client certificates, then place them to
+@file{-ccerts} directory.
+
 @item Watch logs:
 
 @example
@@ -63,7 +67,19 @@ will be shown Tk-dialog through the @command{wish} invocation. GnuTLS'es
 
 @image{dialog,,,Example dialog,.webp}
 
-@item If you want to use TLS client certificates, then place them to
-@file{-ccerts} directory.
+@item
+To list currently accepted, rejected, HTTP authorized, TLS client
+authenticated hosts:
+
+@example
+$ cat fifos/list-@{accepted,rejected,http-auth,tls-auth@}
+@end example
+
+@item
+To remove knowledge of the host from any of the states mentioned above:
+
+@example
+$ echo www.example.com > fifos/del-tls-auth
+@end example
 
 @end itemize
diff --git a/fifos/del.go b/fifos/del.go
new file mode 100644 (file)
index 0000000..2ab755d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+tofuproxy -- HTTP proxy with TLS certificates management
+Copyright (C) 2021 Sergey Matveev <stargrave@stargrave.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 3 of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package fifos
+
+import (
+       "bufio"
+       "log"
+       "os"
+       "sync"
+)
+
+func del(l *sync.RWMutex, deleter func(string), p string) {
+       for {
+               fd, err := os.OpenFile(p, os.O_RDONLY, os.FileMode(0666))
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               var hosts []string
+               scanner := bufio.NewScanner(fd)
+               for scanner.Scan() {
+                       t := scanner.Text()
+                       if len(t) > 0 {
+                               hosts = append(hosts, t)
+                       }
+               }
+               fd.Close()
+               l.Lock()
+               for _, host := range hosts {
+                       log.Printf("%s: deleting host %s\n", p, host)
+                       deleter(host)
+               }
+               l.Unlock()
+       }
+}
index 7aa937ba5a228d19cf21326e2fc7c788b7f76b93..5e5cc7e143f3492851490584d7f3b49f003308d0 100644 (file)
@@ -1,3 +1,7 @@
-for f in cert dane err ok other redir req tls ; do
-    [ -p $f ] || mkfifo $f
+for f in cert dane err http-auth non-ok ok redir req tls tls-auth various ; do
+    [ -p log-$f ] || mkfifo log-$f
+done
+for f in accepted http-auth rejected tls-auth ; do
+    [ -p list-$f ] || mkfifo list-$f
+    [ -p del-$f ] || mkfifo del-$f
 done
diff --git a/fifos/list.go b/fifos/list.go
new file mode 100644 (file)
index 0000000..b06a4cc
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+tofuproxy -- HTTP proxy with TLS certificates management
+Copyright (C) 2021 Sergey Matveev <stargrave@stargrave.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 3 of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package fifos
+
+import (
+       "crypto/x509"
+       "fmt"
+       "log"
+       "os"
+       "sync"
+
+       "go.stargrave.org/tofuproxy/caches"
+)
+
+func list(l *sync.RWMutex, m map[string]string, p string) {
+       for {
+               fd, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               l.RLock()
+               for host, hsh := range m {
+                       if _, err = fd.WriteString(fmt.Sprintf("%s\t%s\n", host, hsh)); err != nil {
+                               break
+                       }
+               }
+               l.RUnlock()
+               fd.Close()
+       }
+}
+
+func listAccepted(p string) {
+       list(&caches.AcceptedM, caches.Accepted, p)
+}
+
+func listRejected(p string) {
+       list(&caches.RejectedM, caches.Rejected, p)
+}
+
+func listHTTPAuth(p string) {
+       for {
+               fd, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               caches.HTTPAuthCacheM.RLock()
+               for host, creds := range caches.HTTPAuthCache {
+                       if _, err = fd.WriteString(fmt.Sprintf("%s\t%s\n", host, creds[0])); err != nil {
+                               break
+                       }
+               }
+               caches.HTTPAuthCacheM.RUnlock()
+               fd.Close()
+       }
+}
+
+func listTLSAuth(p string) {
+       for {
+               fd, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
+               if err != nil {
+                       log.Fatalln(err)
+               }
+               caches.TLSAuthCacheM.RLock()
+               for host, tlsCert := range caches.TLSAuthCache {
+                       cert, err := x509.ParseCertificate(tlsCert.Certificate[0])
+                       if err != nil {
+                               log.Fatalln(err)
+                       }
+                       if _, err = fd.WriteString(fmt.Sprintf("%s\t%s\n", host, cert.Subject)); err != nil {
+                               break
+                       }
+               }
+               caches.TLSAuthCacheM.RUnlock()
+               fd.Close()
+       }
+}
similarity index 60%
rename from fifos/fifos.go
rename to fifos/log.go
index f07085f9d803d4523d1ffff00b697c2bf9bd072d..398aa2562f1a2b7b03e06ab4648ceb357f48f39a 100644 (file)
@@ -20,26 +20,28 @@ package fifos
 import (
        "log"
        "os"
-       "path/filepath"
        "time"
 
        "go.cypherpunks.ru/tai64n/v2"
 )
 
 var (
-       NoTAI     bool
-       FIFOs     string
-       SinkCert  = make(chan string)
-       SinkDANE  = make(chan string)
-       SinkErr   = make(chan string)
-       SinkOK    = make(chan string)
-       SinkOther = make(chan string)
-       SinkRedir = make(chan string)
-       SinkReq   = make(chan string)
-       SinkTLS   = make(chan string)
+       NoTAI bool
+
+       LogCert     = make(chan string)
+       LogDANE     = make(chan string)
+       LogErr      = make(chan string)
+       LogHTTPAuth = make(chan string)
+       LogNonOK    = make(chan string)
+       LogOK       = make(chan string)
+       LogRedir    = make(chan string)
+       LogReq      = make(chan string)
+       LogTLS      = make(chan string)
+       LogTLSAuth  = make(chan string)
+       LogVarious  = make(chan string)
 )
 
-func sinker(c chan string, p string) {
+func logger(c chan string, p string) {
        tai := new(tai64n.TAI64N)
        for {
                fd, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND, os.FileMode(0666))
@@ -60,14 +62,3 @@ func sinker(c chan string, p string) {
                fd.Close()
        }
 }
-
-func Init() {
-       go sinker(SinkCert, filepath.Join(FIFOs, "cert"))
-       go sinker(SinkDANE, filepath.Join(FIFOs, "dane"))
-       go sinker(SinkErr, filepath.Join(FIFOs, "err"))
-       go sinker(SinkOK, filepath.Join(FIFOs, "ok"))
-       go sinker(SinkOther, filepath.Join(FIFOs, "other"))
-       go sinker(SinkRedir, filepath.Join(FIFOs, "redir"))
-       go sinker(SinkReq, filepath.Join(FIFOs, "req"))
-       go sinker(SinkTLS, filepath.Join(FIFOs, "tls"))
-}
index 8a8ccee89ddd150a550a57dd1ae9d64c73a2b41a..ca458e1fd1eeb5b1a0566513fb02d6c25f21af24 100755 (executable)
@@ -2,11 +2,14 @@
 
 multitail \
     -wh 10 \
-    -t "Certificates" -ci magenta -l "while :; do tai64nlocal < cert ; done" \
-    -t "DANE" --label "DANE " -L "while :; do tai64nlocal < dane ; done" \
-    -t "Errors" -ci red -L "while :; do tai64nlocal < err ; done" \
-    -t "Responses" -ci green --label "< " -l "while :; do tai64nlocal < ok ; done" \
-    -t "Others" -ci white -L "while :; do tai64nlocal < other ; done" \
-    -t "Redirections" -ci cyan --label "R " -L "while :; do tai64nlocal < redir ; done" \
-    -t "Requests" -ci blue --label "> " -L "while :; do tai64nlocal < req ; done" \
-    -t "TLS connections" -ci yellow --label "S " -L "while :; do tai64nlocal < tls ; done"
+    -t "Trust" -ci magenta -l "while :; do tai64nlocal < log-cert ; done" \
+    -t "DANE" --label "DANE " -L "while :; do tai64nlocal < log-dane ; done" \
+    -t "Error" -ci red -L "while :; do tai64nlocal < log-err ; done" \
+    -t "HTTPAuth" -ci green --label "Auth " -L "while :; do tai64nlocal < log-http-auth ; done" \
+    -t "TLSAuth" -ci green --label "Auth " -l "while :; do tai64nlocal < log-tls-auth ; done" \
+    -t "Response non-OK" --label "< " -L "while :; do tai64nlocal < log-non-ok ; done" \
+    -t "Respone OK" -ci green --label "< " -L "while :; do tai64nlocal < log-ok ; done" \
+    -t "Redirect " -ci cyan --label "R " -L "while :; do tai64nlocal < log-redir ; done" \
+    -t "Request" -ci blue --label "> " -L "while :; do tai64nlocal < log-req ; done" \
+    -t "TLS connection" -ci yellow --label "S " -L "while :; do tai64nlocal < log-tls ; done" \
+    -t "Various" -ci yellow -L "while :; do tai64nlocal < log-various ; done"
diff --git a/fifos/start.go b/fifos/start.go
new file mode 100644 (file)
index 0000000..f37abe6
--- /dev/null
@@ -0,0 +1,43 @@
+package fifos
+
+import (
+       "path/filepath"
+
+       "go.stargrave.org/tofuproxy/caches"
+)
+
+func Start(fifos string) {
+       go logger(LogCert, filepath.Join(fifos, "log-cert"))
+       go logger(LogDANE, filepath.Join(fifos, "log-dane"))
+       go logger(LogErr, filepath.Join(fifos, "log-err"))
+       go logger(LogHTTPAuth, filepath.Join(fifos, "log-http-auth"))
+       go logger(LogNonOK, filepath.Join(fifos, "log-non-ok"))
+       go logger(LogOK, filepath.Join(fifos, "log-ok"))
+       go logger(LogRedir, filepath.Join(fifos, "log-redir"))
+       go logger(LogReq, filepath.Join(fifos, "log-req"))
+       go logger(LogTLS, filepath.Join(fifos, "log-tls"))
+       go logger(LogTLSAuth, filepath.Join(fifos, "log-tls-auth"))
+       go logger(LogVarious, filepath.Join(fifos, "log-various"))
+
+       go listAccepted(filepath.Join(fifos, "list-accepted"))
+       go listHTTPAuth(filepath.Join(fifos, "list-http-auth"))
+       go listRejected(filepath.Join(fifos, "list-rejected"))
+       go listTLSAuth(filepath.Join(fifos, "list-tls-auth"))
+
+       go del(
+               &caches.AcceptedM, func(host string) { delete(caches.Accepted, host) },
+               filepath.Join(fifos, "del-accepted"),
+       )
+       go del(
+               &caches.HTTPAuthCacheM, func(host string) { delete(caches.HTTPAuthCache, host) },
+               filepath.Join(fifos, "del-http-auth"),
+       )
+       go del(
+               &caches.RejectedM, func(host string) { delete(caches.Rejected, host) },
+               filepath.Join(fifos, "del-rejected"),
+       )
+       go del(
+               &caches.TLSAuthCacheM, func(host string) { delete(caches.TLSAuthCache, host) },
+               filepath.Join(fifos, "del-tls-auth"),
+       )
+}
similarity index 96%
rename from auth.go
rename to httpauth.go
index 62155d88b6a118f2113dbf66d3416ecca37b369b..5e97636cd6c3a88cab878bbc744756c754778e92 100644 (file)
--- a/auth.go
@@ -27,12 +27,6 @@ import (
        "os/exec"
        "path/filepath"
        "strings"
-       "sync"
-)
-
-var (
-       authCache  = make(map[string][2]string)
-       authCacheM sync.Mutex
 )
 
 func findInNetrc(host string) (string, string) {
index 4fe1195197dc0a6167276bbe171f6370f26d34ed..ad55310b58d0ca1006abafbf3f325d24478ef1a5 100644 (file)
@@ -36,12 +36,7 @@ func RoundDenyFonts(
                fallthrough
        case "font/otf", "font/ttf", "font/woff", "font/woff2":
                http.NotFound(w, req)
-               fifos.SinkOther <- fmt.Sprintf(
-                       "%s %s\t%d\tdeny fonts",
-                       req.Method,
-                       req.URL.String(),
-                       http.StatusNotFound,
-               )
+               fifos.LogVarious <- fmt.Sprintf("%s %s\tdeny fonts", req.Method, req.URL)
                resp.Body.Close()
                return false, nil
        }
index e92a4f9bd03f80c9c4e508513fb2bb0bd07f7e56..2bf4ce2b25b7d2dca6ecc1409c557fd3756d5ac1 100644 (file)
@@ -82,8 +82,8 @@ func RoundRedirectHTML(
                        resp.StatusCode, http.StatusText(resp.StatusCode),
                        redirType, location, location,
                )))
-       fifos.SinkRedir <- fmt.Sprintf(
-               "%s %s\t%s\t%s", req.Method, resp.Status, req.URL.String(), location,
+       fifos.LogRedir <- fmt.Sprintf(
+               "%s %s\t%s\t%s", req.Method, req.URL, resp.Status, location,
        )
        return false, nil
 }
index 3b242f8cfd2b686a37d230c80553ee6508a3e558..cb12480d40390be491131234a812707e5e02f99f 100644 (file)
@@ -62,12 +62,7 @@ func RoundDenySpy(
 ) (bool, error) {
        if IsSpy(host) {
                http.NotFound(w, req)
-               fifos.SinkOther <- fmt.Sprintf(
-                       "%s %s\t%d\tdeny spy",
-                       req.Method,
-                       req.URL.String(),
-                       http.StatusNotFound,
-               )
+               fifos.LogVarious <- fmt.Sprintf("%s %s\tdeny spy", req.Method, req.URL)
                return false, nil
        }
        return true, nil
index 2043fb189154a4e851fa8318faf8fa82dd9a9f1d..e8a962861c8edf026967244ad23bee43c5924398 100644 (file)
@@ -64,12 +64,8 @@ func transcodeCmd2Png(
        w.Header().Add("Content-Type", "image/png")
        w.WriteHeader(http.StatusOK)
        w.Write(data)
-       fifos.SinkOther <- fmt.Sprintf(
-               "%s %s\t%d\t%s transcoded to PNG",
-               req.Method,
-               req.URL.String(),
-               http.StatusOK,
-               contentType,
+       fifos.LogVarious <- fmt.Sprintf(
+               "%s %s\t%s transcoded to PNG", req.Method, req.URL, contentType,
        )
        return false, nil
 }
index ff1fd8c7b3c673c0216e4436db6333619c694054..a38b7f28402779ed51958a89132cdf18af60cd00 100644 (file)
@@ -65,11 +65,6 @@ func RoundTranscodeWebP(
        w.Header().Add("Content-Type", "image/png")
        w.WriteHeader(http.StatusOK)
        w.Write(data)
-       fifos.SinkOther <- fmt.Sprintf(
-               "%s %s\t%d\tWebP transcoded to PNG",
-               req.Method,
-               req.URL.String(),
-               http.StatusOK,
-       )
+       fifos.LogVarious <- fmt.Sprintf("%s %s\tWebP transcoded to PNG", req.Method, req.URL)
        return false, nil
 }
diff --git a/tls.go b/tls.go
index 2db3ceb87c20a2a9703c8b3e9efb34f056437171..6f8ce8c5e22709b7bc707e6bf1d0da1be4b2855c 100644 (file)
--- a/tls.go
+++ b/tls.go
@@ -103,8 +103,8 @@ func (h *HTTPSHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 }
 
 func dialTLS(ctx context.Context, network, addr string) (net.Conn, error) {
-       host := strings.TrimSuffix(addr, ":443")
-       ccg := ClientCertificateGetter{host}
+       host := strings.Split(addr, ":")[0]
+       ccg := ClientCertificateGetter{host: host}
        cfg := tls.Config{
                VerifyPeerCertificate: func(
                        rawCerts [][]byte,
@@ -131,15 +131,15 @@ func dialTLS(ctx context.Context, network, addr string) (net.Conn, error) {
                var err error
                conn, err = tls.Dial(network, addr, &cfg)
                if err != nil {
-                       fifos.SinkErr <- fmt.Sprintf("%s\t%s", addr, dialErr.Error())
+                       fifos.LogErr <- fmt.Sprintf("%s\t%s", addr, dialErr.Error())
                        return nil, err
                }
        }
        connState := conn.ConnectionState()
-       if connState.DidResume {
-               fifos.SinkTLS <- fmt.Sprintf(
+       if !connState.DidResume {
+               fifos.LogTLS <- fmt.Sprintf(
                        "%s\t%s %s\t%s\t%s",
-                       strings.TrimSuffix(addr, ":443"),
+                       addr,
                        ucspi.TLSVersion(connState.Version),
                        tls.CipherSuiteName(connState.CipherSuite),
                        spkiHash(connState.PeerCertificates[0]),
index 531245d23f6e15773995a24bbc7655a4bc5c09ed..8622a0cf85abb48b1d96f2d14ed57023ff6c5816 100644 (file)
@@ -31,6 +31,7 @@ import (
        "strings"
 
        "go.cypherpunks.ru/ucspi"
+       "go.stargrave.org/tofuproxy/caches"
        "go.stargrave.org/tofuproxy/fifos"
 )
 
@@ -38,11 +39,18 @@ var CCerts string
 
 type ClientCertificateGetter struct {
        host string
+       auth bool
 }
 
 func (g *ClientCertificateGetter) get(
        cri *tls.CertificateRequestInfo,
 ) (*tls.Certificate, error) {
+       caches.TLSAuthCacheM.RLock()
+       tlsCert := caches.TLSAuthCache[g.host]
+       caches.TLSAuthCacheM.RUnlock()
+       if tlsCert != nil {
+               return tlsCert, nil
+       }
        var b bytes.Buffer
        b.WriteString(fmt.Sprintf(`
 wm title . "TLS client authentication: %s"
@@ -107,6 +115,10 @@ grid .submit
        if err != nil {
                return &tls.Certificate{}, nil
        }
-       fifos.SinkCert <- fmt.Sprintf("ClientAuth\t%s\t%s", g.host, certs[i].Subject)
+       fifos.LogTLSAuth <- fmt.Sprintf("%s\t%s", g.host, certs[i].Subject)
+       caches.TLSAuthCacheM.Lock()
+       caches.TLSAuthCache[g.host] = tlsCerts[i]
+       caches.TLSAuthCacheM.Unlock()
+       g.auth = true
        return tlsCerts[i], nil
 }
diff --git a/trip.go b/trip.go
index a2e2565047626294254055d3ef3ab2f4a6a76391..90a5ad3b145c2c742d31112a2f5c2c4421020ad4 100644 (file)
--- a/trip.go
+++ b/trip.go
@@ -27,6 +27,7 @@ import (
        "time"
 
        "github.com/dustin/go-humanize"
+       "go.stargrave.org/tofuproxy/caches"
        "go.stargrave.org/tofuproxy/fifos"
        "go.stargrave.org/tofuproxy/rounds"
 )
@@ -58,7 +59,7 @@ type Round func(
 ) (bool, error)
 
 func roundTrip(w http.ResponseWriter, req *http.Request) {
-       fifos.SinkReq <- fmt.Sprintf("%s %s", req.Method, req.URL.String())
+       fifos.LogReq <- fmt.Sprintf("%s %s", req.Method, req.URL)
        host := strings.TrimSuffix(req.URL.Host, ":443")
        for _, round := range []Round{
                rounds.RoundNoHead,
@@ -74,40 +75,44 @@ func roundTrip(w http.ResponseWriter, req *http.Request) {
        reqFlags := []string{}
        unauthorized := false
 
-       authCacheM.Lock()
-       if creds, ok := authCache[req.URL.Host]; ok {
+       caches.HTTPAuthCacheM.RLock()
+       if creds, ok := caches.HTTPAuthCache[req.URL.Host]; ok {
                req.SetBasicAuth(creds[0], creds[1])
+               fifos.LogHTTPAuth <- fmt.Sprintf("%s %s\t%s", req.Method, req.URL, creds[0])
                unauthorized = true
        }
-       authCacheM.Unlock()
+       caches.HTTPAuthCacheM.RUnlock()
 
 Retry:
        resp, err := transport.RoundTrip(req)
        if err != nil {
-               fifos.SinkErr <- fmt.Sprintf("%s\t%s", req.URL.Host, err.Error())
+               fifos.LogErr <- fmt.Sprintf("%s\t%s", req.URL.Host, err.Error())
                http.Error(w, err.Error(), http.StatusBadGateway)
                return
        }
 
        if resp.StatusCode == http.StatusUnauthorized {
                resp.Body.Close()
-               authCacheM.Lock()
+               caches.HTTPAuthCacheM.Lock()
                if unauthorized {
-                       delete(authCache, req.URL.Host)
+                       delete(caches.HTTPAuthCache, req.URL.Host)
                } else {
                        unauthorized = true
                }
-               fifos.SinkOther <- fmt.Sprintf("%s\tauthorization required", req.URL.Host)
+               fifos.LogVarious <- fmt.Sprintf(
+                       "%s %s\tHTTP authorization required", req.Method, req.URL.Host,
+               )
                user, pass, err := authDialog(host, resp.Header.Get("WWW-Authenticate"))
                if err != nil {
-                       authCacheM.Unlock()
-                       fifos.SinkErr <- fmt.Sprintf("%s\t%s", req.URL.Host, err.Error())
+                       caches.HTTPAuthCacheM.Unlock()
+                       fifos.LogErr <- fmt.Sprintf("%s\t%s", req.URL.Host, err.Error())
                        http.Error(w, err.Error(), http.StatusInternalServerError)
                        return
                }
-               authCache[req.URL.Host] = [2]string{user, pass}
-               authCacheM.Unlock()
+               caches.HTTPAuthCache[req.URL.Host] = [2]string{user, pass}
+               caches.HTTPAuthCacheM.Unlock()
                req.SetBasicAuth(user, pass)
+               fifos.LogHTTPAuth <- fmt.Sprintf("%s %s\t%s", req.Method, req.URL, user)
                goto Retry
        }
        if unauthorized {
@@ -156,16 +161,15 @@ Retry:
        resp.Body.Close()
        msg := fmt.Sprintf(
                "%s %s\t%s\t%s\t%s\t%s",
-               req.Method,
-               req.URL.String(),
+               req.Method, req.URL,
                resp.Status,
                resp.Header.Get("Content-Type"),
                humanize.IBytes(uint64(n)),
                strings.Join(reqFlags, ","),
        )
        if resp.StatusCode == http.StatusOK {
-               fifos.SinkOK <- msg
+               fifos.LogOK <- msg
        } else {
-               fifos.SinkOther <- msg
+               fifos.LogNonOK <- msg
        }
 }
index b2eb606ab40691cf4ce1b2571a6334bb207d81cd..de71f9145f3e332fd75c748b410a06404b22877c 100644 (file)
--- a/verify.go
+++ b/verify.go
@@ -32,6 +32,7 @@ import (
        "sync"
 
        "go.cypherpunks.ru/ucspi"
+       "go.stargrave.org/tofuproxy/caches"
        "go.stargrave.org/tofuproxy/fifos"
 )
 
@@ -39,12 +40,8 @@ var (
        CmdCerttool = "certtool"
        CmdWish     = "wish8.6"
 
-       Certs     string
-       accepted  = make(map[string]string)
-       acceptedM sync.RWMutex
-       rejected  = make(map[string]string)
-       rejectedM sync.RWMutex
-       VerifyM   sync.Mutex
+       Certs   string
+       VerifyM sync.Mutex
 )
 
 func spkiHash(cert *x509.Certificate) string {
@@ -52,18 +49,6 @@ func spkiHash(cert *x509.Certificate) string {
        return hex.EncodeToString(hsh[:])
 }
 
-func acceptedAdd(addr, h string) {
-       acceptedM.Lock()
-       accepted[addr] = h
-       acceptedM.Unlock()
-}
-
-func rejectedAdd(addr, h string) {
-       rejectedM.Lock()
-       rejected[addr] = h
-       rejectedM.Unlock()
-}
-
 type ErrRejected struct {
        addr string
 }
@@ -108,33 +93,35 @@ func verifyCert(
        certTheirHash := spkiHash(certTheir)
        VerifyM.Lock()
        defer VerifyM.Unlock()
-       acceptedM.RLock()
-       certOurHash := accepted[host]
-       acceptedM.RUnlock()
+       caches.AcceptedM.RLock()
+       certOurHash := caches.Accepted[host]
+       caches.AcceptedM.RUnlock()
        if certTheirHash == certOurHash {
                return nil
        }
-       rejectedM.RLock()
-       certOurHash = rejected[host]
-       rejectedM.RUnlock()
+       caches.RejectedM.RLock()
+       certOurHash = caches.Rejected[host]
+       caches.RejectedM.RUnlock()
        if certTheirHash == certOurHash {
                return ErrRejected{host}
        }
        daneExists, daneMatched := dane(host, certTheir)
        if daneExists {
                if daneMatched {
-                       fifos.SinkDANE <- fmt.Sprintf("%s\tmatched", host)
+                       fifos.LogDANE <- fmt.Sprintf("%s\tACK", host)
                } else {
-                       fifos.SinkDANE <- fmt.Sprintf("%s\tNOT matched", host)
+                       fifos.LogDANE <- fmt.Sprintf("%s\tNAK", host)
                }
        }
        fn := filepath.Join(Certs, host)
        certsOur, _, err := ucspi.CertPoolFromFile(fn)
        if err == nil || dialErr != nil || (daneExists && !daneMatched) {
                if certsOur != nil && certTheirHash == spkiHash(certsOur[0]) {
-                       acceptedAdd(host, certTheirHash)
+                       caches.AcceptedM.Lock()
+                       caches.Accepted[host] = certTheirHash
+                       caches.AcceptedM.Unlock()
                        if bytes.Compare(certsOur[0].Raw, rawCerts[0]) != 0 {
-                               fifos.SinkCert <- fmt.Sprintf("Refresh\t%s\t%s", host, certTheirHash)
+                               fifos.LogCert <- fmt.Sprintf("Refresh\t%s\t%s", host, certTheirHash)
                                goto CertUpdate
                        }
                        return nil
@@ -190,7 +177,7 @@ proc doAccept {} { exit 10 }
 proc doOnce {} { exit 11 }
 proc doReject {} { exit 12 }
 button .bAccept -text "Accept" -bg green -command doAccept
-button .bOnce -text "Once" -command doOnce
+button .bOnce -text "Once" -bg green -command doOnce
 button .bReject -text "Reject" -bg red -command doReject
 grid .bAccept .bOnce .bReject
 grid rowconfigure . 0 -weight 1
@@ -203,29 +190,33 @@ grid columnconfigure . 0 -weight 1
                err = cmd.Run()
                exitError, ok := err.(*exec.ExitError)
                if !ok {
-                       fifos.SinkCert <- fmt.Sprintf("DENY\t%s\t%s", host, certTheirHash)
+                       fifos.LogCert <- fmt.Sprintf("Reject\t%s\t%s", host, certTheirHash)
                        return ErrRejected{host}
                }
                switch exitError.ExitCode() {
                case 10:
-                       fifos.SinkCert <- fmt.Sprintf("ADD\t%s\t%s", host, certTheirHash)
+                       fifos.LogCert <- fmt.Sprintf("Accept\t%s\t%s", host, certTheirHash)
                        goto CertUpdate
                case 11:
-                       fifos.SinkCert <- fmt.Sprintf("ONCE\t%s\t%s", host, certTheirHash)
-                       acceptedAdd(host, certTheirHash)
+                       fifos.LogCert <- fmt.Sprintf("Once\t%s\t%s", host, certTheirHash)
+                       caches.AcceptedM.Lock()
+                       caches.Accepted[host] = certTheirHash
+                       caches.AcceptedM.Unlock()
                        return nil
                case 12:
-                       rejectedAdd(host, certTheirHash)
+                       caches.RejectedM.Lock()
+                       caches.Rejected[host] = certTheirHash
+                       caches.RejectedM.Unlock()
                        fallthrough
                default:
-                       fifos.SinkCert <- fmt.Sprintf("DENY\t%s\t%s", host, certTheirHash)
+                       fifos.LogCert <- fmt.Sprintf("Reject\t%s\t%s", host, certTheirHash)
                        return ErrRejected{host}
                }
        } else {
                if !os.IsNotExist(err) {
                        return err
                }
-               fifos.SinkCert <- fmt.Sprintf("TOFU\t%s\t%s", host, certTheirHash)
+               fifos.LogCert <- fmt.Sprintf("TOFU\t%s\t%s", host, certTheirHash)
        }
 CertUpdate:
        tmp, err := os.CreateTemp(Certs, "")
@@ -240,6 +231,8 @@ CertUpdate:
        }
        tmp.Close()
        os.Rename(tmp.Name(), fn)
-       acceptedAdd(host, certTheirHash)
+       caches.AcceptedM.Lock()
+       caches.Accepted[host] = certTheirHash
+       caches.AcceptedM.Unlock()
        return nil
 }