mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-27 19:59:58 +00:00
TUN-6531: Implement ICMP proxy for Windows using IcmpSendEcho
This commit is contained in:
139
ingress/icmp_windows_test.go
Normal file
139
ingress/icmp_windows_test.go
Normal file
@@ -0,0 +1,139 @@
|
||||
//go:build windows
|
||||
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/net/icmp"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestParseEchoReply tests parsing raw bytes from icmpSendEcho into echoResp
|
||||
func TestParseEchoReply(t *testing.T) {
|
||||
dst, err := inAddrV4(netip.MustParseAddr("192.168.10.20"))
|
||||
require.NoError(t, err)
|
||||
|
||||
validReplyData := []byte(t.Name())
|
||||
validReply := echoReply{
|
||||
Address: dst,
|
||||
Status: success,
|
||||
RoundTripTime: uint32(20),
|
||||
DataSize: uint16(len(validReplyData)),
|
||||
DataPointer: &validReplyData[0],
|
||||
Options: ipOption{
|
||||
TTL: 59,
|
||||
},
|
||||
}
|
||||
|
||||
destHostUnreachableReply := validReply
|
||||
destHostUnreachableReply.Status = destHostUnreachable
|
||||
|
||||
tests := []struct {
|
||||
testCase string
|
||||
replyBuf []byte
|
||||
expectedReply *echoReply
|
||||
expectedData []byte
|
||||
}{
|
||||
{
|
||||
testCase: "empty buffer",
|
||||
},
|
||||
{
|
||||
testCase: "status not success",
|
||||
replyBuf: destHostUnreachableReply.marshal(t, []byte{}),
|
||||
},
|
||||
{
|
||||
testCase: "valid reply",
|
||||
replyBuf: validReply.marshal(t, validReplyData),
|
||||
expectedReply: &validReply,
|
||||
expectedData: validReplyData,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
resp, err := newEchoResp(test.replyBuf)
|
||||
if test.expectedReply == nil {
|
||||
require.Error(t, err)
|
||||
require.Nil(t, resp)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp.reply, test.expectedReply)
|
||||
require.True(t, bytes.Equal(resp.data, test.expectedData))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSendEchoErrors makes sure icmpSendEcho handles error cases
|
||||
func TestSendEchoErrors(t *testing.T) {
|
||||
proxy, err := newICMPProxy(localhostIP, &noopLogger)
|
||||
require.NoError(t, err)
|
||||
winProxy := proxy.(*icmpProxy)
|
||||
|
||||
echo := icmp.Echo{
|
||||
ID: 6193,
|
||||
Seq: 25712,
|
||||
Data: []byte(t.Name()),
|
||||
}
|
||||
documentIP := netip.MustParseAddr("192.0.2.200")
|
||||
resp, err := winProxy.icmpSendEcho(documentIP, &echo)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, resp)
|
||||
}
|
||||
|
||||
func (er *echoReply) marshal(t *testing.T, data []byte) []byte {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
for _, field := range []any{
|
||||
er.Address,
|
||||
er.Status,
|
||||
er.RoundTripTime,
|
||||
er.DataSize,
|
||||
er.Reserved,
|
||||
} {
|
||||
require.NoError(t, binary.Write(buf, endian, field))
|
||||
}
|
||||
|
||||
require.NoError(t, marshalPointer(buf, uintptr(unsafe.Pointer(er.DataPointer))))
|
||||
|
||||
for _, field := range []any{
|
||||
er.Options.TTL,
|
||||
er.Options.Tos,
|
||||
er.Options.Flags,
|
||||
er.Options.OptionsSize,
|
||||
} {
|
||||
require.NoError(t, binary.Write(buf, endian, field))
|
||||
}
|
||||
|
||||
require.NoError(t, marshalPointer(buf, er.Options.OptionsData))
|
||||
|
||||
padSize := buf.Len() % int(unsafe.Alignof(er))
|
||||
padding := make([]byte, padSize)
|
||||
n, err := buf.Write(padding)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, padSize, n)
|
||||
|
||||
n, err = buf.Write(data)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(data), n)
|
||||
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func marshalPointer(buf io.Writer, ptr uintptr) error {
|
||||
size := unsafe.Sizeof(ptr)
|
||||
switch size {
|
||||
case 4:
|
||||
return binary.Write(buf, endian, uint32(ptr))
|
||||
case 8:
|
||||
return binary.Write(buf, endian, uint64(ptr))
|
||||
default:
|
||||
return fmt.Errorf("unexpected pointer size %d", size)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user