dougong5285
2014-09-30 09:58
浏览 51
已采纳

限制来自本地子网的客户端对GO Web服务的访问

I'm writing a small web service in GO using just the GO http package. I want to restrict access to the web service to clients on the local subnets (127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).

I tried using a subnet mask as addr argument to ListenAndServe but it exits with a "no such host" error.

EDIT:

This is the solution I came up with the help of @RickA and @Dewy Broto.

func JustLocal(handler http.Handler) http.Handler {
    var local_subnets []*net.IPNet
    local_subnet_s := []string{"127.0.0.1/31", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"}

    for _,net_s := range local_subnet_s {
        _, n, _ := net.ParseCIDR(net_s)
        local_subnets = append(local_subnets, n)
    }

    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println(r.RemoteAddr)
        remote_ip := net.ParseIP(strings.Split(r.RemoteAddr, ":")[0])
        fmt.Println(remote_ip)

        local := false
        for _, local_subnet := range local_subnets {
            fmt.Println(local_subnet, remote_ip)
            if local_subnet.Contains(remote_ip) {
                local = true
                break
            }
        }
        if !local {
            http.Error(w, "go away", 403)
            return
        }
        handler.ServeHTTP(w, r)
        return
    })
}

It's a bit raw around the edges but it works as far as I could tell. Thanks for all the help!

图片转代码服务由CSDN问答提供 功能建议

我仅使用GO http包在GO中编写了一个小型Web服务。 我想将对Web服务的访问限制为本地子网上的客户端(127.0.0.1、10.0.0.0 / 8、172.16.0.0 / 12、192.168.0.0 / 16)。

我尝试将子网掩码用作 ListenAndServe 的addr参数,但它以“否”退出 这样的主机”错误。

编辑:

这是我在@RickA和@Dewy Broto的帮助下提出的解决方案。

  func JustLocal(handler http.Handler)http.Handler {
 var local_subnets [] * net.IPNet 
 local_subnet_s:= [] string {“ 127.0.0.1/31”,  _,net_s的“ 10.0.0.0/8"、"172.16.0.0/12"、"192.168.0.0/16"}

:=范围local_subnet_s {
 _,n,_:= net.ParseCIDR(  net_s)
 local_subnets = append(local_subnets,n)
} 
 
返回http.HandlerFunc(func(w http.ResponseWriter,r * http.Request){
 fmt.Println(r.RemoteAddr)
  remote_ip:= net.ParseIP(strings.Split(r.RemoteAddr,“:”)[0])
 fmt.Println(remote_ip)
 
本地 := false 
表示_,local_subnet:=范围local_subnets {
 fmt.Println(local_subnet,remote_ip)
 if local_subnet.Contains(remote_ip){
 local = true 
 break 
} 
} 
  if!local {
 http.Error(w,“ go away”,403)
返回
} 
处理函数。ServeHTTP(w,r)
 return 
})
} 
   
 
 

边缘有点生,但据我所知它仍然有效。 感谢您的所有帮助!

  • 写回答
  • 好问题 提建议
  • 关注问题
  • 收藏
  • 邀请回答

3条回答 默认 最新

  • dtjkl42086 2014-09-30 13:48
    已采纳

    Write a handler that checks to see if the client's IP address is allowed before delegating to another handler:

    type authorizationHandler struct {
        nets []*net.IPNet
        h handler
    }
    
    func (ah *authorizationHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        ok := false
        ip := net.ParseIP(r.RemoteAddr)
        for _, n := range ah.nets {
           if n.Contains(ip) {
             ok := true
             break
           }
        }
        if !ok {
           http.Error(w, "go away", 403)
           return
        }
        ah.h(w, r)
    }
    

    Use this handler to wrap your the root handler:

    err := ListenAndServe(addr, 
              &authorizationHandler{nets: allowedNets, h:rootHandler))
    

    Note: I typed in the above code without compiling or testing it. Some tweaks are probably required around parsing and testing the remote address.

    已采纳该答案
    评论
    解决 无用
    打赏 举报
  • doulingzou1712 2014-09-30 12:12

    The address in ListenAndServe is the address your server binds to on the machine where it is running. It is not some sort of ip whitelist thingy. This allows you to specify on what (network)interface you want to bind the server.

    So if this machine has a ethernet card (ifconfig) that has the ipadress 10.0.100.100 you can bind ListenAndServe to 10.0.100.100:8123. The ip-less version :8123 binds the server to all available interfaces. eg. [::]:8123 (netstat -l), and is thus reachable from outside.

    To get what you want you have a couple of options:

    • Put the machine in a private subnet that you trust and bind ListenAndServe to the ip of that subnet on your machine. Thus it should only be routable from within that subnet.
    • Use a webserver in front of this server, have it pass requests to it based on its ip acl (ex. nginx)
    • Implement your own ip(range) filtering in the go server code (eg. use request.URL and test that against your whitelist)
    评论
    解决 无用
    打赏 举报
  • dongxiane0395 2014-09-30 13:26

    You can listen on multiple ports / hosts, you have to call ListenAndServe multiple times.

    func main() {
        addrs := []string{"127.0.0.1:8080", "10.0.0.1:8080", "172.16.0.1:8080", "192.168.0.1:8080", "192.168.1.1:8080"}
        errs := make(chan error)
        for _, addr := range addrs {
            go func(addr string) {
                errs <- http.ListenAndServe(addr, nil) //or replace the nil with your mux
            }(addr)
        }
        i := len(addrs)
        for err := range errs {
            fmt.Println(err)
            if i = i - 1; i == 0 {
                break
            }
        }
    }
    

    Or you could use nging and just make your go server listen on 127.0.0.1.

    评论
    解决 无用
    打赏 举报

相关推荐 更多相似问题