diff --git a/assets/index.html b/assets/index.html
index b05ae4f..2f41b55 100644
--- a/assets/index.html
+++ b/assets/index.html
@@ -27,7 +27,7 @@
local |
{{.sourceIP}} |
- N/A |
+ {{.sourceCountry}} |
ip.sb |
diff --git a/go.mod b/go.mod
index a2f3241..e98e720 100644
--- a/go.mod
+++ b/go.mod
@@ -1,3 +1,10 @@
module ip-checker
go 1.22.5
+
+require github.com/oschwald/geoip2-golang v1.11.0
+
+require (
+ github.com/oschwald/maxminddb-golang v1.13.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..060edde
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,14 @@
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w=
+github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo=
+github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU=
+github.com/oschwald/maxminddb-golang v1.13.0/go.mod h1:BU0z8BfFVhi1LQaonTwwGQlsHUEu9pWNdMfmq4ztm0o=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/main.go b/main.go
index a7305a7..e59037e 100644
--- a/main.go
+++ b/main.go
@@ -4,27 +4,47 @@ import (
"fmt"
"html/template"
"log"
+ "net"
"net/http"
"os"
"strings"
+ "sync"
+
+ "github.com/oschwald/geoip2-golang"
+)
+
+var (
+ db *geoip2.Reader
+ tmpl *template.Template
+ config ServerConfig
+ ipCache sync.Map
)
type ServerConfig struct {
- listen string
+ listen string
+ countrydb string
}
func main() {
- config := ServerConfig{
- listen: getEnvOr("IP_CHECKER_LISTEN", ":8080"),
+ config = ServerConfig{
+ listen: getEnvOr("IP_CHECKER_LISTEN", ":8080"),
+ countrydb: os.Getenv("IP_CHECKER_COUNTRY_DB"),
}
- tmpl := template.Must(template.ParseFiles("assets/index.html"))
+ if config.countrydb != "" {
+ var err error
+ db, err = geoip2.Open(config.countrydb)
+ if err != nil {
+ log.Fatalf("Error opening GeoIP database: %v", err)
+ }
+ defer db.Close()
+ }
+
+ tmpl = template.Must(template.ParseFiles("assets/index.html"))
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./assets/static"))))
- http.HandleFunc("/{$}", func(w http.ResponseWriter, r *http.Request) {
- handleRequest(w, r, tmpl)
- })
+ http.HandleFunc("/{$}", handleRequest)
http.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `User-Agent: *
@@ -38,13 +58,33 @@ Disallow: /harm/to/self
log.Fatal(http.ListenAndServe(config.listen, nil))
}
-func handleRequest(w http.ResponseWriter, r *http.Request, tmpl *template.Template) {
+func getIPCountry(ip string) string {
+ if config.countrydb == "" {
+ return "unknown"
+ }
+
+ if country, found := ipCache.Load(ip); found {
+ return country.(string)
+ }
+
+ record, err := db.Country(net.ParseIP(ip))
+ if err != nil {
+ log.Print(err)
+ return "an error occurred"
+ }
+
+ country := record.Country.Names["en"]
+ ipCache.Store(ip, country) // Cache the result
+ return country
+}
+
+func handleRequest(w http.ResponseWriter, r *http.Request) {
sourceIP := func() string {
- if r.Header.Get("CF-Connecting-IP") != "" {
- return r.Header.Get("CF-Connecting-IP")
+ if ip := r.Header.Get("CF-Connecting-IP"); ip != "" {
+ return ip
}
- if r.Header.Get("X-Forwarded-For") != "" {
- return r.Header.Get("X-Forwarded-For")
+ if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
+ return ip
}
return strings.Split(r.RemoteAddr, ":")[0]
}()
@@ -67,7 +107,8 @@ func handleRequest(w http.ResponseWriter, r *http.Request, tmpl *template.Templa
w.Header().Set("Content-Security-Policy", strings.Join(csp, "; "))
data := map[string]string{
- "sourceIP": sourceIP,
+ "sourceIP": sourceIP,
+ "sourceCountry": getIPCountry(sourceIP),
}
err := tmpl.Execute(w, data)