diff --git a/go.mod b/go.mod
index 695edfb..81968c4 100644
--- a/go.mod
+++ b/go.mod
@@ -2,4 +2,6 @@ module github.com/nscuro/traefik-plugin-geoblock
go 1.19
-require github.com/ip2location/ip2location-go/v9 v9.5.0
+require github.com/ip2location/ip2location-go/v9 v9.7.1
+
+require lukechampine.com/uint128 v1.2.0 // indirect
diff --git a/go.sum b/go.sum
index 45c3a5b..b677260 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +1,6 @@
github.com/ip2location/ip2location-go/v9 v9.5.0 h1:7gqKncm4MhBrpJIK0PmV8o6Bf8YbbSAPjORzyjAv1iM=
github.com/ip2location/ip2location-go/v9 v9.5.0/go.mod h1:s5SV6YZL10TpfPpXw//7fEJC65G/yH7Oh+Tjq9JcQEQ=
+github.com/ip2location/ip2location-go/v9 v9.7.1 h1:eXu/DqS13QE0h1Yrc9oji+6/anLD9KDf6Ulf5GdIQs8=
+github.com/ip2location/ip2location-go/v9 v9.7.1/go.mod h1:MPLnsKxwQlvd2lBNcQCsLoyzJLDBFizuO67wXXdzoyI=
+lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
+lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
diff --git a/vendor/github.com/ip2location/ip2location-go/v9/.readthedocs.yaml b/vendor/github.com/ip2location/ip2location-go/v9/.readthedocs.yaml
new file mode 100644
index 0000000..7728509
--- /dev/null
+++ b/vendor/github.com/ip2location/ip2location-go/v9/.readthedocs.yaml
@@ -0,0 +1,32 @@
+# .readthedocs.yaml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the OS, Python version and other tools you might need
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.11"
+ # You can also specify other tool versions:
+ # nodejs: "19"
+ # rust: "1.64"
+ # golang: "1.19"
+
+# Build documentation in the "docs/" directory with Sphinx
+sphinx:
+ configuration: docs/source/conf.py
+
+# Optionally build your docs in additional formats such as PDF and ePub
+# formats:
+# - pdf
+# - epub
+
+# Optional but recommended, declare the Python requirements required
+# to build your documentation
+# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
+python:
+ install:
+ - requirements: docs/requirements.txt
\ No newline at end of file
diff --git a/vendor/github.com/ip2location/ip2location-go/v9/LICENSE.TXT b/vendor/github.com/ip2location/ip2location-go/v9/LICENSE.TXT
index ed5c13b..c96a21a 100644
--- a/vendor/github.com/ip2location/ip2location-go/v9/LICENSE.TXT
+++ b/vendor/github.com/ip2location/ip2location-go/v9/LICENSE.TXT
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2022 IP2Location.com
+Copyright (c) 2023 - 2024 IP2Location.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/vendor/github.com/ip2location/ip2location-go/v9/README.md b/vendor/github.com/ip2location/ip2location-go/v9/README.md
index 6979973..93876e2 100644
--- a/vendor/github.com/ip2location/ip2location-go/v9/README.md
+++ b/vendor/github.com/ip2location/ip2location-go/v9/README.md
@@ -1,9 +1,9 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/ip2location/ip2location-go/v9)](https://goreportcard.com/report/github.com/ip2location/ip2location-go/v9)
-
+[![PkgGoDev](https://pkg.go.dev/badge/github.com/ip2location/ip2location-go/v9)](https://pkg.go.dev/github.com/ip2location/ip2location-go/v9)
# IP2Location Go Package
-This Go package provides a fast lookup of country, region, city, latitude, longitude, ZIP code, time zone, ISP, domain name, connection type, IDD code, area code, weather station code, station name, mcc, mnc, mobile brand, elevation, usage type, address type and IAB category from IP address by using IP2Location database. This package uses a file based database available at IP2Location.com. This database simply contains IP blocks as keys, and other information such as country, region, city, latitude, longitude, ZIP code, time zone, ISP, domain name, connection type, IDD code, area code, weather station code, station name, mcc, mnc, mobile brand, elevation, usage type, address type and IAB category as values. It supports both IP address in IPv4 and IPv6.
+This Go package provides a fast lookup of country, region, city, latitude, longitude, ZIP code, time zone, ISP, domain name, connection type, IDD code, area code, weather station code, station name, mcc, mnc, mobile brand, elevation, usage type, address type, IAB category, district, autonomous system number (ASN) and autonomous system (AS) from IP address by using IP2Location database. This package uses a file based database available at IP2Location.com. This database simply contains IP blocks as keys, and other information such as country, region, city, latitude, longitude, ZIP code, time zone, ISP, domain name, connection type, IDD code, area code, weather station code, station name, mcc, mnc, mobile brand, elevation, usage type, address type, IAB category, district, autonomous system number (ASN) and autonomous system (AS) as values. It supports both IP address in IPv4 and IPv6.
This package can be used in many types of projects such as:
@@ -20,497 +20,9 @@ The database will be updated in monthly basis for the greater accuracy. Free LIT
The paid databases are available at https://www.ip2location.com under Premium subscription package.
As an alternative, this package can also call the IP2Location Web Service. This requires an API key. If you don't have an existing API key, you can subscribe for one at the below:
-
https://www.ip2location.com/web-service/ip2location
-## Installation
-
-```
-go get github.com/ip2location/ip2location-go/v9
-```
-
-## QUERY USING THE BIN FILE
-
-## Dependencies
-
-This package requires IP2Location BIN data file to function. You may download the BIN data file at
-* IP2Location LITE BIN Data (Free): https://lite.ip2location.com
-* IP2Location Commercial BIN Data (Comprehensive): https://www.ip2location.com
-
-
-## IPv4 BIN vs IPv6 BIN
-
-Use the IPv4 BIN file if you just need to query IPv4 addresses.
-
-Use the IPv6 BIN file if you need to query BOTH IPv4 and IPv6 addresses.
-
-
-## Methods
-
-Below are the methods supported in this package.
-
-|Method Name|Description|
-|---|---|
-|OpenDB|Initialize the package with the BIN file.|
-|Get_all|Returns the geolocation information in an object.|
-|Get_country_short|Returns the country code.|
-|Get_country_long|Returns the country name.|
-|Get_region|Returns the region name.|
-|Get_city|Returns the city name.|
-|Get_isp|Returns the ISP name.|
-|Get_latitude|Returns the latitude.|
-|Get_longitude|Returns the longitude.|
-|Get_domain|Returns the domain name.|
-|Get_zipcode|Returns the ZIP code.|
-|Get_timezone|Returns the time zone.|
-|Get_netspeed|Returns the net speed.|
-|Get_iddcode|Returns the IDD code.|
-|Get_areacode|Returns the area code.|
-|Get_weatherstationcode|Returns the weather station code.|
-|Get_weatherstationname|Returns the weather station name.|
-|Get_mcc|Returns the mobile country code.|
-|Get_mnc|Returns the mobile network code.|
-|Get_mobilebrand|Returns the mobile brand.|
-|Get_elevation|Returns the elevation in meters.|
-|Get_usagetype|Returns the usage type.|
-|Get_addresstype|Returns the address type.|
-|Get_category|Returns the IAB category.|
-|Close|Closes BIN file.|
-
-## Usage
-
-```go
-package main
-
-import (
- "fmt"
- "github.com/ip2location/ip2location-go/v9"
-)
-
-func main() {
- db, err := ip2location.OpenDB("./IP-COUNTRY-REGION-CITY-LATITUDE-LONGITUDE-ZIPCODE-TIMEZONE-ISP-DOMAIN-NETSPEED-AREACODE-WEATHER-MOBILE-ELEVATION-USAGETYPE-ADDRESSTYPE-CATEGORY.BIN")
-
- if err != nil {
- fmt.Print(err)
- return
- }
- ip := "8.8.8.8"
- results, err := db.Get_all(ip)
-
- if err != nil {
- fmt.Print(err)
- return
- }
-
- fmt.Printf("country_short: %s\n", results.Country_short)
- fmt.Printf("country_long: %s\n", results.Country_long)
- fmt.Printf("region: %s\n", results.Region)
- fmt.Printf("city: %s\n", results.City)
- fmt.Printf("isp: %s\n", results.Isp)
- fmt.Printf("latitude: %f\n", results.Latitude)
- fmt.Printf("longitude: %f\n", results.Longitude)
- fmt.Printf("domain: %s\n", results.Domain)
- fmt.Printf("zipcode: %s\n", results.Zipcode)
- fmt.Printf("timezone: %s\n", results.Timezone)
- fmt.Printf("netspeed: %s\n", results.Netspeed)
- fmt.Printf("iddcode: %s\n", results.Iddcode)
- fmt.Printf("areacode: %s\n", results.Areacode)
- fmt.Printf("weatherstationcode: %s\n", results.Weatherstationcode)
- fmt.Printf("weatherstationname: %s\n", results.Weatherstationname)
- fmt.Printf("mcc: %s\n", results.Mcc)
- fmt.Printf("mnc: %s\n", results.Mnc)
- fmt.Printf("mobilebrand: %s\n", results.Mobilebrand)
- fmt.Printf("elevation: %f\n", results.Elevation)
- fmt.Printf("usagetype: %s\n", results.Usagetype)
- fmt.Printf("addresstype: %s\n", results.Addresstype)
- fmt.Printf("category: %s\n", results.Category)
- fmt.Printf("api version: %s\n", ip2location.Api_version())
-
- db.Close()
-}
-```
-
-## QUERY USING THE IP2LOCATION WEB SERVICE
-
-## Methods
-Below are the methods supported in this package.
-
-|Method Name|Description|
-|---|---|
-|OpenWS| 3 input parameters:
- IP2Location API Key.
- Package (WS1 - WS25)
- Use HTTPS or HTTP
|
-|LookUp|Query IP address. This method returns an object containing the geolocation info. - country_code
- country_name
- region_name
- city_name
- latitude
- longitude
- zip_code
- time_zone
- isp
- domain
- net_speed
- idd_code
- area_code
- weather_station_code
- weather_station_name
- mcc
- mnc
- mobile_brand
- elevation
- usage_type
- address_type
- category
- continent
- name
- code
- hemisphere
- translations
- country
- name
- alpha3_code
- numeric_code
- demonym
- flag
- capital
- total_area
- population
- currency
- language
- idd_code
- tld
- is_eu
- translations
- region
- city
- geotargeting
- country_groupings
- time_zone_info
- olson
- current_time
- gmt_offset
- is_dst
- sunrise
- sunset
|
-|GetCredit|This method returns the web service credit balance in an object.|
-
-## Usage
-
-```go
-package main
-
-import (
- "github.com/ip2location/ip2location-go/v9"
- "fmt"
-)
-
-func main() {
- apikey := "YOUR_API_KEY"
- apipackage := "WS25"
- usessl := true
- addon := "continent,country,region,city,geotargeting,country_groupings,time_zone_info" // leave blank if no need
- lang := "en" // leave blank if no need
-
- ws, err := ip2location.OpenWS(apikey, apipackage, usessl)
-
- if err != nil {
- fmt.Print(err)
- return
- }
- ip := "8.8.8.8"
- res, err := ws.LookUp(ip, addon, lang)
-
- if err != nil {
- fmt.Print(err)
- return
- }
-
- if res.Response != "OK" {
- fmt.Printf("Error: %s\n", res.Response)
- } else {
- // standard results
- fmt.Printf("Response: %s\n", res.Response)
- fmt.Printf("CountryCode: %s\n", res.CountryCode)
- fmt.Printf("CountryName: %s\n", res.CountryName)
- fmt.Printf("RegionName: %s\n", res.RegionName)
- fmt.Printf("CityName: %s\n", res.CityName)
- fmt.Printf("Latitude: %f\n", res.Latitude)
- fmt.Printf("Longitude: %f\n", res.Longitude)
- fmt.Printf("ZipCode: %s\n", res.ZipCode)
- fmt.Printf("TimeZone: %s\n", res.TimeZone)
- fmt.Printf("Isp: %s\n", res.Isp)
- fmt.Printf("Domain: %s\n", res.Domain)
- fmt.Printf("NetSpeed: %s\n", res.NetSpeed)
- fmt.Printf("IddCode: %s\n", res.IddCode)
- fmt.Printf("AreaCode: %s\n", res.AreaCode)
- fmt.Printf("WeatherStationCode: %s\n", res.WeatherStationCode)
- fmt.Printf("WeatherStationName: %s\n", res.WeatherStationName)
- fmt.Printf("Mcc: %s\n", res.Mcc)
- fmt.Printf("Mnc: %s\n", res.Mnc)
- fmt.Printf("MobileBrand: %s\n", res.MobileBrand)
- fmt.Printf("Elevation: %d\n", res.Elevation)
- fmt.Printf("UsageType: %s\n", res.UsageType)
- fmt.Printf("AddressType: %s\n", res.AddressType)
- fmt.Printf("Category: %s\n", res.Category)
- fmt.Printf("CategoryName: %s\n", res.CategoryName)
- fmt.Printf("CreditsConsumed: %d\n", res.CreditsConsumed)
-
- // continent addon
- fmt.Printf("Continent => Name: %s\n", res.Continent.Name)
- fmt.Printf("Continent => Code: %s\n", res.Continent.Code)
- fmt.Printf("Continent => Hemisphere: %+v\n", res.Continent.Hemisphere)
-
- // country addon
- fmt.Printf("Country => Name: %s\n", res.Country.Name)
- fmt.Printf("Country => Alpha3Code: %s\n", res.Country.Alpha3Code)
- fmt.Printf("Country => NumericCode: %s\n", res.Country.NumericCode)
- fmt.Printf("Country => Demonym: %s\n", res.Country.Demonym)
- fmt.Printf("Country => Flag: %s\n", res.Country.Flag)
- fmt.Printf("Country => Capital: %s\n", res.Country.Capital)
- fmt.Printf("Country => TotalArea: %s\n", res.Country.TotalArea)
- fmt.Printf("Country => Population: %s\n", res.Country.Population)
- fmt.Printf("Country => IddCode: %s\n", res.Country.IddCode)
- fmt.Printf("Country => Tld: %s\n", res.Country.Tld)
- fmt.Printf("Country => IsEu: %t\n", res.Country.IsEu)
-
- fmt.Printf("Country => Currency => Code: %s\n", res.Country.Currency.Code)
- fmt.Printf("Country => Currency => Name: %s\n", res.Country.Currency.Name)
- fmt.Printf("Country => Currency => Symbol: %s\n", res.Country.Currency.Symbol)
-
- fmt.Printf("Country => Language => Code: %s\n", res.Country.Language.Code)
- fmt.Printf("Country => Language => Name: %s\n", res.Country.Language.Name)
-
- // region addon
- fmt.Printf("Region => Name: %s\n", res.Region.Name)
- fmt.Printf("Region => Code: %s\n", res.Region.Code)
-
- // city addon
- fmt.Printf("City => Name: %s\n", res.City.Name)
-
- // geotargeting addon
- fmt.Printf("Geotargeting => Metro: %s\n", res.Geotargeting.Metro)
-
- // country_groupings addon
- for i, s := range res.CountryGroupings {
- fmt.Printf("CountryGroupings => #%d => Acronym: %s\n", i, s.Acronym)
- fmt.Printf("CountryGroupings => #%d => Name: %s\n", i, s.Name)
- }
-
- // time_zone_info addon
- fmt.Printf("TimeZoneInfo => Olson: %s\n", res.TimeZoneInfo.Olson)
- fmt.Printf("TimeZoneInfo => CurrentTime: %s\n", res.TimeZoneInfo.CurrentTime)
- fmt.Printf("TimeZoneInfo => GmtOffset: %d\n", res.TimeZoneInfo.GmtOffset)
- fmt.Printf("TimeZoneInfo => IsDst: %s\n", res.TimeZoneInfo.IsDst)
- fmt.Printf("TimeZoneInfo => Sunrise: %s\n", res.TimeZoneInfo.Sunrise)
- fmt.Printf("TimeZoneInfo => Sunset: %s\n", res.TimeZoneInfo.Sunset)
- }
-
- res2, err := ws.GetCredit()
-
- if err != nil {
- fmt.Print(err)
- return
- }
-
- fmt.Printf("Credit Balance: %d\n", res2.Response)
-}
-```
-
-## IPTOOLS CLASS
-
-## Methods
-Below are the methods supported in this package.
-
-|Method Name|Description|
-|---|---|
-|func (t *IPTools) IsIPv4(IP string) bool|Returns true if string contains an IPv4 address. Otherwise false.|
-|func (t *IPTools) IsIPv6(IP string) bool|Returns true if string contains an IPv6 address. Otherwise false.|
-|func (t *IPTools) IPv4ToDecimal(IP string) (*big.Int, error)|Returns the IP number for an IPv4 address.|
-|func (t *IPTools) IPv6ToDecimal(IP string) (*big.Int, error)|Returns the IP number for an IPv6 address.|
-|func (t *IPTools) DecimalToIPv4(IPNum *big.Int) (string, error)|Returns the IPv4 address for the supplied IP number.|
-|func (t *IPTools) DecimalToIPv6(IPNum *big.Int) (string, error)|Returns the IPv6 address for the supplied IP number.|
-|func (t *IPTools) CompressIPv6(IP string) (string, error)|Returns the IPv6 address in compressed form.|
-|func (t *IPTools) ExpandIPv6(IP string) (string, error)|Returns the IPv6 address in expanded form.|
-|func (t *IPTools) IPv4ToCIDR(IPFrom string, IPTo string) ([]string, error)|Returns a list of CIDR from the supplied IPv4 range.|
-|func (t *IPTools) IPv6ToCIDR(IPFrom string, IPTo string) ([]string, error)|Returns a list of CIDR from the supplied IPv6 range.|
-|func (t *IPTools) CIDRToIPv4(CIDR string) ([]string, error)|Returns the IPv4 range from the supplied CIDR.|
-|func (t *IPTools) CIDRToIPv6(CIDR string) ([]string, error)|Returns the IPv6 range from the supplied CIDR.|
-
-## Usage
-
-```go
-package main
-
-import (
- "github.com/ip2location/ip2location-go/v9"
- "fmt"
- "math/big"
-)
-
-func main() {
- t := ip2location.OpenTools()
-
- ip := "8.8.8.8"
- res := t.IsIPv4(ip)
-
- fmt.Printf("Is IPv4: %t\n", res)
-
- ipnum, err := t.IPv4ToDecimal(ip)
- if err != nil {
- fmt.Print(err)
- } else {
- fmt.Printf("IPNum: %v\n", ipnum)
- }
-
- ip2 := "2600:1f18:45b0:5b00:f5d8:4183:7710:ceec"
- res2 := t.IsIPv6(ip2)
-
- fmt.Printf("Is IPv6: %t\n", res2)
-
- ipnum2, err := t.IPv6ToDecimal(ip2)
- if err != nil {
- fmt.Print(err)
- } else {
- fmt.Printf("IPNum: %v\n", ipnum2)
- }
-
- ipnum3 := big.NewInt(42534)
- res3, err := t.DecimalToIPv4(ipnum3)
-
- if err != nil {
- fmt.Print(err)
- } else {
- fmt.Printf("IPv4: %v\n", res3)
- }
-
- ipnum4, ok := big.NewInt(0).SetString("22398978840339333967292465152", 10)
- if ok {
- res4, err := t.DecimalToIPv6(ipnum4)
- if err != nil {
- fmt.Print(err)
- } else {
- fmt.Printf("IPv6: %v\n", res4)
- }
- }
-
- ip3 := "2600:1f18:045b:005b:f5d8:0:000:ceec"
- res5, err := t.CompressIPv6(ip3)
-
- if err != nil {
- fmt.Print(err)
- } else {
- fmt.Printf("Compressed: %v\n", res5)
- }
-
- ip4 := "::45b:05b:f5d8:0:000:ceec"
- res6, err := t.ExpandIPv6(ip4)
-
- if err != nil {
- fmt.Print(err)
- } else {
- fmt.Printf("Expanded: %v\n", res6)
- }
-
- res7, err := t.IPv4ToCIDR("10.0.0.0", "10.10.2.255")
-
- if err != nil {
- fmt.Print(err)
- } else {
- for _, element := range res7 {
- fmt.Println(element)
- }
- }
-
- res8, err := t.IPv6ToCIDR("2001:4860:4860:0000:0000:0000:0000:8888", "2001:4860:4860:0000:eeee:ffff:ffff:ffff")
-
- if err != nil {
- fmt.Print(err)
- } else {
- for _, element := range res8 {
- fmt.Println(element)
- }
- }
-
- res9, err := t.CIDRToIPv4("123.245.99.13/26")
-
- if err != nil {
- fmt.Print(err)
- } else {
- fmt.Printf("IPv4 Range: %v\n", res9)
- }
-
- res10, err := t.CIDRToIPv6("2002:1234::abcd:ffff:c0a8:101/62")
-
- if err != nil {
- fmt.Print(err)
- } else {
- fmt.Printf("IPv6 Range: %v\n", res10)
- }
-}
-```
-
-## COUNTRY CLASS
-
-## Methods
-Below are the methods supported in this package.
-
-|Method Name|Description|
-|---|---|
-|func OpenCountryInfo(csvFile string) (*CI, error)|Expect a IP2Location Country Information CSV file. This database is free for download at https://www.ip2location.com/free/country-information|
-|func (c *CI) GetCountryInfo(countryCode ...string) ([]CountryInfoRecord, error)|Returns the country information for specified country or all countries.|
-
-## Usage
-
-```go
-package main
-
-import (
- "github.com/ip2location/ip2location-go"
- "fmt"
-)
-
-func main() {
- c, err := ip2location.OpenCountryInfo("./IP2LOCATION-COUNTRY-INFORMATION.CSV")
-
- if err != nil {
- fmt.Print(err)
- return
- }
-
- res, err := c.GetCountryInfo("US")
-
- if err != nil {
- fmt.Print(err)
- return
- }
-
- fmt.Printf("country_code: %s\n", res[0].Country_code)
- fmt.Printf("country_name: %s\n", res[0].Country_name)
- fmt.Printf("country_alpha3_code: %s\n", res[0].Country_alpha3_code)
- fmt.Printf("country_numeric_code: %s\n", res[0].Country_numeric_code)
- fmt.Printf("capital: %s\n", res[0].Capital)
- fmt.Printf("country_demonym: %s\n", res[0].Country_demonym)
- fmt.Printf("total_area: %s\n", res[0].Total_area)
- fmt.Printf("population: %s\n", res[0].Population)
- fmt.Printf("idd_code: %s\n", res[0].Idd_code)
- fmt.Printf("currency_code: %s\n", res[0].Currency_code)
- fmt.Printf("currency_name: %s\n", res[0].Currency_name)
- fmt.Printf("currency_symbol: %s\n", res[0].Currency_symbol)
- fmt.Printf("lang_code: %s\n", res[0].Lang_code)
- fmt.Printf("lang_name: %s\n", res[0].Lang_name)
- fmt.Printf("cctld: %s\n", res[0].Cctld)
- fmt.Print("==============================================\n")
-
- res2, err := c.GetCountryInfo()
-
- if err != nil {
- fmt.Print(err)
- return
- }
-
- for _, v := range res2 {
- fmt.Printf("country_code: %s\n", v.Country_code)
- fmt.Printf("country_name: %s\n", v.Country_name)
- fmt.Printf("country_alpha3_code: %s\n", v.Country_alpha3_code)
- fmt.Printf("country_numeric_code: %s\n", v.Country_numeric_code)
- fmt.Printf("capital: %s\n", v.Capital)
- fmt.Printf("country_demonym: %s\n", v.Country_demonym)
- fmt.Printf("total_area: %s\n", v.Total_area)
- fmt.Printf("population: %s\n", v.Population)
- fmt.Printf("idd_code: %s\n", v.Idd_code)
- fmt.Printf("currency_code: %s\n", v.Currency_code)
- fmt.Printf("currency_name: %s\n", v.Currency_name)
- fmt.Printf("currency_symbol: %s\n", v.Currency_symbol)
- fmt.Printf("lang_code: %s\n", v.Lang_code)
- fmt.Printf("lang_name: %s\n", v.Lang_name)
- fmt.Printf("cctld: %s\n", v.Cctld)
- fmt.Print("==============================================\n")
- }
-}
-```
-
-## REGION CLASS
-
-## Methods
-Below are the methods supported in this package.
-
-|Method Name|Description|
-|---|---|
-|func OpenRegionInfo(csvFile string) (*RI, error)|Expect a IP2Location ISO 3166-2 Subdivision Code CSV file. This database is free for download at https://www.ip2location.com/free/iso3166-2|
-|func (r *RI) GetRegionCode(countryCode string, regionName string) (string, error)|Returns the region code for the supplied country code and region name.|
-
-## Usage
-
-```go
-package main
-
-import (
- "github.com/ip2location/ip2location-go"
- "fmt"
-)
-
-func main() {
- r, err := ip2location.OpenRegionInfo("./IP2LOCATION-ISO3166-2.CSV")
-
- if err != nil {
- fmt.Print(err)
- return
- }
-
- res, err := r.GetRegionCode("US", "California")
-
- if err != nil {
- fmt.Print(err)
- return
- }
+Developer Documentation
+=====================
- fmt.Printf("region code: %s\n", res)
-}
-```
\ No newline at end of file
+To learn more about installation, usage, and code examples, please visit the developer documentation at [https://ip2location-go.readthedocs.io/en/latest/](https://ip2location-go.readthedocs.io/en/latest/).
\ No newline at end of file
diff --git a/vendor/github.com/ip2location/ip2location-go/v9/ip2location.go b/vendor/github.com/ip2location/ip2location-go/v9/ip2location.go
index 66e8f35..d6cd6dc 100644
--- a/vendor/github.com/ip2location/ip2location-go/v9/ip2location.go
+++ b/vendor/github.com/ip2location/ip2location-go/v9/ip2location.go
@@ -1,6 +1,7 @@
// This ip2location package provides a fast lookup of country, region, city, latitude, longitude, ZIP code, time zone,
// ISP, domain name, connection type, IDD code, area code, weather station code, station name, MCC, MNC,
-// mobile brand, elevation, usage type, address type and IAB category from IP address by using IP2Location database.
+// mobile brand, elevation, usage type, address type, IAB category, district, autonomous system number (ASN) and
+// autonomous system (AS) from IP address by using IP2Location database.
package ip2location
import (
@@ -9,11 +10,13 @@ import (
"errors"
"fmt"
"io"
+ "lukechampine.com/uint128"
"math"
"math/big"
"net"
"os"
"strconv"
+ "unsafe"
)
type DBReader interface {
@@ -67,6 +70,9 @@ type IP2Locationrecord struct {
Usagetype string
Addresstype string
Category string
+ District string
+ Asn string
+ As string
}
type DB struct {
@@ -94,6 +100,9 @@ type DB struct {
usagetype_position_offset uint32
addresstype_position_offset uint32
category_position_offset uint32
+ district_position_offset uint32
+ asn_position_offset uint32
+ as_position_offset uint32
country_enabled bool
region_enabled bool
@@ -116,81 +125,97 @@ type DB struct {
usagetype_enabled bool
addresstype_enabled bool
category_enabled bool
+ district_enabled bool
+ asn_enabled bool
+ as_enabled bool
metaok bool
}
var defaultDB = &DB{}
-var country_position = [26]uint8{0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
-var region_position = [26]uint8{0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
-var city_position = [26]uint8{0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}
-var isp_position = [26]uint8{0, 0, 3, 0, 5, 0, 7, 5, 7, 0, 8, 0, 9, 0, 9, 0, 9, 0, 9, 7, 9, 0, 9, 7, 9, 9}
-var latitude_position = [26]uint8{0, 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}
-var longitude_position = [26]uint8{0, 0, 0, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}
-var domain_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 6, 8, 0, 9, 0, 10, 0, 10, 0, 10, 0, 10, 8, 10, 0, 10, 8, 10, 10}
-var zipcode_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 7, 7, 7, 0, 7, 0, 7, 7, 7, 0, 7, 7}
-var timezone_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 7, 8, 8, 8, 7, 8, 0, 8, 8, 8, 0, 8, 8}
-var netspeed_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 11, 0, 11, 8, 11, 0, 11, 0, 11, 0, 11, 11}
-var iddcode_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 12, 0, 12, 0, 12, 9, 12, 0, 12, 12}
-var areacode_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 13, 0, 13, 0, 13, 10, 13, 0, 13, 13}
-var weatherstationcode_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 14, 0, 14, 0, 14, 0, 14, 14}
-var weatherstationname_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 15, 0, 15, 0, 15, 0, 15, 15}
-var mcc_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 16, 0, 16, 9, 16, 16}
-var mnc_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 17, 0, 17, 10, 17, 17}
-var mobilebrand_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 18, 0, 18, 11, 18, 18}
-var elevation_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 19, 0, 19, 19}
-var usagetype_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 20, 20}
-var addresstype_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21}
-var category_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22}
-
-const api_version string = "9.5.0"
-
-var max_ipv4_range = big.NewInt(4294967295)
-var max_ipv6_range = big.NewInt(0)
-var from_v4mapped = big.NewInt(281470681743360)
-var to_v4mapped = big.NewInt(281474976710655)
-var from_6to4 = big.NewInt(0)
-var to_6to4 = big.NewInt(0)
-var from_teredo = big.NewInt(0)
-var to_teredo = big.NewInt(0)
-var last_32bits = big.NewInt(4294967295)
-
-const countryshort uint32 = 0x000001
-const countrylong uint32 = 0x000002
-const region uint32 = 0x000004
-const city uint32 = 0x000008
-const isp uint32 = 0x000010
-const latitude uint32 = 0x000020
-const longitude uint32 = 0x000040
-const domain uint32 = 0x000080
-const zipcode uint32 = 0x000100
-const timezone uint32 = 0x000200
-const netspeed uint32 = 0x000400
-const iddcode uint32 = 0x000800
-const areacode uint32 = 0x001000
-const weatherstationcode uint32 = 0x002000
-const weatherstationname uint32 = 0x004000
-const mcc uint32 = 0x008000
-const mnc uint32 = 0x010000
-const mobilebrand uint32 = 0x020000
-const elevation uint32 = 0x040000
-const usagetype uint32 = 0x080000
-const addresstype uint32 = 0x100000
-const category uint32 = 0x200000
-
-const all uint32 = countryshort | countrylong | region | city | isp | latitude | longitude | domain | zipcode | timezone | netspeed | iddcode | areacode | weatherstationcode | weatherstationname | mcc | mnc | mobilebrand | elevation | usagetype | addresstype | category
+var country_position = [27]uint8{0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
+var region_position = [27]uint8{0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
+var city_position = [27]uint8{0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}
+var isp_position = [27]uint8{0, 0, 3, 0, 5, 0, 7, 5, 7, 0, 8, 0, 9, 0, 9, 0, 9, 0, 9, 7, 9, 0, 9, 7, 9, 9, 9}
+var latitude_position = [27]uint8{0, 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}
+var longitude_position = [27]uint8{0, 0, 0, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}
+var domain_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 6, 8, 0, 9, 0, 10, 0, 10, 0, 10, 0, 10, 8, 10, 0, 10, 8, 10, 10, 10}
+var zipcode_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 7, 7, 7, 0, 7, 0, 7, 7, 7, 0, 7, 7, 7}
+var timezone_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 7, 8, 8, 8, 7, 8, 0, 8, 8, 8, 0, 8, 8, 8}
+var netspeed_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 11, 0, 11, 8, 11, 0, 11, 0, 11, 0, 11, 11, 11}
+var iddcode_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 12, 0, 12, 0, 12, 9, 12, 0, 12, 12, 12}
+var areacode_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 13, 0, 13, 0, 13, 10, 13, 0, 13, 13, 13}
+var weatherstationcode_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 14, 0, 14, 0, 14, 0, 14, 14, 14}
+var weatherstationname_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 15, 0, 15, 0, 15, 0, 15, 15, 15}
+var mcc_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 16, 0, 16, 9, 16, 16, 16}
+var mnc_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 17, 0, 17, 10, 17, 17, 17}
+var mobilebrand_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 18, 0, 18, 11, 18, 18, 18}
+var elevation_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 19, 0, 19, 19, 19}
+var usagetype_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 20, 20, 20}
+var addresstype_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 21}
+var category_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 22}
+var district_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23}
+var asn_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24}
+var as_position = [27]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25}
+
+const api_version string = "9.7.1"
+
+var max_ipv4_range = uint128.From64(4294967295)
+var max_ipv6_range = uint128.From64(0)
+var from_v4mapped = uint128.From64(281470681743360)
+var to_v4mapped = uint128.From64(281474976710655)
+var from_6to4 = uint128.From64(0)
+var to_6to4 = uint128.From64(0)
+var from_teredo = uint128.From64(0)
+var to_teredo = uint128.From64(0)
+var last_32bits = uint128.From64(4294967295)
+
+const countryshort uint32 = 0x0000001
+const countrylong uint32 = 0x0000002
+const region uint32 = 0x0000004
+const city uint32 = 0x0000008
+const isp uint32 = 0x0000010
+const latitude uint32 = 0x0000020
+const longitude uint32 = 0x0000040
+const domain uint32 = 0x0000080
+const zipcode uint32 = 0x0000100
+const timezone uint32 = 0x0000200
+const netspeed uint32 = 0x0000400
+const iddcode uint32 = 0x0000800
+const areacode uint32 = 0x0001000
+const weatherstationcode uint32 = 0x0002000
+const weatherstationname uint32 = 0x0004000
+const mcc uint32 = 0x0008000
+const mnc uint32 = 0x0010000
+const mobilebrand uint32 = 0x0020000
+const elevation uint32 = 0x0040000
+const usagetype uint32 = 0x0080000
+const addresstype uint32 = 0x0100000
+const category uint32 = 0x0200000
+const district uint32 = 0x0400000
+const asn uint32 = 0x0800000
+const as uint32 = 0x1000000
+
+const all uint32 = countryshort | countrylong | region | city | isp | latitude | longitude | domain | zipcode | timezone | netspeed | iddcode | areacode | weatherstationcode | weatherstationname | mcc | mnc | mobilebrand | elevation | usagetype | addresstype | category | district | asn | as
const invalid_address string = "Invalid IP address."
const missing_file string = "Invalid database file."
const not_supported string = "This parameter is unavailable for selected data file. Please upgrade the data file."
const invalid_bin string = "Incorrect IP2Location BIN file format. Please make sure that you are using the latest IP2Location BIN file."
+const ipv6_not_supported string = "IPv6 address missing in IPv4 BIN."
+
+func reverseBytes(s []byte) {
+ for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
+ s[i], s[j] = s[j], s[i]
+ }
+}
// get IP type and calculate IP number; calculates index too if exists
-func (d *DB) checkip(ip string) (iptype uint32, ipnum *big.Int, ipindex uint32) {
+func (d *DB) checkip(ip string) (iptype uint32, ipnum uint128.Uint128, ipindex uint32) {
iptype = 0
- ipnum = big.NewInt(0)
- ipnumtmp := big.NewInt(0)
+ ipnum = uint128.From64(0)
+ ipnumtmp := uint128.From64(0)
ipindex = 0
ipaddress := net.ParseIP(ip)
@@ -199,43 +224,44 @@ func (d *DB) checkip(ip string) (iptype uint32, ipnum *big.Int, ipindex uint32)
if v4 != nil {
iptype = 4
- ipnum.SetBytes(v4)
+ ipnum = uint128.From64(uint64(binary.BigEndian.Uint32(v4)))
} else {
v6 := ipaddress.To16()
if v6 != nil {
iptype = 6
- ipnum.SetBytes(v6)
+ reverseBytes(v6)
+ ipnum = uint128.FromBytes(v6)
if ipnum.Cmp(from_v4mapped) >= 0 && ipnum.Cmp(to_v4mapped) <= 0 {
// ipv4-mapped ipv6 should treat as ipv4 and read ipv4 data section
iptype = 4
- ipnum.Sub(ipnum, from_v4mapped)
+ ipnum = ipnum.Sub(from_v4mapped)
} else if ipnum.Cmp(from_6to4) >= 0 && ipnum.Cmp(to_6to4) <= 0 {
// 6to4 so need to remap to ipv4
iptype = 4
- ipnum.Rsh(ipnum, 80)
- ipnum.And(ipnum, last_32bits)
+ ipnum = ipnum.Rsh(80)
+ ipnum = ipnum.And(last_32bits)
} else if ipnum.Cmp(from_teredo) >= 0 && ipnum.Cmp(to_teredo) <= 0 {
// Teredo so need to remap to ipv4
iptype = 4
- ipnum.Not(ipnum)
- ipnum.And(ipnum, last_32bits)
+ ipnum = uint128.Uint128{^ipnum.Lo, ^ipnum.Hi}
+ ipnum = ipnum.And(last_32bits)
}
}
}
}
if iptype == 4 {
if d.meta.ipv4indexed {
- ipnumtmp.Rsh(ipnum, 16)
- ipnumtmp.Lsh(ipnumtmp, 3)
- ipindex = uint32(ipnumtmp.Add(ipnumtmp, big.NewInt(int64(d.meta.ipv4indexbaseaddr))).Uint64())
+ ipnumtmp = ipnum.Rsh(16)
+ ipnumtmp = ipnumtmp.Lsh(3)
+ ipindex = uint32(ipnumtmp.Add(uint128.From64(uint64(d.meta.ipv4indexbaseaddr))).Lo)
}
} else if iptype == 6 {
if d.meta.ipv6indexed {
- ipnumtmp.Rsh(ipnum, 112)
- ipnumtmp.Lsh(ipnumtmp, 3)
- ipindex = uint32(ipnumtmp.Add(ipnumtmp, big.NewInt(int64(d.meta.ipv6indexbaseaddr))).Uint64())
+ ipnumtmp = ipnum.Rsh(112)
+ ipnumtmp = ipnumtmp.Lsh(3)
+ ipindex = uint32(ipnumtmp.Add(uint128.From64(uint64(d.meta.ipv6indexbaseaddr))).Lo)
}
}
return
@@ -290,33 +316,33 @@ func (d *DB) readuint32(pos uint32) (uint32, error) {
}
// read unsigned 128-bit integer from slices
-func (d *DB) readuint128_row(row []byte, pos uint32) *big.Int {
- retval := big.NewInt(0)
+func (d *DB) readuint128_row(row []byte, pos uint32) uint128.Uint128 {
+ retval := uint128.From64(0)
data := row[pos : pos+16]
// little endian to big endian
- for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
- data[i], data[j] = data[j], data[i]
- }
- retval.SetBytes(data)
+ // for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
+ // data[i], data[j] = data[j], data[i]
+ // }
+ retval = uint128.FromBytes(data)
return retval
}
// read unsigned 128-bit integer
-func (d *DB) readuint128(pos uint32) (*big.Int, error) {
+func (d *DB) readuint128(pos uint32) (uint128.Uint128, error) {
pos2 := int64(pos)
- retval := big.NewInt(0)
+ retval := uint128.From64(0)
data := make([]byte, 16)
_, err := d.f.ReadAt(data, pos2-1)
if err != nil {
- return nil, err
+ return uint128.From64(0), err
}
// little endian to big endian
- for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
- data[i], data[j] = data[j], data[i]
- }
- retval.SetBytes(data)
+ // for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
+ // data[i], data[j] = data[j], data[i]
+ // }
+ retval = uint128.FromBytes(data)
return retval, nil
}
@@ -331,7 +357,7 @@ func (d *DB) readstr(pos uint32) (string, error) {
return "", err
}
strlen := data[0]
- retval = string(data[1:(strlen + 1)])
+ retval = convertBytesToString(data[1:(strlen + 1)])
return retval, nil
}
@@ -365,11 +391,25 @@ func OpenDB(dbpath string) (*DB, error) {
func OpenDBWithReader(reader DBReader) (*DB, error) {
var db = &DB{}
- max_ipv6_range.SetString("340282366920938463463374607431768211455", 10)
- from_6to4.SetString("42545680458834377588178886921629466624", 10)
- to_6to4.SetString("42550872755692912415807417417958686719", 10)
- from_teredo.SetString("42540488161975842760550356425300246528", 10)
- to_teredo.SetString("42540488241204005274814694018844196863", 10)
+ _max_ipv6_range := big.NewInt(0)
+ _max_ipv6_range.SetString("340282366920938463463374607431768211455", 10)
+ max_ipv6_range = uint128.FromBig(_max_ipv6_range)
+
+ _from_6to4 := big.NewInt(0)
+ _from_6to4.SetString("42545680458834377588178886921629466624", 10)
+ from_6to4 = uint128.FromBig(_from_6to4)
+
+ _to_6to4 := big.NewInt(0)
+ _to_6to4.SetString("42550872755692912415807417417958686719", 10)
+ to_6to4 = uint128.FromBig(_to_6to4)
+
+ _from_teredo := big.NewInt(0)
+ _from_teredo.SetString("42540488161975842760550356425300246528", 10)
+ from_teredo = uint128.FromBig(_from_teredo)
+
+ _to_teredo := big.NewInt(0)
+ _to_teredo.SetString("42540488241204005274814694018844196863", 10)
+ to_teredo = uint128.FromBig(_to_teredo)
db.f = reader
@@ -498,6 +538,18 @@ func OpenDBWithReader(reader DBReader) (*DB, error) {
db.category_position_offset = uint32(category_position[dbt]-2) << 2
db.category_enabled = true
}
+ if district_position[dbt] != 0 {
+ db.district_position_offset = uint32(district_position[dbt]-2) << 2
+ db.district_enabled = true
+ }
+ if asn_position[dbt] != 0 {
+ db.asn_position_offset = uint32(asn_position[dbt]-2) << 2
+ db.asn_enabled = true
+ }
+ if as_position[dbt] != 0 {
+ db.as_position_offset = uint32(as_position[dbt]-2) << 2
+ db.as_enabled = true
+ }
db.metaok = true
@@ -529,6 +581,16 @@ func Api_version() string {
return api_version
}
+// PackageVersion returns the database type.
+func (d *DB) PackageVersion() string {
+ return strconv.Itoa(int(d.meta.databasetype))
+}
+
+// DatabaseVersion returns the database version.
+func (d *DB) DatabaseVersion() string {
+ return "20" + strconv.Itoa(int(d.meta.databaseyear)) + "." + strconv.Itoa(int(d.meta.databasemonth)) + "." + strconv.Itoa(int(d.meta.databaseday))
+}
+
// populate record with message
func loadmessage(mesg string) IP2Locationrecord {
var x IP2Locationrecord
@@ -552,6 +614,9 @@ func loadmessage(mesg string) IP2Locationrecord {
x.Usagetype = mesg
x.Addresstype = mesg
x.Category = mesg
+ x.District = mesg
+ x.Asn = mesg
+ x.As = mesg
return x
}
@@ -563,6 +628,13 @@ func handleError(rec IP2Locationrecord, err error) IP2Locationrecord {
return rec
}
+// convertBytesToString provides a no-copy []byte to string conversion.
+// This implementation is adopted by official strings.Builder.
+// Reference: https://github.com/golang/go/issues/25484
+func convertBytesToString(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
+
// Get_all will return all geolocation fields based on the queried IP address.
//
// Deprecated: No longer being updated.
@@ -825,6 +897,21 @@ func (d *DB) Get_category(ipaddress string) (IP2Locationrecord, error) {
return d.query(ipaddress, category)
}
+// Get_district will return the district name based on the queried IP address.
+func (d *DB) Get_district(ipaddress string) (IP2Locationrecord, error) {
+ return d.query(ipaddress, district)
+}
+
+// Get_asn will return the autonomous system number (ASN) based on the queried IP address.
+func (d *DB) Get_asn(ipaddress string) (IP2Locationrecord, error) {
+ return d.query(ipaddress, asn)
+}
+
+// Get_as will return the autonomous system (AS) based on the queried IP address.
+func (d *DB) Get_as(ipaddress string) (IP2Locationrecord, error) {
+ return d.query(ipaddress, as)
+}
+
// main query
func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
x := loadmessage(not_supported) // default message
@@ -854,9 +941,9 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
var row []byte
var fullrow []byte
var readlen uint32
- ipfrom := big.NewInt(0)
- ipto := big.NewInt(0)
- maxip := big.NewInt(0)
+ ipfrom := uint128.From64(0)
+ ipto := uint128.From64(0)
+ maxip := uint128.From64(0)
if iptype == 4 {
baseaddr = d.meta.ipv4databaseaddr
@@ -864,6 +951,10 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
maxip = max_ipv4_range
colsize = d.meta.ipv4columnsize
} else {
+ if d.meta.ipv6databasecount == 0 {
+ x = loadmessage(ipv6_not_supported)
+ return x, nil
+ }
firstcol = 16 // 16 bytes for ip from
baseaddr = d.meta.ipv6databaseaddr
high = d.meta.ipv6databasecount
@@ -882,7 +973,7 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
}
if ipno.Cmp(maxip) >= 0 {
- ipno.Sub(ipno, big.NewInt(1))
+ ipno = ipno.Sub(uint128.From64(1))
}
for low <= high {
@@ -898,10 +989,10 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
if iptype == 4 {
ipfrom32 := d.readuint32_row(fullrow, 0)
- ipfrom = big.NewInt(int64(ipfrom32))
+ ipfrom = uint128.From64(uint64(ipfrom32))
ipto32 := d.readuint32_row(fullrow, colsize)
- ipto = big.NewInt(int64(ipto32))
+ ipto = uint128.From64(uint64(ipto32))
} else {
ipfrom = d.readuint128_row(fullrow, 0)
@@ -1044,6 +1135,24 @@ func (d *DB) query(ipaddress string, mode uint32) (IP2Locationrecord, error) {
}
}
+ if mode&district != 0 && d.district_enabled {
+ if x.District, err = d.readstr(d.readuint32_row(row, d.district_position_offset)); err != nil {
+ return x, err
+ }
+ }
+
+ if mode&asn != 0 && d.asn_enabled {
+ if x.Asn, err = d.readstr(d.readuint32_row(row, d.asn_position_offset)); err != nil {
+ return x, err
+ }
+ }
+
+ if mode&as != 0 && d.as_enabled {
+ if x.As, err = d.readstr(d.readuint32_row(row, d.as_position_offset)); err != nil {
+ return x, err
+ }
+ }
+
return x, nil
} else {
if ipno.Cmp(ipfrom) < 0 {
@@ -1084,4 +1193,7 @@ func Printrecord(x IP2Locationrecord) {
fmt.Printf("usagetype: %s\n", x.Usagetype)
fmt.Printf("addresstype: %s\n", x.Addresstype)
fmt.Printf("category: %s\n", x.Category)
+ fmt.Printf("district: %s\n", x.District)
+ fmt.Printf("asn: %s\n", x.Asn)
+ fmt.Printf("as: %s\n", x.As)
}
diff --git a/vendor/github.com/ip2location/ip2location-go/v9/iptools.go b/vendor/github.com/ip2location/ip2location-go/v9/iptools.go
index 5b9786f..9808698 100644
--- a/vendor/github.com/ip2location/ip2location-go/v9/iptools.go
+++ b/vendor/github.com/ip2location/ip2location-go/v9/iptools.go
@@ -448,31 +448,43 @@ func (t *IPTools) CIDRToIPv6(CIDR string) ([]string, error) {
return nil, errors.New("Not a valid CIDR.")
}
- hexstartaddress, _ := t.ExpandIPv6(ip)
- hexstartaddress = strings.ReplaceAll(hexstartaddress, ":", "")
- hexendaddress := hexstartaddress
-
- bits := 128 - prefix
- pos := 31
-
- for bits > 0 {
- values := []int{4, bits}
- min, _ := t.minMax(values)
- x, _ := strconv.ParseInt(string(hexendaddress[pos]), 16, 64)
- y := fmt.Sprintf("%x", (x | int64(math.Pow(2, float64(min))-1)))
+ expand, _ := t.ExpandIPv6(ip)
+ parts := strings.Split(expand, ":")
+
+ bitStart := strings.Repeat("1", prefix) + strings.Repeat("0", 128-prefix)
+ bitEnd := strings.Repeat("0", prefix) + strings.Repeat("1", 128-prefix)
+
+ n := 16 // split string into 16-char parts
+ floors := []string{}
+ for i := 0; i < len(bitStart); i += n {
+ end := i + n
+ if end > len(bitStart) {
+ end = len(bitStart)
+ }
+ floors = append(floors, bitStart[i:end])
+ }
+ ceilings := []string{}
+ for i := 0; i < len(bitEnd); i += n {
+ end := i + n
+ if end > len(bitEnd) {
+ end = len(bitEnd)
+ }
+ ceilings = append(ceilings, bitEnd[i:end])
+ }
- hexendaddress = hexendaddress[:pos] + y + hexendaddress[pos+1:]
+ start := []string{}
+ end := []string{}
- bits = bits - 4
- pos = pos - 1
+ for i := 0; i < 8; i += 1 {
+ p, _ := strconv.ParseUint(parts[i], 16, 64)
+ f, _ := strconv.ParseUint(floors[i], 2, 64)
+ c, _ := strconv.ParseUint(ceilings[i], 2, 64)
+ start = append(start, strconv.FormatUint(p&f, 16))
+ end = append(end, strconv.FormatUint(p|c, 16))
}
- re2 := regexp.MustCompile(`(.{4})`)
- hexstartaddress = re2.ReplaceAllString(hexstartaddress, "$1:")
- hexstartaddress = strings.TrimSuffix(hexstartaddress, ":")
- hexendaddress = re2.ReplaceAllString(hexendaddress, "$1:")
- hexendaddress = strings.TrimSuffix(hexendaddress, ":")
-
+ hexstartaddress, _ := t.ExpandIPv6(strings.Join(start, ":"))
+ hexendaddress, _ := t.ExpandIPv6(strings.Join(end, ":"))
result := []string{hexstartaddress, hexendaddress}
return result, nil
diff --git a/vendor/lukechampine.com/uint128/LICENSE b/vendor/lukechampine.com/uint128/LICENSE
new file mode 100644
index 0000000..a14c6cf
--- /dev/null
+++ b/vendor/lukechampine.com/uint128/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2019 Luke Champine
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/lukechampine.com/uint128/README.md b/vendor/lukechampine.com/uint128/README.md
new file mode 100644
index 0000000..1ea5d7d
--- /dev/null
+++ b/vendor/lukechampine.com/uint128/README.md
@@ -0,0 +1,46 @@
+uint128
+-------
+
+[![GoDoc](https://godoc.org/github.com/lukechampine/uint128?status.svg)](https://godoc.org/github.com/lukechampine/uint128)
+[![Go Report Card](http://goreportcard.com/badge/github.com/lukechampine/uint128)](https://goreportcard.com/report/github.com/lukechampine/uint128)
+
+```
+go get lukechampine.com/uint128
+```
+
+`uint128` provides a high-performance `Uint128` type that supports standard arithmetic
+operations. Unlike `math/big`, operations on `Uint128` values always produce new values
+instead of modifying a pointer receiver. A `Uint128` value is therefore immutable, just
+like `uint64` and friends.
+
+The name `uint128.Uint128` stutters, so I recommend either using a "dot import"
+or aliasing `uint128.Uint128` to give it a project-specific name. Embedding the type
+is not recommended, because methods will still return `uint128.Uint128`; this means that,
+if you want to extend the type with new methods, your best bet is probably to copy the
+source code wholesale and rename the identifier. ¯\\\_(ツ)\_/¯
+
+
+# Benchmarks
+
+Addition, multiplication, and subtraction are on par with their native 64-bit
+equivalents. Division is slower: ~20x slower when dividing a `Uint128` by a
+`uint64`, and ~100x slower when dividing by a `Uint128`. However, division is
+still faster than with `big.Int` (for the same operands), especially when
+dividing by a `uint64`.
+
+```
+BenchmarkArithmetic/Add-4 2000000000 0.45 ns/op 0 B/op 0 allocs/op
+BenchmarkArithmetic/Sub-4 2000000000 0.67 ns/op 0 B/op 0 allocs/op
+BenchmarkArithmetic/Mul-4 2000000000 0.42 ns/op 0 B/op 0 allocs/op
+BenchmarkArithmetic/Lsh-4 2000000000 1.06 ns/op 0 B/op 0 allocs/op
+BenchmarkArithmetic/Rsh-4 2000000000 1.06 ns/op 0 B/op 0 allocs/op
+
+BenchmarkDivision/native_64/64-4 2000000000 0.39 ns/op 0 B/op 0 allocs/op
+BenchmarkDivision/Div_128/64-4 2000000000 6.28 ns/op 0 B/op 0 allocs/op
+BenchmarkDivision/Div_128/128-4 30000000 45.2 ns/op 0 B/op 0 allocs/op
+BenchmarkDivision/big.Int_128/64-4 20000000 98.2 ns/op 8 B/op 1 allocs/op
+BenchmarkDivision/big.Int_128/128-4 30000000 53.4 ns/op 48 B/op 1 allocs/op
+
+BenchmarkString/Uint128-4 10000000 173 ns/op 48 B/op 1 allocs/op
+BenchmarkString/big.Int-4 5000000 350 ns/op 144 B/op 3 allocs/op
+```
diff --git a/vendor/lukechampine.com/uint128/uint128.go b/vendor/lukechampine.com/uint128/uint128.go
new file mode 100644
index 0000000..04e6578
--- /dev/null
+++ b/vendor/lukechampine.com/uint128/uint128.go
@@ -0,0 +1,440 @@
+package uint128 // import "lukechampine.com/uint128"
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "math"
+ "math/big"
+ "math/bits"
+)
+
+// Zero is a zero-valued uint128.
+var Zero Uint128
+
+// Max is the largest possible uint128 value.
+var Max = New(math.MaxUint64, math.MaxUint64)
+
+// A Uint128 is an unsigned 128-bit number.
+type Uint128 struct {
+ Lo, Hi uint64
+}
+
+// IsZero returns true if u == 0.
+func (u Uint128) IsZero() bool {
+ // NOTE: we do not compare against Zero, because that is a global variable
+ // that could be modified.
+ return u == Uint128{}
+}
+
+// Equals returns true if u == v.
+//
+// Uint128 values can be compared directly with ==, but use of the Equals method
+// is preferred for consistency.
+func (u Uint128) Equals(v Uint128) bool {
+ return u == v
+}
+
+// Equals64 returns true if u == v.
+func (u Uint128) Equals64(v uint64) bool {
+ return u.Lo == v && u.Hi == 0
+}
+
+// Cmp compares u and v and returns:
+//
+// -1 if u < v
+// 0 if u == v
+// +1 if u > v
+//
+func (u Uint128) Cmp(v Uint128) int {
+ if u == v {
+ return 0
+ } else if u.Hi < v.Hi || (u.Hi == v.Hi && u.Lo < v.Lo) {
+ return -1
+ } else {
+ return 1
+ }
+}
+
+// Cmp64 compares u and v and returns:
+//
+// -1 if u < v
+// 0 if u == v
+// +1 if u > v
+//
+func (u Uint128) Cmp64(v uint64) int {
+ if u.Hi == 0 && u.Lo == v {
+ return 0
+ } else if u.Hi == 0 && u.Lo < v {
+ return -1
+ } else {
+ return 1
+ }
+}
+
+// And returns u&v.
+func (u Uint128) And(v Uint128) Uint128 {
+ return Uint128{u.Lo & v.Lo, u.Hi & v.Hi}
+}
+
+// And64 returns u&v.
+func (u Uint128) And64(v uint64) Uint128 {
+ return Uint128{u.Lo & v, u.Hi & 0}
+}
+
+// Or returns u|v.
+func (u Uint128) Or(v Uint128) Uint128 {
+ return Uint128{u.Lo | v.Lo, u.Hi | v.Hi}
+}
+
+// Or64 returns u|v.
+func (u Uint128) Or64(v uint64) Uint128 {
+ return Uint128{u.Lo | v, u.Hi | 0}
+}
+
+// Xor returns u^v.
+func (u Uint128) Xor(v Uint128) Uint128 {
+ return Uint128{u.Lo ^ v.Lo, u.Hi ^ v.Hi}
+}
+
+// Xor64 returns u^v.
+func (u Uint128) Xor64(v uint64) Uint128 {
+ return Uint128{u.Lo ^ v, u.Hi ^ 0}
+}
+
+// Add returns u+v.
+func (u Uint128) Add(v Uint128) Uint128 {
+ lo, carry := bits.Add64(u.Lo, v.Lo, 0)
+ hi, carry := bits.Add64(u.Hi, v.Hi, carry)
+ if carry != 0 {
+ panic("overflow")
+ }
+ return Uint128{lo, hi}
+}
+
+// AddWrap returns u+v with wraparound semantics; for example,
+// Max.AddWrap(From64(1)) == Zero.
+func (u Uint128) AddWrap(v Uint128) Uint128 {
+ lo, carry := bits.Add64(u.Lo, v.Lo, 0)
+ hi, _ := bits.Add64(u.Hi, v.Hi, carry)
+ return Uint128{lo, hi}
+}
+
+// Add64 returns u+v.
+func (u Uint128) Add64(v uint64) Uint128 {
+ lo, carry := bits.Add64(u.Lo, v, 0)
+ hi, carry := bits.Add64(u.Hi, 0, carry)
+ if carry != 0 {
+ panic("overflow")
+ }
+ return Uint128{lo, hi}
+}
+
+// AddWrap64 returns u+v with wraparound semantics; for example,
+// Max.AddWrap64(1) == Zero.
+func (u Uint128) AddWrap64(v uint64) Uint128 {
+ lo, carry := bits.Add64(u.Lo, v, 0)
+ hi := u.Hi + carry
+ return Uint128{lo, hi}
+}
+
+// Sub returns u-v.
+func (u Uint128) Sub(v Uint128) Uint128 {
+ lo, borrow := bits.Sub64(u.Lo, v.Lo, 0)
+ hi, borrow := bits.Sub64(u.Hi, v.Hi, borrow)
+ if borrow != 0 {
+ panic("underflow")
+ }
+ return Uint128{lo, hi}
+}
+
+// SubWrap returns u-v with wraparound semantics; for example,
+// Zero.SubWrap(From64(1)) == Max.
+func (u Uint128) SubWrap(v Uint128) Uint128 {
+ lo, borrow := bits.Sub64(u.Lo, v.Lo, 0)
+ hi, _ := bits.Sub64(u.Hi, v.Hi, borrow)
+ return Uint128{lo, hi}
+}
+
+// Sub64 returns u-v.
+func (u Uint128) Sub64(v uint64) Uint128 {
+ lo, borrow := bits.Sub64(u.Lo, v, 0)
+ hi, borrow := bits.Sub64(u.Hi, 0, borrow)
+ if borrow != 0 {
+ panic("underflow")
+ }
+ return Uint128{lo, hi}
+}
+
+// SubWrap64 returns u-v with wraparound semantics; for example,
+// Zero.SubWrap64(1) == Max.
+func (u Uint128) SubWrap64(v uint64) Uint128 {
+ lo, borrow := bits.Sub64(u.Lo, v, 0)
+ hi := u.Hi - borrow
+ return Uint128{lo, hi}
+}
+
+// Mul returns u*v, panicking on overflow.
+func (u Uint128) Mul(v Uint128) Uint128 {
+ hi, lo := bits.Mul64(u.Lo, v.Lo)
+ p0, p1 := bits.Mul64(u.Hi, v.Lo)
+ p2, p3 := bits.Mul64(u.Lo, v.Hi)
+ hi, c0 := bits.Add64(hi, p1, 0)
+ hi, c1 := bits.Add64(hi, p3, c0)
+ if (u.Hi != 0 && v.Hi != 0) || p0 != 0 || p2 != 0 || c1 != 0 {
+ panic("overflow")
+ }
+ return Uint128{lo, hi}
+}
+
+// MulWrap returns u*v with wraparound semantics; for example,
+// Max.MulWrap(Max) == 1.
+func (u Uint128) MulWrap(v Uint128) Uint128 {
+ hi, lo := bits.Mul64(u.Lo, v.Lo)
+ hi += u.Hi*v.Lo + u.Lo*v.Hi
+ return Uint128{lo, hi}
+}
+
+// Mul64 returns u*v, panicking on overflow.
+func (u Uint128) Mul64(v uint64) Uint128 {
+ hi, lo := bits.Mul64(u.Lo, v)
+ p0, p1 := bits.Mul64(u.Hi, v)
+ hi, c0 := bits.Add64(hi, p1, 0)
+ if p0 != 0 || c0 != 0 {
+ panic("overflow")
+ }
+ return Uint128{lo, hi}
+}
+
+// MulWrap64 returns u*v with wraparound semantics; for example,
+// Max.MulWrap64(2) == Max.Sub64(1).
+func (u Uint128) MulWrap64(v uint64) Uint128 {
+ hi, lo := bits.Mul64(u.Lo, v)
+ hi += u.Hi * v
+ return Uint128{lo, hi}
+}
+
+// Div returns u/v.
+func (u Uint128) Div(v Uint128) Uint128 {
+ q, _ := u.QuoRem(v)
+ return q
+}
+
+// Div64 returns u/v.
+func (u Uint128) Div64(v uint64) Uint128 {
+ q, _ := u.QuoRem64(v)
+ return q
+}
+
+// QuoRem returns q = u/v and r = u%v.
+func (u Uint128) QuoRem(v Uint128) (q, r Uint128) {
+ if v.Hi == 0 {
+ var r64 uint64
+ q, r64 = u.QuoRem64(v.Lo)
+ r = From64(r64)
+ } else {
+ // generate a "trial quotient," guaranteed to be within 1 of the actual
+ // quotient, then adjust.
+ n := uint(bits.LeadingZeros64(v.Hi))
+ v1 := v.Lsh(n)
+ u1 := u.Rsh(1)
+ tq, _ := bits.Div64(u1.Hi, u1.Lo, v1.Hi)
+ tq >>= 63 - n
+ if tq != 0 {
+ tq--
+ }
+ q = From64(tq)
+ // calculate remainder using trial quotient, then adjust if remainder is
+ // greater than divisor
+ r = u.Sub(v.Mul64(tq))
+ if r.Cmp(v) >= 0 {
+ q = q.Add64(1)
+ r = r.Sub(v)
+ }
+ }
+ return
+}
+
+// QuoRem64 returns q = u/v and r = u%v.
+func (u Uint128) QuoRem64(v uint64) (q Uint128, r uint64) {
+ if u.Hi < v {
+ q.Lo, r = bits.Div64(u.Hi, u.Lo, v)
+ } else {
+ q.Hi, r = bits.Div64(0, u.Hi, v)
+ q.Lo, r = bits.Div64(r, u.Lo, v)
+ }
+ return
+}
+
+// Mod returns r = u%v.
+func (u Uint128) Mod(v Uint128) (r Uint128) {
+ _, r = u.QuoRem(v)
+ return
+}
+
+// Mod64 returns r = u%v.
+func (u Uint128) Mod64(v uint64) (r uint64) {
+ _, r = u.QuoRem64(v)
+ return
+}
+
+// Lsh returns u< 64 {
+ s.Lo = 0
+ s.Hi = u.Lo << (n - 64)
+ } else {
+ s.Lo = u.Lo << n
+ s.Hi = u.Hi<>(64-n)
+ }
+ return
+}
+
+// Rsh returns u>>n.
+func (u Uint128) Rsh(n uint) (s Uint128) {
+ if n > 64 {
+ s.Lo = u.Hi >> (n - 64)
+ s.Hi = 0
+ } else {
+ s.Lo = u.Lo>>n | u.Hi<<(64-n)
+ s.Hi = u.Hi >> n
+ }
+ return
+}
+
+// LeadingZeros returns the number of leading zero bits in u; the result is 128
+// for u == 0.
+func (u Uint128) LeadingZeros() int {
+ if u.Hi > 0 {
+ return bits.LeadingZeros64(u.Hi)
+ }
+ return 64 + bits.LeadingZeros64(u.Lo)
+}
+
+// TrailingZeros returns the number of trailing zero bits in u; the result is
+// 128 for u == 0.
+func (u Uint128) TrailingZeros() int {
+ if u.Lo > 0 {
+ return bits.TrailingZeros64(u.Lo)
+ }
+ return 64 + bits.TrailingZeros64(u.Hi)
+}
+
+// OnesCount returns the number of one bits ("population count") in u.
+func (u Uint128) OnesCount() int {
+ return bits.OnesCount64(u.Hi) + bits.OnesCount64(u.Lo)
+}
+
+// RotateLeft returns the value of u rotated left by (k mod 128) bits.
+func (u Uint128) RotateLeft(k int) Uint128 {
+ const n = 128
+ s := uint(k) & (n - 1)
+ return u.Lsh(s).Or(u.Rsh(n - s))
+}
+
+// RotateRight returns the value of u rotated left by (k mod 128) bits.
+func (u Uint128) RotateRight(k int) Uint128 {
+ return u.RotateLeft(-k)
+}
+
+// Reverse returns the value of u with its bits in reversed order.
+func (u Uint128) Reverse() Uint128 {
+ return Uint128{bits.Reverse64(u.Hi), bits.Reverse64(u.Lo)}
+}
+
+// ReverseBytes returns the value of u with its bytes in reversed order.
+func (u Uint128) ReverseBytes() Uint128 {
+ return Uint128{bits.ReverseBytes64(u.Hi), bits.ReverseBytes64(u.Lo)}
+}
+
+// Len returns the minimum number of bits required to represent u; the result is
+// 0 for u == 0.
+func (u Uint128) Len() int {
+ return 128 - u.LeadingZeros()
+}
+
+// String returns the base-10 representation of u as a string.
+func (u Uint128) String() string {
+ if u.IsZero() {
+ return "0"
+ }
+ buf := []byte("0000000000000000000000000000000000000000") // log10(2^128) < 40
+ for i := len(buf); ; i -= 19 {
+ q, r := u.QuoRem64(1e19) // largest power of 10 that fits in a uint64
+ var n int
+ for ; r != 0; r /= 10 {
+ n++
+ buf[i-n] += byte(r % 10)
+ }
+ if q.IsZero() {
+ return string(buf[i-n:])
+ }
+ u = q
+ }
+}
+
+// PutBytes stores u in b in little-endian order. It panics if len(b) < 16.
+func (u Uint128) PutBytes(b []byte) {
+ binary.LittleEndian.PutUint64(b[:8], u.Lo)
+ binary.LittleEndian.PutUint64(b[8:], u.Hi)
+}
+
+// Big returns u as a *big.Int.
+func (u Uint128) Big() *big.Int {
+ i := new(big.Int).SetUint64(u.Hi)
+ i = i.Lsh(i, 64)
+ i = i.Xor(i, new(big.Int).SetUint64(u.Lo))
+ return i
+}
+
+// Scan implements fmt.Scanner.
+func (u *Uint128) Scan(s fmt.ScanState, ch rune) error {
+ i := new(big.Int)
+ if err := i.Scan(s, ch); err != nil {
+ return err
+ } else if i.Sign() < 0 {
+ return errors.New("value cannot be negative")
+ } else if i.BitLen() > 128 {
+ return errors.New("value overflows Uint128")
+ }
+ u.Lo = i.Uint64()
+ u.Hi = i.Rsh(i, 64).Uint64()
+ return nil
+}
+
+// New returns the Uint128 value (lo,hi).
+func New(lo, hi uint64) Uint128 {
+ return Uint128{lo, hi}
+}
+
+// From64 converts v to a Uint128 value.
+func From64(v uint64) Uint128 {
+ return New(v, 0)
+}
+
+// FromBytes converts b to a Uint128 value.
+func FromBytes(b []byte) Uint128 {
+ return New(
+ binary.LittleEndian.Uint64(b[:8]),
+ binary.LittleEndian.Uint64(b[8:]),
+ )
+}
+
+// FromBig converts i to a Uint128 value. It panics if i is negative or
+// overflows 128 bits.
+func FromBig(i *big.Int) (u Uint128) {
+ if i.Sign() < 0 {
+ panic("value cannot be negative")
+ } else if i.BitLen() > 128 {
+ panic("value overflows Uint128")
+ }
+ u.Lo = i.Uint64()
+ u.Hi = i.Rsh(i, 64).Uint64()
+ return u
+}
+
+// FromString parses s as a Uint128 value.
+func FromString(s string) (u Uint128, err error) {
+ _, err = fmt.Sscan(s, &u)
+ return
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 4259b99..ed1f467 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,3 +1,6 @@
-# github.com/ip2location/ip2location-go/v9 v9.5.0
+# github.com/ip2location/ip2location-go/v9 v9.7.1
## explicit; go 1.14
github.com/ip2location/ip2location-go/v9
+# lukechampine.com/uint128 v1.2.0
+## explicit; go 1.12
+lukechampine.com/uint128