diff --git a/.gitignore b/.gitignore index d0b7f31..a7988a9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -bin/* -lookupip +bin/* +lookupip diff --git a/README.md b/README.md index 432db02..6e583e2 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,60 @@ -# lookupip - -Simple go executable to task an ip and get the results from ip-api -https://ip-api.com/ - -This is a fantastic site and I hope the continue to provide this - -Allows flag -p to replace the properties output - -## Build - -I build this on Windows with - - go build -o bin/ - -## Usage - -> **Default (Country Name)** -> -> lookupip.exe -ip 8.8.8.8 -> -> **Output:** -> -> United States - -> **Custom return (Country Name and ISP)** -> -> lookupip.exe -ip 8.8.8.8 -p country,isp -> -> **Output:** -> -> United States,Google LLC - -## Custom Properties - -https://ip-api.com/docs/api:json - -| name | description | example | type | -| ------------- | ------------------------------------------ | ------------------- | ------ | -| Continent | Continent name | North America | string | -| ContinentCode | Two-letter continent code | NA | string | -| Country | Country name | United States | string | -| CountryCode | Two-letter country code ISO 3166-1 alpha-2 | US | string | -| Region | Region/state short code (FIPS or ISO) | CA or 10 | string | -| RegionName | Region/state | California | string | -| City | City | Mountain View | string | -| District | District (subdivision of city) | Old Farm District | string | -| Zip | Zip code | 94043 | string | -| Lat | Latitude | 37.4192 | float | -| Lon | Longitude | -122.0574 | float | -| Timezone | Timezone (tz) | America/Los_Angeles | string | -| Offset | Timezone UTC DST offset in seconds | -25200 | int | -| Currency | National currency | USD | string | -| ISP | ISP name | Google | string | -| Org | Organization name | Google | string | -| AS | AS number and organization (RIR). | AS15169 Google Inc. | string | -| ASName | AS name (RIR). | GOOGLE | string | -| Reverse | Reverse DNS of the IP (can delay response) | wi-in-f94.1e100.net | string | -| Hosting | Hosting, colocated or data center | true | bool | -| Query | IP used for the query | 173.194.67.94 | string | +# lookupip + +Simple go executable to task an ip and get the results from ip-api +https://ip-api.com/ + +This is a fantastic site and I hope the continue to provide this + +Allows flag -p to replace the properties output + +## Build + +I build this on Windows with + + go build -o bin/ + +## Usage + +> **Default (Country Name)** +> +> lookupip.exe -ip 8.8.8.8 +> +> **Output:** +> +> United States + +> **Custom return (Country Name and ISP)** +> +> lookupip.exe -ip 8.8.8.8 -p country,isp +> +> **Output:** +> +> United States,Google LLC + +## Custom Properties + +https://ip-api.com/docs/api:json + +| name | description | example | type | +| ------------- | ------------------------------------------ | ------------------- | ------ | +| Continent | Continent name | North America | string | +| ContinentCode | Two-letter continent code | NA | string | +| Country | Country name | United States | string | +| CountryCode | Two-letter country code ISO 3166-1 alpha-2 | US | string | +| Region | Region/state short code (FIPS or ISO) | CA or 10 | string | +| RegionName | Region/state | California | string | +| City | City | Mountain View | string | +| District | District (subdivision of city) | Old Farm District | string | +| Zip | Zip code | 94043 | string | +| Lat | Latitude | 37.4192 | float | +| Lon | Longitude | -122.0574 | float | +| Timezone | Timezone (tz) | America/Los_Angeles | string | +| Offset | Timezone UTC DST offset in seconds | -25200 | int | +| Currency | National currency | USD | string | +| ISP | ISP name | Google | string | +| Org | Organization name | Google | string | +| AS | AS number and organization (RIR). | AS15169 Google Inc. | string | +| ASName | AS name (RIR). | GOOGLE | string | +| Reverse | Reverse DNS of the IP (can delay response) | wi-in-f94.1e100.net | string | +| Hosting | Hosting, colocated or data center | true | bool | +| Query | IP used for the query | 173.194.67.94 | string | diff --git a/main.go b/main.go index 42eadaa..30e2e99 100644 --- a/main.go +++ b/main.go @@ -1,26 +1,26 @@ -package main - -import ( - "flag" - - "github.com/ryanehamil/lookupip/src/ipapi" - "github.com/ryanehamil/lookupip/src/utils" -) - -func main() { - ip := flag.String("ip", "", "IP address to lookup") - properties := flag.String("p", "", "Properties to retrieve") - detail := flag.Bool("d", false, "Show Detail") - flag.Parse() - - // Use the IP-API to lookup the IP address - data, err := ipapi.Lookup(*ip) - utils.HandleError(err) - - // Format the data to a string - result := ipapi.GetProperties(data, *properties, *detail) - - // Print result with PrintOut - utils.PrintOut(result) - utils.Exit(0) -} +package main + +import ( + "flag" + + "github.com/ryanehamil/lookupip/src/ipapi" + "github.com/ryanehamil/lookupip/src/utils" +) + +func main() { + ip := flag.String("ip", "", "IP address to lookup") + properties := flag.String("p", "", "Properties to retrieve") + detail := flag.Bool("d", false, "Show Detail") + flag.Parse() + + // Use the IP-API to lookup the IP address + data, err := ipapi.Lookup(*ip) + utils.HandleError(err) + + // Format the data to a string + result := ipapi.GetProperties(data, *properties, *detail) + + // Print result with PrintOut + utils.PrintOut(result) + utils.Exit(0) +} diff --git a/main_test.go b/main_test.go index d198d1a..a3acf6e 100644 --- a/main_test.go +++ b/main_test.go @@ -1,38 +1,38 @@ -package main - -import ( - "testing" - - "github.com/ryanehamil/lookupip/src/ipapi" - "github.com/ryanehamil/lookupip/src/utils" -) - -// TestBuildURL -// Tests that the buildURL function returns a correct URL -func TestLookup(t *testing.T) { - var tests = []struct { - input string - want string - explain string - }{ - {"", "Any IPV4", "Lookup my own IP"}, - {"8.8.8.8", "United States", "Lookup Google's DNS"}, - } - - for _, test := range tests { - ip := test.input - // Use the IP-API to lookup anything - data, _ := ipapi.Lookup(ip) - - got := ipapi.GetProperties(data, "", false) - - if test.want == "Any IPV4" { - if !utils.CheckValidIP(data.Query) { - t.Errorf("%q. error-buildURL(%q) = %v, want %v", test.explain, test.input, got, test.want) - } - } else if got != test.want { - t.Errorf("%q. lookup(%q) = %v, want %v", test.explain, test.input, got, test.want) - } - - } -} +package main + +import ( + "testing" + + "github.com/ryanehamil/lookupip/src/ipapi" + "github.com/ryanehamil/lookupip/src/utils" +) + +// TestBuildURL +// Tests that the buildURL function returns a correct URL +func TestLookup(t *testing.T) { + var tests = []struct { + input string + want string + explain string + }{ + {"", "Any IPV4", "Lookup my own IP"}, + {"8.8.8.8", "United States", "Lookup Google's DNS"}, + } + + for _, test := range tests { + ip := test.input + // Use the IP-API to lookup anything + data, _ := ipapi.Lookup(ip) + + got := ipapi.GetProperties(data, "", false) + + if test.want == "Any IPV4" { + if !utils.CheckValidIP(data.Query) { + t.Errorf("%q. error-buildURL(%q) = %v, want %v", test.explain, test.input, got, test.want) + } + } else if got != test.want { + t.Errorf("%q. lookup(%q) = %v, want %v", test.explain, test.input, got, test.want) + } + + } +} diff --git a/src/ipapi/ip_api.go b/src/ipapi/ip_api.go index f817b94..a8126f0 100644 --- a/src/ipapi/ip_api.go +++ b/src/ipapi/ip_api.go @@ -1,115 +1,115 @@ -package ipapi - -import ( - "encoding/json" - "errors" - "fmt" - "net/http" - "reflect" - "strings" - - "github.com/ryanehamil/lookupip/src/utils" -) - -// IP-API data struct -// https://ip-api.com/docs/api:json -type IPAPI struct { - Continent string `json:"continent"` - ContinentCode string `json:"continentCode"` - Country string `json:"country"` - CountryCode string `json:"countryCode"` - Region string `json:"region"` - RegionName string `json:"regionName"` - City string `json:"city"` - Zip string `json:"zip"` - Lat float32 `json:"lat"` - Lon float32 `json:"lon"` - Timezone string `json:"timezone"` - Offset int `json:"offset"` - Currency string `json:"currency"` - ISP string `json:"isp"` - Org string `json:"org"` - AS string `json:"as"` - ASName string `json:"asname"` - Reverse string `json:"reverse"` - Hosting bool `json:"hosting"` - Query string `json:"query"` - Status string `json:"status"` - Message string `json:"message"` -} - -// Add the .String() method to IPAPI -func (i *IPAPI) String() string { - return i.Query -} - -// Build URL to query IP-API -// https://ip-api.com/docs/api:json -func buildURL(ip string) (string, error) { - url := "http://ip-api.com/json" - if ip != "" { - ip = strings.TrimSpace(ip) - if !utils.CheckValidIP(ip) { - var err = errors.New("invalid IP address, failed CheckValidIP") - return url, err - } - url += fmt.Sprintf("/%s", ip) - } - return url, nil -} - -// Get IP-API data about IP -// -// https://ip-api.com/docs/api:json -func Lookup(ip string) (data IPAPI, err error) { - - url, error := buildURL(ip) - if error != nil { - return data, error - } - - resp, err := http.Get(url) - if error != nil { - return data, error - } - - defer resp.Body.Close() - - err = json.NewDecoder(resp.Body).Decode(&data) - if error != nil { - return data, error - } - - if data.Status == "fail" { - utils.PrintOut("IP-API returned an error: " + data.Message) - utils.Exit(1) - } - return data, nil -} - -func GetProperties(data IPAPI, properties_string string, detail bool) (output string) { - if properties_string == "" { - properties_string = "Country" - } - result := "" - properties := strings.Split(properties_string, ",") - - for _, property := range properties { - datafield := reflect.Indirect(reflect.ValueOf(data)).FieldByName(property).String() - if datafield != "" { - result = datafield - } else { - result = "" - } - - if detail { - output += property + ": " + result + "\n" - } else { - if output != "" { - output += "," - } - output += result - } - } - return output -} +package ipapi + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "reflect" + "strings" + + "github.com/ryanehamil/lookupip/src/utils" +) + +// IP-API data struct +// https://ip-api.com/docs/api:json +type IPAPI struct { + Continent string `json:"continent"` + ContinentCode string `json:"continentCode"` + Country string `json:"country"` + CountryCode string `json:"countryCode"` + Region string `json:"region"` + RegionName string `json:"regionName"` + City string `json:"city"` + Zip string `json:"zip"` + Lat float32 `json:"lat"` + Lon float32 `json:"lon"` + Timezone string `json:"timezone"` + Offset int `json:"offset"` + Currency string `json:"currency"` + ISP string `json:"isp"` + Org string `json:"org"` + AS string `json:"as"` + ASName string `json:"asname"` + Reverse string `json:"reverse"` + Hosting bool `json:"hosting"` + Query string `json:"query"` + Status string `json:"status"` + Message string `json:"message"` +} + +// Add the .String() method to IPAPI +func (i *IPAPI) String() string { + return i.Query +} + +// Build URL to query IP-API +// https://ip-api.com/docs/api:json +func buildURL(ip string) (string, error) { + url := "http://ip-api.com/json" + if ip != "" { + ip = strings.TrimSpace(ip) + if !utils.CheckValidIP(ip) { + var err = errors.New("invalid IP address, failed CheckValidIP") + return url, err + } + url += fmt.Sprintf("/%s", ip) + } + return url, nil +} + +// Get IP-API data about IP +// +// https://ip-api.com/docs/api:json +func Lookup(ip string) (data IPAPI, err error) { + + url, error := buildURL(ip) + if error != nil { + return data, error + } + + resp, err := http.Get(url) + if error != nil { + return data, error + } + + defer resp.Body.Close() + + err = json.NewDecoder(resp.Body).Decode(&data) + if error != nil { + return data, error + } + + if data.Status == "fail" { + utils.PrintOut("IP-API returned an error: " + data.Message) + utils.Exit(1) + } + return data, nil +} + +func GetProperties(data IPAPI, properties_string string, detail bool) (output string) { + if properties_string == "" { + properties_string = "Country" + } + result := "" + properties := strings.Split(properties_string, ",") + + for _, property := range properties { + datafield := reflect.Indirect(reflect.ValueOf(data)).FieldByName(property).String() + if datafield != "" { + result = datafield + } else { + result = "" + } + + if detail { + output += property + ": " + result + "\n" + } else { + if output != "" { + output += "," + } + output += result + } + } + return output +} diff --git a/src/ipapi/ip_api_test.go b/src/ipapi/ip_api_test.go index a5b8df6..154707d 100644 --- a/src/ipapi/ip_api_test.go +++ b/src/ipapi/ip_api_test.go @@ -1,87 +1,87 @@ -package ipapi - -import ( - "testing" - - "github.com/ryanehamil/lookupip/src/utils" -) - -// TestBuildURL -// Tests that the buildURL function returns a correct URL -func TestBuildURL(t *testing.T) { - var tests = []struct { - ip string - want string - explain string - }{ - {"127.0.0.1", "http://ip-api.com/json/127.0.0.1", "Valid IP"}, - {" 127.0.0.1 ", "http://ip-api.com/json/127.0.0.1", "Dirty IP"}, - {"127.foo.bar.1", "invalid IP address, failed CheckValidIP", "Unsantized input"}, - } - - for _, test := range tests { - got, err := buildURL(test.ip) - - if err != nil { - if err.Error() != test.want { - t.Errorf("%q. error-buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) - } - } else if got != test.want { - t.Errorf("%q. buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) - } - } -} - -// TestLookup -// Tests that the lookup function returns IPAPI data and no error -func TestLookup(t *testing.T) { - var tests = []struct { - ip string - want string - explain string - }{ - {"8.8.8.8", "United States", "Google Public DNS"}, - {"199.211.133.90", "United States", "Naval Oceanography"}, - {"116.202.3.251", "Germany", "JAM Software Germany"}, - {"", "Any IP", "Get my IP"}, - } - - for _, test := range tests { - data, err := Lookup(test.ip) - got := data.Country - if err != nil && err.Error() != test.want { - t.Errorf("%q. error-buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) - } else if test.want == "Any IP" { - if !utils.CheckValidIP(data.Query) { - t.Errorf("%q. error-buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) - } - } else if got != test.want { - t.Errorf("%q. buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) - } - - } -} - -func TestGetProperties(t *testing.T) { - var tests = []struct { - properties string - want string - explain string - }{ - {"", "United States", "No properties requested"}, - {"Country", "United States", "Properties: Country"}, - {"Country,ISP", "United States,Google LLC", "Properties: Country,ISP"}, - } - - for _, test := range tests { - // This test relies on the lookup function - ip := "8.8.8.8" - // Use the IP-API to lookup anything - data, _ := Lookup(ip) - - got := GetProperties(data, test.properties, false) - if got != test.want { - t.Errorf("%q. GetProperties(%q) = %v, want %v", test.explain, test.properties, got, test.want) - } - } -} +package ipapi + +import ( + "testing" + + "github.com/ryanehamil/lookupip/src/utils" +) + +// TestBuildURL +// Tests that the buildURL function returns a correct URL +func TestBuildURL(t *testing.T) { + var tests = []struct { + ip string + want string + explain string + }{ + {"127.0.0.1", "http://ip-api.com/json/127.0.0.1", "Valid IP"}, + {" 127.0.0.1 ", "http://ip-api.com/json/127.0.0.1", "Dirty IP"}, + {"127.foo.bar.1", "invalid IP address, failed CheckValidIP", "Unsantized input"}, + } + + for _, test := range tests { + got, err := buildURL(test.ip) + + if err != nil { + if err.Error() != test.want { + t.Errorf("%q. error-buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) + } + } else if got != test.want { + t.Errorf("%q. buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) + } + } +} + +// TestLookup +// Tests that the lookup function returns IPAPI data and no error +func TestLookup(t *testing.T) { + var tests = []struct { + ip string + want string + explain string + }{ + {"8.8.8.8", "United States", "Google Public DNS"}, + {"199.211.133.90", "United States", "Naval Oceanography"}, + {"116.202.3.251", "Germany", "JAM Software Germany"}, + {"", "Any IP", "Get my IP"}, + } + + for _, test := range tests { + data, err := Lookup(test.ip) + got := data.Country + if err != nil && err.Error() != test.want { + t.Errorf("%q. error-buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) + } else if test.want == "Any IP" { + if !utils.CheckValidIP(data.Query) { + t.Errorf("%q. error-buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) + } + } else if got != test.want { + t.Errorf("%q. buildURL(%q) = %v, want %v", test.explain, test.ip, got, test.want) + } + + } +} + +func TestGetProperties(t *testing.T) { + var tests = []struct { + properties string + want string + explain string + }{ + {"", "United States", "No properties requested"}, + {"Country", "United States", "Properties: Country"}, + {"Country,ISP", "United States,Google LLC", "Properties: Country,ISP"}, + } + + for _, test := range tests { + // This test relies on the lookup function + ip := "8.8.8.8" + // Use the IP-API to lookup anything + data, _ := Lookup(ip) + + got := GetProperties(data, test.properties, false) + if got != test.want { + t.Errorf("%q. GetProperties(%q) = %v, want %v", test.explain, test.properties, got, test.want) + } + } +} diff --git a/src/utils/utils.go b/src/utils/utils.go index 792f2f8..a293370 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -1,42 +1,42 @@ -package utils - -import ( - "fmt" - "os" - "regexp" -) - -// For printing to the console -// -// Currently using fmt.Println -func PrintOut(msg ...interface{}) { - fmt.Println(msg...) -} - -// Check if a string is a valid ipv4 address -// -// Currently using regexp.MustCompile and regexp.MatchString to return boolean -func CheckValidIP(ip string) bool { - re := regexp.MustCompile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`) - return re.MatchString(ip) -} - -// Error handler for the program -// -// Checks if error !nil and prints the error to the console -func HandleError(err error) { - if err != nil { - PrintOut(err) - Exit(1) - } -} - -// Simple Exit function to handle exit codes -// -// Might need to be changed to a more robust one -func Exit(code int) { - if code != 0 { - panic("exit") - } - os.Exit(code) -} +package utils + +import ( + "fmt" + "os" + "regexp" +) + +// For printing to the console +// +// Currently using fmt.Println +func PrintOut(msg ...interface{}) { + fmt.Println(msg...) +} + +// Check if a string is a valid ipv4 address +// +// Currently using regexp.MustCompile and regexp.MatchString to return boolean +func CheckValidIP(ip string) bool { + re := regexp.MustCompile(`^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$`) + return re.MatchString(ip) +} + +// Error handler for the program +// +// Checks if error !nil and prints the error to the console +func HandleError(err error) { + if err != nil { + PrintOut(err) + Exit(1) + } +} + +// Simple Exit function to handle exit codes +// +// Might need to be changed to a more robust one +func Exit(code int) { + if code != 0 { + panic("exit") + } + os.Exit(code) +} diff --git a/src/utils/utils_test.go b/src/utils/utils_test.go index ae9d529..c08b4af 100644 --- a/src/utils/utils_test.go +++ b/src/utils/utils_test.go @@ -1,24 +1,24 @@ -package utils - -import ( - "testing" -) - -func TestCheckValidIP(t *testing.T) { - - var tests = []struct { - ip string - want bool - explain string - }{ - {"127.0.0.1", true, "Valid IP"}, - {"127.X.X.1", false, "Invalid IP"}, - } - - for _, test := range tests { - got := CheckValidIP(test.ip) - if got != test.want { - t.Errorf("%q. CheckValidIP(%q) = %v", test.explain, test.ip, got) - } - } -} +package utils + +import ( + "testing" +) + +func TestCheckValidIP(t *testing.T) { + + var tests = []struct { + ip string + want bool + explain string + }{ + {"127.0.0.1", true, "Valid IP"}, + {"127.X.X.1", false, "Invalid IP"}, + } + + for _, test := range tests { + got := CheckValidIP(test.ip) + if got != test.want { + t.Errorf("%q. CheckValidIP(%q) = %v", test.explain, test.ip, got) + } + } +}