From cb0d759766dd7183adc00f097760fc82ff2796d0 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Wed, 8 Sep 2021 12:14:58 +0300 Subject: [PATCH] Another refactor --- .gitignore | 3 +- all.do | 2 +- cert.pem.do | 4 +- cert.tmpl | 4 - cmd/certgen/main.go | 95 +++++++++++++++++++ cmd/tofuproxy/main.go | 2 +- default.cmd.do | 3 + doc/usage.texi | 4 +- fifos/ensure.do | 2 +- fifos/fifos.go | 2 + fifos/multitail.sh | 1 + prv.pem.do | 2 - rounds/10log.go | 35 ------- rounds/{35denyFonts.go => denyFonts.go} | 0 rounds/{25habrImage.go => habrImage.go} | 0 rounds/{05noHead.go => noHead.go} | 0 rounds/{20reddit.go => reddit.go} | 0 rounds/{50redirectHTML.go => redirectHTML.go} | 0 rounds/{15spy.go => spy.go} | 30 +++--- .../{45transcodeAVIF.go => transcodeAVIF.go} | 0 rounds/{45transcodeJXL.go => transcodeJXL.go} | 0 .../{40transcodeWebP.go => transcodeWebP.go} | 0 trip.go | 2 +- verify.go | 6 +- 24 files changed, 133 insertions(+), 64 deletions(-) delete mode 100644 cert.tmpl create mode 100644 cmd/certgen/main.go create mode 100644 default.cmd.do delete mode 100644 prv.pem.do delete mode 100644 rounds/10log.go rename rounds/{35denyFonts.go => denyFonts.go} (100%) rename rounds/{25habrImage.go => habrImage.go} (100%) rename rounds/{05noHead.go => noHead.go} (100%) rename rounds/{20reddit.go => reddit.go} (100%) rename rounds/{50redirectHTML.go => redirectHTML.go} (100%) rename rounds/{15spy.go => spy.go} (82%) rename rounds/{45transcodeAVIF.go => transcodeAVIF.go} (100%) rename rounds/{45transcodeJXL.go => transcodeJXL.go} (100%) rename rounds/{40transcodeWebP.go => transcodeWebP.go} (100%) diff --git a/.gitignore b/.gitignore index 7902b80..1132f68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /cert.pem +/certgen.cmd /certs /prv.pem -/tofuproxy +/tofuproxy.cmd diff --git a/all.do b/all.do index 7288dc0..fbac54c 100644 --- a/all.do +++ b/all.do @@ -1,2 +1,2 @@ -redo-ifchange cert.pem tofuproxy fifos/ensure +redo-ifchange cert.pem tofuproxy.cmd fifos/ensure mkdir -p certs diff --git a/cert.pem.do b/cert.pem.do index 09c82a3..f50920a 100644 --- a/cert.pem.do +++ b/cert.pem.do @@ -1,2 +1,2 @@ -redo-ifchange prv.pem cert.tmpl -certtool --generate-self-signed --load-privkey prv.pem --template cert.tmpl +[ -e certgen.cmd ] || redo certgen.cmd +./certgen.cmd -cert $3 diff --git a/cert.tmpl b/cert.tmpl deleted file mode 100644 index 3b4a452..0000000 --- a/cert.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -dn = "cn=tofu.localhost" -expiration_days = 365 -ca -cert_signing_key diff --git a/cmd/certgen/main.go b/cmd/certgen/main.go new file mode 100644 index 0000000..f4a0d97 --- /dev/null +++ b/cmd/certgen/main.go @@ -0,0 +1,95 @@ +/* +tofuproxy -- HTTP proxy with TLS certificates management +Copyright (C) 2021 Sergey Matveev + +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 . +*/ + +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "flag" + "io" + "log" + "math/big" + "os" + "time" +) + +func main() { + cn := flag.String("cn", "tofuproxy.localhost", "CommonName") + crtPath := flag.String("cert", "cert.pem", "Path to server X.509 certificate") + prvPath := flag.String("key", "prv.pem", "Path to server PKCS#8 private key") + flag.Parse() + log.SetFlags(log.Lshortfile) + + prv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + log.Fatalln(err) + } + pub := prv.Public() + notBefore := time.Now() + notAfter := notBefore.Add(365 * 24 * time.Hour) + + serialRaw := make([]byte, 16) + if _, err = io.ReadFull(rand.Reader, serialRaw); err != nil { + log.Fatalln(err) + } + serial := big.NewInt(0) + serial = serial.SetBytes(serialRaw) + + template := x509.Certificate{ + SerialNumber: serial, + Subject: pkix.Name{CommonName: *cn}, + DNSNames: []string{*cn}, + NotBefore: notBefore, + NotAfter: notAfter, + BasicConstraintsValid: true, + IsCA: true, + } + certRaw, err := x509.CreateCertificate( + rand.Reader, &template, &template, pub, prv, + ) + if err != nil { + log.Fatalln(err) + } + if _, err = x509.ParseCertificate(certRaw); err != nil { + log.Fatalln(err) + } + pkcs8, err := x509.MarshalPKCS8PrivateKey(prv) + if err != nil { + log.Fatalln(err) + } + + fd, err := os.OpenFile(*prvPath, os.O_WRONLY|os.O_CREATE, 0600) + if err != nil { + log.Fatalln(err) + } + err = pem.Encode(fd, &pem.Block{Type: "PRIVATE KEY", Bytes: pkcs8}) + if err != nil { + log.Fatalln(err) + } + fd.Close() + + fd, err = os.OpenFile(*crtPath, os.O_WRONLY|os.O_CREATE, 0600) + err = pem.Encode(fd, &pem.Block{Type: "CERTIFICATE", Bytes: certRaw}) + if err != nil { + log.Fatalln(err) + } +} diff --git a/cmd/tofuproxy/main.go b/cmd/tofuproxy/main.go index 5ad6e62..5335ffb 100644 --- a/cmd/tofuproxy/main.go +++ b/cmd/tofuproxy/main.go @@ -32,7 +32,7 @@ func main() { crtPath := flag.String("cert", "cert.pem", "Path to server X.509 certificate") prvPath := flag.String("key", "prv.pem", "Path to server PKCS#8 private key") bind := flag.String("bind", "[::1]:8080", "Bind address") - certs := flag.String("certs", "certs", "Directory with pinned certificates") + certs := flag.String("certs", "./certs", "Directory with pinned certificates") dnsSrv := flag.String("dns", "[::1]:53", "DNS server") fifosDir := flag.String("fifos", "fifos", "Directory with FIFOs") notai := flag.Bool("notai", false, "Do not prepend TAI64N to logs") diff --git a/default.cmd.do b/default.cmd.do new file mode 100644 index 0000000..d15196b --- /dev/null +++ b/default.cmd.do @@ -0,0 +1,3 @@ +redo-ifchange *.go cmd/*/*.go fifos/*.go rounds/*.go +GO_LDFLAGS="${GO_LDFLAGS:--ldflags=-s}" +${GO:-go} build -o $3 $GO_LDFLAGS ./cmd/${1%.cmd} diff --git a/doc/usage.texi b/doc/usage.texi index 6965994..8cfbb06 100644 --- a/doc/usage.texi +++ b/doc/usage.texi @@ -36,8 +36,8 @@ Run @command{tofuproxy} itself. By default it will bind to (set to an empty string to disable DANE lookups): @example -$ ./tofuproxy -main.go:316: listening: [::1]:8080 +$ ./tofuproxy.cmd +main.go:316: listening: [::1]:8080 certs: ./certs @end example @item Trust your newly generated CA: diff --git a/fifos/ensure.do b/fifos/ensure.do index 682d687..7aa937b 100644 --- a/fifos/ensure.do +++ b/fifos/ensure.do @@ -1,3 +1,3 @@ -for f in cert err ok other redir req tls ; do +for f in cert dane err ok other redir req tls ; do [ -p $f ] || mkfifo $f done diff --git a/fifos/fifos.go b/fifos/fifos.go index 6e78096..61f0f63 100644 --- a/fifos/fifos.go +++ b/fifos/fifos.go @@ -30,6 +30,7 @@ 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) @@ -63,6 +64,7 @@ func sinker(c chan string, p string) { 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")) diff --git a/fifos/multitail.sh b/fifos/multitail.sh index e6f29fb..8a8ccee 100755 --- a/fifos/multitail.sh +++ b/fifos/multitail.sh @@ -3,6 +3,7 @@ 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" \ diff --git a/prv.pem.do b/prv.pem.do deleted file mode 100644 index c14af89..0000000 --- a/prv.pem.do +++ /dev/null @@ -1,2 +0,0 @@ -umask 077 -certtool --generate-privkey --bits 256 --ecc > $3 diff --git a/rounds/10log.go b/rounds/10log.go deleted file mode 100644 index 135394d..0000000 --- a/rounds/10log.go +++ /dev/null @@ -1,35 +0,0 @@ -/* -tofuproxy -- HTTP proxy with TLS certificates management -Copyright (C) 2021 Sergey Matveev - -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 . -*/ - -package rounds - -import ( - "fmt" - "net/http" - - "go.stargrave.org/tofuproxy/fifos" -) - -func RoundLog( - host string, - resp *http.Response, - w http.ResponseWriter, - req *http.Request, -) (bool, error) { - fifos.SinkReq <- fmt.Sprintf("%s %s", req.Method, req.URL.String()) - return true, nil -} diff --git a/rounds/35denyFonts.go b/rounds/denyFonts.go similarity index 100% rename from rounds/35denyFonts.go rename to rounds/denyFonts.go diff --git a/rounds/25habrImage.go b/rounds/habrImage.go similarity index 100% rename from rounds/25habrImage.go rename to rounds/habrImage.go diff --git a/rounds/05noHead.go b/rounds/noHead.go similarity index 100% rename from rounds/05noHead.go rename to rounds/noHead.go diff --git a/rounds/20reddit.go b/rounds/reddit.go similarity index 100% rename from rounds/20reddit.go rename to rounds/reddit.go diff --git a/rounds/50redirectHTML.go b/rounds/redirectHTML.go similarity index 100% rename from rounds/50redirectHTML.go rename to rounds/redirectHTML.go diff --git a/rounds/15spy.go b/rounds/spy.go similarity index 82% rename from rounds/15spy.go rename to rounds/spy.go index 42ebd9e..3b242f8 100644 --- a/rounds/15spy.go +++ b/rounds/spy.go @@ -29,6 +29,7 @@ var spyDomains = []string{ "google-analytics.com", "goo.gl", "ads.google.com", + "googletagmanager.com", "facebook.com", "facebook.net", "fbcdn.com", @@ -44,23 +45,30 @@ var spyDomains = []string{ "tns-counter.ru", } +func IsSpy(host string) bool { + for _, spy := range spyDomains { + if strings.HasSuffix(host, spy) { + return true + } + } + return false +} + func RoundDenySpy( host string, resp *http.Response, w http.ResponseWriter, req *http.Request, ) (bool, error) { - for _, spy := range spyDomains { - if strings.HasSuffix(host, spy) { - http.NotFound(w, req) - fifos.SinkOther <- fmt.Sprintf( - "%s %s\t%d\tdeny spy", - req.Method, - req.URL.String(), - http.StatusNotFound, - ) - return false, nil - } + if IsSpy(host) { + http.NotFound(w, req) + fifos.SinkOther <- fmt.Sprintf( + "%s %s\t%d\tdeny spy", + req.Method, + req.URL.String(), + http.StatusNotFound, + ) + return false, nil } return true, nil } diff --git a/rounds/45transcodeAVIF.go b/rounds/transcodeAVIF.go similarity index 100% rename from rounds/45transcodeAVIF.go rename to rounds/transcodeAVIF.go diff --git a/rounds/45transcodeJXL.go b/rounds/transcodeJXL.go similarity index 100% rename from rounds/45transcodeJXL.go rename to rounds/transcodeJXL.go diff --git a/rounds/40transcodeWebP.go b/rounds/transcodeWebP.go similarity index 100% rename from rounds/40transcodeWebP.go rename to rounds/transcodeWebP.go diff --git a/trip.go b/trip.go index 27d4e9e..3ad6eb1 100644 --- a/trip.go +++ b/trip.go @@ -58,10 +58,10 @@ type Round func( ) (bool, error) func roundTrip(w http.ResponseWriter, req *http.Request) { + fifos.SinkReq <- fmt.Sprintf("%s %s", req.Method, req.URL.String()) host := strings.TrimSuffix(req.URL.Host, ":443") for _, round := range []Round{ rounds.RoundNoHead, - rounds.RoundLog, rounds.RoundDenySpy, rounds.RoundRedditOld, rounds.RoundHabrImage, diff --git a/verify.go b/verify.go index 4c20c0e..b2eb606 100644 --- a/verify.go +++ b/verify.go @@ -123,9 +123,9 @@ func verifyCert( daneExists, daneMatched := dane(host, certTheir) if daneExists { if daneMatched { - fifos.SinkCert <- fmt.Sprintf("DANE\t%s\tmatched", host) + fifos.SinkDANE <- fmt.Sprintf("%s\tmatched", host) } else { - fifos.SinkErr <- fmt.Sprintf("DANE\t%s\tnot matched", host) + fifos.SinkDANE <- fmt.Sprintf("%s\tNOT matched", host) } } fn := filepath.Join(Certs, host) @@ -154,7 +154,7 @@ $tErr configure -wrap word -height 5 if daneMatched { b.WriteString("label .lDANE -bg green -text \"DANE matched\"\n") } else { - b.WriteString("label .lDANE -bg red -text \"DANE not matched!\"\n") + b.WriteString("label .lDANE -bg red -text \"DANE NOT matched\"\n") } b.WriteString("grid .lDANE\n") } -- 2.44.0