Skip to content
This repository has been archived by the owner on Aug 6, 2024. It is now read-only.

Commit

Permalink
core: pin request host
Browse files Browse the repository at this point in the history
  • Loading branch information
h3adex committed Dec 6, 2023
1 parent c5b7d73 commit 66cb58f
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 47 deletions.
29 changes: 10 additions & 19 deletions pkg/annotations/annotations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,86 +16,77 @@ func TestAnnotations(t *testing.T) {
"guardgress/limit-ip-whitelist": "127.0.0.1,127.0.0.2",
}

assert.Equal(
assert.True(
t,
IsTlsFingerprintBlacklisted(
mockAnnotations,
models.ClientHelloParsed{Ja3: "d41d8cd98f00b204e9800998ecf8427a"},
),
true,
)

assert.Equal(
assert.False(
t,
IsTlsFingerprintBlacklisted(
mockAnnotations,
models.ClientHelloParsed{Ja3: "d41d8cd98f00b204e9800998ecf8427a_false"},
),
false,
)

assert.Equal(
assert.True(
t,
IsTlsFingerprintBlacklisted(
mockAnnotations,
models.ClientHelloParsed{Ja4: "t13d1715h2_5b57614c22b0_93c746dc12af"},
),
true,
)

assert.Equal(
assert.False(
t,
IsTlsFingerprintBlacklisted(
mockAnnotations,
models.ClientHelloParsed{Ja4: "t13d1715h2_5b57614c22b0_93c746dc12af_false"},
),
false,
)

assert.Equal(
assert.True(
t,
IsUserAgentBlacklisted(
mockAnnotations,
"curl/7.64.1",
),
true,
)

assert.Equal(
assert.False(
t,
IsUserAgentBlacklisted(
mockAnnotations,
"curl/7.64.1_false",
),
false,
)

assert.Equal(
assert.True(
t,
IsIpWhitelisted(
mockAnnotations,
"127.0.0.1",
),
true,
)

assert.Equal(
assert.True(
t,
IsIpWhitelisted(
mockAnnotations,
"127.0.0.2",
),
true,
)

assert.Equal(
assert.False(
t,
IsIpWhitelisted(
mockAnnotations,
"127.0.0.1_false",
),
false,
)

assert.Equal(t, AddJa3Header(mockAnnotations), true)
assert.True(t, AddJa3Header(mockAnnotations))
}
44 changes: 22 additions & 22 deletions pkg/limitHandler/limiter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ func TestLimiterModule5H(t *testing.T) {
}

if i <= 5 {
assert.Equal(t, increment.Reached, false)
assert.False(t, increment.Reached)
} else {
assert.Equal(t, increment.Reached, true)
assert.True(t, increment.Reached)
}
}
}
Expand All @@ -54,14 +54,14 @@ func TestLimiterModule1S(t *testing.T) {

for i := 1; i <= 3; i++ {
increment, _ := instance.Increment(ctx, key, 1)
assert.Equal(t, increment.Reached, false)
assert.False(t, increment.Reached)
time.Sleep(time.Second * 1)
}

_, _ = instance.Increment(ctx, key, 1)
for i := 1; i <= 5; i++ {
increment, _ := instance.Increment(ctx, key, 1)
assert.Equal(t, increment.Reached, true)
assert.True(t, increment.Reached)
}

}
Expand All @@ -74,9 +74,9 @@ func TestIsIpLimited(t *testing.T) {
}
ingressLimiter := GetIngressLimiter(ingressExactPathMock)

assert.Equal(t, false, IpIsLimited(ingressLimiter, map[string]string{}, ip))
assert.Equal(t, true, IpIsLimited(ingressLimiter, map[string]string{}, ip))
assert.Equal(t, false, IpIsLimited(ingressLimiter, map[string]string{
assert.False(t, IpIsLimited(ingressLimiter, map[string]string{}, ip))
assert.True(t, IpIsLimited(ingressLimiter, map[string]string{}, ip))
assert.False(t, IpIsLimited(ingressLimiter, map[string]string{
"guardgress/limit-ip-whitelist": "127.0.0.1",
}, ip))

Expand All @@ -88,17 +88,17 @@ func TestGetIngressLimiter(t *testing.T) {
"guardgress/limit-period": "20-S",
}
ingressLimiter := GetIngressLimiter(ingressExactPathMock)
assert.Equal(t, ingressLimiter.Rate.Limit, int64(20))
assert.Equal(t, ingressLimiter.Rate.Period, time.Second)
assert.Equal(t, int64(20), ingressLimiter.Rate.Limit)
assert.Equal(t, time.Second, ingressLimiter.Rate.Period)

ingressExactPathMock = mocks.IngressExactPathTypeMock()
ingressExactPathMock.Annotations = map[string]string{
"guardgress/limit-period": "20-H",
}
ingressLimiter = GetIngressLimiter(ingressExactPathMock)

assert.Equal(t, ingressLimiter.Rate.Limit, int64(20))
assert.Equal(t, ingressLimiter.Rate.Period, time.Hour)
assert.Equal(t, int64(20), ingressLimiter.Rate.Limit)
assert.Equal(t, time.Hour, ingressLimiter.Rate.Period)

ingressExactPathMock = mocks.IngressExactPathTypeMock()
ingressExactPathMock.Annotations = map[string]string{}
Expand All @@ -113,16 +113,16 @@ func TestRateLimitTriggeredRPS1(t *testing.T) {
"guardgress/limit-period": "1-S",
}
ingressLimiter := GetIngressLimiter(ingressExactPathMock)
assert.Equal(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp), false)
assert.Equal(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp), true)
assert.Equal(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp), true)
assert.False(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
assert.True(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
assert.True(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
time.Sleep(time.Second * 1)
assert.Equal(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp), false)
assert.Equal(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp), true)
assert.False(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
assert.True(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
time.Sleep(time.Millisecond * 500)
assert.Equal(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp), true)
assert.True(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
time.Sleep(time.Millisecond * 500)
assert.Equal(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp), false)
assert.False(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
}

func TestRateLimitTriggeredRPS10(t *testing.T) {
Expand All @@ -144,13 +144,13 @@ func TestRateLimitTriggeredRPS10(t *testing.T) {
go func(wg *sync.WaitGroup) {
defer wg.Done()
log.Info("simulating request")
assert.Equal(t, false, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
assert.False(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
}(&wg)
}
wg.Wait()

// The IP should be limited after reaching the specified limit
assert.Equal(t, true, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
assert.True(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
}

func TestRateLimitTriggeredRPM10(t *testing.T) {
Expand All @@ -164,9 +164,9 @@ func TestRateLimitTriggeredRPM10(t *testing.T) {
// range 10
for i := 1; i <= 10; i++ {
if i <= 5 {
assert.Equal(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp), false)
assert.False(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
} else {
assert.Equal(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp), true)
assert.True(t, IpIsLimited(ingressLimiter, ingressExactPathMock.Annotations, mockIp))
}

}
Expand Down
4 changes: 2 additions & 2 deletions pkg/router/router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ func TestGetTlsCertificateForceLocalhost(t *testing.T) {
}

_, ok := os.LookupEnv("FORCE_LOCALHOST_CERT")
assert.Equal(t, ok, false)
assert.False(t, ok)
err := os.Setenv("FORCE_LOCALHOST_CERT", "true")
assert.NoError(t, err)
_, ok = os.LookupEnv("FORCE_LOCALHOST_CERT")
assert.Equal(t, ok, true)
assert.True(t, ok)

// sni does not matter should return localhost cert
_, err = routingTable.GetTlsCertificate("www.foo.com")
Expand Down
6 changes: 3 additions & 3 deletions pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (s Server) Run(ctx context.Context) {

wg.Add(1)
go func() {
log.Info("Starting HTTPS-Server on ", s.Config.Port)
log.Info("Starting HTTPS-Server on ", s.Config.TlsPort)
handle := gin.Default()
handle.Any("/*path", s.ServeHttps)
err := fp.Server(
Expand Down Expand Up @@ -151,7 +151,7 @@ func (s Server) ServeHttps(ctx *gin.Context) {

proxy.Director = func(req *http.Request) {
req.Header = ctx.Request.Header
req.Host = svcUrl.Host
req.Host = ctx.Request.Host
req.URL.Scheme = svcUrl.Scheme
req.URL.Host = svcUrl.Host
req.URL.Path = svcUrl.Path
Expand Down Expand Up @@ -190,7 +190,7 @@ func (s Server) ServeHTTP(ctx *gin.Context) {

proxy.Director = func(req *http.Request) {
req.Header = ctx.Request.Header
req.Host = svcUrl.Host
req.Host = ctx.Request.Host
req.URL.Scheme = svcUrl.Scheme
req.URL.Host = svcUrl.Host
req.URL.Path = svcUrl.Path
Expand Down
61 changes: 60 additions & 1 deletion pkg/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,59 @@ func TestHealthzRoute(t *testing.T) {
assert.Equal(t, string(bs), "ok")
}

func TestProxyDirectorParams(t *testing.T) {
mockServerPort := freePort()
mockServerAddress := fmt.Sprintf("127.0.0.1:%d", mockServerPort)
testReverseProxyConfig.Port = freePort()
testReverseProxyConfig.TlsPort = freePort()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

ingressExactPathMock := mocks.IngressExactPathTypeMock()
ingressExactPathMock.Spec.Rules[0].HTTP.Paths[0].Backend.Service.Port.Number = int32(mockServerPort)
ingressExactPathMock.Spec.Rules[0].HTTP.Paths[0].Path = "/bar"
ingressExactPathMock.Spec.Rules[0].Host = "www.guardgress.com"
ingressLimiterPathExact := limitHandler.GetIngressLimiter(ingressExactPathMock)

startMockServer(mockServerAddress, ctx)

srv := New(testReverseProxyConfig)

srv.RoutingTable = &router.RoutingTable{
Ingresses: &v1.IngressList{
TypeMeta: v12.TypeMeta{},
ListMeta: v12.ListMeta{},
Items: []v1.Ingress{
ingressExactPathMock,
},
},
TlsCertificates: mocks.TlsCertificatesMock(),
IngressLimiters: []*limiter.Limiter{ingressLimiterPathExact},
}

go func() {
srv.Run(ctx)
}()

waitForServer(ctx, testReverseProxyConfig.Port)

// check if proxy router params are correct
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
req, err := http.NewRequest(
"GET",
fmt.Sprintf("https://%s:%d/bar", testReverseProxyConfig.Host, testReverseProxyConfig.TlsPort),
nil,
)
req.Host = ingressExactPathMock.Spec.Rules[0].Host
assert.NoError(t, err)
res, err := http.DefaultClient.Do(req)
assert.NoError(t, err)
assert.Equal(t, 200, res.StatusCode)
bs, err := io.ReadAll(res.Body)
assert.Equal(t, mockServerResponse, string(bs))
assert.Equal(t, res.Header.Get("X-Requested-With-Host"), ingressExactPathMock.Spec.Rules[0].Host)
}

func startMockServer(addr string, ctx context.Context) *http.Server {
mockSrv := &http.Server{
Addr: addr,
Expand All @@ -704,6 +757,7 @@ func startMockServer(addr string, ctx context.Context) *http.Server {
w.Header().Set(v, r.Header.Get(v))
}
}
w.Header().Set("X-Requested-With-Host", r.Host)
_, _ = io.WriteString(w, mockServerResponse)
}),
}
Expand Down Expand Up @@ -745,7 +799,12 @@ func waitForServer(ctx context.Context, port int) bool {
func freePort() int {
// Listen on a random port
listener, _ := net.Listen("tcp", ":0")
defer listener.Close()
defer func(listener net.Listener) {
err := listener.Close()
if err != nil {
log.Error(err)
}
}(listener)

// Retrieve the address information
address := listener.Addr().(*net.TCPAddr)
Expand Down

0 comments on commit 66cb58f

Please sign in to comment.