From 5713e8e87191f4eafc132ea0fc15f8cf080ca740 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Fri, 1 Nov 2019 21:50:49 +1300 Subject: [PATCH 1/9] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6fbe31f..95b392a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ goiplookup self-update Go >= 1.11 required: ``` -go get github.com:axllent/goiplookup.git +go get github.com/axllent/goiplookup ``` ## Basic usage From d973296bf520299ecf7553b46905e363e2055623 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 4 Jan 2020 10:39:37 +1300 Subject: [PATCH 2/9] Update year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 511d5ec..a7098d4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ The MIT License (MIT) -Copyright (c) 2019 Ralph Slooten +Copyright (c) 2020 Ralph Slooten Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the From 2a9b1c7d92349fa7f5c7ce5e43bf91a4cd6f412b Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 4 Jan 2020 10:40:48 +1300 Subject: [PATCH 3/9] Update README --- README.md | 70 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 95b392a..ca7f922 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/axllent/goiplookup)](https://goreportcard.com/report/github.com/axllent/goiplookup) -GoipLookup is a geoiplookup replacement for the [free GeoLite2-Country](https://dev.maxmind.com/geoip/geoip2/geolite2/), +GoipLookup is a geoiplookup replacement for the [free MaxMind GeoLite2-Country](https://dev.maxmind.com/geoip/geoip2/geolite2/), written in [Go](https://golang.org/). It currently only supports the free GeoLite2-Country database, and there is no planned support for the other types. @@ -11,10 +11,10 @@ It currently only supports the free GeoLite2-Country database, and there is no p ## Features - Drop-in replacement for the now defunt `geoiplookup` utility, simply rename it -- Works with the current Maxmind database format (mmdd) +- Works with the current MaxMind database format (mmdd) - IPv4, IPv6 and fully qualified domain name (FQDN) support - Options to return just the country iso (`NZ`) or country name (`New Zealand`), rather than the full `GeoIP Country Edition: NZ, New Zealand` -- Built-in database update support +- Built-in database update support (see [Database updates](#database-updates)) - Built-in self updater (if new release is available) @@ -25,23 +25,6 @@ Multiple OS/Architecture binaries are supplied with releases. Extract the binary If you wish to replace an existing defunct implementation of geoiplookup, then simply name the file `geoiplookup`. -## Updating - -GoipLookup comes with a built-in self-updater: - -``` -goiplookup self-update -``` - - -## Compiling from source - -Go >= 1.11 required: - -``` -go get github.com/axllent/goiplookup -``` - ## Basic usage ``` @@ -64,3 +47,50 @@ goiplookup -c 8.8.8.8 Return just the country name goiplookup db-update Update the GeoLite2-Country database (do not run more than once a month) goiplookup self-update Update the GoIpLookup binary with the latest release ``` + + +## GoipLookup updates + +GoipLookup comes with a built-in self-updater: + +``` +goiplookup self-update +``` + +Version checked (`goiplookup -V`) will tell you if your version is out of date. + + +## Database updates + +GoipLookup is able to update your GeoLite2 Country database. As of 01/01/2020 MaxMind require a (free) License Key in order to download these updates. The release (binary) versions of goiplookup (>= 0.2.2) already contain a key for this, however if you are compiling from source you will need to set your own licence key in your environment (see below). + + +### Binary release database updates + +``` +goiplookup db-update +``` + + +### Self-compiled database updates + +If you wish to use your own MaxMind license key, or you are compiling from source, then you must provide a key in your environment. +To generate your own license key from MaxMind you must first [register a free account](https://www.maxmind.com/en/geolite2/signup) and follow the instructions. + +``` +LICENSEKEY="xxxxxxxx" goiplookup db-update +``` +or +``` +export LICENSEKEY="xxxxxxxx" +goiplookup db-update +``` + + +## Compiling from source + +Go >= 1.11 required: + +``` +go get github.com/axllent/goiplookup +``` From 2e04ca277f59738b0f983103c870cd14e5ea8cbc Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 4 Jan 2020 10:42:10 +1300 Subject: [PATCH 4/9] Support for GeoLite2 license key requirements --- Makefile | 2 +- goiplookup.go | 7 ++----- updater.go | 13 +++++++++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index b37d6a6..322971f 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ TAG=`git describe --tags` VERSION ?= `git describe --tags` -LDFLAGS=-ldflags "-s -extldflags \"--static\" -w -X main.version=${VERSION}" +LDFLAGS=-ldflags "-s -extldflags \"--static\" -w -X main.version=${VERSION} -X main.licenseKey=${LICENSEKEY}" build = echo "\n\nBuilding $(1)-$(2)" && CGO_ENABLED=0 GOOS=$(1) GOARCH=$(2) go build ${LDFLAGS} -o dist/goiplookup_${VERSION}_$(1)_$(2) \ && bzip2 dist/goiplookup_${VERSION}_$(1)_$(2) diff --git a/goiplookup.go b/goiplookup.go index 1f40481..82bea37 100644 --- a/goiplookup.go +++ b/goiplookup.go @@ -16,16 +16,13 @@ var ( verboseoutput bool showversion bool dataDir string + licenseKey string // GeoLite2 license key for updating version = "dev" ) -// we set this in `main()` based on OS -// var dataDir (*string) - // URLs const ( - dbUpdateURL = "https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz" - releaseURL = "https://api.github.com/repos/axllent/goiplookup/releases/latest" + releaseURL = "https://api.github.com/repos/axllent/goiplookup/releases/latest" ) // Main function diff --git a/updater.go b/updater.go index d45de8b..bad9ab6 100644 --- a/updater.go +++ b/updater.go @@ -17,6 +17,19 @@ import ( // UpdateGeoLite2Country updates GeoLite2-Country.mmdb func UpdateGeoLite2Country() { + + key := os.Getenv("LICENSEKEY") + if key == "" && licenseKey != "" { + key = licenseKey + } + + if key == "" { + fmt.Println("Error: GeoIP License Key not set.\nPlease see https://github.com/axllent/goiplookup/blob/develop/README.md#database-updates") + os.Exit(1) + } + + dbUpdateURL := fmt.Sprintf("https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=%s&suffix=tar.gz", key) + Verbose("Updating GeoLite2-Country.mmdb") tmpDir := os.TempDir() From 7a63849d4fb11243643da9744b27530180e270d7 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 4 Jan 2020 10:45:26 +1300 Subject: [PATCH 5/9] Update Changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c51ffb..74ce6ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## [dev] + +- Add support for MaxMind (free) license key requirement to update GeoLite2 databases + + ## [0.2.1] - Fix dataDir flag parsing From 0fa16176e9080df347cbb3720ec1ab1764d4c76f Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 4 Jan 2020 10:59:13 +1300 Subject: [PATCH 6/9] Switch to ghru for release updates --- go.mod | 1 + go.sum | 4 ++ goiplookup.go | 22 ++++---- updater.go | 67 ----------------------- utils.go | 143 -------------------------------------------------- 5 files changed, 17 insertions(+), 220 deletions(-) diff --git a/go.mod b/go.mod index 6f6e840..c9d2f92 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/axllent/goiplookup go 1.13 require ( + github.com/axllent/ghru v1.1.3 github.com/oschwald/geoip2-golang v1.3.0 github.com/oschwald/maxminddb-golang v1.5.0 // indirect github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index ba68f12..ebcf356 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +github.com/axllent/ghru v1.1.3 h1:n0jYsuqCYaHHAR6DraXZl8hpBY4j0XV47y5Lyym/jGo= +github.com/axllent/ghru v1.1.3/go.mod h1:rFvMhcO1UAv2Cv6bXscS8EOc7qqNpfe8ZLp23utzs88= +github.com/axllent/semver v0.0.0-20191103011746-394cefa91ee9 h1:LHNcCfePzgC/agAJs5a/5K3hFo8uW04bEdDKDkoX4do= +github.com/axllent/semver v0.0.0-20191103011746-394cefa91ee9/go.mod h1:2xSPzvG8n9mRfdtxSvWvfTfQGWfHsMsHO1iZnKATMSc= github.com/oschwald/geoip2-golang v1.3.0 h1:D+Hsdos1NARPbzZ2aInUHZL+dApIzo8E0ErJVsWcku8= github.com/oschwald/geoip2-golang v1.3.0/go.mod h1:0LTTzix/Ao1uMvOhAV4iLU0Lz7eCrP94qZWBTDKf0iE= github.com/oschwald/maxminddb-golang v1.5.0 h1:rmyoIV6z2/s9TCJedUuDiKht2RN12LWJ1L7iRGtWY64= diff --git a/goiplookup.go b/goiplookup.go index 82bea37..e5189da 100644 --- a/goiplookup.go +++ b/goiplookup.go @@ -5,6 +5,7 @@ import ( "os" "runtime" + "github.com/axllent/ghru" flag "github.com/spf13/pflag" ) @@ -45,16 +46,12 @@ func main() { if showversion { fmt.Println(fmt.Sprintf("Version %s", version)) - latest, err := LatestRelease() - if err == nil && version != latest { - fmt.Println(fmt.Sprintf("Version %s available", latest)) - if _, err := GetUpdateURL(); err == nil { - fmt.Println(fmt.Sprintf("Run `%s self-update` to update", os.Args[0])) - } - } else { - fmt.Println("You have the latest version") + + latest, _, _, err := ghru.Latest("axllent/goiplookup", "goiplookup") + if err == nil && ghru.GreaterThan(latest, version) { + fmt.Printf("Update available: %s\nRun `%s self-update` to update\n", latest, os.Args[0]) } - return + os.Exit(0) } if len(flag.Args()) != 1 || showhelp { @@ -69,7 +66,12 @@ func main() { UpdateGeoLite2Country() } else if lookup == "self-update" { // update app if needed - SelfUpdate() + rel, err := ghru.Update("axllent/goiplookup", "goiplookup", version) + if err != nil { + panic(err) + } + fmt.Printf("Updated %s to version %s\n", os.Args[0], rel) + os.Exit(0) } else { // lookup ip/hostname Lookup(lookup) diff --git a/updater.go b/updater.go index bad9ab6..c9081e8 100644 --- a/updater.go +++ b/updater.go @@ -2,7 +2,6 @@ package main import ( "archive/tar" - "compress/bzip2" "compress/gzip" "fmt" "io" @@ -139,69 +138,3 @@ func ExtractDatabaseFile(dst string, targz string) error { } } } - -// SelfUpdate is a built-in updater -func SelfUpdate() { - tmpDir := os.TempDir() - bz2file := filepath.Join(tmpDir, "goiplookup.bz2") - newexec := filepath.Join(tmpDir, "goiplookup.tmp") - - downloadURL, err := GetUpdateURL() - fmt.Println(fmt.Sprintf("Updating %s", os.Args[0])) - if err != nil { - fmt.Println(fmt.Sprintf("Error: %s", err)) - os.Exit(1) - } - - if err := DownloadToFile(bz2file, downloadURL); err != nil { - fmt.Println(err) - os.Exit(1) - } - - Verbose(fmt.Sprintf("Opening %s", bz2file)) - f, err := os.OpenFile(bz2file, 0, 0) - if err != nil { - fmt.Println(fmt.Sprintf("Error: %s", err)) - os.Exit(1) - } - defer f.Close() - - // create a bzip2 reader - br := bzip2.NewReader(f) - - // write the file - out, err := os.OpenFile(newexec, os.O_CREATE|os.O_RDWR, 0755) - if err != nil { - fmt.Println(fmt.Sprintf("Error: %s", err)) - os.Exit(1) - } - - Verbose(fmt.Sprintf("Extracting %s", newexec)) - - _, err = io.Copy(out, br) - if err != nil { - fmt.Println(fmt.Sprintf("Error: %s", err)) - os.Exit(1) - } - - // replace os.Args[0] with new file - // cannot overwrite open file so rename then delete - // get executable's absolute path - oldexec, _ := os.Readlink("/proc/self/exe") - - err = ReplaceFile(oldexec, newexec) - if err != nil { - fmt.Println(fmt.Sprintf("Error: %s", err)) - fmt.Println("You may require root permissions.") - os.Exit(1) - } - - // remove the src file - Verbose(fmt.Sprintf("Deleting %s", bz2file)) - if err := os.Remove(bz2file); err != nil { - fmt.Println(fmt.Sprintf("Error: %s", err)) - os.Exit(1) - } - - fmt.Println("Done") -} diff --git a/utils.go b/utils.go index 7949670..1c51679 100644 --- a/utils.go +++ b/utils.go @@ -1,36 +1,17 @@ package main import ( - "encoding/json" "fmt" "io" - "io/ioutil" "net" "net/http" "os" "path" - "path/filepath" - "runtime" "strings" "github.com/oschwald/geoip2-golang" ) -// Repository Struct for Github release json -type Repository struct { - Assets []struct { - BrowserDownloadURL string `json:"browser_download_url"` - CreatedAt string `json:"created_at"` - ID int64 `json:"id"` - Name string `json:"name"` - Size int64 `json:"size"` - } `json:"assets"` - Name string `json:"name"` - Prerelease bool `json:"prerelease"` - PublishedAt string `json:"published_at"` - TagName string `json:"tag_name"` -} - // Lookup ip or hostname func Lookup(lookup string) { @@ -134,130 +115,6 @@ func DownloadToFile(filepath string, url string) error { return err } -// LatestRelease fetches the latest release -func LatestRelease() (string, error) { - resp, err := http.Get(releaseURL) - if err != nil { - return "", err - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - - if err != nil { - return "", err - } - - var result Repository - - json.Unmarshal(body, &result) - - return result.TagName, nil -} - -// GetUpdateURL returns a download URL based on OS & architecture -func GetUpdateURL() (string, error) { - Verbose(fmt.Sprintf("Fetching %s", releaseURL)) - resp, err := http.Get(releaseURL) - if err != nil { - return "", err - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - - if err != nil { - return "", err - } - - var result Repository - - json.Unmarshal(body, &result) - - Verbose(fmt.Sprintf("Latest release is %s", result.TagName)) - if version == result.TagName { - return "", fmt.Errorf("You already have the latest version (%s)", version) - } - - linkOS := runtime.GOOS - linkArch := runtime.GOARCH - releaseName := fmt.Sprintf("goiplookup_%s_%s_%s.bz2", result.TagName, linkOS, linkArch) - - Verbose(fmt.Sprintf("Searching %s", releaseName)) - - for _, v := range result.Assets { - if v.Name == releaseName { - Verbose(fmt.Sprintf("Found download URL %s", v.BrowserDownloadURL)) - return v.BrowserDownloadURL, nil - } - } - - return "", fmt.Errorf("No downlodable update found for %s", releaseName) // nothing found -} - -// ReplaceFile replaces one file with another -func ReplaceFile(dst string, src string) error { - // open the source file for reading - Verbose(fmt.Sprintf("Opening %s", src)) - source, err := os.Open(src) - if err != nil { - return err - } - defer source.Close() - - // destination directory eg: /usr/local/bin - dstDir := filepath.Dir(dst) - // binary filename eg: goiplookup - binaryFilename := filepath.Base(dst) - // old tmp file name - dstOld := fmt.Sprintf("%s.old", binaryFilename) - // new tmp file name - dstNew := fmt.Sprintf("%s.new", binaryFilename) - // absolute path of new tmp file - newTmpAbs := filepath.Join(dstDir, dstNew) - // absolute path of old tmp file - oldTmpAbs := filepath.Join(dstDir, dstOld) - - // create the new file - tmpNew, err := os.OpenFile(newTmpAbs, os.O_CREATE|os.O_RDWR, 0755) - if err != nil { - return err - } - defer tmpNew.Close() - - // copy new binary to .new - Verbose(fmt.Sprintf("Copying %s to %s", src, newTmpAbs)) - if _, err := io.Copy(tmpNew, source); err != nil { - return err - } - - // rename the current executable to .old - Verbose(fmt.Sprintf("Renaming %s to %s", dst, oldTmpAbs)) - if err := os.Rename(dst, oldTmpAbs); err != nil { - return err - } - - // rename the .new to current executable - Verbose(fmt.Sprintf("Renaming %s to %s", newTmpAbs, dst)) - if err := os.Rename(newTmpAbs, dst); err != nil { - return err - } - - // delete the old binary - Verbose(fmt.Sprintf("Deleting %s", oldTmpAbs)) - if err := os.Remove(oldTmpAbs); err != nil { - return err - } - - // remove the src file - Verbose(fmt.Sprintf("Deleting %s", src)) - if err := os.Remove(src); err != nil { - return err - } - - return nil -} - // Verbose displays debug information with `-v` func Verbose(m string) { if verboseoutput { From 5d02a7c4cb88061813b91f424f5e4ab1fb84e35e Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 4 Jan 2020 10:59:45 +1300 Subject: [PATCH 7/9] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74ce6ef..7e5f7f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [dev] - Add support for MaxMind (free) license key requirement to update GeoLite2 databases +- Switch to [ghru](https://github.com/axllent/ghru) for binary release updates ## [0.2.1] From 74bc4fa84fe7c741833b84429227914bc154be42 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 4 Jan 2020 11:02:48 +1300 Subject: [PATCH 8/9] Shorten help link --- updater.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/updater.go b/updater.go index c9081e8..e0cbd6c 100644 --- a/updater.go +++ b/updater.go @@ -23,7 +23,7 @@ func UpdateGeoLite2Country() { } if key == "" { - fmt.Println("Error: GeoIP License Key not set.\nPlease see https://github.com/axllent/goiplookup/blob/develop/README.md#database-updates") + fmt.Println("Error: GeoIP License Key not set.\nPlease see https://github.com/axllent/goiplookup#database-updates") os.Exit(1) } From 9bada8822ca462eea8fa398608a4839153b75da1 Mon Sep 17 00:00:00 2001 From: Ralph Slooten Date: Sat, 4 Jan 2020 11:03:58 +1300 Subject: [PATCH 9/9] 0.2.2 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e5f7f8..cb1487e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [dev] +## [0.2.2] - Add support for MaxMind (free) license key requirement to update GeoLite2 databases - Switch to [ghru](https://github.com/axllent/ghru) for binary release updates