Building a CLI based IP Tracing application in Go

Sujay ks
3 min readAug 20, 2023

In this blog we’ll be developing a CLI tool, This tool will be designed to handle user input through command-line arguments and we will be using IPinfo.io API to gather comprehensive geolocation information .

This information will encompass crucial details such as the city, region, country, latitude, longitude, timezone, and more. feel free to refer the code:

github.com/sujay2306/IP-Lookup

Setting Up the Project

To start, let’s set up the basic project structure and install any necessary dependencies. We’ll use the Cobra library to create our CLI app.

  1. Create a new Go project directory and navigate into it:
    mkdir IP-Lookup
    cd IP-Lookup
mkdir IP-Lookup
cd IP-Lookup

2, Lets initialize a Go module:

go mod init IP-Lookup

3. We will be using cobra, so lets get it install

go get -u github.com/spf13/cobra@latest

4. Now, create a cmd directory within your project directory to organize your CLI-related code:

mkdir cmd

Designing the Command Structure

Our CLI app will have a root command and a subcommand named “trace” that will allow us to trace IP addresses. Let’s set up the command structure using Cobra.

cmd/root.go

package cmd

import (
"github.com/spf13/cobra"
)

var (

rootCmd = &cobra.Command{
Use: "IPLookup-CLI",
Short: "A CLI for tracking IP",
Long: `IPLookup-cli is a CLI application which gives info about the user provided IP Address.`,
}
)

// Execute executes the root command.
func Execute() error {
return rootCmd.Execute()
}

cmd/trace.go

Now, let's dive into the heart of our CLI app – fetching and displaying IP geolocation data. We'll use the IPinfo.io API to retrieve the data. Here's how we do it:

package cmd

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"github.com/fatih/color"
"github.com/spf13/cobra"
)

// traceCmd represents the trace command
var traceCmd = &cobra.Command{
Use: "trace",
Short: "Trace the IP",
Long: `Trace the IP.`,
Run: func(cmd *cobra.Command, args []string) {
if len(args) > 0 {
for _, ip := range args {
showData(ip)
}
} else {
fmt.Println("Please provide IP to trace.")
}
},
}

func init() {
rootCmd.AddCommand(traceCmd)
}

// {
// "ip": "1.1.1.1",
// "hostname": "one.one.one.one",
// "anycast": true,
// "city": "Miami",
// "region": "Florida",
// "country": "US",
// "loc": "25.7867,-80.1800",
// "org": "AS13335 Cloudflare, Inc.",
// "postal": "33132",
// "timezone": "America/New_York",
// "readme": "https://ipinfo.io/missingauth"
// }

type Ip struct {
IP string `json:"ip"`
City string `json:"city"`
Region string `json:"region"`
Country string `json:"country"`
Loc string `json:"loc"`
Timezone string `json:"timezone"`
Postal string `json:"postal"`
}

func showData(ip string) {
url := "http://ipinfo.io/" + ip + "/geo"
responseByte := getData(url)

data := Ip{}

err := json.Unmarshal(responseByte, &data)
if err != nil {
log.Println("Unable to unmarshal the response")
}

c := color.New(color.FgRed).Add(color.Underline).Add(color.Bold)
c.Println("DATA FOUND :")

fmt.Printf("IP :%s\nCITY :%s\nREGION :%s\nCOUNTRY :%s\nLOCATION :%s\nTIMEZONE:%s\nPOSTAL :%s\n", data.IP, data.City, data.Region, data.Country, data.Loc, data.Timezone, data.Postal)

}

func getData(url string) []byte {

response, err := http.Get(url)
if err != nil {
log.Println("Unable to get the response")
}

responseByte, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Println("Unable to read the response")
}

return responseByte
}

To make our CLI app more visually appealing, we’ll use the github.com/fatih/color package to add color, underline, and bold formatting to our output.

Lets try out our application:
Hurray 🥂 ✨ , here we have the info about the given IP

Wrapping Up

Feel free to explore the complete code on github.com/sujay2306/IP-Lookup and make further enhancements. If you found this tutorial helpful, don’t hesitate to share your feedback and experiences in the comments.

Happy coding!

--

--