diff --git a/cmd/check-ip/main.go b/cmd/check-ip/main.go index b7ff6f4..8f390bc 100644 --- a/cmd/check-ip/main.go +++ b/cmd/check-ip/main.go @@ -36,13 +36,13 @@ var webFS embed.FS // Replaced by goreleaser / ldflags at build time. var ( - name = "check-ip" - version = "0.0.0-dev" - commit = "0000000" - date = "0001-01-01" - licenseYear = "2026" + name = "check-ip" + version = "0.0.0-dev" + commit = "0000000" + date = "0001-01-01" + licenseYear = "2026" licenseOwner = "AJ ONeal" - licenseType = "MPL-2.0" + licenseType = "MPL-2.0" ) // versionFromGit returns a tag scoped to this subdirectory, falling back to a short commit hash. @@ -316,10 +316,15 @@ func main() { tGeo := time.Now() if err := geoSet.Load(context.Background()); err != nil { fmt.Fprintln(os.Stderr) - log.Fatalf("geoip: %v", err) + log.Printf("geoip unavailable: %v", err) + } else { + fmt.Fprintf(os.Stderr, "%s\n", time.Since(tGeo).Round(time.Millisecond)) } - fmt.Fprintf(os.Stderr, "%s\n", time.Since(tGeo).Round(time.Millisecond)) - defer func() { _ = cfg.geo.Value().Close() }() + defer func() { + if databases := cfg.geo.Value(); databases != nil { + _ = databases.Close() + } + }() // Whitelist: combined IPs + CIDRs in one file, polled for mtime changes. // A match here overrides any block decision from the blocklists. diff --git a/cmd/check-ip/server.go b/cmd/check-ip/server.go index 2eeac02..c22f589 100644 --- a/cmd/check-ip/server.go +++ b/cmd/check-ip/server.go @@ -34,7 +34,10 @@ type Result struct { // lookup builds a Result for ip against the currently loaded blocklists // and GeoIP databases. func (c *IPCheck) lookup(ip string) Result { - res := Result{IP: ip, Geo: c.geo.Value().Lookup(ip)} + res := Result{IP: ip} + if databases := c.geo.Value(); databases != nil { + res.Geo = databases.Lookup(ip) + } addr, err := netip.ParseAddr(ip) if err != nil { res.Blocked = true @@ -54,12 +57,18 @@ func (c *IPCheck) lookup(ip string) Result { // lookupRaw returns the raw geoip.Info for an IP. func (c *IPCheck) lookupRaw(ip string) geoip.Info { - return c.geo.Value().Lookup(ip) + if databases := c.geo.Value(); databases != nil { + return databases.Lookup(ip) + } + return geoip.Info{} } // lookupRawCity returns the raw *geoip2.City record for an IP. func (c *IPCheck) lookupRawCity(ip string) *geoip2.City { - return c.geo.Value().LookupRaw(ip) + if databases := c.geo.Value(); databases != nil { + return databases.LookupRaw(ip) + } + return nil } // writePretty renders res as space-aligned plain text. @@ -172,8 +181,8 @@ type dsStatus struct { } // healthz reports per-dataset load state and an overall ready flag. -// Returns 200 when all required sets (inbound, outbound, geoip) are -// loaded, 503 while any are still empty. +// Returns 200 when the blocklist sets are loaded. GeoIP is optional and may +// be unavailable while blocklist checks continue to work. func (c *IPCheck) healthz(w http.ResponseWriter, _ *http.Request) { cohortStatus := func(v *dataset.View[ipcohort.Cohort]) dsStatus { s := dsStatus{LoadedAt: v.LoadedAt()} @@ -195,7 +204,7 @@ func (c *IPCheck) healthz(w http.ResponseWriter, _ *http.Request) { datasets["whitelist"] = cohortStatus(c.whitelist) } - ready := datasets["inbound"].Loaded && datasets["outbound"].Loaded && datasets["geoip"].Loaded + ready := datasets["inbound"].Loaded && datasets["outbound"].Loaded resp := struct { Ready bool `json:"ready"` Version string `json:"version"`