13

I want to integrate ReCAPTCHA to my GAE Golang web application. In order to verify a captcha, I need to get user's IP address. How can I fetch user's IP address from a form post?

ThePiachu
  • 8,695
  • 17
  • 65
  • 94

4 Answers4

49

Use net.SplitHostPort:

ip, _, _ := net.SplitHostPort(r.RemoteAddr)
Jesse Beder
  • 33,081
  • 21
  • 109
  • 146
Aigars Matulis
  • 1,469
  • 17
  • 22
26

inside your handler function call r.RemoteAddr to receive ip:port

like this:

func renderIndexPage(w http.ResponseWriter, r *http.Request) {
  ip := strings.Split(r.RemoteAddr,":")[0] 

}

update 02/15/2017 as @Aigars Matulis pointed out, in current version there is already a function todo this

ip, _, _ := net.SplitHostPort(r.RemoteAddr)
Community
  • 1
  • 1
fmt.Println.MKO
  • 2,065
  • 1
  • 17
  • 25
  • 1
    +1 For completeness, I had issue as I used localhost in my url. see the discussion here. https://groups.google.com/forum/#!topic/golang-nuts/rqo1--qR-8Y – bsr Jun 22 '13 at 15:00
  • 1
    yes localhost is always special, and I guess you use a mac who resolves ipv6, which causes localhost and ip problems since years – fmt.Println.MKO Jun 23 '13 at 11:56
  • 1
    Add the end what worked for me was to just use "r.RemoteAddr". – Greivin López Jun 02 '15 at 02:04
26

The answers above neglect to check if user's IP is forwarded by a proxy. In a lot of cases, the IP that you will find in the RemoteAddr is the IP of a proxy that is forwarding the user's request to you - not the user's IP address!

A more accurate solution would look like this:

package main

import (
    "net"
    "net/http"
)

func GetIP(r *http.Request) string {
    if ipProxy := r.Header.Get("X-FORWARDED-FOR"); len(ipProxy) > 0 {
        return ipProxy
    }
    ip, _, _ := net.SplitHostPort(r.RemoteAddr)
    return ip
}
orcaman
  • 6,263
  • 8
  • 54
  • 69
  • 4
    This answer suggests that X-Forwarded-For can be a list: http://stackoverflow.com/a/27235620/214070 – bugloaf Feb 25 '15 at 16:16
  • 1
    @orcaman this is indeed true, if a request is passed through multiple proxies, like in Elastic Load Balancer in AWS, to content will be a list of IPs. the left most ip should be the client IP. You can find more info here http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/x-forwarded-headers.html#x-forwarded-for – Eran Chetzroni May 08 '15 at 23:19
  • When logging an IP address. Make sure to log both RemoteAddr AND X-Forwarded-For. Reason? A hacker can always set the X-Forwarded-For header ;-). On the other hand. A hacker will most likely use TOR or another way to hide his IP. – Patrick Boos Aug 03 '15 at 06:46
0

This worked for me. I run go in 8081 and made a request from port 8080.

fmt.Printf("r: %+v\n", r) // Print all fields that you get in request

Output:

r: &{Method:POST URL:/email Proto:HTTP/1.1 ProtoMajor:1 ProtoMinor:1 Header:map[User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/602.2.11 (KHTML, like Gecko) Version/10.0.1 Safari/602.2.11] Accept-Language:[en-us] Accept-Encoding:[gzip, deflate] Connection:[keep-alive] Accept:[/] Referer:[http://127.0.0.1:8080/] Content-Length:[9] Content-Type:[application/x-www-form-urlencoded; charset=UTF-8] Origin:[http://127.0.0.1:8080]] Body:0xc420012800 ContentLength:9 TransferEncoding:[] Close:false Host:127.0.0.1:8081 Form:map[] PostForm:map[] MultipartForm: Trailer:map[] RemoteAddr:127.0.0.1:62232 RequestURI:/email TLS: Cancel: Response: ctx:0xc420017860}

The Referer and Origin have my client IP.

ip := r.Referer() // Get Referer value
fmt.Println(ip) // print ip

Output:

http://127.0.0.1:8080/

deepakssn
  • 5,195
  • 2
  • 24
  • 19