Welcome To Golang By Example

Get the IP address from an incoming HTTP request

Table of Contents

Overview

In this article, we will get the IP address of the client for an incoming HTTP request using

Please do note that

Please refer to this article for more information on X-REAL-IP and X-FORWARDED-FOR header

https://distinctplace.com/2014/04/23/story-behind-x-forwarded-for-and-x-real-ip-headers/

Out of the above 3 values, RemoteAddr is the most reliable but it will never give correct IP address if the client is behind the proxy or when using a load balancer or a reverse proxy server, therefore the order is first  X-REAL-IP then X-FORWARDED-FOR  and then RemoteAddr. Although please note that a malicious user can still create the fake X-REAL-IP and X-FORWARDED-FOR header

Code

Let’s see a working code in GOLANG

package main

import (
    "fmt"
    "net"
    "net/http"
    "strings"
)

func main() {
    handlerFunc := http.HandlerFunc(handleRequest)
    http.Handle("/getIp", handlerFunc)
    http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
    ip, err := getIP(r)
    if err != nil {
        w.WriteHeader(400)
        w.Write([]byte("No valid ip"))
    }
    w.WriteHeader(200)
    w.Write([]byte(ip))
}

func getIP(r *http.Request) (string, error) {
    //Get IP from the X-REAL-IP header
    ip := r.Header.Get("X-REAL-IP")
    netIP := net.ParseIP(ip)
    if netIP != nil {
        return ip, nil
    }

    //Get IP from X-FORWARDED-FOR header
    ips := r.Header.Get("X-FORWARDED-FOR")
    splitIps := strings.Split(ips, ",")
    for _, ip := range splitIps {
        netIP := net.ParseIP(ip)
        if netIP != nil {
            return ip, nil
        }
    }

    //Get IP from RemoteAddr
    ip, _, err := net.SplitHostPort(r.RemoteAddr)
    if err != nil {
        return "", err
    }
    netIP = net.ParseIP(ip)
    if netIP != nil {
        return ip, nil
    }
    return "", fmt.Errorf("No valid ip found")
}

Make a curl call

curl -v -X  GET http://localhost:8080/getIp

Output:

On my machine it outputs ::1 which is actually loopback address for IPV6

On your machine, it will either output 127.0.0.1 for IPV4 or ::1 for IPV6

https://en.wikipedia.org/wiki/Localhost