Verify IP addresses
Fix lint errors Add more test
This commit is contained in:
parent
c6fdfc9cd5
commit
e21a425f88
4 changed files with 42 additions and 20 deletions
2
AUTHORS
2
AUTHORS
|
@ -13,6 +13,8 @@ Frederick F. Kautz IV <fkautz@alumni.cmu.edu>
|
||||||
Josh Hawn <josh.hawn@docker.com>
|
Josh Hawn <josh.hawn@docker.com>
|
||||||
Nghia Tran <tcnghia@gmail.com>
|
Nghia Tran <tcnghia@gmail.com>
|
||||||
Olivier Gambier <olivier@docker.com>
|
Olivier Gambier <olivier@docker.com>
|
||||||
|
Richard <richard.scothern@gmail.com>
|
||||||
|
Shreyas Karnik <karnik.shreyas@gmail.com>
|
||||||
Stephen J Day <stephen.day@docker.com>
|
Stephen J Day <stephen.day@docker.com>
|
||||||
Tianon Gravi <admwiggin@gmail.com>
|
Tianon Gravi <admwiggin@gmail.com>
|
||||||
xiekeyang <xiekeyang@huawei.com>
|
xiekeyang <xiekeyang@huawei.com>
|
||||||
|
|
|
@ -2,6 +2,7 @@ package context
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -17,26 +18,27 @@ var (
|
||||||
ErrNoRequestContext = errors.New("no http request in context")
|
ErrNoRequestContext = errors.New("no http request in context")
|
||||||
)
|
)
|
||||||
|
|
||||||
// http.Request.RemoteAddr is not the originating IP if the request
|
// RemoteAddr extracts the remote address of the request, taking into
|
||||||
// came through a reverse proxy.
|
// account proxy headers.
|
||||||
// X-Forwarded-For and X-Real-IP provide this information with decreased
|
|
||||||
// support, so check in that order. There may be multiple 'X-Forwarded-For'
|
|
||||||
// headers, but go maps don't retain order so just pick one.
|
|
||||||
func RemoteAddr(r *http.Request) string {
|
func RemoteAddr(r *http.Request) string {
|
||||||
remoteAddr := r.RemoteAddr
|
if prior := r.Header.Get("X-Forwarded-For"); prior != "" {
|
||||||
|
proxies := strings.Split(prior, ",")
|
||||||
if prior, ok := r.Header["X-Forwarded-For"]; ok {
|
|
||||||
proxies := strings.Split(prior[0], ",")
|
|
||||||
if len(proxies) > 0 {
|
if len(proxies) > 0 {
|
||||||
remoteAddr = strings.Trim(proxies[0], " ")
|
remoteAddr := strings.Trim(proxies[0], " ")
|
||||||
|
if net.ParseIP(remoteAddr) != nil {
|
||||||
|
return remoteAddr
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if realip, ok := r.Header["X-Real-Ip"]; ok {
|
}
|
||||||
if len(realip) > 0 {
|
// X-Real-Ip is less supported, but worth checking in the
|
||||||
remoteAddr = realip[0]
|
// absence of X-Forwarded-For
|
||||||
|
if realIP := r.Header.Get("X-Real-Ip"); realIP != "" {
|
||||||
|
if net.ParseIP(realIP) != nil {
|
||||||
|
return realIP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return remoteAddr
|
return r.RemoteAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithRequest places the request on the context. The context of the request
|
// WithRequest places the request on the context. The context of the request
|
||||||
|
@ -44,7 +46,6 @@ func RemoteAddr(r *http.Request) string {
|
||||||
// is available at "http.request". Other common attributes are available under
|
// is available at "http.request". Other common attributes are available under
|
||||||
// the prefix "http.request.". If a request is already present on the context,
|
// the prefix "http.request.". If a request is already present on the context,
|
||||||
// this method will panic.
|
// this method will panic.
|
||||||
|
|
||||||
func WithRequest(ctx context.Context, r *http.Request) context.Context {
|
func WithRequest(ctx context.Context, r *http.Request) context.Context {
|
||||||
if ctx.Value("http.request") != nil {
|
if ctx.Value("http.request") != nil {
|
||||||
// NOTE(stevvooe): This needs to be considered a programming error. It
|
// NOTE(stevvooe): This needs to be considered a programming error. It
|
||||||
|
|
|
@ -214,16 +214,15 @@ func TestWithVars(t *testing.T) {
|
||||||
// at the transport layer to 127.0.0.1:<port> . However, as the X-Forwarded-For header
|
// at the transport layer to 127.0.0.1:<port> . However, as the X-Forwarded-For header
|
||||||
// just contains the IP address, it is different enough for testing.
|
// just contains the IP address, it is different enough for testing.
|
||||||
func TestRemoteAddr(t *testing.T) {
|
func TestRemoteAddr(t *testing.T) {
|
||||||
expectedRemote := "127.0.0.1"
|
var expectedRemote string
|
||||||
var actualRemote string
|
|
||||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
if r.RemoteAddr == expectedRemote {
|
if r.RemoteAddr == expectedRemote {
|
||||||
t.Errorf("Unexpected matching remote addresses")
|
t.Errorf("Unexpected matching remote addresses")
|
||||||
}
|
}
|
||||||
actualRemote = RemoteAddr(r)
|
|
||||||
|
|
||||||
|
actualRemote := RemoteAddr(r)
|
||||||
if expectedRemote != actualRemote {
|
if expectedRemote != actualRemote {
|
||||||
t.Errorf("Mismatching remote hosts: %v != %v", expectedRemote, actualRemote)
|
t.Errorf("Mismatching remote hosts: %v != %v", expectedRemote, actualRemote)
|
||||||
}
|
}
|
||||||
|
@ -241,14 +240,35 @@ func TestRemoteAddr(t *testing.T) {
|
||||||
frontend := httptest.NewServer(proxy)
|
frontend := httptest.NewServer(proxy)
|
||||||
defer frontend.Close()
|
defer frontend.Close()
|
||||||
|
|
||||||
getReq, err := http.NewRequest("GET", frontend.URL, nil)
|
// X-Forwarded-For set by proxy
|
||||||
|
expectedRemote = "127.0.0.1"
|
||||||
|
proxyReq, err := http.NewRequest("GET", frontend.URL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = http.DefaultClient.Do(proxyReq)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteAddr in X-Real-Ip
|
||||||
|
getReq, err := http.NewRequest("GET", backend.URL, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedRemote = "1.2.3.4"
|
||||||
|
getReq.Header["X-Real-ip"] = []string{expectedRemote}
|
||||||
_, err = http.DefaultClient.Do(getReq)
|
_, err = http.DefaultClient.Do(getReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Valid X-Real-Ip and invalid X-Forwarded-For
|
||||||
|
getReq.Header["X-forwarded-for"] = []string{"1.2.3"}
|
||||||
|
_, err = http.DefaultClient.Do(getReq)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@ func NewBridge(ub URLBuilder, source SourceRecord, actor ActorRecord, request Re
|
||||||
|
|
||||||
// NewRequestRecord builds a RequestRecord for use in NewBridge from an
|
// NewRequestRecord builds a RequestRecord for use in NewBridge from an
|
||||||
// http.Request, associating it with a request id.
|
// http.Request, associating it with a request id.
|
||||||
|
|
||||||
func NewRequestRecord(id string, r *http.Request) RequestRecord {
|
func NewRequestRecord(id string, r *http.Request) RequestRecord {
|
||||||
return RequestRecord{
|
return RequestRecord{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
|
Loading…
Reference in a new issue