From 992121d5af333f5528aee90fd60b554ded41e641 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Wed, 20 Dec 2023 14:25:58 +0100 Subject: [PATCH] Introduce a discontinued mode --- cmd/log4shell-tools-server/main.go | 191 ++++++++++-------- .../templates/index.html | 21 +- 2 files changed, 115 insertions(+), 97 deletions(-) diff --git a/cmd/log4shell-tools-server/main.go b/cmd/log4shell-tools-server/main.go index ffea76c..96e0651 100644 --- a/cmd/log4shell-tools-server/main.go +++ b/cmd/log4shell-tools-server/main.go @@ -33,6 +33,7 @@ var ( flagHTTPAddr = flag.String("http-addr", "127.0.0.1:8001", "listening address for the HTTP server") flagHTTPAddrExternal = flag.String("http-addr-external", "127.0.0.1:8001", "address where the HTTP server can be reached externally") flagTestTimeout = flag.Int("test-timeout", 30, "test timeout in minutes") + flagDiscontinued = flag.Bool("discontinued", false, "whether this service has been discontinued") testTimeout = time.Duration(*flagTestTimeout) className = "Log4Shell" @@ -56,6 +57,7 @@ type IndexModel struct { DNSZone string ActiveTests int64 Error string + Discontinued bool } type StatsCache struct { @@ -97,66 +99,72 @@ func main() { flag.Parse() testTimeout = time.Minute * time.Duration(*flagTestTimeout) - log.WithField("uri", *flagStorage).Info("Opening storage backend") - var err error - store, err = storage.NewBackend(*flagStorage) - if err != nil { - log.WithError(err).Fatal("Unable to open storage backend") - } - defer store.Close() - statsCache = &StatsCache{store: store} - - go func() { - for { - <-time.After(1 * time.Minute) - - deleted, err := store.PruneTestResults(context.Background()) - if err != nil { - log.WithError(err).Error("Unable to delete old test results") - } else { - log.WithField("count", deleted).Info("Deleted old test results") - } + if !*flagDiscontinued { + log.WithField("uri", *flagStorage).Info("Opening storage backend") + var err error + store, err = storage.NewBackend(*flagStorage) + if err != nil { + log.WithError(err).Fatal("Unable to open storage backend") } - }() + defer store.Close() + statsCache = &StatsCache{store: store} - ldapServer := NewLDAPServer(store) - go func() { - log.WithFields(log.Fields{ - "addr": *flagLDAPAddr, - "addr_ext": *flagLDAPAddrExternal, - }).Info("Starting LDAP server") - - if err := ldapServer.ListenAndServe(*flagLDAPAddr); err != nil { - log.WithError(err).Fatal("Unable to run LDAP server") - } - }() - - if *flagDNSEnable { - dnsServer := NewDNSServer(store, DNSServerOpts{ - Addr: *flagDNSAddr, - Zone: *flagDNSZone, - A: *flagDNSA, - AAAA: *flagDNSAAAA, - }) + go func() { + for { + <-time.After(1 * time.Minute) + + deleted, err := store.PruneTestResults(context.Background()) + if err != nil { + log.WithError(err).Error("Unable to delete old test results") + } else { + log.WithField("count", deleted).Info("Deleted old test results") + } + } + }() + ldapServer := NewLDAPServer(store) go func() { log.WithFields(log.Fields{ - "addr": *flagDNSAddr, - }).Info("Starting DNS server") + "addr": *flagLDAPAddr, + "addr_ext": *flagLDAPAddrExternal, + }).Info("Starting LDAP server") - if err := dnsServer.ListenAndServe(); err != nil { - log.WithError(err).Fatal("Unable to run DNS server") + if err := ldapServer.ListenAndServe(*flagLDAPAddr); err != nil { + log.WithError(err).Fatal("Unable to run LDAP server") } }() + + if *flagDNSEnable { + dnsServer := NewDNSServer(store, DNSServerOpts{ + Addr: *flagDNSAddr, + Zone: *flagDNSZone, + A: *flagDNSA, + AAAA: *flagDNSAAAA, + }) + + go func() { + log.WithFields(log.Fields{ + "addr": *flagDNSAddr, + }).Info("Starting DNS server") + + if err := dnsServer.ListenAndServe(); err != nil { + log.WithError(err).Fatal("Unable to run DNS server") + } + }() + } + } else { + log.Warn("Running in discontinued mode") } - promHandler := promhttp.Handler() router := httprouter.New() router.GET("/", handleIndex) - router.GET("/metrics", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { - promHandler.ServeHTTP(w, r) - }) - router.GET(fmt.Sprintf("/api/tests/:uuid/payload/%s.class", className), handleTestPayloadDownload) + if !*flagDiscontinued { + promHandler := promhttp.Handler() + router.GET("/metrics", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + promHandler.ServeHTTP(w, r) + }) + router.GET(fmt.Sprintf("/api/tests/:uuid/payload/%s.class", className), handleTestPayloadDownload) + } log.WithFields(log.Fields{ "addr": *flagHTTPAddr, @@ -169,13 +177,18 @@ func main() { } func handleIndex(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + var activeTests int64 + if !*flagDiscontinued { + activeTests = statsCache.getActiveTests(r.Context()) + } model := IndexModel{ Context: r.Context(), - ActiveTests: statsCache.getActiveTests(r.Context()), + ActiveTests: activeTests, AddrLDAP: *flagLDAPAddr, AddrLDAPExternal: *flagLDAPAddrExternal, DNSEnabled: *flagDNSEnable, DNSZone: *flagDNSZone, + Discontinued: *flagDiscontinued, } ctxLog := log.WithFields(log.Fields{ "server": "http", @@ -183,50 +196,54 @@ func handleIndex(w http.ResponseWriter, r *http.Request, p httprouter.Params) { "req": r.URL.Path, }) - idString := r.URL.Query().Get("uuid") - if idString != "" { - var err error - if model.UUID, err = uuid.Parse(idString); err != nil { - ctxLog.WithField("id", idString).WithError(err).Error("Unable to parse UUID") - writeHttpError(w, http.StatusBadRequest) - return - } - ctxLog = ctxLog.WithField("test", model.UUID) + if !*flagDiscontinued { + idString := r.URL.Query().Get("uuid") + if idString != "" { + var err error + if model.UUID, err = uuid.Parse(idString); err != nil { + ctxLog.WithField("id", idString).WithError(err).Error("Unable to parse UUID") + writeHttpError(w, http.StatusBadRequest) + return + } + ctxLog = ctxLog.WithField("test", model.UUID) - model.Test, err = store.Test(r.Context(), model.UUID) - if err != nil { - ctxLog.WithError(err).Error("Unable to lookup test in storage") - writeHttpError(w, http.StatusInternalServerError) - return - } - if model.Test == nil { - if r.URL.Query().Get("terms") != "y" { - model.Error = "You cannot continue before agreeing to only testing on machines that you have permission to test on." - } else { - ctxLog.Info("Inserting new test") - - if err := store.InsertTest(r.Context(), model.UUID); err != nil { - ctxLog.WithError(err).Error("Unable to insert new test") - writeHttpError(w, http.StatusInternalServerError) - return - } - if model.Test, err = store.Test(r.Context(), model.UUID); err != nil { - ctxLog.WithError(err).Error("Unable to lookup test in storage") - writeHttpError(w, http.StatusInternalServerError) - return - } - if model.Test == nil { - ctxLog.Error("Unable to obtain test right after insert") - writeHttpError(w, http.StatusInternalServerError) - return + model.Test, err = store.Test(r.Context(), model.UUID) + if err != nil { + ctxLog.WithError(err).Error("Unable to lookup test in storage") + writeHttpError(w, http.StatusInternalServerError) + return + } + if model.Test == nil { + if r.URL.Query().Get("terms") != "y" { + model.Error = "You cannot continue before agreeing to only testing on machines that you have permission to test on." + } else { + ctxLog.Info("Inserting new test") + + if err := store.InsertTest(r.Context(), model.UUID); err != nil { + ctxLog.WithError(err).Error("Unable to insert new test") + writeHttpError(w, http.StatusInternalServerError) + return + } + if model.Test, err = store.Test(r.Context(), model.UUID); err != nil { + ctxLog.WithError(err).Error("Unable to lookup test in storage") + writeHttpError(w, http.StatusInternalServerError) + return + } + if model.Test == nil { + ctxLog.Error("Unable to obtain test right after insert") + writeHttpError(w, http.StatusInternalServerError) + return + } + + counterTestsCreated.Inc() } - - counterTestsCreated.Inc() } + } else { + model.New = true + model.UUID = uuid.New() } } else { model.New = true - model.UUID = uuid.New() } var buf bytes.Buffer diff --git a/cmd/log4shell-tools-server/templates/index.html b/cmd/log4shell-tools-server/templates/index.html index 12dd71a..4677502 100644 --- a/cmd/log4shell-tools-server/templates/index.html +++ b/cmd/log4shell-tools-server/templates/index.html @@ -59,15 +59,16 @@

Log4Shell Vulnerabilit {{ if gt .ActiveTests 0 }} ({{ .ActiveTests }} tests currently active) {{ end }} - + {{ if .Discontinued }} + + {{ end }}

This tool allows you to run a test to check whether one of your applications is affected by the recent vulnerabilities in log4j: @@ -100,7 +101,7 @@

Log4Shell Vulnerabilit I'm testing a device that I personally own, or a device for which I have permission from the owner to run this test - +