Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit fc5d6dd

Browse files
Bisstocuzthinkerou
authored andcommittedNov 24, 2021
Tidy: Complete TrustedProxies feature (#2887)
1 parent 7d20914 commit fc5d6dd

6 files changed

+80
-72
lines changed
 

‎README.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -2130,11 +2130,17 @@ Gin lets you specify which headers to hold the real client IP (if any),
21302130
as well as specifying which proxies (or direct clients) you trust to
21312131
specify one of these headers.
21322132

2133-
The `TrustedProxies` slice on your `gin.Engine` specifes network addresses or
2134-
network CIDRs from where clients which their request headers related to client
2133+
Use function `SetTrustedProxies()` on your `gin.Engine` to specify network addresses
2134+
or network CIDRs from where clients which their request headers related to client
21352135
IP can be trusted. They can be IPv4 addresses, IPv4 CIDRs, IPv6 addresses or
21362136
IPv6 CIDRs.
21372137

2138+
**Attention:** Gin trust all proxies by default if you don't specify a trusted
2139+
proxy using the function above, **this is NOT safe**. At the same time, if you don't
2140+
use any proxy, you can disable this feature by using `Engine.SetTrustedProxies(nil)`,
2141+
then `Context.ClientIP()` will return the remote address directly to avoid some
2142+
unnecessary computation.
2143+
21382144
```go
21392145
import (
21402146
"fmt"
@@ -2145,7 +2151,7 @@ import (
21452151
func main() {
21462152

21472153
router := gin.Default()
2148-
router.TrustedProxies = []string{"192.168.1.2"}
2154+
router.SetTrustedProxies([]string{"192.168.1.2"})
21492155

21502156
router.GET("/", func(c *gin.Context) {
21512157
// If the client is 192.168.1.2, use the X-Forwarded-For

‎context.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ func (c *Context) ClientIP() string {
771771
// RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port).
772772
// It also checks if the remoteIP is a trusted proxy or not.
773773
// In order to perform this validation, it will see if the IP is contained within at least one of the CIDR blocks
774-
// defined in Engine.TrustedProxies
774+
// defined by Engine.SetTrustedProxies()
775775
func (c *Context) RemoteIP() (net.IP, bool) {
776776
ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr))
777777
if err != nil {

‎context_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -1411,6 +1411,10 @@ func TestContextClientIP(t *testing.T) {
14111411
c.engine.RemoteIPHeaders = []string{"X-Forwarded-For"}
14121412
assert.Equal(t, "40.40.40.40", c.ClientIP())
14131413

1414+
// Disabled TrustedProxies feature
1415+
_ = c.engine.SetTrustedProxies(nil)
1416+
assert.Equal(t, "40.40.40.40", c.ClientIP())
1417+
14141418
// Last proxy is trusted, but the RemoteAddr is not
14151419
_ = c.engine.SetTrustedProxies([]string{"30.30.30.30"})
14161420
assert.Equal(t, "40.40.40.40", c.ClientIP())

‎gin.go

+40-30
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"net/http"
1212
"os"
1313
"path"
14+
"reflect"
1415
"strings"
1516
"sync"
1617

@@ -27,6 +28,8 @@ var (
2728

2829
var defaultPlatform string
2930

31+
var defaultTrustedCIDRs = []*net.IPNet{{IP: net.IP{0x0, 0x0, 0x0, 0x0}, Mask: net.IPMask{0x0, 0x0, 0x0, 0x0}}} // 0.0.0.0/0
32+
3033
// HandlerFunc defines the handler used by gin middleware as return value.
3134
type HandlerFunc func(*Context)
3235

@@ -119,15 +122,9 @@ type Engine struct {
119122
// List of headers used to obtain the client IP when
120123
// `(*gin.Engine).ForwardedByClientIP` is `true` and
121124
// `(*gin.Context).Request.RemoteAddr` is matched by at least one of the
122-
// network origins of `(*gin.Engine).TrustedProxies`.
125+
// network origins of list defined by `(*gin.Engine).SetTrustedProxies()`.
123126
RemoteIPHeaders []string
124127

125-
// List of network origins (IPv4 addresses, IPv4 CIDRs, IPv6 addresses or
126-
// IPv6 CIDRs) from which to trust request's headers that contain
127-
// alternative client IP when `(*gin.Engine).ForwardedByClientIP` is
128-
// `true`.
129-
TrustedProxies []string
130-
131128
// If set to a constant of value gin.Platform*, trusts the headers set by
132129
// that platform, for example to determine the client IP
133130
TrustedPlatform string
@@ -147,6 +144,7 @@ type Engine struct {
147144
pool sync.Pool
148145
trees methodTrees
149146
maxParams uint16
147+
trustedProxies []string
150148
trustedCIDRs []*net.IPNet
151149
}
152150

@@ -174,7 +172,6 @@ func New() *Engine {
174172
HandleMethodNotAllowed: false,
175173
ForwardedByClientIP: true,
176174
RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"},
177-
TrustedProxies: []string{"0.0.0.0/0"},
178175
TrustedPlatform: defaultPlatform,
179176
UseRawPath: false,
180177
RemoveExtraSlash: false,
@@ -183,7 +180,8 @@ func New() *Engine {
183180
trees: make(methodTrees, 0, 9),
184181
delims: render.Delims{Left: "{{", Right: "}}"},
185182
secureJSONPrefix: "while(1);",
186-
trustedCIDRs: []*net.IPNet{{IP: net.IP{0x0, 0x0, 0x0, 0x0}, Mask: net.IPMask{0x0, 0x0, 0x0, 0x0}}},
183+
trustedProxies: []string{"0.0.0.0/0"},
184+
trustedCIDRs: defaultTrustedCIDRs,
187185
}
188186
engine.RouterGroup.engine = engine
189187
engine.pool.New = func() interface{} {
@@ -342,9 +340,9 @@ func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo {
342340
func (engine *Engine) Run(addr ...string) (err error) {
343341
defer func() { debugPrintError(err) }()
344342

345-
err = engine.parseTrustedProxies()
346-
if err != nil {
347-
return err
343+
if engine.isUnsafeTrustedProxies() {
344+
debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
345+
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
348346
}
349347

350348
address := resolveAddress(addr)
@@ -354,12 +352,12 @@ func (engine *Engine) Run(addr ...string) (err error) {
354352
}
355353

356354
func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) {
357-
if engine.TrustedProxies == nil {
355+
if engine.trustedProxies == nil {
358356
return nil, nil
359357
}
360358

361-
cidr := make([]*net.IPNet, 0, len(engine.TrustedProxies))
362-
for _, trustedProxy := range engine.TrustedProxies {
359+
cidr := make([]*net.IPNet, 0, len(engine.trustedProxies))
360+
for _, trustedProxy := range engine.trustedProxies {
363361
if !strings.Contains(trustedProxy, "/") {
364362
ip := parseIP(trustedProxy)
365363
if ip == nil {
@@ -382,13 +380,25 @@ func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) {
382380
return cidr, nil
383381
}
384382

385-
// SetTrustedProxies set Engine.TrustedProxies
383+
// SetTrustedProxies set a list of network origins (IPv4 addresses,
384+
// IPv4 CIDRs, IPv6 addresses or IPv6 CIDRs) from which to trust
385+
// request's headers that contain alternative client IP when
386+
// `(*gin.Engine).ForwardedByClientIP` is `true`. `TrustedProxies`
387+
// feature is enabled by default, and it also trusts all proxies
388+
// by default. If you want to disable this feature, use
389+
// Engine.SetTrustedProxies(nil), then Context.ClientIP() will
390+
// return the remote address directly.
386391
func (engine *Engine) SetTrustedProxies(trustedProxies []string) error {
387-
engine.TrustedProxies = trustedProxies
392+
engine.trustedProxies = trustedProxies
388393
return engine.parseTrustedProxies()
389394
}
390395

391-
// parseTrustedProxies parse Engine.TrustedProxies to Engine.trustedCIDRs
396+
// isUnsafeTrustedProxies compares Engine.trustedCIDRs and defaultTrustedCIDRs, it's not safe if equal (returns true)
397+
func (engine *Engine) isUnsafeTrustedProxies() bool {
398+
return reflect.DeepEqual(engine.trustedCIDRs, defaultTrustedCIDRs)
399+
}
400+
401+
// parseTrustedProxies parse Engine.trustedProxies to Engine.trustedCIDRs
392402
func (engine *Engine) parseTrustedProxies() error {
393403
trustedCIDRs, err := engine.prepareTrustedCIDRs()
394404
engine.trustedCIDRs = trustedCIDRs
@@ -416,9 +426,9 @@ func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) {
416426
debugPrint("Listening and serving HTTPS on %s\n", addr)
417427
defer func() { debugPrintError(err) }()
418428

419-
err = engine.parseTrustedProxies()
420-
if err != nil {
421-
return err
429+
if engine.isUnsafeTrustedProxies() {
430+
debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
431+
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
422432
}
423433

424434
err = http.ListenAndServeTLS(addr, certFile, keyFile, engine)
@@ -432,9 +442,9 @@ func (engine *Engine) RunUnix(file string) (err error) {
432442
debugPrint("Listening and serving HTTP on unix:/%s", file)
433443
defer func() { debugPrintError(err) }()
434444

435-
err = engine.parseTrustedProxies()
436-
if err != nil {
437-
return err
445+
if engine.isUnsafeTrustedProxies() {
446+
debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
447+
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
438448
}
439449

440450
listener, err := net.Listen("unix", file)
@@ -455,9 +465,9 @@ func (engine *Engine) RunFd(fd int) (err error) {
455465
debugPrint("Listening and serving HTTP on fd@%d", fd)
456466
defer func() { debugPrintError(err) }()
457467

458-
err = engine.parseTrustedProxies()
459-
if err != nil {
460-
return err
468+
if engine.isUnsafeTrustedProxies() {
469+
debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
470+
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
461471
}
462472

463473
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd))
@@ -476,9 +486,9 @@ func (engine *Engine) RunListener(listener net.Listener) (err error) {
476486
debugPrint("Listening and serving HTTP on listener what's bind with address@%s", listener.Addr())
477487
defer func() { debugPrintError(err) }()
478488

479-
err = engine.parseTrustedProxies()
480-
if err != nil {
481-
return err
489+
if engine.isUnsafeTrustedProxies() {
490+
debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
491+
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
482492
}
483493

484494
err = http.Serve(listener, engine)

‎gin_integration_test.go

+7
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ func TestRunEmpty(t *testing.T) {
7676
testRequest(t, "http://localhost:8080/example")
7777
}
7878

79+
func TestBadTrustedCIDRs(t *testing.T) {
80+
router := New()
81+
assert.Error(t, router.SetTrustedProxies([]string{"hello/world"}))
82+
}
83+
84+
/* legacy tests
7985
func TestBadTrustedCIDRsForRun(t *testing.T) {
8086
os.Setenv("PORT", "")
8187
router := New()
@@ -143,6 +149,7 @@ func TestBadTrustedCIDRsForRunTLS(t *testing.T) {
143149
router.TrustedProxies = []string{"hello/world"}
144150
assert.Error(t, router.RunTLS(":8080", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem"))
145151
}
152+
*/
146153

147154
func TestRunTLS(t *testing.T) {
148155
router := New()

‎gin_test.go

+19-38
Original file line numberDiff line numberDiff line change
@@ -539,79 +539,64 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
539539
// valid ipv4 cidr
540540
{
541541
expectedTrustedCIDRs := []*net.IPNet{parseCIDR("0.0.0.0/0")}
542-
r.TrustedProxies = []string{"0.0.0.0/0"}
543-
544-
trustedCIDRs, err := r.prepareTrustedCIDRs()
542+
err := r.SetTrustedProxies([]string{"0.0.0.0/0"})
545543

546544
assert.NoError(t, err)
547-
assert.Equal(t, expectedTrustedCIDRs, trustedCIDRs)
545+
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
548546
}
549547

550548
// invalid ipv4 cidr
551549
{
552-
r.TrustedProxies = []string{"192.168.1.33/33"}
553-
554-
_, err := r.prepareTrustedCIDRs()
550+
err := r.SetTrustedProxies([]string{"192.168.1.33/33"})
555551

556552
assert.Error(t, err)
557553
}
558554

559555
// valid ipv4 address
560556
{
561557
expectedTrustedCIDRs := []*net.IPNet{parseCIDR("192.168.1.33/32")}
562-
r.TrustedProxies = []string{"192.168.1.33"}
563558

564-
trustedCIDRs, err := r.prepareTrustedCIDRs()
559+
err := r.SetTrustedProxies([]string{"192.168.1.33"})
565560

566561
assert.NoError(t, err)
567-
assert.Equal(t, expectedTrustedCIDRs, trustedCIDRs)
562+
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
568563
}
569564

570565
// invalid ipv4 address
571566
{
572-
r.TrustedProxies = []string{"192.168.1.256"}
573-
574-
_, err := r.prepareTrustedCIDRs()
567+
err := r.SetTrustedProxies([]string{"192.168.1.256"})
575568

576569
assert.Error(t, err)
577570
}
578571

579572
// valid ipv6 address
580573
{
581574
expectedTrustedCIDRs := []*net.IPNet{parseCIDR("2002:0000:0000:1234:abcd:ffff:c0a8:0101/128")}
582-
r.TrustedProxies = []string{"2002:0000:0000:1234:abcd:ffff:c0a8:0101"}
583-
584-
trustedCIDRs, err := r.prepareTrustedCIDRs()
575+
err := r.SetTrustedProxies([]string{"2002:0000:0000:1234:abcd:ffff:c0a8:0101"})
585576

586577
assert.NoError(t, err)
587-
assert.Equal(t, expectedTrustedCIDRs, trustedCIDRs)
578+
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
588579
}
589580

590581
// invalid ipv6 address
591582
{
592-
r.TrustedProxies = []string{"gggg:0000:0000:1234:abcd:ffff:c0a8:0101"}
593-
594-
_, err := r.prepareTrustedCIDRs()
583+
err := r.SetTrustedProxies([]string{"gggg:0000:0000:1234:abcd:ffff:c0a8:0101"})
595584

596585
assert.Error(t, err)
597586
}
598587

599588
// valid ipv6 cidr
600589
{
601590
expectedTrustedCIDRs := []*net.IPNet{parseCIDR("::/0")}
602-
r.TrustedProxies = []string{"::/0"}
603-
604-
trustedCIDRs, err := r.prepareTrustedCIDRs()
591+
err := r.SetTrustedProxies([]string{"::/0"})
605592

606593
assert.NoError(t, err)
607-
assert.Equal(t, expectedTrustedCIDRs, trustedCIDRs)
594+
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
608595
}
609596

610597
// invalid ipv6 cidr
611598
{
612-
r.TrustedProxies = []string{"gggg:0000:0000:1234:abcd:ffff:c0a8:0101/129"}
613-
614-
_, err := r.prepareTrustedCIDRs()
599+
err := r.SetTrustedProxies([]string{"gggg:0000:0000:1234:abcd:ffff:c0a8:0101/129"})
615600

616601
assert.Error(t, err)
617602
}
@@ -623,36 +608,32 @@ func TestPrepareTrustedCIRDsWith(t *testing.T) {
623608
parseCIDR("192.168.0.0/16"),
624609
parseCIDR("172.16.0.1/32"),
625610
}
626-
r.TrustedProxies = []string{
611+
err := r.SetTrustedProxies([]string{
627612
"::/0",
628613
"192.168.0.0/16",
629614
"172.16.0.1",
630-
}
631-
632-
trustedCIDRs, err := r.prepareTrustedCIDRs()
615+
})
633616

634617
assert.NoError(t, err)
635-
assert.Equal(t, expectedTrustedCIDRs, trustedCIDRs)
618+
assert.Equal(t, expectedTrustedCIDRs, r.trustedCIDRs)
636619
}
637620

638621
// invalid combination
639622
{
640-
r.TrustedProxies = []string{
623+
err := r.SetTrustedProxies([]string{
641624
"::/0",
642625
"192.168.0.0/16",
643626
"172.16.0.256",
644-
}
645-
_, err := r.prepareTrustedCIDRs()
627+
})
646628

647629
assert.Error(t, err)
648630
}
649631

650632
// nil value
651633
{
652-
r.TrustedProxies = nil
653-
trustedCIDRs, err := r.prepareTrustedCIDRs()
634+
err := r.SetTrustedProxies(nil)
654635

655-
assert.Nil(t, trustedCIDRs)
636+
assert.Nil(t, r.trustedCIDRs)
656637
assert.Nil(t, err)
657638
}
658639

0 commit comments

Comments
 (0)
Please sign in to comment.