Its really strange how hard i am finding it to get the client IP.
All i get back is "::1". Weird ????
// Call down
clientIP, err := getClientIPByRequest(c.Request)
// getClientIPByRequest tries to get directly from the Request.
// https://blog.golang.org/context/userip/userip.go
func getClientIPByRequest(req *http.Request) (ip string, err error) {
// Try via request
ip, port, err := net.SplitHostPort(req.RemoteAddr)
if err != nil {
log.Printf("debug: Getting req.RemoteAddr %v", err)
return "", err
} else {
log.Printf("debug: With req.RemoteAddr found IP:%v; Port: %v", ip, port)
}
userIP := net.ParseIP(ip)
if userIP == nil {
message := fmt.Sprintf("debug: Parsing IP from Request.RemoteAddr got nothing.")
log.Printf(message)
return "", fmt.Errorf(message)
}
log.Printf("debug: Found IP: %v", userIP)
return userIP.String(), nil
}
What are you expecting to get back? ::1is the IPv6 equivalent of localhost
Are you behind a proxy?
@joeblew99 did you tried Gin method? https://godoc.org/github.com/gin-gonic/gin#Context.ClientIP
ah. was wondering if that might be happening.
The first Client (web app) is running on a standard gin / golang server.
Its running on my laptop.
When i check his IP, i get ::1
The 2nd Client (web app) is running on top of Caddy.
Have not checked what i get back from him yet.
So, at the end of the day, how can i get the real LAN IP. Thast what i want.
Thanks in advance !!
I also coded up a check by sniffing the Forwarding Headers. Figured that proxy could be messing me around.
// getClientIPByHeaders tries to get directly from the Request Headers.
// This is only way when the client is behind a Proxy.
func getClientIPByHeaders(req *http.Request) (ip string, err error) {
// Client could be behid a Proxy, so Try Request Headers (X-Forwarder)
ipSlice := []string{}
ipSlice = append(ipSlice, req.Header.Get("X-Forwarded-For"))
ipSlice = append(ipSlice, req.Header.Get("x-forwarded-for"))
ipSlice = append(ipSlice, req.Header.Get("X-FORWARDED-FOR"))
for _, v := range ipSlice {
log.Printf("debug: client request header check gives ip: %v", v)
if v != "" {
return v, nil
}
}
err = errors.New("error: Could not find clients IP address from the Request Headers")
return "", err
}
@javierprovecho that looks like a nice wrapper.
But i just tried, but if i call me with the client running on "localhost" and it gets ::1
If i call me with client running on real local IP "http://192.168.178.159/", i also get ::1
Mhhh. Amazing how hard it is to do this.
I found a cheating way, but its fragile i suspect because not all Browser send this header ?
// Try Request Header ("Origin")
origin := req.Header.Get("Origin")
log.Printf("debug: header origin ip: %v", origin)
Origin works from 127.0.0.1 and the real local IP.
But its maybe flakey because browsrs dont all sent it ?
i ended up writing a deep checker.
package controllers
import (
"errors"
"fmt"
"log"
"net"
"net/http"
"net/url"
)
// GetClientIPHelper gets the client IP using a mixture of techniques.
// This is how it is with golang at the moment.
func GetClientIPHelper(req *http.Request) (ipResult string, errResult error) {
// Try lots of ways :) Order is important.
// Try Request Header ("Origin")
url, err := url.Parse(req.Header.Get("Origin"))
if err == nil {
host := url.Host
ip, _, err := net.SplitHostPort(host)
if err == nil {
log.Printf("debug: Found IP using Header (Origin) sniffing. ip: %v", ip)
return ip, nil
}
}
// Try by Request
ip, err := getClientIPByRequestRemoteAddr(req)
if err == nil {
log.Printf("debug: Found IP using Request sniffing. ip: %v", ip)
return ip, nil
}
// Try Request Headers (X-Forwarder). Client could be behind a Proxy
ip, err = getClientIPByHeaders(req)
if err == nil {
log.Printf("debug: Found IP using Request Headers sniffing. ip: %v", ip)
return ip, nil
}
err = errors.New("error: Could not find clients IP address")
return "", err
}
// getClientIPByRequest tries to get directly from the Request.
// https://blog.golang.org/context/userip/userip.go
func getClientIPByRequestRemoteAddr(req *http.Request) (ip string, err error) {
// Try via request
ip, port, err := net.SplitHostPort(req.RemoteAddr)
if err != nil {
log.Printf("debug: Getting req.RemoteAddr %v", err)
return "", err
} else {
log.Printf("debug: With req.RemoteAddr found IP:%v; Port: %v", ip, port)
}
userIP := net.ParseIP(ip)
if userIP == nil {
message := fmt.Sprintf("debug: Parsing IP from Request.RemoteAddr got nothing.")
log.Printf(message)
return "", fmt.Errorf(message)
}
log.Printf("debug: Found IP: %v", userIP)
return userIP.String(), nil
}
// getClientIPByHeaders tries to get directly from the Request Headers.
// This is only way when the client is behind a Proxy.
func getClientIPByHeaders(req *http.Request) (ip string, err error) {
// Client could be behid a Proxy, so Try Request Headers (X-Forwarder)
ipSlice := []string{}
ipSlice = append(ipSlice, req.Header.Get("X-Forwarded-For"))
ipSlice = append(ipSlice, req.Header.Get("x-forwarded-for"))
ipSlice = append(ipSlice, req.Header.Get("X-FORWARDED-FOR"))
for _, v := range ipSlice {
log.Printf("debug: client request header check gives ip: %v", v)
if v != "" {
return v, nil
}
}
err = errors.New("error: Could not find clients IP address from the Request Headers")
return "", err
}
// getMyInterfaceAddr gets this private network IP. Basically the Servers IP.
func getMyInterfaceAddr() (net.IP, error) {
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
addresses := []net.IP{}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
}
addresses = append(addresses, ip)
}
}
if len(addresses) == 0 {
return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses)
}
//only need first
return addresses[0], nil
}
how this going
Most helpful comment
@joeblew99 did you tried Gin method? https://godoc.org/github.com/gin-gonic/gin#Context.ClientIP