17 Commits
mvp ... v1.3.10

9 changed files with 209 additions and 31 deletions

63
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,63 @@
name: Build
on:
push:
tags: '*'
jobs:
prepare-data:
name: Prepare Data
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.prepare.outputs.SOURCE_TAG }}
repo: ${{ steps.prepare.outputs.REPO }}
lrepo: ${{ steps.prepare.outputs.LREPO }}
steps:
- id: prepare
name: Prepare environment variables
run: |
echo ::set-output name=SOURCE_NAME::${GITHUB_REF#refs/*/}
echo ::set-output name=SOURCE_BRANCH::${GITHUB_REF#refs/heads/}
echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/}
echo ::set-output name=REPO::${GITHUB_REPOSITORY#luketainton/}
echo ::set-output name=LREPO::${GITHUB_REPOSITORY#luketainton/} | tr '[:upper:]' '[:lower:]'
docker:
name: GitHub Package Registry
runs-on: ubuntu-latest
needs: [prepare-data]
steps:
- uses: actions/checkout@v2
- name: Login to GitHub Package Registry
run: echo ${{ secrets.PAT }} | docker login ghcr.io -u luketainton --password-stdin
- name: Build image for GitHub Package Registry
run: docker build . --file Dockerfile --tag ghcr.io/luketainton/${{ needs.prepare-data.outputs.lrepo }}:${{ needs.prepare-data.outputs.tag }} --tag ghcr.io/luketainton/${{ needs.prepare-data.outputs.lrepo }}:latest
- name: Push image to GitHub Package Registry
run: |
docker push ghcr.io/luketainton/${{ needs.prepare-data.outputs.lrepo }}:latest
docker push ghcr.io/luketainton/${{ needs.prepare-data.outputs.lrepo }}:${{ needs.prepare-data.outputs.tag }}
build:
name: Build and Release
runs-on: ubuntu-latest
needs: [prepare-data]
steps:
- uses: actions/checkout@v2
- name: Build artifacts
run: |
docker run --rm -w /go/src/app -v ${PWD}:/go/src/app -e CGO_ENABLED=0 -e GOARCH=amd64 -e GOOS=darwin golang:alpine go build -o /go/src/app/${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-darwin-amd64
docker run --rm -w /go/src/app -v ${PWD}:/go/src/app -e CGO_ENABLED=0 -e GOARCH=arm64 -e GOOS=darwin golang:alpine go build -o /go/src/app/${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-darwin-arm64
docker run --rm -w /go/src/app -v ${PWD}:/go/src/app -e CGO_ENABLED=0 -e GOARCH=amd64 -e GOOS=linux golang:alpine go build -o /go/src/app/${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-linux-amd64
docker run --rm -w /go/src/app -v ${PWD}:/go/src/app -e CGO_ENABLED=0 -e GOARCH=amd64 -e GOOS=windows golang:alpine go build -o /go/src/app/${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-win-amd64.exe
docker run --rm -w /go/src/app -v ${PWD}:/go/src/app -e CGO_ENABLED=0 -e GOARCH=386 -e GOOS=windows golang:alpine go build -o /go/src/app/${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-win-x86.exe
- uses: meeDamian/github-release@v2.0.3
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ needs.prepare-data.outputs.tag }}
gzip: false
files: >
${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-darwin-amd64
${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-darwin-arm64
${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-linux-amd64
${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-win-amd64.exe
${{ needs.prepare-data.outputs.repo }}-${{ needs.prepare-data.outputs.tag }}-win-x86.exe

46
API.go
View File

@@ -1,13 +1,23 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"sort"
"strings"
)
func getLocalIP() string {
resp, _ := http.Get("https://api.ipify.org")
resp, err := http.Get("https://api.ipify.org")
if err != nil {
fmt.Println("FATAL: Cannot get local IP.")
os.Exit(2)
return ""
}
body, _ := ioutil.ReadAll(resp.Body)
return string(body[:])
}
@@ -24,3 +34,37 @@ func resolveDNSHostname(hostname string) string {
address, _ := net.LookupHost(hostname)
return address[0]
}
func getIPInfo(ipaddress string) IPAddressInfo {
apiEndpoint := "http://ip-api.com/json/" + ipaddress
resp, err := http.Get(apiEndpoint)
if err != nil {
fmt.Println("FATAL: Cannot contact IP address information API.")
os.Exit(3)
}
body, _ := ioutil.ReadAll(resp.Body)
infoString := string(body)
var info IPAddressInfo
err = json.Unmarshal([]byte(infoString), &info)
if err != nil {
fmt.Println("FATAL: Cannot serialize recieved IP address data.")
os.Exit(4)
}
return info
}
func getBGPPrefixes(as string) {
apiEndpoint := "https://api.hackertarget.com/aslookup/?q=" + as
resp, err := http.Get(apiEndpoint)
if err != nil {
fmt.Println("FATAL: Cannot contact BGP Prefixes API.")
os.Exit(5)
}
body, _ := ioutil.ReadAll(resp.Body)
prefixesString := string(body)
var prefixes = strings.Split(prefixesString, "\n")[1:]
sort.Strings(prefixes)
for index := range prefixes {
fmt.Println(prefixes[index])
}
}

9
Dockerfile Normal file
View File

@@ -0,0 +1,9 @@
FROM golang:1.16-alpine as build
WORKDIR /go/src/app
COPY . /go/src/app
RUN CGO_ENABLED=0 go build -o /go/bin/app
FROM gcr.io/distroless/base-debian10
LABEL maintainer="Luke Tainton <luke@tainton.uk>"
COPY --from=build /go/bin/app /
CMD ["/app"]

View File

@@ -11,4 +11,5 @@ func printHeader() {
fmt.Println("| By Luke Tainton |")
fmt.Println("| @luketainton |")
fmt.Println("------------------------------")
fmt.Println("")
}

View File

@@ -1,10 +1,7 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
)
@@ -26,26 +23,17 @@ type IPAddressInfo struct {
IPAddress string `json:"query"`
}
func getIPInfo(ipaddress string) IPAddressInfo {
apiEndpoint := "http://ip-api.com/json/" + ipaddress
resp, _ := http.Get(apiEndpoint)
body, _ := ioutil.ReadAll(resp.Body)
// fmt.Print(string(body))
infoString := string(body)
var info IPAddressInfo
err := json.Unmarshal([]byte(infoString), &info)
if err != nil {
fmt.Println(err)
}
return info
}
func printIPInfo(input string) {
func printIPInfo(input string, wantPrefixes bool) {
var IPInfo IPAddressInfo = getIPInfo(input)
var location string = IPInfo.Country + "/" + IPInfo.RegionName + "/" + IPInfo.City
var bgpAS string = strings.Fields(IPInfo.AS)[0]
fmt.Println("IP Address: ", IPInfo.IPAddress)
fmt.Println("Location: ", location)
fmt.Println("Timezone: ", IPInfo.Timezone)
fmt.Println("ISP: ", IPInfo.ISP)
fmt.Println("BGP AS: ", strings.Fields(IPInfo.AS)[0])
fmt.Println("BGP AS: ", bgpAS)
if wantPrefixes == true {
fmt.Println("\nBGP Prefixes:")
getBGPPrefixes(bgpAS)
}
}

21
LICENSE.md Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Luke Tainton
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.

51
Main.go
View File

@@ -3,23 +3,52 @@ package main
import (
"flag"
"fmt"
"os"
)
func main() {
printHeader()
var input string
localIPAddress := getLocalIP()
flag.StringVar(&input, "i", localIPAddress, "Specify IP address or domain name.")
var wantPrefixes bool
var wantHeader bool
flag.StringVar(&input, "i", "", "IP address or domain")
flag.BoolVar(&wantPrefixes, "p", false, "print BGP prefixes")
flag.BoolVar(&wantHeader, "b", true, "enable/disable header")
flag.Usage = func() {
fmt.Printf("Usage of iPilot: \n")
fmt.Printf("Example: iPilot -b=false -i=me -p \n")
fmt.Printf(" -b bool enable/disable header (default true)\n")
fmt.Printf(" -h bool view help\n")
fmt.Printf(" -i string IP address or domain\n")
fmt.Printf(" -p bool print BGP prefixes (default false)\n")
}
flag.Parse()
var isIPCorrect bool = checkIPSyntax(input)
if isIPCorrect == true {
printIPInfo(input)
if wantHeader {
printHeader()
}
if input == "" {
fmt.Println("FATAL: No IP address or domain name was specified.")
os.Exit(1)
} else {
// fmt.Println(ipaddress, "is not a valid IP address.")
fmt.Println("Domain Name: ", input)
ipaddress := resolveDNSHostname(input)
printIPInfo(ipaddress)
if input == "me" {
input = getLocalIP()
}
var isIPCorrect bool = checkIPSyntax(input)
if isIPCorrect == true {
printIPInfo(input, wantPrefixes)
} else {
ipaddress := resolveDNSHostname(input)
if checkIPSyntax(ipaddress) == true {
fmt.Println("Domain Name: ", input)
printIPInfo(ipaddress, wantPrefixes)
} else {
fmt.Println("Invalid query.")
}
}
}
}

20
README.md Normal file
View File

@@ -0,0 +1,20 @@
# IP Information Lookup Tool (iPilot)
This Go application takes an IP address or domain name and gathers the following information:
- Location
- Timezone
- Internet Service Provider
- Autonomous System
- Advertised Prefixes
## Running the script
Here are some ways that you can run the script:
| Command | Description |
| ---------------------- | ---------------------------------------- |
| `./iPilot -i me` | Run against your own connection |
| `./iPilot -i 1.1.1.1` | Run against the IP address `1.1.1.1` |
| `./iPilot -i google.com` | Run against the domain name `google.com` |
| `./iPilot -i google.com -p` | Run against the domain name `google.com` and lists BGP prefixes |
## Credits
This script runs thanks to the APIs provided by [IP-API](http://ip-api.com) and [HackerTarget](https://hackertarget.com/as-ip-lookup).

3
go.mod Normal file
View File

@@ -0,0 +1,3 @@
module github.com/luketainton/iPilot
go 1.16