From ec413030f774a381bcec6cfb4b0900c84d104231 Mon Sep 17 00:00:00 2001 From: Daniel Areiza Date: Thu, 7 Dec 2017 17:21:48 -0500 Subject: [PATCH] Added support to handle CF-Connecting-IP header and if no header is set at all, fallback to requesting IP --- .gitignore | 2 ++ api/get_ip.go | 29 ++++++++++++++++++++--------- main.go | 8 ++++---- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 045d3fe..8a5503f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .elasticbeanstalk/* !.elasticbeanstalk/*.cfg.yml !.elasticbeanstalk/*.global.yml +# GoLand / IntelliJ +.idea diff --git a/api/get_ip.go b/api/get_ip.go index 2020f50..1a93197 100644 --- a/api/get_ip.go +++ b/api/get_ip.go @@ -8,11 +8,12 @@ package api import ( "encoding/json" "fmt" - "github.com/julienschmidt/httprouter" - "github.com/rdegges/ipify-api/models" "net" "net/http" "strings" + + "github.com/julienschmidt/httprouter" + "github.com/rdegges/ipify-api/models" ) // GetIP returns a user's public facing IP address (IPv4 OR IPv6). @@ -26,16 +27,26 @@ func GetIP(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { panic(err) } - // We'll always grab the first IP address in the X-Forwarded-For header - // list. We do this because this is always the *origin* IP address, which - // is the *true* IP of the user. For more information on this, see the - // Wikipedia page: https://en.wikipedia.org/wiki/X-Forwarded-For - ip := net.ParseIP(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0]).String() + // We test in order of priority valid client IP headers + ip := net.ParseIP(r.Header.Get("CF-Connecting-IP")) + + if ip == nil { + // We'll always grab the first IP address in the X-Forwarded-For header + // list. We do this because this is always the *origin* IP address, which + // is the *true* IP of the user. For more information on this, see the + // Wikipedia page: https://en.wikipedia.org/wiki/X-Forwarded-For + ip = net.ParseIP(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0]) + } + + if ip == nil { + host, _, _ := net.SplitHostPort(r.RemoteAddr) + ip = net.ParseIP(host) + } // If the user specifies a 'format' querystring, we'll try to return the // user's IP address in the specified format. if format, ok := r.Form["format"]; ok && len(format) > 0 { - jsonStr, _ := json.Marshal(models.IPAddress{ip}) + jsonStr, _ := json.Marshal(models.IPAddress{ip.String()}) switch format[0] { case "json": @@ -59,5 +70,5 @@ func GetIP(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { // If no 'format' querystring was specified, we'll default to returning the // IP in plain text. w.Header().Set("Content-Type", "text/plain") - fmt.Fprintf(w, ip) + fmt.Fprintf(w, ip.String()) } diff --git a/main.go b/main.go index 771b457..9fde6cb 100644 --- a/main.go +++ b/main.go @@ -8,12 +8,13 @@ package main import ( - "github.com/julienschmidt/httprouter" - "github.com/rdegges/ipify-api/api" - "github.com/rs/cors" "log" "net/http" "os" + + "github.com/julienschmidt/httprouter" + "github.com/rdegges/ipify-api/api" + "github.com/rs/cors" ) // main launches our web server which runs indefinitely. @@ -39,5 +40,4 @@ func main() { log.Println("Starting HTTP server on port:", port) log.Fatal(http.ListenAndServe(":"+port, handler)) - }