限制来自本地子网的客户端对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!
我仅使用GO http包在GO中编写了一个小型Web服务。 我想将对Web服务的访问限制为本地子网上的客户端(127.0.0.1、10.0.0.0 / 8、172.16.0.0 / 12、192.168.0.0 / 16)。 p>
我尝试将子网掩码用作 ListenAndServe 的addr参数,但它以“否”退出 这样的主机”错误。 p>
编辑: p>
这是我在@RickA和@Dewy Broto的帮助下提出的解决方案。 p >
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
})
}
code > pre>
边缘有点生,但据我所知它仍然有效。 感谢您的所有帮助! p>
div>
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.
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)
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
.