From 39179cb00efde42651d771bfc2a482b1760a1c91 Mon Sep 17 00:00:00 2001 From: Maxb Date: Tue, 4 Feb 2025 16:25:32 -0800 Subject: [PATCH 1/2] Add end to end UDP integration test This also refactors a bunch of the netstack configuration/setup/initialization into the shared TestMain so that each integration test can contain simply its specific exercise logic --- tests/integration/benchmark_test.go | 138 ++--------------------- tests/integration/https_get_test.go | 144 +----------------------- tests/integration/setup_test.go | 168 +++++++++++++++++++++++++++- tests/integration/udp_test.go | 114 +++++++++++++++++++ 4 files changed, 288 insertions(+), 276 deletions(-) create mode 100644 tests/integration/udp_test.go diff --git a/tests/integration/benchmark_test.go b/tests/integration/benchmark_test.go index 515afc7..7f50ea8 100644 --- a/tests/integration/benchmark_test.go +++ b/tests/integration/benchmark_test.go @@ -15,34 +15,29 @@ import ( "testing" "time" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" "github.com/invisv-privacy/pseudotcp" "github.com/stretchr/testify/require" - "gvisor.dev/gvisor/pkg/buffer" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" - "gvisor.dev/gvisor/pkg/tcpip/link/channel" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" - "gvisor.dev/gvisor/pkg/tcpip/stack" - "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" - "gvisor.dev/gvisor/pkg/tcpip/transport/udp" ) var sizes = []int{10000, 100000, 1000000, 10000000, 100000000} func BenchmarkThroughput(b *testing.B) { + // Disable debug logging (which is setup in TestMain) + // because output is too verbose level := slog.LevelInfo logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ Level: level, })) slog.SetDefault(logger) - chanBufferLength := 1000 + // Set verbose to false + err := pseudotcp.Init(sendPacket, false, containerIP, "8444") + require.NoError(b, err, "pseudotcp.Init") - // We need 2 channels, one where we can put packets coming from pseudotcp destined for our netstack and the other in the opposite direction - var pseudoToNetstackChan = make(chan []byte, chanBufferLength) - var netstackToPseudoChan = make(chan []byte, chanBufferLength) + defer pseudotcp.Shutdown() // Start target HTTP/S server that replies with a payload determined by "?size" url query ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -73,125 +68,6 @@ func BenchmarkThroughput(b *testing.B) { logger.Debug("Test server listening", "ts", ts, "dockerHostURL", dockerHostURL) - // Create the network Stack - endpointIP := tcpip.AddrFrom4([4]byte{10, 0, 0, 2}) - gatewayIP := tcpip.AddrFrom4([4]byte{10, 0, 0, 1}) - - var nicID tcpip.NICID = 1 - s := stack.New(stack.Options{ - NetworkProtocols: []stack.NetworkProtocolFactory{ - ipv4.NewProtocol, - }, - TransportProtocols: []stack.TransportProtocolFactory{ - tcp.NewProtocol, - udp.NewProtocol, - }, - }) - defer s.Close() - - // Create the network interface - linkEP := channel.New(128, 1024, "") - defer linkEP.Close() - - tcpErr := s.CreateNIC(nicID, linkEP) - require.Empty(b, tcpErr, "CreateNIC") - - // Read from the netstack link and send appropriate packets to pseudotcp - go func() { - for { - pkt := linkEP.ReadContext(context.Background()) - if pkt == nil { - break - } else if pkt.PktType == tcpip.PacketOutgoing { - b := pkt.ToBuffer() - pkt.DecRef() - - buf := make([]byte, b.Size()) - _, _ = b.ReadAt(buf, 0) - - packet := gopacket.NewPacket(buf[:], layers.LayerTypeIPv4, gopacket.Default) - - logger.Debug("Sending to pseudotcp", "packet", packet) - - netstackToPseudoChan <- buf - } - } - }() - - // Start a goroutine which reads from the pseudoToNetstackChan and injects those packets into netstack - go func() { - for { - buf := <-pseudoToNetstackChan - // ctxLogger.Debug("From pseudoToNetstackChan", "buf", buf) - pktBufferPayload := buffer.MakeWithData(buf) - pktBufferOptions := stack.PacketBufferOptions{ - Payload: pktBufferPayload, - } - pktBuffer := stack.NewPacketBuffer(pktBufferOptions) - - linkEP.InjectInbound(ipv4.ProtocolNumber, pktBuffer) - } - }() - - // Start a goroutine which reads from the netstackToPseudoChan and sends those packets to the pseudotcp stack - go func() { - for { - buf := <-netstackToPseudoChan - pseudotcp.Send(buf) - } - }() - - // Attach an address to the network interface - tcpErr = s.AddProtocolAddress(nicID, tcpip.ProtocolAddress{ - Protocol: ipv4.ProtocolNumber, - AddressWithPrefix: endpointIP.WithPrefix(), - }, stack.AddressProperties{}) - require.Empty(b, tcpErr, "AddProtocolAddress") - - s.SetSpoofing(1, true) - s.SetPromiscuousMode(1, true) - s.SetForwardingDefaultAndAllNICs(ipv4.ProtocolNumber, true) - - subnet, err := tcpip.NewSubnet(tcpip.AddrFromSlice([]byte("\x00\x00\x00\x00")), tcpip.MaskFrom("\x00\x00\x00\x00")) - r := tcpip.Route{ - Destination: subnet, - Gateway: gatewayIP, - NIC: nicID, - } - require.NoError(b, err, "NewSubnet") - s.AddRoute(r) - - logger.Debug("Route table", "GetRouteTable", s.GetRouteTable()) - nicAddress, tcpErr := s.GetMainNICAddress(nicID, ipv4.ProtocolNumber) - require.Empty(b, tcpErr, "GetMainNICAddress") - logger.Debug("NICAddress", "GetMainNICAddress", nicAddress) - - protectConnection := pseudotcp.SocketProtector(func(fd int) error { - logger.Debug("Protecting", "fd", fd) - return nil - }) - - pseudotcp.ConfigureProtect(protectConnection) - - sendPacket := func(packet []byte, length int) error { - ctxLogger := logger.With("context", "in sendPacket sending to pseudoToNetstackChan") - p := gopacket.NewPacket(packet[:], layers.LayerTypeIPv4, gopacket.Default) - ctxLogger.Debug("Sending to netstack", "p", p) - - sendPacketBuf := make([]byte, len(packet)) - copy(sendPacketBuf, packet) - pseudoToNetstackChan <- sendPacketBuf - return nil - } - - // Our test sends to a non-publicly route-able IP - pseudotcp.ProhibitDisallowedIPPorts = false - - err = pseudotcp.Init(sendPacket, false, containerIP, "8444") - require.NoError(b, err, "Init") - - defer pseudotcp.Shutdown() - dialWrapper := func(ctx context.Context, network, addr string) (net.Conn, error) { logger.Debug("dialing", "addr", addr) split := strings.Split(addr, ":") @@ -203,7 +79,7 @@ func BenchmarkThroughput(b *testing.B) { require.NoError(b, err, "LookupIP") require.NotEmpty(b, ips, "LookupIP not Empty") - return gonet.DialTCPWithBind(context.Background(), s, tcpip.FullAddress{ + return gonet.DialTCPWithBind(context.Background(), netstack, tcpip.FullAddress{ NIC: nicID, Addr: tcpip.AddrFrom4(endpointIP.As4()), }, tcpip.FullAddress{ diff --git a/tests/integration/https_get_test.go b/tests/integration/https_get_test.go index db59e48..132b8dc 100644 --- a/tests/integration/https_get_test.go +++ b/tests/integration/https_get_test.go @@ -15,28 +15,20 @@ import ( "time" "golang.org/x/net/http2" - "gvisor.dev/gvisor/pkg/buffer" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" - "gvisor.dev/gvisor/pkg/tcpip/link/channel" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" - "gvisor.dev/gvisor/pkg/tcpip/stack" - "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" - "gvisor.dev/gvisor/pkg/tcpip/transport/udp" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" "github.com/invisv-privacy/pseudotcp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestHTTPSGet(t *testing.T) { - chanBufferLength := 1000 + err := pseudotcp.Init(sendPacket, true, containerIP, "8444") + require.NoError(t, err, "pseudotcp.Init") - // We need 2 channels, one where we can put packets coming from pseudotcp destined for our netstack and the other in the opposite direction - var pseudoToNetstackChan = make(chan []byte, chanBufferLength) - var netstackToPseudoChan = make(chan []byte, chanBufferLength) + defer pseudotcp.Shutdown() // Start target HTTP/S server expectedResponse := "test http response data" @@ -66,134 +58,6 @@ func TestHTTPSGet(t *testing.T) { port := urlSplit[len(urlSplit)-1] dockerHostURL := fmt.Sprintf("https://%v:%v", containerGateway, port) - - // Create the network Stack - endpointIP := tcpip.AddrFrom4([4]byte{10, 0, 0, 2}) - gatewayIP := tcpip.AddrFrom4([4]byte{10, 0, 0, 1}) - var nicID tcpip.NICID = 1 - s := stack.New(stack.Options{ - NetworkProtocols: []stack.NetworkProtocolFactory{ - ipv4.NewProtocol, - }, - TransportProtocols: []stack.TransportProtocolFactory{ - tcp.NewProtocol, - udp.NewProtocol, - }, - }) - defer s.Close() - - // Create the network interface - linkEP := channel.New(128, 1024, "") - defer linkEP.Close() - - tcpErr := s.CreateNIC(nicID, linkEP) - require.Empty(t, tcpErr, "CreateNIC") - - // Read from the netstack link and send appropriate packets to pseudotcp - go func() { - ctxLogger := logger.With("context", "Reading from linkEP and sending to netstackToPseudoChan") - for { - pkt := linkEP.ReadContext(context.Background()) - ctxLogger.Debug("Read Packet from linkEP", "pkt", pkt) - if pkt == nil { - break - } else if pkt.PktType == tcpip.PacketOutgoing { - b := pkt.ToBuffer() - pkt.DecRef() - - buf := make([]byte, b.Size()) - _, err := b.ReadAt(buf, 0) - - // EOF is the only acceptable "error" here - if err != nil { - require.ErrorIs(t, err, io.EOF) - } - - packet := gopacket.NewPacket(buf[:], layers.LayerTypeIPv4, gopacket.Default) - - ctxLogger.Debug("Sending to netstackToPseudoChan", "packet", packet) - - netstackToPseudoChan <- buf - } - } - }() - - // Start a goroutine which reads from the pseudoToNetstackChan and injects those packets into netstack - go func() { - ctxLogger := logger.With("context", "reading from pseudoToNetstackChan and writing to linkEP") - for { - buf := <-pseudoToNetstackChan - ctxLogger.Debug("From pseudoToNetstackChan", "buf", buf) - pktBufferPayload := buffer.MakeWithData(buf) - pktBufferOptions := stack.PacketBufferOptions{ - Payload: pktBufferPayload, - } - pktBuffer := stack.NewPacketBuffer(pktBufferOptions) - - ctxLogger.Debug("Writing packet to linkEP", "pktBuffer", pktBuffer) - linkEP.InjectInbound(ipv4.ProtocolNumber, pktBuffer) - } - }() - - // Start a goroutine which reads from the netstackToPseudoChan and sends those packets to the pseudotcp stack - go func() { - for { - buf := <-netstackToPseudoChan - pseudotcp.Send(buf) - } - }() - - // Attach an address to the network interface - tcpErr = s.AddProtocolAddress(nicID, tcpip.ProtocolAddress{ - Protocol: ipv4.ProtocolNumber, - AddressWithPrefix: endpointIP.WithPrefix(), - }, stack.AddressProperties{}) - require.Empty(t, tcpErr, "AddProtocolAddress") - - s.SetSpoofing(1, true) - s.SetPromiscuousMode(1, true) - s.SetForwardingDefaultAndAllNICs(ipv4.ProtocolNumber, true) - - subnet, err := tcpip.NewSubnet(tcpip.AddrFromSlice([]byte("\x00\x00\x00\x00")), tcpip.MaskFrom("\x00\x00\x00\x00")) - r := tcpip.Route{ - Destination: subnet, - Gateway: gatewayIP, - NIC: nicID, - } - require.NoError(t, err, "NewSubnet") - s.AddRoute(r) - - logger.Debug("Route table", "GetRouteTable", s.GetRouteTable()) - nicAddress, tcpErr := s.GetMainNICAddress(nicID, ipv4.ProtocolNumber) - require.Empty(t, tcpErr, "GetMainNICAddress") - logger.Debug("NICAddress", "GetMainNICAddress", nicAddress) - - protectConnection := pseudotcp.SocketProtector(func(fd int) error { - logger.Debug("Protecting", "fd", fd) - return nil - }) - - pseudotcp.ConfigureProtect(protectConnection) - - sendPacket := func(packet []byte, length int) error { - ctxLogger := logger.With("context", "in sendPacket sending to pseudoToNetstackChan") - p := gopacket.NewPacket(packet[:], layers.LayerTypeIPv4, gopacket.Default) - ctxLogger.Debug("Sending to netstack", "p", p) - - sendPacketBuf := make([]byte, len(packet)) - copy(sendPacketBuf, packet) - pseudoToNetstackChan <- sendPacketBuf - return nil - } - - // Our test sends to a non-publicly route-able IP - pseudotcp.ProhibitDisallowedIPPorts = false - - err = pseudotcp.Init(sendPacket, true, containerIP, "8444") - require.NoError(t, err, "Init") - - defer pseudotcp.Shutdown() - certpool := x509.NewCertPool() certpool.AddCert(ts.Certificate()) @@ -215,7 +79,7 @@ func TestHTTPSGet(t *testing.T) { require.NoError(t, err, "LookupIP") require.NotEmpty(t, ips, "LookupIP not Empty") - tcpConn, err := gonet.DialTCPWithBind(context.Background(), s, tcpip.FullAddress{ + tcpConn, err := gonet.DialTCPWithBind(context.Background(), netstack, tcpip.FullAddress{ NIC: nicID, Addr: tcpip.AddrFrom4(endpointIP.As4()), }, tcpip.FullAddress{ diff --git a/tests/integration/setup_test.go b/tests/integration/setup_test.go index 2b6641b..d42bcd5 100644 --- a/tests/integration/setup_test.go +++ b/tests/integration/setup_test.go @@ -2,7 +2,9 @@ package integration import ( "context" + "errors" "fmt" + "io" "log" "log/slog" "os" @@ -10,19 +12,36 @@ import ( "testing" "time" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "github.com/invisv-privacy/pseudotcp" "github.com/invisv-privacy/pseudotcp/internal/testutils" + "gvisor.dev/gvisor/pkg/buffer" + "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/link/channel" + "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" + "gvisor.dev/gvisor/pkg/tcpip/stack" + "gvisor.dev/gvisor/pkg/tcpip/transport/tcp" + "gvisor.dev/gvisor/pkg/tcpip/transport/udp" tc "github.com/testcontainers/testcontainers-go/modules/compose" "github.com/testcontainers/testcontainers-go/wait" ) +var netstack *stack.Stack +var endpointIP tcpip.Address + const h2oServiceName string = "h2o" +var sendPacket func(packet []byte, length int) error + var containerGateway string var containerIP string var logger *slog.Logger +var nicID tcpip.NICID = 1 + func TestMain(m *testing.M) { level := slog.LevelDebug logger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ @@ -51,7 +70,7 @@ func TestMain(m *testing.M) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - stack := compose.WaitForService(h2oServiceName, + composeStack := compose.WaitForService(h2oServiceName, // The h2o conf provides a /status endpoint listening on // non-TLS port 8081 wait. @@ -60,16 +79,16 @@ func TestMain(m *testing.M) { WithStartupTimeout(10*time.Second), ) - if err := stack.Up(ctx, tc.Wait(true)); err != nil { + if err := composeStack.Up(ctx, tc.Wait(true)); err != nil { log.Fatalf("error in compose.Up(): %v", err) } - container, err := stack.ServiceContainer(ctx, h2oServiceName) + container, err := composeStack.ServiceContainer(ctx, h2oServiceName) if err != nil { - log.Fatalf("error in stack.ServiceContainer: %v", err) + log.Fatalf("error in composeStack.ServiceContainer: %v", err) } - logger.Info("compose up", "services", stack.Services(), "container", container) + logger.Info("compose up", "services", composeStack.Services(), "container", container) // Kind of awkward network info parsing here. // We need the container's gateway IP because that _should_ be the address the host can ListenUDP on where the container can access it. @@ -84,5 +103,144 @@ func TestMain(m *testing.M) { containerGateway = fmt.Sprintf("%v.1", containerNet) + chanBufferLength := 1000 + + // We need 2 channels, one where we can put packets coming from pseudotcp destined for our netstack and the other in the opposite direction + var pseudoToNetstackChan = make(chan []byte, chanBufferLength) + var netstackToPseudoChan = make(chan []byte, chanBufferLength) + + // Create the network Stack + endpointIP = tcpip.AddrFrom4([4]byte{10, 0, 0, 2}) + gatewayIP := tcpip.AddrFrom4([4]byte{10, 0, 0, 1}) + netstack = stack.New(stack.Options{ + NetworkProtocols: []stack.NetworkProtocolFactory{ + ipv4.NewProtocol, + }, + TransportProtocols: []stack.TransportProtocolFactory{ + tcp.NewProtocol, + udp.NewProtocol, + }, + }) + defer netstack.Close() + + // Create the network interface + linkEP := channel.New(128, 1024, "") + defer linkEP.Close() + + tcpErr := netstack.CreateNIC(nicID, linkEP) + if tcpErr != nil { + log.Fatalf("failed to createNIC: %v", tcpErr) + } + + tcpErr = netstack.SetNICMTU(nicID, pseudotcp.TUN_MTU) + if tcpErr != nil { + log.Fatalf("failed to SetNICMTU: %v", tcpErr) + } + + // Read from the netstack link and send appropriate packets to pseudotcp + go func() { + for { + pkt := linkEP.ReadContext(context.Background()) + logger.Debug("Read Packet from linkEP", "pkt", pkt) + if pkt == nil { + break + } else if pkt.PktType == tcpip.PacketOutgoing { + b := pkt.ToBuffer() + pkt.DecRef() + + buf := make([]byte, b.Size()) + _, err := b.ReadAt(buf, 0) + + // EOF is the only acceptable "error" here + if err != nil { + if !errors.Is(err, io.EOF) { + log.Fatalf("recieved non-EOF error: %v", err) + } + } + + packet := gopacket.NewPacket(buf[:], layers.LayerTypeIPv4, gopacket.Default) + + logger.Debug("Sending to netstackToPseudoChan", "packet", packet) + + netstackToPseudoChan <- buf + } + } + }() + + // Start a goroutine which reads from the pseudoToNetstackChan and injects those packets into netstack + go func() { + for { + buf := <-pseudoToNetstackChan + logger.Debug("From pseudoToNetstackChan", "buf", buf) + pktBufferPayload := buffer.MakeWithData(buf) + pktBufferOptions := stack.PacketBufferOptions{ + Payload: pktBufferPayload, + } + pktBuffer := stack.NewPacketBuffer(pktBufferOptions) + + logger.Debug("Writing packet to linkEP", "pktBuffer", pktBuffer) + linkEP.InjectInbound(ipv4.ProtocolNumber, pktBuffer) + } + }() + + // Start a goroutine which reads from the netstackToPseudoChan and sends those packets to the pseudotcp stack + go func() { + for { + buf := <-netstackToPseudoChan + pseudotcp.Send(buf) + } + }() + + // Attach an address to the network interface + tcpErr = netstack.AddProtocolAddress(nicID, tcpip.ProtocolAddress{ + Protocol: ipv4.ProtocolNumber, + AddressWithPrefix: endpointIP.WithPrefix(), + }, stack.AddressProperties{}) + if tcpErr != nil { + log.Fatalf("failed to AddProtocolAddress: %v", tcpErr) + } + + netstack.SetSpoofing(1, true) + netstack.SetPromiscuousMode(1, true) + netstack.SetForwardingDefaultAndAllNICs(ipv4.ProtocolNumber, true) + + subnet, err := tcpip.NewSubnet(tcpip.AddrFromSlice([]byte("\x00\x00\x00\x00")), tcpip.MaskFrom("\x00\x00\x00\x00")) + r := tcpip.Route{ + Destination: subnet, + Gateway: gatewayIP, + NIC: nicID, + } + if err != nil { + log.Fatalf("failed to create NewSubnet: %v", err) + } + + netstack.AddRoute(r) + + logger.Debug("Route table", "GetRouteTable", netstack.GetRouteTable()) + nicAddress, tcpErr := netstack.GetMainNICAddress(nicID, ipv4.ProtocolNumber) + if tcpErr != nil { + log.Fatalf("failed to GetMainNICAddress: %v", tcpErr) + } + logger.Debug("NICAddress", "GetMainNICAddress", nicAddress) + + protectConnection := pseudotcp.SocketProtector(func(fd int) error { + logger.Debug("Protecting", "fd", fd) + return nil + }) + + pseudotcp.ConfigureProtect(protectConnection) + + sendPacket = func(packet []byte, length int) error { + p := gopacket.NewPacket(packet[:], layers.LayerTypeIPv4, gopacket.Default) + logger.Debug("Sending to netstack", "p", p) + + sendPacketBuf := make([]byte, len(packet)) + copy(sendPacketBuf, packet) + pseudoToNetstackChan <- sendPacketBuf + return nil + } + + // Our test sends to a non-publicly route-able IP + pseudotcp.ProhibitDisallowedIPPorts = false m.Run() } diff --git a/tests/integration/udp_test.go b/tests/integration/udp_test.go new file mode 100644 index 0000000..f2781bb --- /dev/null +++ b/tests/integration/udp_test.go @@ -0,0 +1,114 @@ +package integration + +import ( + "crypto/rand" + "errors" + "io" + "net" + "testing" + + "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" + "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" + + "github.com/invisv-privacy/pseudotcp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestUDP(t *testing.T) { + err := pseudotcp.Init(sendPacket, true, containerIP, "8444") + require.NoError(t, err, "pseudotcp.Init") + + defer pseudotcp.Shutdown() + + sendBufferSize := pseudotcp.TUN_MTU - 150 + receiveBufferSize := pseudotcp.INTERNET_MTU - 150 + expectedRequest := make([]byte, sendBufferSize) + _, err = rand.Read(expectedRequest) + require.NoError(t, err, "rand.Read") + expectedReply := make([]byte, receiveBufferSize) + _, err = rand.Read(expectedReply) + require.NoError(t, err, "rand.Read") + + // We want to listen on 0.0.0.0 because the proxy container will be on a different non-localhost network. + // In order to do that we have this kind of awkward hack borrowed from: + // https://stackoverflow.com/a/42218765/1787596 + addr, err := net.ResolveUDPAddr("udp", "0.0.0.0:0") + require.NoError(t, err, "ResolveUDPAddr") + + // Create UDP connection + udpListenConn, err := net.ListenUDP("udp", addr) + require.NoError(t, err, "ListenUDP") + defer func() { + err := udpListenConn.Close() + require.NoError(t, err, "conn.Close") + }() + + localAddr := udpListenConn.LocalAddr().(*net.UDPAddr) + logger.Debug("UDP Server listening", "localAddr", localAddr) + + go func() { + + var remoteAddr *net.UDPAddr + buffer := make([]byte, sendBufferSize) + readLength := 0 + for { + n := 0 + // Read incoming data + n, remoteAddr, err = udpListenConn.ReadFromUDP(buffer[readLength:]) + + logger.Debug("ReadFromUDP", "remoteAddr", remoteAddr, "n", n, "err", err) + + readLength += n + if readLength >= sendBufferSize || errors.Is(err, io.EOF) { + break + } + require.NoError(t, err, "ReadFromUDP") + } + + logger.Debug("Received message", "remoteAddr", remoteAddr, "readLength", readLength) + assert.Equal(t, expectedRequest, buffer[:readLength]) + + // Send response back to client + n, err := udpListenConn.WriteToUDP(expectedReply, remoteAddr) + logger.Debug("udpListenConn.WriteToUDP", "n", n, "err", err) + require.NoError(t, err, "WriteToUDP") + }() + + containerGatewayIP := net.ParseIP(containerGateway) + var udpServerIPBytes [4]byte + copy(udpServerIPBytes[:], containerGatewayIP.To4()) + + logger.Debug("dialing UDP", "containerGatewayIP", containerGatewayIP, "udpServerIPBytes", udpServerIPBytes, "port", localAddr.Port) + + udpClientConn, err := gonet.DialUDP(netstack, &tcpip.FullAddress{ + NIC: nicID, + Addr: tcpip.AddrFrom4(endpointIP.As4()), + }, &tcpip.FullAddress{ + Addr: tcpip.AddrFrom4(udpServerIPBytes), + Port: uint16(localAddr.Port), + }, ipv4.ProtocolNumber) + + require.NoError(t, err, "gonet.DialUDP") + defer func() { + err := udpClientConn.Close() + require.NoError(t, err, "conn.Close") + }() + + n, err := udpClientConn.Write(expectedRequest) + logger.Debug("udpClientConn.Write", "n", n, "err", err) + require.NoError(t, err, "udpClientConn.Write") + + readBuffer := make([]byte, receiveBufferSize) + + n, err = udpClientConn.Read(readBuffer) + + logger.Debug("udpClientConn.Read", "n", n, "err", err) + + require.NoError(t, err, "udpClientConn.Read") + + logger.Debug("received message from udpClientConn.Read", "n", n, "err", err) + + assert.Equal(t, expectedReply, readBuffer[:n]) +} From 7a3cbfccab1a1e297aacabe3398352d3ed58f690 Mon Sep 17 00:00:00 2001 From: Maxb Date: Thu, 20 Feb 2025 13:06:16 -0700 Subject: [PATCH 2/2] Fix golangci-lint config --- .golangci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 8ecf48e..13b8ea9 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -2,7 +2,6 @@ run: tests: true go: "" modules-download-mode: "readonly" - skip-cache: true linters: disable-all: true