commit b441e33c8989cab48c95d358b744b2dcda76da8f Author: Ryan Hamilton Date: Wed Nov 10 11:28:54 2021 -0600 initial commit diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..768724f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,20 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Go Build", + "type": "shell", + "command": "go build -o bin/", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "silent", + "clear": true + }, + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8eab024 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# GetCountryFromIP + +Simple go executable to task an ip and get the results from ip-api +https://ip-api.com/ +https://ip-api.com/docs/api:json + +This is a fantastic site and I hope the continue to provide this + +Allows flag -p to replace the properties output + +## Usage Example + +GetCountryFromIP.exe -ip 8.8.8.8 + +Output: + +United States + +GetCountryFromIP.exe -ip 8.8.8.8 -p country,isp + +Output: + +United States,Google LLC diff --git a/bin/GetCountryFromIP.exe b/bin/GetCountryFromIP.exe new file mode 100644 index 0000000..b6d048c Binary files /dev/null and b/bin/GetCountryFromIP.exe differ diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..af3575f --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module GetCountryFromIP + +go 1.17 diff --git a/ip_api.go b/ip_api.go new file mode 100644 index 0000000..4b219cc --- /dev/null +++ b/ip_api.go @@ -0,0 +1,56 @@ +package main + +import ( + "encoding/json" + "net/http" +) + +// Build URL to query IP-API +// https://ip-api.com/docs/api:json +func buildURL(ip string) string { + return "http://ip-api.com/json/" + ip +} + +func Lookup(ip string, properties []string) map[string]interface{} { + CheckValidIP(ip) + url := buildURL(ip) + resp, err := http.Get(url) + + if err != nil { + debugOut(Error, err.Error()) + } + defer resp.Body.Close() + + var data map[string]interface{} + err = json.NewDecoder(resp.Body).Decode(&data) + if err != nil { + debugOut(Error, err.Error()) + } + if data["status"] == "fail" { + debugOut(Error, data["message"].(string)) + } + return data +} + +func GetProperties(data map[string]interface{}) string { + + var output string = "" + + for _, property := range properties { + found := false + for key, value := range data { + if key == property { + if output != "" { + output += "," + } + output += value.(string) + found = true + } + } + if !found { + debugOut(Error, "Property '"+property+"' not found") + } + } + + return output +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..67a3f77 --- /dev/null +++ b/main.go @@ -0,0 +1,15 @@ +package main + +import "fmt" + +var verbose bool = false +var ip string +var properties []string + +func main() { + parseFlags() + + result := GetProperties(Lookup(ip, properties)) + + fmt.Println(result) +} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..a87659d --- /dev/null +++ b/utils.go @@ -0,0 +1,71 @@ +package main + +import ( + "flag" + "fmt" + "os" + "regexp" + "strings" +) + +type Verbosity int + +const ( + Info Verbosity = iota + Warning + Error + Debug +) + +func debugOut(level Verbosity, text string) { + switch level { + case Info: + if verbose { + fmt.Println("[INFO] " + text) + } else { + fmt.Println(text) + } + case Warning: + if verbose { + fmt.Println("[WARNING] " + text) + } + case Error: + fmt.Println("[ERROR] " + text) + os.Exit(1) + case Debug: + if verbose { + fmt.Println("[DEBUG] " + text) + } + } +} + +func CheckValidIP(ip string) { + 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])$`) + if !re.MatchString(ip) { + debugOut(Error, "Please enter a valid IP address") + } +} + +func parseFlags() { + _ip := flag.String("ip", "", "IP address to lookup") + _props := flag.String("p", "country", "Properties to retrieve") + _verbose := flag.Bool("v", false, "Verbose output") + flag.Parse() + _loose := flag.Args() + + if *_verbose { + verbose = true + } + if *_ip == "" { + if len(_loose) == 0 { + debugOut(Error, "Please enter an IP address or use -h for help") + } else { + ip = _loose[0] + } + } else { + ip = *_ip + } + if _props != nil { + properties = strings.Split(*_props, ",") + } +}