web-dev-qa-db-fra.com

Méthode correcte pour obtenir les adresses IP du client à partir de http.Request

Quelle est la bonne façon d'obtenir toutes les adresses IP du client à partir de http.Request? Dans PHP il y a beaucoup de variables que je devrais vérifier. Est-ce la même chose sur Go?

Celui que j'ai trouvé est:

req.RemoteAddr

Et la demande est-elle sensible à la casse? Par exemple, x-forwarded-for est identique à X-Forwarded-For et X-FORWARDED-FOR? (de req.Header.Get("X-FORWARDED-FOR"))

55
Kokizzu

En regardant http.Request , vous pouvez trouver les variables de membre suivantes:

// HTTP defines that header names are case-insensitive.
// The request parser implements this by canonicalizing the
// name, making the first character and any characters
// following a hyphen uppercase and the rest lowercase.
//
// For client requests certain headers are automatically
// added and may override values in Header.
//
// See the documentation for the Request.Write method.
Header Header

// RemoteAddr allows HTTP servers and other software to record
// the network address that sent the request, usually for
// logging. This field is not filled in by ReadRequest and
// has no defined format. The HTTP server in this package
// sets RemoteAddr to an "IP:port" address before invoking a
// handler.
// This field is ignored by the HTTP client.
RemoteAddr string

Vous pouvez utiliser RemoteAddr pour obtenir l'adresse IP et le port du client distant (le format est "IP: port"), qui correspond à l'adresse du demandeur d'origine ou du dernier proxy. (par exemple un équilibreur de charge situé devant votre serveur).

C'est tout ce que vous avez à coup sûr.

Ensuite, vous pouvez rechercher les en-têtes, qui sont insensibles à la casse (selon la documentation ci-dessus), ce qui signifie que tous vos exemples fonctionneront et produiront le même résultat:

req.Header.Get("X-Forwarded-For") // capitalisation
req.Header.Get("x-forwarded-for") // doesn't
req.Header.Get("X-FORWARDED-FOR") // matter

En effet, en interne http.Header.Get normalisera la clé pour vous. (Si vous souhaitez accéder directement à la mappe d'en-tête, et non via Get, vous devez d'abord utiliser http.CanonicalHeaderKey .)

Finalement, "X-Forwarded-For" est probablement le champ que vous souhaitez consulter afin de récupérer plus d’informations sur l’IP du client. Cela dépend cependant beaucoup du logiciel HTTP utilisé du côté distant, car le client peut y mettre n'importe quoi s'il le souhaite. Notez également que le format attendu de ce champ est la liste d'adresses IP séparées par des virgules + espaces. Vous devrez l'analyser un peu pour obtenir une seule adresse IP de votre choix (probablement la première de la liste), par exemple:

// Assuming format is as expected
ips := strings.Split("10.0.0.1, 10.0.0.2, 10.0.0.3", ", ")
for _, ip := range ips {
    fmt.Println(ip)
}

produira:

10.0.0.1
10.0.0.2
10.0.0.3
66
tomasz

Voici un exemple complètement fonctionnel

package main

import (  
    // Standard library packages
    "fmt"
    "strconv"
    "log"
    "net"
    "net/http"

    // Third party packages
    "github.com/julienschmidt/httprouter"
    "github.com/skratchdot/open-golang/open"
)



// https://blog.golang.org/context/userip/userip.go
func getIP(w http.ResponseWriter, req *http.Request, _ httprouter.Params){
    fmt.Fprintf(w, "<h1>static file server</h1><p><a href='./static'>folder</p></a>")

    ip, port, err := net.SplitHostPort(req.RemoteAddr)
    if err != nil {
        //return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)

        fmt.Fprintf(w, "userip: %q is not IP:port", req.RemoteAddr)
    }

    userIP := net.ParseIP(ip)
    if userIP == nil {
        //return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)
        fmt.Fprintf(w, "userip: %q is not IP:port", req.RemoteAddr)
        return
    }

    // This will only be defined when site is accessed via non-anonymous proxy
    // and takes precedence over RemoteAddr
    // Header.Get is case-insensitive
    forward := req.Header.Get("X-Forwarded-For")

    fmt.Fprintf(w, "<p>IP: %s</p>", ip)
    fmt.Fprintf(w, "<p>Port: %s</p>", port)
    fmt.Fprintf(w, "<p>Forwarded for: %s</p>", forward)
}


func main() {  
    myport := strconv.Itoa(10002);


    // Instantiate a new router
    r := httprouter.New()

    r.GET("/ip", getIP)

    // Add a handler on /test
    r.GET("/test", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
        // Simply write some test data for now
        fmt.Fprint(w, "Welcome!\n")
    })  


    l, err := net.Listen("tcp", "localhost:" + myport)
    if err != nil {
        log.Fatal(err)
    }
    // The browser can connect now because the listening socket is open.


    //err = open.Start("http://localhost:"+ myport + "/test")
    err = open.Start("http://localhost:"+ myport + "/ip")
    if err != nil {
         log.Println(err)
    }

    // Start the blocking server loop.
    log.Fatal(http.Serve(l, r)) 
}
13
Stefan Steiger

Voici comment je viens avec l'IP

func ReadUserIP(r *http.Request) string {
    IPAddress := r.Header.Get("X-Real-Ip")
    if IPAddress == "" {
        IPAddress = r.Header.Get("X-Forwarded-For")
    }
    if IPAddress == "" {
        IPAddress = r.RemoteAddr
    }
    return IPAddress
}
  • X-Real-Ip - récupère la première adresse IP vraie (si les demandes se trouvent derrière plusieurs NAT sources/équilibreur de charge)

  • X-Forwarded-For - si pour une raison quelconque X-Real-Ip est vide et ne renvoie pas de réponse, obtenez-le à partir de X-Forwarded-For

  • Adresse distante - dernier recours (ne sera généralement pas fiable car il peut s'agir de la dernière adresse IP ou s'il s'agit d'une requête http nue au serveur, c'est-à-dire sans équilibreur de charge)
4
mel3kings

Dans PHP, il y a beaucoup de variables que je devrais vérifier. Est-ce la même chose sur Go?

Cela n'a rien à faire avec Go (ou PHP d'ailleurs). Cela dépend de ce que le client, Envoi par un proxy, un équilibreur de charge ou un serveur. Procurez-vous celui dont vous avez besoin en fonction de votre environnement.

http.Request.RemoteAddr contient l'adresse IP distante. Ce peut être ou ne pas être votre client réel.

Et la demande est-elle sensible à la casse? par exemple, x-forwarded-for est-il identique à X-Forwarded-For et X-FORWARDED-FOR? (de req.Header.Get ("X-FORWARDED-FOR"))

Non, pourquoi ne pas l'essayer toi-même? http://play.golang.org/p/YMf_UBvDsH

2
JimB