From 6a9202851d0df6b47a4eedfa9566fcf6a3b473cb Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Wed, 6 Jul 2016 23:44:33 +0200 Subject: [PATCH] Include IP in decimal format Fixes #19 --- README.md | 3 ++- api/api.go | 30 ++++++++++++++++++++++-------- api/api_test.go | 19 ++++++++++++++++++- index.html | 3 ++- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5958027..3cffea3 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,8 @@ $ http --json ifconfig.co { "city": "Bornyasherk", "country": "Elbonia", - "ip": "127.0.0.1" + "ip": "127.0.0.1", + "ip_decimal": 2130706433 } ``` diff --git a/api/api.go b/api/api.go index 5a6d49e..9f44c0f 100644 --- a/api/api.go +++ b/api/api.go @@ -6,6 +6,7 @@ import ( "html/template" "io" "log" + "math/big" "net" "net/http" "path/filepath" @@ -29,10 +30,11 @@ type API struct { } type Response struct { - IP net.IP `json:"ip"` - Country string `json:"country,omitempty"` - City string `json:"city,omitempty"` - Hostname string `json:"hostname,omitempty"` + IP net.IP `json:"ip"` + IPDecimal *big.Int `json:"ip_decimal"` + Country string `json:"country,omitempty"` + City string `json:"city,omitempty"` + Hostname string `json:"hostname,omitempty"` } type PortResponse struct { @@ -45,6 +47,16 @@ func New(oracle Oracle) *API { return &API{oracle: oracle} } +func ipToDecimal(ip net.IP) *big.Int { + i := big.NewInt(0) + if to4 := ip.To4(); to4 != nil { + i.SetBytes(to4) + } else { + i.SetBytes(ip) + } + return i +} + func ipFromRequest(header string, r *http.Request) (net.IP, error) { remoteIP := r.Header.Get(header) if remoteIP == "" { @@ -66,6 +78,7 @@ func (a *API) newResponse(r *http.Request) (Response, error) { if err != nil { return Response{}, err } + ipDecimal := ipToDecimal(ip) country, err := a.oracle.LookupCountry(ip) if err != nil { log.Print(err) @@ -79,10 +92,11 @@ func (a *API) newResponse(r *http.Request) (Response, error) { log.Print(err) } return Response{ - IP: ip, - Country: country, - City: city, - Hostname: strings.Join(hostnames, " "), + IP: ip, + IPDecimal: ipDecimal, + Country: country, + City: city, + Hostname: strings.Join(hostnames, " "), }, nil } diff --git a/api/api_test.go b/api/api_test.go index 8de94e2..42e5075 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -3,6 +3,7 @@ package api import ( "io/ioutil" "log" + "math/big" "net" "net/http" "net/http/httptest" @@ -84,7 +85,7 @@ func TestJSONHandlers(t *testing.T) { out string status int }{ - {s.URL, `{"ip":"127.0.0.1","country":"Elbonia","city":"Bornyasherk","hostname":"localhost"}`, 200}, + {s.URL, `{"ip":"127.0.0.1","ip_decimal":2130706433,"country":"Elbonia","city":"Bornyasherk","hostname":"localhost"}`, 200}, {s.URL + "/port/foo", `{"error":"404 page not found"}`, 404}, {s.URL + "/port/0", `{"error":"Invalid port: 0"}`, 400}, {s.URL + "/port/65356", `{"error":"Invalid port: 65356"}`, 400}, @@ -161,3 +162,19 @@ func TestCLIMatcher(t *testing.T) { } } } + +func TestIPToDecimal(t *testing.T) { + var tests = []struct { + in string + out *big.Int + }{ + {"127.0.0.1", big.NewInt(2130706433)}, + {"::1", big.NewInt(1)}, + } + for _, tt := range tests { + i := ipToDecimal(net.ParseIP(tt.in)) + if i.Cmp(tt.out) != 0 { + t.Errorf("Expected %d, got %d for IP %s", tt.out, i, tt.in) + } + } +} diff --git a/index.html b/index.html index a0f0d05..44d3a5c 100644 --- a/index.html +++ b/index.html @@ -80,7 +80,8 @@ $ http ifconfig.co/json "city": "{{ .City }}",{{ end }}{{ if .IsLookupCountryEnabled }} "country": "{{ .Country }}",{{ end }}{{ if .IsLookupAddrEnabled }} "hostname": "{{ .Hostname }}",{{ end }} - "ip": "{{ .IP }}" + "ip": "{{ .IP }}", + "ip_decimal": {{ .IPDecimal }} } # or set Accept header: