diff --git a/.gitignore b/.gitignore index 9fc6773..5187ffb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ results.txt in.txt out.txt out.csv +Country.mmdb diff --git a/README.md b/README.md index 7c19bbf..d6a1aaa 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,14 @@ It is recommended to run this tool locally, as running the scanner in the cloud ./RealiTLScanner -addr 107.172.1.1/16 -timeout 5 ``` +### Enable Geo IP + +To enable Geo IP information, place a MaxMind GeoLite2/GeoIP2 Country Database in the executing folder with the exact name `Country.mmdb`. You can download one from [here](https://github.com/Loyalsoldier/geoip/releases/latest/download/Country.mmdb). + +## Demo + Example stdout: + ```bash 2024/02/08 20:51:10 INFO Started all scanning threads time=2024-02-08T20:51:10.017+08:00 2024/02/08 20:51:10 INFO Connected to target feasible=true host=107.172.103.9 tls=1.3 alpn=h2 domain=rocky-linux.tk issuer="Let's Encrypt" @@ -57,16 +64,16 @@ Example stdout: Example output file: ```csv -IP,ORIGIN,CERT_DOMAIN,CERT_ISSUER -52.140.219.235,www.cherryservers.com,*.cherryservers.com,"GlobalSign nv-sa" -172.66.40.234,veesp.com,veesp.com,"Cloudflare, Inc." -172.66.43.22,veesp.com,veesp.com,"Cloudflare, Inc." -193.1.193.205,www.heanet.ie,www.heanet.ie,"GEANT Vereniging" -185.242.104.18,mirror.veesp.com,mirror.veesp.com,"Let's Encrypt" -79.98.24.240,www.serveriai.lt,*.serveriai.lt,"Sectigo Limited" -91.211.244.3,www.vpsnet.com,*.vpsnet.com,"Sectigo Limited" -31.131.0.101,www.ihost.md,ihost.md,"Sectigo Limited" -194.127.172.131,nl.mirrors.clouvider.net,nl.mirrors.clouvider.net,"Let's Encrypt" -31.131.0.222,mirror.ihost.md,mirror.ihost.md,"Let's Encrypt" +IP,ORIGIN,CERT_DOMAIN,CERT_ISSUER,GEO_CODE +202.70.64.2,ntc.net.np,*.ntc.net.np,"GlobalSign nv-sa",NP +196.200.160.70,mirror.marwan.ma,mirror.marwan.ma,"Let's Encrypt",MA +103.194.167.213,mirror.i3d.net,*.i3d.net,"Sectigo Limited",JP +194.127.172.131,nl.mirrors.clouvider.net,nl.mirrors.clouvider.net,"Let's Encrypt",NL +202.36.220.86,mirror.2degrees.nz,mirror.2degrees.nz,"Let's Encrypt",NZ +202.36.220.86,ubuntu.mirrors.theom.nz,mirror.2degrees.nz,"Let's Encrypt",NZ +158.37.28.65,ubuntu.hi.no,alma.hi.no,"Let's Encrypt",NO +193.136.164.6,ftp.rnl.tecnico.ulisboa.pt,ftp.rnl.ist.utl.pt,"Let's Encrypt",PT +75.2.60.5,cesium.di.uminho.pt,cesium.di.uminho.pt,"Let's Encrypt",US +195.14.50.21,mirror.corbina.net,ftp.corbina.net,"Let's Encrypt",RU ``` diff --git a/geo.go b/geo.go new file mode 100644 index 0000000..d5e9c67 --- /dev/null +++ b/geo.go @@ -0,0 +1,41 @@ +package main + +import ( + "github.com/oschwald/geoip2-golang" + "log/slog" + "net" + "sync" +) + +type Geo struct { + geoReader *geoip2.Reader + mu sync.Mutex +} + +func NewGeo() *Geo { + geo := &Geo{ + mu: sync.Mutex{}, + } + reader, err := geoip2.Open("Country.mmdb") + if err != nil { + slog.Warn("Cannot open Country.mmdb") + return geo + } + slog.Info("Enabled GeoIP") + geo.geoReader = reader + return geo +} + +func (o *Geo) GetGeo(ip net.IP) string { + if o.geoReader == nil { + return "N/A" + } + o.mu.Lock() + defer o.mu.Unlock() + country, err := o.geoReader.Country(ip) + if err != nil { + slog.Debug("Error reading geo", "err", err) + return "N/A" + } + return country.Country.IsoCode +} diff --git a/go.mod b/go.mod index c58f0aa..365f4a9 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,10 @@ module github.com/xtls/RealiTLScanner go 1.21 + +require github.com/oschwald/geoip2-golang v1.9.0 + +require ( + github.com/oschwald/maxminddb-golang v1.12.0 // indirect + golang.org/x/sys v0.17.0 // indirect +) diff --git a/go.sum b/go.sum index e69de29..6c55e68 100644 --- a/go.sum +++ 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.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= +github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= +github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= +github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= +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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.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 df7673e..a7c77ea 100644 --- a/main.go +++ b/main.go @@ -61,7 +61,7 @@ func main() { return } defer f.Close() - _, _ = f.WriteString("IP,ORIGIN,CERT_DOMAIN,CERT_ISSUER\n") + _, _ = f.WriteString("IP,ORIGIN,CERT_DOMAIN,CERT_ISSUER,GEO_CODE\n") outWriter = f } var hostChan <-chan Host @@ -99,12 +99,13 @@ func main() { } outCh := OutWriter(outWriter) defer close(outCh) + geo := NewGeo() var wg sync.WaitGroup wg.Add(thread) for i := 0; i < thread; i++ { go func() { for ip := range hostChan { - ScanTLS(ip, outCh) + ScanTLS(ip, outCh, geo) } wg.Done() }() diff --git a/scanner.go b/scanner.go index b541f94..b2d2dc9 100644 --- a/scanner.go +++ b/scanner.go @@ -9,7 +9,7 @@ import ( "time" ) -func ScanTLS(host Host, out chan<- string) { +func ScanTLS(host Host, out chan<- string, geo *Geo) { if host.IP == nil { ip, err := LookupIP(host.Origin) if err != nil { @@ -50,14 +50,17 @@ func ScanTLS(host Host, out chan<- string) { issuers := strings.Join(state.PeerCertificates[0].Issuer.Organization, " | ") log := slog.Info feasible := true + geoCode := geo.GetGeo(host.IP) if state.Version != tls.VersionTLS13 || alpn != "h2" || len(domain) == 0 || len(issuers) == 0 { // not feasible log = slog.Debug feasible = false } else { - out <- strings.Join([]string{host.IP.String(), host.Origin, domain, "\"" + issuers + "\""}, ",") + "\n" + out <- strings.Join([]string{host.IP.String(), host.Origin, domain, "\"" + issuers + "\"", geoCode}, ",") + + "\n" } log("Connected to target", "feasible", feasible, "ip", host.IP.String(), "origin", host.Origin, - "tls", tls.VersionName(state.Version), "alpn", alpn, "cert-domain", domain, "cert-issuer", issuers) + "tls", tls.VersionName(state.Version), "alpn", alpn, "cert-domain", domain, "cert-issuer", issuers, + "geo", geoCode) }