2016-06-18 75 views
3

我正在使用golang http包。服務器如何限制客戶端IP地址?如何在使用golang http包時限制客戶端IP地址

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() 
    }() 
} 
+0

的可能的複製[如何限制HTTP服務器的連接數實現在去?](http://stackoverflow.com/questions/22625367/how-to-limit-the-connection-count-of-an-http-server-implemented-in-go) – Tinwor

+0

@Tinwor不是真的重複的那 –

+0

類似的問題:http://stackoverflow.com/questions/28070923/golang-net-http-and-gorilla-run-code-before-handler –

回答

6

你需要做兩件事情:一個是中間件處理程序前處理您的要求和驗證IP包的多路複用器。另一個是獲取用戶的真實IP,如果您位於防火牆或負載平衡器的後面(導致地址始終是LB的地址),或者您的用戶位於代理之後,這非常重要。

至於包裹你的多路複用器,這是很簡單的:

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) 
    }), 
} 

而且我安裝了getRealAddr功能,是在我做了這樣的一個實際的項目:

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 

} 

至於過濾,它可以基於一組ips或CIDR範圍,當然這取決於你。

如果你感興趣的話,上面的代碼是從API工具包構建我寫的並用所謂的頂點,它有這個建於:https://github.com/EverythingMe/vertex

+0

爲什麼你使用最後一個前鋒而不是第一個? – lf215

+0

@ lf215第一個可能是內部LAN地址或類似的。最後一個應該是您的反向代理或LB所看到的地址,並且通常是您想要的國家/地區過濾的內容,即客戶的ISP給定地址。 –

+0

引用維基百科關於該主題的文章:「最後一個IP地址始終是連接到最後一個代理的IP地址,這意味着它是最可靠的信息來源。 https://en.wikipedia.org/wiki/X-Forwarded-For#Format –