/
GeoUtil.go
186 lines (154 loc) · 4.69 KB
/
GeoUtil.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package util
import (
"bytes"
"errors"
"fmt"
"github.com/oschwald/maxminddb-golang"
"io"
"log"
"net"
"net/http"
"os"
"path/filepath"
"time"
)
//var maxMindGeoDB []geoLiteEntry
type Asc []geoLiteEntry
func (s Asc) Len() int {
return len(s)
}
func (s Asc) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s Asc) Less(i, j int) bool {
return bytes.Compare(s[i].network.IP, s[j].network.IP) == -1
}
const GEODB_FOLDER = "geodb"
const MAXMIND_GEO_DB_ZIP_FILE_NAME = "GeoLite2-Country.mmdb.gz"
const MAXMIND_GEO_DB_FILE_NAME = "GeoLite2-Country.mmdb"
//const MAXMIND_GEO_DB_COUNTRY_CODES_FILE_NAME = "GeoLite2-Country-Locations-en.csv"
const MAXMIND_GEOIP_URL = "http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz"
var countries map[string]countryEntry
var maxMindGeoDB *maxminddb.Reader
type countryEntry struct {
countryCode string
continentCode string
}
type geoLiteEntry struct {
network *net.IPNet
firstIP string
lastIP string
registeredCountryCode string
geolocationCountryCode string
registeredContinentCode string
geolocationContinentCode string
}
func (c geoLiteEntry) String() string {
return fmt.Sprintf("Network: %s, Continent: %s,Last IP: %s, First IP: %s", c.network, c.registeredContinentCode, c.lastIP, c.firstIP)
}
type GeoData struct {
RegisteredCountryCode string `json:"RegCountry" maxminddb:"iso_code"`
GeolocationCountryCode string `json:"GeoCountry"`
Continent string `json:"Continent"`
}
type geoData struct {
RegisteredCountry struct {
ISOCode string `maxminddb:"iso_code"`
} `maxminddb:"registered_country"`
GeolocationCountry struct {
ISOCode string `maxminddb:"iso_code"`
} `maxminddb:"country"`
Continent struct {
ISOCode string `maxminddb:"code"`
} `maxminddb:"continent"`
}
func (c geoData) String() string {
return fmt.Sprintf("registered country %s, geolocation country: %s, continent: %s", c.RegisteredCountry.ISOCode,
c.GeolocationCountry.ISOCode, c.Continent.ISOCode)
}
func GeoUtilInitialise() {
defer TimeTrack(time.Now(), "Initialising GeoDB")
if !CheckPathExist(GEODB_FOLDER) {
err := os.MkdirAll(GEODB_FOLDER, FILE_ACCESS_PERMISSION)
Check(err)
}
geoFileFilePath := filepath.Join(GEODB_FOLDER, MAXMIND_GEO_DB_FILE_NAME)
geoFileZipFilePath := filepath.Join(GEODB_FOLDER, MAXMIND_GEO_DB_ZIP_FILE_NAME)
if !CheckPathExist(geoFileFilePath) {
downloadMaxMindGeoLite()
err := Ungzip(geoFileZipFilePath, GEODB_FOLDER)
Check(err)
maxMindCleanUp()
} else {
info, err := os.Stat(geoFileFilePath)
Check(err)
dateFile := time.Date(info.ModTime().Year(), info.ModTime().Month(), info.ModTime().Day(), 0, 0, 0, 0, time.UTC)
dateNewFileAvailable := time.Date(time.Now().Year(), time.Now().Month(), firstTuesdayOfMonth(time.Now().Month()), 0, 0, 0, 0, time.UTC)
if dateFile.Before(dateNewFileAvailable) && time.Now().After(dateNewFileAvailable) {
os.Remove(geoFileFilePath)
downloadMaxMindGeoLite()
err := Ungzip(geoFileZipFilePath, GEODB_FOLDER)
Check(err)
maxMindCleanUp()
}
}
var err error
maxMindGeoDB, err = maxminddb.Open(geoFileFilePath)
if err != nil {
log.Fatal(err)
}
}
func GeoUtilShutdown() {
defer TimeTrack(time.Now(), "Shuting down GeoDB")
maxMindGeoDB.Close()
}
func maxMindCleanUp() {
geoFileZipFilePath := filepath.Join(GEODB_FOLDER, MAXMIND_GEO_DB_ZIP_FILE_NAME)
os.Remove(geoFileZipFilePath)
d, err := os.Open(GEODB_FOLDER)
Check(err)
defer d.Close()
names, err := d.Readdirnames(-1)
Check(err)
for _, name := range names {
if name != MAXMIND_GEO_DB_FILE_NAME {
err := os.Remove(filepath.Join(GEODB_FOLDER, name))
Check(err)
}
}
}
func FindGeoData(ip string) GeoData {
if maxMindGeoDB == nil {
panic(errors.New("GeoDB(s) have not been initialised! Initialise first."))
}
registeredCountryCode := "Not found"
geolocationCountryCode := "Not found"
continent := "Not found"
ipToCheck := net.ParseIP(ip)
if ipToCheck.To4() == nil {
log.Print(errors.New(fmt.Sprintf("%v is not an IPv4 address\n", ipToCheck)))
} else {
var geoData geoData
err := maxMindGeoDB.Lookup(ipToCheck, &geoData)
if err != nil {
log.Fatal(err)
} else {
registeredCountryCode = geoData.RegisteredCountry.ISOCode
geolocationCountryCode = geoData.GeolocationCountry.ISOCode
continent = geoData.Continent.ISOCode
}
}
return GeoData{registeredCountryCode, geolocationCountryCode,
continent}
}
func downloadMaxMindGeoLite() {
geoFileZipFilePath := filepath.Join(GEODB_FOLDER, MAXMIND_GEO_DB_ZIP_FILE_NAME)
out, err := os.Create(geoFileZipFilePath)
defer out.Close()
Check(err)
resp, err1 := http.Get(MAXMIND_GEOIP_URL)
defer resp.Body.Close()
Check(err1)
_, err2 := io.Copy(out, resp.Body)
Check(err2)
}