Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit client IP address when using golang http package

Tags:

http

go

I'm using golang http package. How could the server limit client IP address?

func (s *Worker) Run(c chan error) {
    apiMux := http.NewServeMux()
    apiMux.HandleFunc("/test", s.test)
    apiMux.HandleFunc("/block/create", s.CreateBlock)
    apiMux.HandleFunc("/block/delete", s.DeleteBlock)

    apiServer := &http.Server{
        Addr:    "0.0.0.0:" + strconv.Itoa(s.ListenPort),
        Handler: apiMux,
    }

    go func() {
        log.Println("Worker listening on " + apiServer.Addr)
        c <- apiServer.ListenAndServe()
    }()
}
like image 754
Will Lee Avatar asked Jun 18 '16 12:06

Will Lee


People also ask

What is HTTP Go client?

The http package in GoLang allows HTTP functions to be carried out in GoLang scripts.

What is GoLang PostForm?

The docs: "PostForm issues a POST to the specified URL, with data's keys and values URL-encoded as the request body. The Content-Type header is set to application/x-www-form-urlencoded ."

What is HTTP server in GoLang?

Go can be also used to create web applications. Net/http is a library package used to build web applications. It has HandelFunc() function which routes the incoming request to its corresponding function. The ListenAndServe function is used to create a resource server which listens to the provided port.


1 Answers

You need to do two things: one is to wrap your mux with a middleware handler that pre-processes your requests and validates the IP. The other is get the real IP of the user, which is important if you are behind a firewall or load balancer (resulting in the address being always that of the LB), or if your user is behind a proxy.

As for wrapping your mux, it's pretty simple:

apiServer := &http.Server{
    Addr:    "0.0.0.0:8080",
    Handler: http.HandlerFunc( func(w http.ResponseWriter, req *http.Request) {
        // get the real IP of the user, see below
        addr := getRealAddr(req)

       // the actual vaildation - replace with whatever you want
       if (addr != "1.2.3.4") {
            http.Error(w, "Blocked", 401)
            return
        }
        // pass the request to the mux
        apiMux.ServeHTTP(w,req)
    }),
}

And I'm attaching the getRealAddr function which is from an actual project in which I did something like this:

func getRealAddr(r *http.Request)  string {

    remoteIP := ""
    // the default is the originating ip. but we try to find better options because this is almost
    // never the right IP
    if parts := strings.Split(r.RemoteAddr, ":"); len(parts) == 2 {
        remoteIP = parts[0]
    }
    // If we have a forwarded-for header, take the address from there
    if xff := strings.Trim(r.Header.Get("X-Forwarded-For"), ","); len(xff) > 0 {
        addrs := strings.Split(xff, ",")
        lastFwd := addrs[len(addrs)-1]
        if ip := net.ParseIP(lastFwd); ip != nil {
            remoteIP = ip.String()
        }
    // parse X-Real-Ip header
    } else if xri := r.Header.Get("X-Real-Ip"); len(xri) > 0 {
        if ip := net.ParseIP(xri); ip != nil {
            remoteIP = ip.String()
        }
    }

    return remoteIP

}

As for the filtering, it can be based on a set of ips, or CIDR ranges, it's up to you of course.

If you're interested, the above code is from an API building toolkit I wrote and used called Vertex, which has this built in: https://github.com/EverythingMe/vertex

like image 197
Not_a_Golfer Avatar answered Sep 24 '22 08:09

Not_a_Golfer