Socket
Socket
Sign inDemoInstall

github.com/ooni/netem

Package Overview
Dependencies
15
Alerts
File Explorer

Install Socket

Detect and block malicious and high-risk dependencies

Install

    github.com/ooni/netem

Package netem is a framework to write integration tests that use TCP/IP stacks implemented in userspace. Assuming that your code depends on UnderlyingNetwork (or on its wrapper Net), you can write your tests to create and use Gvisor-based TCP/IP stacks in userspace. To this end, use the NewUNetStack constructor or create it in the context of a specific network topology (explained below). Because UNetStack implements the UnderlyingNetwork model, your code can now use the TCP/IP stack in userspace as opposed to the Go standard library. For normal operations, instead, you can use the [Stdlib] struct. This struct implements UnderlyingNetwork using the Go standard library. So, when your code uses a [Stdlib] as its UnderlyingNetwork, it will use your host network as usual. A UNetStack alone is not attached to any link and so it cannot communicate with any other host. To connect two UNetStack, use NewLink. This factory will create a Link, which implements the following: - delivery of TCP/IP packets between the two UNetStack; - optionally, emulation of packet loss rate, addition of extra round trip time, and presence of DPI rules. You configure the link properties using LinkConfig, which is the structure you pass to NewLink. Rather than using a Link to connect two UNetStack in point-to-point fashion, you can alternatively create a Router. A new Router is not attached to any other host and so is not routing. To attach a UNetStack to a router, create a RouterPort and a Link between such a UNetStack and the RouterPort. Using the Router you can create complex topologies. Because creating topologies manually is error prone, we have two predefined topologies: - the PPPTopology automates creating a Link between two UNetStack instances; - the StarTopology automates creating a Router and links between UNetStack and RouterPort. The UnderlyingNetwork model includes a method to obtain the root X.509 certificate pool to use. When you are using a UNetStack, the root X.509 is constructed such that we are able to automatically produce a certificate for any SNI on the server side as long as the client code uses such a root. This example shows how to use DPI to provoke an EOF when you see an offending string. This is a scenario where a www server modeling www.example.com communicates with itself, therefore, the DPI does not have any effect. This example shows how to use DPI to drop traffic after you see a given string, This example shows how to use DPI to spoof a blockpage for a string This example shows how DNS servers implement whoami.v4.powerdns.org This example shows how to create a star topology, a DNS server, and an HTTPS server. Then we create an HTTPS client and we use such a client to fetch a very important message from the server.


Version published

Readme

Source

Netem

alltests GoDoc Coverage Status Slack

Netem allows writing integration tests in Go where networking code uses Gvisor-based networking. Netem also includes primitives to emulate link latency, losses, and internet censorship (null routing, SNI-based blocking, throttling). Using netem, one can easily simulate complex integration testing scenarios involving difficult or adversarial networks.

Install instructions

We currently support go1.20.

To add netem as a dependency, run:

go get -u -v -d github.com/ooni/netem

This command will download netem and update your go.mod and go.sum.

You probably also want to manually force using the Gvisor version we're using in this library with:

go get -u -v -d gvisor.dev/gvisor@COMMIT_HASH

because Gvisor's default branch is not ready to be used with Go tools and go get would misbehave.

When updating Gvisor in this library, make sure you pin to a commit from the go branch, which is the Gvisor branch supporting go tools.

Running tests

go test .

To enable the race detector, run:

go test -race .

Note: we notice that the race detector would be very slow under macOS and many tests will fail; it still seems to be fine under Linux.

Usage

TODO(bassosimone): this section needs to be updated because we have recently removed the stdlib.go file and functionality, since we have much better functionality inside of ooni/probe-cli.

Existing Go code needs to be adjusted to support netem.

Suppose you have this Go code:

func yourCode(ctx context.Context) error {
	addrs, err := net.DefaultResolver.LookupHost(ctx, "www.example.com")
	// ...
}

You need to convert this code to use netem:

func yourCode(ctx context.Context, nn *netem.Net) error {
	addrs, err := nn.LookupHost(ctx, "www.example.com")
	// ...
}

Normally, you would create a netem.Net like this:

nn := &netem.Net{
	Stack: &netem.Stdlib{},
}

Your code will still work as intended. But, now you have the option to replace the Net underlying stack with an userspace TCP/IP network stack, for writing integration tests.

Let us do that. We start by creating a StarTopology:

topology, err := netem.NewStarTopology(&netem.NullLogger{})
if err != nil { /* ... */ }

defer topology.Close()

Then, we use AddHost to add two userspace network stacks to such a topology:

clientStack, err := netem.AddHost(
	"1.2.3.4",            // stack IPv4 address
	"5.4.3.2",            // resolver IPv4 address
	&netem.LinkConfig{},  // link with no delay, losses, or DPI
)
if err != nil { /* ... */ }

serverStack, err := netem.AddHost(
	"5.4.3.2",            // stack IPv4 address
	"5.4.3.2",            // resolver IPv4 address
	&netem.LinkConfig{},  // link with no delay, losses, or DPI
)
if err != nil { /* ... */ }

We now have the following topology:

graph TD
 client[clientStack<br>1.2.3.4]---router{Router}
 server[serverStack<br>5.4.3.2]---router

Now, we can create a DNSServer on 5.4.3.2 as follows:

dnsCfg := netem.NewDNSConfig()
dnsCfg.AddRecord(
	"www.example.com",
	"",                 // empty CNAME
	"5.6.7.8",
)

dnsServer, err := netem.NewDNSServer(
	&netem.NullLogger{},
	serverStack,
	"5.4.3.2",
	dnsCfg,
)
if err != nil { /* ... */ }

Finally, we create a netem.Net as follows:

nn2 := &netem.Net{
	Stack: clientStack,
}

and we can test yourCode as follows:

func TestYourCode(t *testing.T) {
	// ... create nn2 ...
	err := yourCode(context.Background(), nn2)
	if err != nil {
		t.Fatal(err)
	}
}

This test will test your code using the above network stacks and topology.

FAQs

Last updated on 13 Dec 2023

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc