package util import ( "encoding/json" "io/ioutil" "net/http" "strings" "time" "github.com/naiba/nezha/pkg/utils" ) type geoIP struct { CountryCode string `json:"country_code,omitempty"` IP string `json:"ip,omitempty"` Query string `json:"query,omitempty"` } var ( geoIPApiList = []string{ "https://api.ip.sb/geoip", "https://ip.seeip.org/geoip", "https://ipapi.co/json", "https://freegeoip.app/json/", "http://ip-api.com/json/", "https://extreme-ip-lookup.com/json/", } cachedIP, cachedCountry string httpClientV4 = utils.NewSingleStackHTTPClient(time.Second*20, time.Second*5, time.Second*10, false) httpClientV6 = utils.NewSingleStackHTTPClient(time.Second*20, time.Second*5, time.Second*10, true) ) func FetchGeoIP(isV6 bool) geoIP { servers := geoIPApiList var ip geoIP var resp *http.Response var err error for i := 0; i < len(servers); i++ { if isV6 { resp, err = httpClientV6.Get(servers[i]) } else { resp, err = httpClientV4.Get(servers[i]) } if err == nil { body, err := ioutil.ReadAll(resp.Body) if err != nil { continue } resp.Body.Close() err = json.Unmarshal(body, &ip) if err != nil { continue } if ip.IP == "" && ip.Query != "" { ip.IP = ip.Query } // 没取到 v6 IP if isV6 && !strings.Contains(ip.IP, ":") { continue } // 没取到 v4 IP if !isV6 && !strings.Contains(ip.IP, ".") { continue } return ip } } return ip }