2022-09-02 16:29:50 +00:00
|
|
|
//go:build darwin || linux
|
|
|
|
|
|
|
|
package ingress
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/google/gopacket/layers"
|
|
|
|
"github.com/rs/zerolog"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"golang.org/x/net/icmp"
|
|
|
|
"golang.org/x/net/ipv4"
|
|
|
|
|
|
|
|
"github.com/cloudflare/cloudflared/packet"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestFunnelIdleTimeout(t *testing.T) {
|
|
|
|
const (
|
|
|
|
idleTimeout = time.Second
|
|
|
|
echoID = 42573
|
|
|
|
startSeq = 8129
|
|
|
|
)
|
|
|
|
logger := zerolog.New(os.Stderr)
|
2022-09-20 10:39:51 +00:00
|
|
|
proxy, err := newICMPProxy(localhostIP, "", &logger, idleTimeout)
|
2022-09-02 16:29:50 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
|
|
|
proxyDone := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
proxy.Serve(ctx)
|
|
|
|
close(proxyDone)
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Send a packet to register the flow
|
|
|
|
pk := packet.ICMP{
|
|
|
|
IP: &packet.IP{
|
|
|
|
Src: localhostIP,
|
|
|
|
Dst: localhostIP,
|
|
|
|
Protocol: layers.IPProtocolICMPv4,
|
|
|
|
},
|
|
|
|
Message: &icmp.Message{
|
|
|
|
Type: ipv4.ICMPTypeEcho,
|
|
|
|
Code: 0,
|
|
|
|
Body: &icmp.Echo{
|
|
|
|
ID: echoID,
|
|
|
|
Seq: startSeq,
|
|
|
|
Data: []byte(t.Name()),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2022-10-13 10:01:25 +00:00
|
|
|
muxer := newMockMuxer(0)
|
|
|
|
responder := packetResponder{
|
|
|
|
datagramMuxer: muxer,
|
2022-09-02 16:29:50 +00:00
|
|
|
}
|
2022-10-13 10:01:25 +00:00
|
|
|
require.NoError(t, proxy.Request(ctx, &pk, &responder))
|
2022-10-19 13:37:10 +00:00
|
|
|
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
|
2022-09-02 16:29:50 +00:00
|
|
|
|
|
|
|
// Send second request, should reuse the funnel
|
2022-10-13 10:01:25 +00:00
|
|
|
require.NoError(t, proxy.Request(ctx, &pk, &packetResponder{
|
2022-11-08 23:12:33 +00:00
|
|
|
datagramMuxer: muxer,
|
2022-10-13 10:01:25 +00:00
|
|
|
}))
|
2022-10-19 13:37:10 +00:00
|
|
|
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
|
2022-09-02 16:29:50 +00:00
|
|
|
|
|
|
|
time.Sleep(idleTimeout * 2)
|
2022-10-13 10:01:25 +00:00
|
|
|
newMuxer := newMockMuxer(0)
|
|
|
|
newResponder := packetResponder{
|
|
|
|
datagramMuxer: newMuxer,
|
2022-09-02 16:29:50 +00:00
|
|
|
}
|
2022-10-13 10:01:25 +00:00
|
|
|
require.NoError(t, proxy.Request(ctx, &pk, &newResponder))
|
2022-10-19 13:37:10 +00:00
|
|
|
validateEchoFlow(t, <-newMuxer.cfdToEdge, &pk)
|
2022-09-02 16:29:50 +00:00
|
|
|
|
|
|
|
cancel()
|
|
|
|
<-proxyDone
|
|
|
|
}
|
2022-11-10 17:09:47 +00:00
|
|
|
|
|
|
|
func TestReuseFunnel(t *testing.T) {
|
|
|
|
const (
|
|
|
|
idleTimeout = time.Second
|
|
|
|
echoID = 42573
|
|
|
|
startSeq = 8129
|
|
|
|
)
|
|
|
|
logger := zerolog.New(os.Stderr)
|
|
|
|
proxy, err := newICMPProxy(localhostIP, "", &logger, idleTimeout)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
|
|
|
proxyDone := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
proxy.Serve(ctx)
|
|
|
|
close(proxyDone)
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Send a packet to register the flow
|
|
|
|
pk := packet.ICMP{
|
|
|
|
IP: &packet.IP{
|
|
|
|
Src: localhostIP,
|
|
|
|
Dst: localhostIP,
|
|
|
|
Protocol: layers.IPProtocolICMPv4,
|
|
|
|
},
|
|
|
|
Message: &icmp.Message{
|
|
|
|
Type: ipv4.ICMPTypeEcho,
|
|
|
|
Code: 0,
|
|
|
|
Body: &icmp.Echo{
|
|
|
|
ID: echoID,
|
|
|
|
Seq: startSeq,
|
|
|
|
Data: []byte(t.Name()),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
tuple := flow3Tuple{
|
|
|
|
srcIP: pk.Src,
|
|
|
|
dstIP: pk.Dst,
|
|
|
|
originalEchoID: echoID,
|
|
|
|
}
|
|
|
|
muxer := newMockMuxer(0)
|
|
|
|
responder := packetResponder{
|
|
|
|
datagramMuxer: muxer,
|
|
|
|
}
|
|
|
|
require.NoError(t, proxy.Request(ctx, &pk, &responder))
|
|
|
|
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
|
|
|
|
funnel1, found := getFunnel(t, proxy, tuple)
|
|
|
|
require.True(t, found)
|
|
|
|
|
|
|
|
// Send second request, should reuse the funnel
|
|
|
|
require.NoError(t, proxy.Request(ctx, &pk, &packetResponder{
|
|
|
|
datagramMuxer: muxer,
|
|
|
|
}))
|
|
|
|
validateEchoFlow(t, <-muxer.cfdToEdge, &pk)
|
|
|
|
funnel2, found := getFunnel(t, proxy, tuple)
|
|
|
|
require.True(t, found)
|
|
|
|
require.Equal(t, funnel1, funnel2)
|
|
|
|
|
|
|
|
cancel()
|
|
|
|
<-proxyDone
|
|
|
|
}
|