Skip to content

Commit

Permalink
Setting trusted platform using an enum-like
Browse files Browse the repository at this point in the history
  • Loading branch information
ItalyPaleAle committed May 28, 2021
1 parent 6703dea commit 66dbc0d
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 13 deletions.
16 changes: 13 additions & 3 deletions context.go
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
"math"
"mime/multipart"
"net"
Expand Down Expand Up @@ -731,17 +732,26 @@ func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (e
// If the headers are nots syntactically valid OR the remote IP does not correspong to a trusted proxy,
// the remote IP (coming form Request.RemoteAddr) is returned.
func (c *Context) ClientIP() string {
switch {
case c.engine.AppEngine:
// Check if we're running on a tursted platform
switch c.engine.TrustedPlatform {
case PlatformGoogleAppEngine:
if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" {
return addr
}
case c.engine.CloudflareProxy:
case PlatformCloudflare:
if addr := c.requestHeader("CF-Connecting-IP"); addr != "" {
return addr
}
}

// Legacy "AppEngine" flag
if c.engine.AppEngine {
log.Println(`The AppEngine flag is going to be deprecated. Please check issue #XXX and use 'TrustedPlatform: gin.PlatformGoogleAppEngine' instead.`)
if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" {
return addr
}
}

remoteIP, trusted := c.RemoteIP()
if remoteIP == nil {
return ""
Expand Down
2 changes: 1 addition & 1 deletion context_appengine.go
Expand Up @@ -8,5 +8,5 @@
package gin

func init() {
defaultAppEngine = true
defaultPlatform = PlatformGoogleAppEngine
}
15 changes: 12 additions & 3 deletions context_test.go
Expand Up @@ -1410,7 +1410,7 @@ func TestContextClientIP(t *testing.T) {

c.Request.Header.Del("X-Forwarded-For")
c.Request.Header.Del("X-Real-IP")
c.engine.AppEngine = true
c.engine.TrustedPlatform = PlatformGoogleAppEngine
assert.Equal(t, "50.50.50.50", c.ClientIP())

c.Request.Header.Del("X-Appengine-Remote-Addr")
Expand Down Expand Up @@ -1470,19 +1470,27 @@ func TestContextClientIP(t *testing.T) {
assert.Equal(t, "10.10.10.10", c.ClientIP())

c.engine.RemoteIPHeaders = []string{}
c.engine.TrustedPlatform = PlatformGoogleAppEngine
assert.Equal(t, "50.50.50.50", c.ClientIP())

// Test the legacy flag
c.engine.TrustedPlatform = ""
c.engine.AppEngine = true
assert.Equal(t, "50.50.50.50", c.ClientIP())
c.engine.AppEngine = false
c.engine.TrustedPlatform = PlatformGoogleAppEngine

c.Request.Header.Del("X-Appengine-Remote-Addr")
assert.Equal(t, "40.40.40.40", c.ClientIP())

c.engine.AppEngine = false
c.engine.CloudflareProxy = true
c.engine.TrustedPlatform = PlatformCloudflare
assert.Equal(t, "60.60.60.60", c.ClientIP())

c.Request.Header.Del("CF-Connecting-IP")
assert.Equal(t, "40.40.40.40", c.ClientIP())

c.engine.TrustedPlatform = ""

// no port
c.Request.RemoteAddr = "50.50.50.50"
assert.Empty(t, c.ClientIP())
Expand All @@ -1494,6 +1502,7 @@ func resetContextForClientIPTests(c *Context) {
c.Request.Header.Set("X-Appengine-Remote-Addr", "50.50.50.50")
c.Request.Header.Set("CF-Connecting-IP", "60.60.60.60")
c.Request.RemoteAddr = " 40.40.40.40:42123 "
c.engine.TrustedPlatform = ""
c.engine.AppEngine = false
}

Expand Down
23 changes: 17 additions & 6 deletions gin.go
Expand Up @@ -25,7 +25,7 @@ var (
default405Body = []byte("405 method not allowed")
)

var defaultAppEngine bool
var defaultPlatform string

// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)
Expand All @@ -52,6 +52,16 @@ type RouteInfo struct {
// RoutesInfo defines a RouteInfo array.
type RoutesInfo []RouteInfo

// Trusted platforms
const (
// When running on Google App Engine. Trust X-Appengine-Remote-Addr
// for determining the client's IP
PlatformGoogleAppEngine = "google-app-engine"
// When using Cloudflare's CDN. Trust CF-Connecting-IP for determining
// the client's IP
PlatformCloudflare = "cloudflare"
)

// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
// Create an instance of Engine, by using New() or Default()
type Engine struct {
Expand Down Expand Up @@ -101,14 +111,15 @@ type Engine struct {
// `true`.
TrustedProxies []string

// If set to a constant of value gin.Platform*, trusts the headers set by
// that platform, for example to determine the client IP
TrustedPlatform string

// DEPRECATED: USE `TrustedPlatform` WITH VALUE `gin.GoogleAppEngine` INSTEAD
// #726 #755 If enabled, it will trust some headers starting with
// 'X-AppEngine...' for better integration with that PaaS.
AppEngine bool

// If enabled, it will trust the CF-Connecting-IP header to determine the
// IP of the client.
CloudflareProxy bool

// If enabled, the url.RawPath will be used to find parameters.
UseRawPath bool

Expand Down Expand Up @@ -164,7 +175,7 @@ func New() *Engine {
ForwardedByClientIP: true,
RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"},
TrustedProxies: []string{"0.0.0.0/0"},
AppEngine: defaultAppEngine,
TrustedPlatform: defaultPlatform,
UseRawPath: false,
RemoveExtraSlash: false,
UnescapePathValues: true,
Expand Down

0 comments on commit 66dbc0d

Please sign in to comment.