Skip to content

Commit

Permalink
🔥 Add DialDualStack option to proxy middleware for upstream IPv6 support
Browse files Browse the repository at this point in the history
  • Loading branch information
negrel committed Mar 5, 2024
1 parent 370cc8b commit cbb4a09
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 20 deletions.
1 change: 1 addition & 0 deletions docs/api/middleware/proxy.md
Expand Up @@ -151,6 +151,7 @@ app.Use(proxy.BalancerForward([]string{
| ReadBufferSize | `int` | Per-connection buffer size for requests' reading. This also limits the maximum header size. Increase this buffer if your clients send multi-KB RequestURIs and/or multi-KB headers (for example, BIG cookies). | (Not specified) |
| WriteBufferSize | `int` | Per-connection buffer size for responses' writing. | (Not specified) |
| TlsConfig | `*tls.Config` (or `*fasthttp.TLSConfig` in v3) | TLS config for the HTTP client. | `nil` |
| DialDualStack | `bool` | Client will attempt to connect to both ipv4 and ipv6 host addresses if set to true. | `false` |
| Client | `*fasthttp.LBClient` | Client is a custom client when client config is complex. | `nil` |

## Default Config
Expand Down
12 changes: 10 additions & 2 deletions middleware/proxy/config.go
Expand Up @@ -51,9 +51,17 @@ type Config struct {
TlsConfig *tls.Config //nolint:stylecheck,revive // TODO: Rename to "TLSConfig" in v3

// Client is custom client when client config is complex.
// Note that Servers, Timeout, WriteBufferSize, ReadBufferSize and TlsConfig
// will not be used if the client are set.
// Note that Servers, Timeout, WriteBufferSize, ReadBufferSize, TlsConfig
// and DialDualStack will not be used if the client are set.
Client *fasthttp.LBClient

// Attempt to connect to both ipv4 and ipv6 host addresses if set to true.
//
// By default client connects only to ipv4 addresses, since unfortunately ipv6
// remains broken in many networks worldwide :)
//
// Optional. Default: false
DialDualStack bool
}

// ConfigDefault is the default config
Expand Down
2 changes: 2 additions & 0 deletions middleware/proxy/proxy.go
Expand Up @@ -45,6 +45,8 @@ func Balancer(config Config) fiber.Handler {
WriteBufferSize: config.WriteBufferSize,

TLSConfig: config.TlsConfig,

DialDualStack: config.DialDualStack,
}

lbc.Clients = append(lbc.Clients, client)
Expand Down
95 changes: 77 additions & 18 deletions middleware/proxy/proxy_test.go
Expand Up @@ -18,13 +18,13 @@ import (
"github.com/valyala/fasthttp"
)

func createProxyTestServer(t *testing.T, handler fiber.Handler) (*fiber.App, string) {
func createProxyTestServer(t *testing.T, handler fiber.Handler, network, address string) (*fiber.App, string) {
t.Helper()

target := fiber.New()
target.Get("/", handler)

ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
ln, err := net.Listen(network, address)
require.NoError(t, err)

go func() {
Expand All @@ -39,6 +39,16 @@ func createProxyTestServer(t *testing.T, handler fiber.Handler) (*fiber.App, str
return target, addr
}

func createProxyTestServerIPv4(t *testing.T, handler fiber.Handler) (*fiber.App, string) {
t.Helper()
return createProxyTestServer(t, handler, fiber.NetworkTCP4, "127.0.0.1:0")
}

func createProxyTestServerIPv6(t *testing.T, handler fiber.Handler) (*fiber.App, string) {
t.Helper()
return createProxyTestServer(t, handler, fiber.NetworkTCP6, "[::1]:0")
}

// go test -run Test_Proxy_Empty_Host
func Test_Proxy_Empty_Upstream_Servers(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -86,7 +96,7 @@ func Test_Proxy_Next(t *testing.T) {
func Test_Proxy(t *testing.T) {
t.Parallel()

target, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
target, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.SendStatus(fiber.StatusTeapot)
})

Expand Down Expand Up @@ -148,11 +158,60 @@ func Test_Proxy_Balancer_WithTlsConfig(t *testing.T) {
resp.Close()
}

// go test -run Test_Proxy_Balancer_IPv6_Upstream
func Test_Proxy_Balancer_IPv6_Upstream(t *testing.T) {
t.Parallel()

target, addr := createProxyTestServerIPv6(t, func(c fiber.Ctx) error {
return c.SendStatus(fiber.StatusTeapot)
})

resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2*time.Second)
require.NoError(t, err)
require.Equal(t, fiber.StatusTeapot, resp.StatusCode)

app := fiber.New()

app.Use(Balancer(Config{Servers: []string{addr}}))

req := httptest.NewRequest(fiber.MethodGet, "/", nil)
req.Host = addr
resp, err = app.Test(req)
require.NoError(t, err)
require.Equal(t, fiber.StatusInternalServerError, resp.StatusCode)
}

// go test -run Test_Proxy_Balancer_IPv6_Upstream
func Test_Proxy_Balancer_IPv6_Upstream_With_DialDualStack(t *testing.T) {
t.Parallel()

target, addr := createProxyTestServerIPv6(t, func(c fiber.Ctx) error {
return c.SendStatus(fiber.StatusTeapot)
})

resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2*time.Second)
require.NoError(t, err)
require.Equal(t, fiber.StatusTeapot, resp.StatusCode)

app := fiber.New()

app.Use(Balancer(Config{
Servers: []string{addr},
DialDualStack: true,
}))

req := httptest.NewRequest(fiber.MethodGet, "/", nil)
req.Host = addr
resp, err = app.Test(req)
require.NoError(t, err)
require.Equal(t, fiber.StatusTeapot, resp.StatusCode)
}

// go test -run Test_Proxy_Forward_WithTlsConfig_To_Http
func Test_Proxy_Forward_WithTlsConfig_To_Http(t *testing.T) {
t.Parallel()

_, targetAddr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, targetAddr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.SendString("hello from target")
})

Expand Down Expand Up @@ -193,7 +252,7 @@ func Test_Proxy_Forward(t *testing.T) {

app := fiber.New()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.SendString("forwarded")
})

Expand Down Expand Up @@ -255,7 +314,7 @@ func Test_Proxy_Forward_WithClient_TLSConfig(t *testing.T) {
func Test_Proxy_Modify_Response(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.Status(500).SendString("not modified")
})

Expand All @@ -281,7 +340,7 @@ func Test_Proxy_Modify_Response(t *testing.T) {
func Test_Proxy_Modify_Request(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
b := c.Request().Body()
return c.SendString(string(b))
})
Expand All @@ -308,7 +367,7 @@ func Test_Proxy_Modify_Request(t *testing.T) {
func Test_Proxy_Timeout_Slow_Server(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
time.Sleep(300 * time.Millisecond)
return c.SendString("fiber is awesome")
})
Expand All @@ -332,7 +391,7 @@ func Test_Proxy_Timeout_Slow_Server(t *testing.T) {
func Test_Proxy_With_Timeout(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
time.Sleep(1 * time.Second)
return c.SendString("fiber is awesome")
})
Expand All @@ -356,7 +415,7 @@ func Test_Proxy_With_Timeout(t *testing.T) {
func Test_Proxy_Buffer_Size_Response(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
long := strings.Join(make([]string, 5000), "-")
c.Set("Very-Long-Header", long)
return c.SendString("ok")
Expand All @@ -383,7 +442,7 @@ func Test_Proxy_Buffer_Size_Response(t *testing.T) {
// go test -race -run Test_Proxy_Do_RestoreOriginalURL
func Test_Proxy_Do_RestoreOriginalURL(t *testing.T) {
t.Parallel()
_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.SendString("proxied")
})

Expand Down Expand Up @@ -470,7 +529,7 @@ func Test_Proxy_DoRedirects_TooManyRedirects(t *testing.T) {
func Test_Proxy_DoTimeout_RestoreOriginalURL(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.SendString("proxied")
})

Expand All @@ -492,7 +551,7 @@ func Test_Proxy_DoTimeout_RestoreOriginalURL(t *testing.T) {
func Test_Proxy_DoTimeout_Timeout(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
time.Sleep(time.Second * 5)
return c.SendString("proxied")
})
Expand All @@ -510,7 +569,7 @@ func Test_Proxy_DoTimeout_Timeout(t *testing.T) {
func Test_Proxy_DoDeadline_RestoreOriginalURL(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.SendString("proxied")
})

Expand All @@ -532,7 +591,7 @@ func Test_Proxy_DoDeadline_RestoreOriginalURL(t *testing.T) {
func Test_Proxy_DoDeadline_PastDeadline(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
time.Sleep(time.Second * 5)
return c.SendString("proxied")
})
Expand All @@ -550,7 +609,7 @@ func Test_Proxy_DoDeadline_PastDeadline(t *testing.T) {
func Test_Proxy_Do_HTTP_Prefix_URL(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.SendString("hello world")
})

Expand Down Expand Up @@ -641,7 +700,7 @@ func Test_Proxy_Forward_Local_Client(t *testing.T) {
func Test_ProxyBalancer_Custom_Client(t *testing.T) {
t.Parallel()

target, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
target, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.SendStatus(fiber.StatusTeapot)
})

Expand Down Expand Up @@ -721,7 +780,7 @@ func Test_Proxy_Balancer_Forward_Local(t *testing.T) {

app := fiber.New()

_, addr := createProxyTestServer(t, func(c fiber.Ctx) error {
_, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error {
return c.SendString("forwarded")
})

Expand Down

0 comments on commit cbb4a09

Please sign in to comment.