Gin: Trying to get IP of client ?? Gin is not mesing with Request i assume ?

Created on 26 Apr 2016  路  7Comments  路  Source: gin-gonic/gin

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

}
help wanted

Most helpful comment

All 7 comments

What are you expecting to get back? ::1is the IPv6 equivalent of localhost
Are you behind a proxy?

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iiinsomnia picture iiinsomnia  路  3Comments

CodingPapi picture CodingPapi  路  3Comments

ccaza picture ccaza  路  3Comments

xpbliss picture xpbliss  路  3Comments

rawoke083 picture rawoke083  路  3Comments