Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ run:
tests: true
go: ""
modules-download-mode: "readonly"
skip-cache: true

linters:
disable-all: true
Expand Down
138 changes: 7 additions & 131 deletions tests/integration/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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, ":")
Expand All @@ -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{
Expand Down
144 changes: 4 additions & 140 deletions tests/integration/https_get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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())

Expand All @@ -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{
Expand Down
Loading
Loading