Documentation
¶
Overview ¶
Package netsim provides a simple network simulation framework that developers can use to write integration tests.
Usage and Features ¶
The NewStack function creates a new, simulated network stack using a given IP address. You can invoke usual functions on the stack, such as:
- DialContext - Listen - ListenPacket
These functions return simulated net.Conn, net.Listener, and net.PacketConn respectively.
When a connection sends data, the data is wrapped inside a [*Packet] emitted on the channel returned by [*Stack.Output]. The *Link type allows connecting two *Stack such that they can send [*Packet] to each other. To send a [*Packet] to a *Stack, you need to post the packet on the channel returned by [*Stack.Input]. You don't need to use a *Link as long as you correctly forward packets. In fact, for simulating complex censorship scenarios, you probably want to write custom code to forward or drop [*Packet]. In the future, there will be subpackages of netsim providing this functionality.
Subpackages of this package contain extensions. For example, the netsim/simpki package code helps to simulate a PKI.
The implementation of net.Conn, net.Listener, and net.PacketConn are [*TCPConn], [*UDPConn], and [*UDPListener]. These types, which can also be created manually, are tiny wrappers around [*Port], which contains most of the common implementation code. These types are public to enable writing more complex tests (e.g., the sending of unexpected TCP flags).
The errors returned by these types are the same syscall.Errno the standard library and the kernel would generate in similar cases (we use the x/sys repository to pull system-dependent error values).
This package contains comprehensive examples showing how to use it.
Design Documents ¶
This package is experimental and has no design documents for now.
Example (BlockpageTransparentProxy) ¶
This example shows how to use netsim to simulate transparent proxying of HTTP requests to serve blockpages.
package main import ( "fmt" "io" "log" "net/http" "net/netip" "github.com/rbmk-project/x/netsim" "github.com/rbmk-project/x/netsim/censor" ) func main() { // Create scenario scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create blockpage server blockpage := scenario.MustNewBlockpageStack() scenario.Attach(blockpage) // Create target website scenario.Attach(scenario.MustNewExampleComStack()) // Configure DNAT to send blocked traffic to blockpage server scenario.Router().AddFilter(censor.NewDNatter( netip.MustParseAddr("193.206.158.22"), // source addr netip.MustParseAddrPort("93.184.216.34:80"), // target dest epnt netip.MustParseAddrPort("10.10.34.35:80"), // repl dest epnt )) // Create client stack clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create the HTTP client clientTxp := scenario.NewHTTPTransport(clientStack) defer clientTxp.CloseIdleConnections() clientHTTP := &http.Client{Transport: clientTxp} // Get the response body. resp, err := clientHTTP.Get("http://93.184.216.34/") if err != nil { log.Fatal(err) } if resp.StatusCode != http.StatusForbidden { log.Fatalf("HTTP request failed: %d", resp.StatusCode) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } // Print the response body fmt.Printf("%s", string(body)) }
Output: Access to this website has been blocked by network policy.
Example (CensorDNS) ¶
This example shows how to use netsim to simulate GFW-style DNS censorship, where poisoned responses are injected before the legitimate response arrives. The example demonstrates:
1. how to configure DNS poisoning using a database 2. how to collect multiple DNS responses using dnscore 3. the expected order of responses (poisoned then legitimate)
This example DOES NOT show how to validate responses using [dnscore] since that is outside its specific scope.
package main import ( "context" "fmt" "log" "time" "github.com/miekg/dns" "github.com/rbmk-project/dnscore" "github.com/rbmk-project/x/netsim" "github.com/rbmk-project/x/netsim/censor" netsimdns "github.com/rbmk-project/x/netsim/dns" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google (8.8.8.8). // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewGoogleDNSStack()) // Configure DNS poisoning happening on the scenario router // thus modeling the typical behaviour of the GFW. censorDB := netsimdns.NewDatabase() censorDB.AddAddresses([]string{"dns.google"}, []string{"10.0.0.1"}) scenario.Router().AddFilter(censor.NewDNSPoisoner(censorDB)) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create a context with a watchdog timeout. // // In real measurements this would typically be controlled by // --wait-duplicates or natural timing of other operations like // TCP/TLS handshakes and fetching related web pages. ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() // Create DNS query for dns.google A record query, err := dnscore.NewQuery("dns.google.", dns.TypeA) if err != nil { log.Fatal(err) } // Configure transport to use our simulated network txp := &dnscore.Transport{} txp.DialContext = clientStack.DialContext // Query 8.8.8.8 over UDP and collect responses serverAddr := &dnscore.ServerAddr{ Protocol: dnscore.ProtocolUDP, Address: "8.8.8.8:53", } results := txp.QueryWithDuplicates(ctx, serverAddr, query) // Print responses as they arrive. // // We expect: // // 1. poisoned response (10.0.0.1) from router // // 2. legitimate response (8.8.8.8) from server // // After two responses, we cancel the context. In production, // we will stop after a timeout or perform other operations and // then check whether there are more addresses to measure. var count int for result := range results { if err := result.Err; err != nil { // Errors here typically are caused by us closing // the connection and, anyway, for this test we only // care about seeing the duplicate responses. break } for _, ans := range result.Msg.Answer { if a, ok := ans.(*dns.A); ok { fmt.Printf("%s\n", a.A.String()) } } count++ if count >= 2 { cancel() } } }
Output: 10.0.0.1 8.8.8.8
Example (DnsOverHTTPS) ¶
This example shows how to use netsim to simulate a DNS server that listens for incoming requests over HTTPS.
package main import ( "context" "crypto/tls" "fmt" "log" "net/http" "time" "github.com/miekg/dns" "github.com/rbmk-project/dnscore" "github.com/rbmk-project/x/netsim" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google. // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewGoogleDNSStack()) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create a context with a watchdog timeout. ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() // Create the dnscore transport and the server address txp := &dnscore.Transport{ HTTPClient: &http.Client{ Transport: &http.Transport{ DialContext: clientStack.DialContext, TLSClientConfig: &tls.Config{ RootCAs: scenario.RootCAs(), ServerName: "dns.google", }, }, }, } serverAddr := dnscore.NewServerAddr( dnscore.ProtocolDoH, "https://8.8.8.8/dns-query") // Create the query to send query, err := dnscore.NewQuery("dns.google", dns.TypeA) if err != nil { log.Fatal(err) } // Perform the DNS round trip resp, err := txp.Query(ctx, serverAddr, query) if err != nil { log.Fatal(err) } // Print the responses for _, ans := range resp.Answer { if a, ok := ans.(*dns.A); ok { fmt.Printf("%s\n", a.A.String()) } } }
Output: 8.8.8.8
Example (DnsOverTCP) ¶
This example shows how to use netsim to simulate a DNS server that listens for incoming requests over TCP.
package main import ( "context" "fmt" "log" "time" "github.com/miekg/dns" "github.com/rbmk-project/x/netsim" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google. // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewGoogleDNSStack()) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create a context with a watchdog timeout. ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() // Create the client connection with the DNS server. conn, err := clientStack.DialContext(ctx, "tcp", "8.8.8.8:53") if err != nil { log.Fatal(err) } defer conn.Close() // Create the query to send query := new(dns.Msg) query.Id = dns.Id() query.RecursionDesired = true query.Question = []dns.Question{{ Name: "dns.google.", Qtype: dns.TypeA, Qclass: dns.ClassINET, }} // Perform the DNS round trip clientDNS := &dns.Client{Net: "tcp"} resp, _, err := clientDNS.ExchangeWithConnContext(ctx, query, &dns.Conn{Conn: conn}) if err != nil { log.Fatal(err) } // Print the responses for _, ans := range resp.Answer { if a, ok := ans.(*dns.A); ok { fmt.Printf("%s\n", a.A.String()) } } }
Output: 8.8.8.8
Example (DnsOverTLS) ¶
This example shows how to use netsim to simulate a DNS server that listens for incoming requests over TLS.
package main import ( "context" "crypto/tls" "fmt" "log" "time" "github.com/miekg/dns" "github.com/rbmk-project/x/netsim" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google. // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewGoogleDNSStack()) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create a context with a watchdog timeout. ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() // Create the client connection with the DNS server. conn, err := clientStack.DialContext(ctx, "tcp", "8.8.8.8:853") if err != nil { log.Fatal(err) } defer conn.Close() tconn := tls.Client(conn, &tls.Config{ RootCAs: scenario.RootCAs(), NextProtos: []string{"dot"}, ServerName: "dns.google", }) defer tconn.Close() if err := tconn.HandshakeContext(ctx); err != nil { log.Fatal(err) } // Create the query to send query := new(dns.Msg) query.Id = dns.Id() query.RecursionDesired = true query.Question = []dns.Question{{ Name: "dns.google.", Qtype: dns.TypeA, Qclass: dns.ClassINET, }} // Perform the DNS round trip clientDNS := &dns.Client{Net: "tcp-tls"} resp, _, err := clientDNS.ExchangeWithConnContext(ctx, query, &dns.Conn{Conn: tconn}) if err != nil { log.Fatal(err) } // Print the responses for _, ans := range resp.Answer { if a, ok := ans.(*dns.A); ok { fmt.Printf("%s\n", a.A.String()) } } }
Output: 8.8.8.8
Example (DnsOverUDP) ¶
This example shows how to use netsim to simulate a DNS server that listens for incoming requests over UDP.
package main import ( "context" "fmt" "log" "time" "github.com/miekg/dns" "github.com/rbmk-project/x/netsim" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google. // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewGoogleDNSStack()) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create a context with a watchdog timeout. ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() // Create the client connection with the DNS server. conn, err := clientStack.DialContext(ctx, "udp", "8.8.8.8:53") if err != nil { log.Fatal(err) } defer conn.Close() // Create the query to send query := new(dns.Msg) query.Id = dns.Id() query.RecursionDesired = true query.Question = []dns.Question{{ Name: "dns.google.", Qtype: dns.TypeA, Qclass: dns.ClassINET, }} // Perform the DNS round trip clientDNS := &dns.Client{} resp, _, err := clientDNS.ExchangeWithConnContext(ctx, query, &dns.Conn{Conn: conn}) if err != nil { log.Fatal(err) } // Print the responses for _, ans := range resp.Answer { if a, ok := ans.(*dns.A); ok { fmt.Printf("%s\n", a.A.String()) } } }
Output: 8.8.8.8
Example (Http) ¶
This example shows how to use netsim to simulate an HTTP server that listens for incoming cleartext requests.
package main import ( "fmt" "io" "log" "net/http" "github.com/rbmk-project/x/netsim" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating www.example.com. // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewExampleComStack()) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create the HTTP client clientTxp := scenario.NewHTTPTransport(clientStack) defer clientTxp.CloseIdleConnections() clientHTTP := &http.Client{Transport: clientTxp} // Get the response body. resp, err := clientHTTP.Get("http://93.184.216.34/") if err != nil { log.Fatal(err) } if resp.StatusCode != http.StatusOK { log.Fatalf("HTTP request failed: %d", resp.StatusCode) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } // Print the response body fmt.Printf("%s", string(body)) }
Output: Example Web Server.
Example (Https) ¶
This example shows how to use netsim to simulate an HTTPS server that listens for incoming encrypted requests.
package main import ( "fmt" "io" "log" "net/http" "github.com/rbmk-project/x/netsim" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google. // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewGoogleDNSStack()) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create the HTTP client clientTxp := scenario.NewHTTPTransport(clientStack) defer clientTxp.CloseIdleConnections() clientHTTP := &http.Client{Transport: clientTxp} // Get the response body. resp, err := clientHTTP.Get("https://8.8.8.8/") if err != nil { log.Fatal(err) } if resp.StatusCode != http.StatusOK { log.Fatalf("HTTP request failed: %d", resp.StatusCode) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } // Print the response body fmt.Printf("%s", string(body)) }
Output: Google Public DNS server.
Example (Router) ¶
This example shows how to use a router to simulate a network topology consisting of a client and multiple servers.
package main import ( "fmt" "io" "log" "net/http" "time" "github.com/rbmk-project/x/netsim" "github.com/rbmk-project/x/netsim/geolink" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google. // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewGoogleDNSStack()) // Create server stack emulating www.example.com. scenario.Attach(scenario.MustNewExampleComStack()) // Create the client stack, build a geographic point-to-point link // and attach the scenario router to the other end of the link. clientStack := scenario.MustNewClientStack() linkDev := geolink.Extend(clientStack, &geolink.Config{ Delay: 10 * time.Millisecond, Log: true, }) scenario.Attach(linkDev) // Create the HTTP client clientTxp := scenario.NewHTTPTransport(clientStack) defer clientTxp.CloseIdleConnections() clientHTTP := &http.Client{Transport: clientTxp} // Get the response body. resp, err := clientHTTP.Get("https://www.example.com/") if err != nil { log.Fatal(err) } if resp.StatusCode != http.StatusOK { log.Fatalf("HTTP request failed: %d", resp.StatusCode) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } // Print the response body fmt.Printf("%s", string(body)) }
Output: Example Web Server.
Example (Tls) ¶
This example shows how to use netsim to simulate a TLS server that listens for incoming encrypted requests.
package main import ( "context" "crypto/tls" "fmt" "log" "time" "github.com/rbmk-project/x/netsim" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google. // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewGoogleDNSStack()) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create a context with a watchdog timeout. ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() // Connect to the server conn, err := clientStack.DialContext(ctx, "tcp", "8.8.8.8:443") if err != nil { log.Fatal(err) } defer conn.Close() // Perform the TLS handshake tconn := tls.Client(conn, &tls.Config{ RootCAs: scenario.RootCAs(), ServerName: "dns.google", }) defer tconn.Close() if err := tconn.HandshakeContext(ctx); err != nil { log.Fatal(err) } // Print the handshake result fmt.Printf("%v", err) }
Output: <nil>
Example (TlsBlackholing) ¶
This example shows how to use netsim to simulate SNI-based TLS blocking using connection blackholing.
package main import ( "fmt" "net/http" "net/netip" "time" "github.com/rbmk-project/x/netsim" "github.com/rbmk-project/x/netsim/censor" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google. scenario.Attach(scenario.MustNewGoogleDNSStack()) // Configure blackholing on the scenario router targeting // connections where the SNI matches "dns.google" scenario.Router().AddFilter(censor.NewBlackholer( 300*time.Second, // residual censorship duration netip.AddrPort{}, // match any endpoint []byte("dns.google"), // match SNI )) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create the HTTP client with a short timeout clientTxp := scenario.NewHTTPTransport(clientStack) defer clientTxp.CloseIdleConnections() clientHTTP := &http.Client{ Transport: clientTxp, Timeout: 200 * time.Millisecond, // short timeout for testing } // Attempt the HTTPS request, which should time out _, err := clientHTTP.Get("https://dns.google/") fmt.Printf("err: %v\n", err) }
Output: err: Get "https://dns.google/": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
Example (TlsRSTInjection) ¶
This example shows how to use netsim to simulate SNI-based TLS blocking using RST injection.
package main import ( "fmt" "net/http" "net/netip" "github.com/rbmk-project/x/netsim" "github.com/rbmk-project/x/netsim/censor" ) func main() { // Create a new scenario using the given directory to cache // the certificates used by the simulated PKI scenario := netsim.NewScenario("testdata") defer scenario.Close() // Create server stack emulating dns.google. // // This includes: // // 1. creating, attaching, and enabling routing for a server stack // // 2. registering the proper domain names and addresses // // 3. updating the PKI database to include the server's certificate scenario.Attach(scenario.MustNewGoogleDNSStack()) // Configure RST injection on the scenario router targeting // connections where the SNI matches "dns.google" scenario.Router().AddFilter(censor.NewTCPResetter( netip.AddrPort{}, // match any endpoint []byte("dns.google"), // match SNI )) // Create and attach the client stack. clientStack := scenario.MustNewClientStack() scenario.Attach(clientStack) // Create the HTTP client clientTxp := scenario.NewHTTPTransport(clientStack) defer clientTxp.CloseIdleConnections() clientHTTP := &http.Client{Transport: clientTxp} // Attempt the HTTPS request, which should fail due to RST _, err := clientHTTP.Get("https://dns.google/") fmt.Printf("err: %v\n", err) }
Output: err: Get "https://dns.google/": connection reset by peer
Index ¶
- Variables
- func NewDNSHTTPHandler(dd dns.Database) http.Handler
- type DNSHandler
- type Link
- type Scenario
- func (s *Scenario) Attach(dev packet.NetworkDevice)
- func (s *Scenario) Close() error
- func (s *Scenario) DNSHandler() DNSHandler
- func (s *Scenario) MustNewBlockpageStack() *Stack
- func (s *Scenario) MustNewClientStack() *Stack
- func (s *Scenario) MustNewExampleComStack() *Stack
- func (s *Scenario) MustNewGoogleDNSStack() *Stack
- func (s *Scenario) MustNewStack(config *StackConfig) *Stack
- func (s *Scenario) NewHTTPTransport(stack *Stack) *http.Transport
- func (s *Scenario) RootCAs() *x509.CertPool
- func (s *Scenario) Router() *router.Router
- type Stack
- type StackConfig
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var NewLink = link.New
NewLink is an alias for link.New.
var NewStack = netstack.New
NewStack is an alias for netstack.New.
Functions ¶
func NewDNSHTTPHandler ¶
NewDNSHTTPHandler returns an http.Handler handling DNS-over-HTTPS.
Types ¶
type Scenario ¶
type Scenario struct {
// contains filtered or unexported fields
}
Scenario manages network simulation components using a star topology, where all stacks are connected through a central router.
This means:
1. Each stack is connected only to the central router;
2. The router forwards packets between stacks.
func NewScenario ¶
NewScenario creates a new network simulation scenario.
The cacheDir caches simulated-PKI-related data.
func (*Scenario) Attach ¶
func (s *Scenario) Attach(dev packet.NetworkDevice)
Attach connects a device to the scenario's central router to read packets from the device, and sets up the route to that return packets correctly reach the device.
The common case is to attach a *Stack but other cases are also possible. Suppose a *Stack is linked to a firewall through a link, then you can also attach the firewall to the router.
All network traffic to/from this device will flow through the router.
func (*Scenario) DNSHandler ¶
func (s *Scenario) DNSHandler() DNSHandler
DNSHandler returns the DNSHandler for the scenario. The returned handler will serve queries based on the scenario's DNS database.
func (*Scenario) MustNewBlockpageStack ¶
MustNewBlockpageStack creates a new stack simulating a censorship blockpage server.
It serves a simple warning page on HTTP/HTTPS indicating that the content has been blocked.
func (*Scenario) MustNewClientStack ¶
MustNewClientStack creates a new client stack with standard testing configuration.
We use GARR's (Italian Research & Education Network) public addresses (193.206.158.22 and 2001:760:0:158::22) as default client addresses. These are chosen over documentation ranges (like 192.0.2.0/24) to avoid triggering bogon filters in network simulation scenarios, while still being associated with a public research institution.
The stack uses Google's public DNS addresses as the default resolvers.
func (*Scenario) MustNewExampleComStack ¶
MustNewExampleComStack creates a new stack simulating www.example.com.
func (*Scenario) MustNewGoogleDNSStack ¶
MustNewGoogleDNSStack creates a new stack simulating dns.google.
func (*Scenario) MustNewStack ¶
func (s *Scenario) MustNewStack(config *StackConfig) *Stack
MustNewStack creates a new network stack using the given configuration.
This method panics on error.
This method IS NOT goroutine safe.
func (*Scenario) NewHTTPTransport ¶
NewHTTPTransport creates an *http.Transport configured to use the given stack and the scenario's root CAs.
func (*Scenario) RootCAs ¶
RootCAs returns the *x509.CertPool that clients should use.
type StackConfig ¶
type StackConfig struct { // Addresses contains the IP addresses for this stack. // // The config is invalid if there is not at least one address. Addresses []string // ClientResolvers optionally specifies resolvers for client stacks. ClientResolvers []string // DNSOverUDPHandler optionally specifies a handler for DNS-over-UDP. DNSOverUDPHandler DNSHandler // DNSOverTCPHandler optionally specifies a handler for DNS-over-TCP. DNSOverTCPHandler DNSHandler // DNSOverTLSHandler optionally specifies a handler for DNS-over-TLS. DNSOverTLSHandler DNSHandler // DomainNames contains the optional domain names associated with this stack. // // If there are associated domain names, we will configure the DNS and // register related certificates for emulating the PKI. DomainNames []string // HTTPHandler optionally specifies a handle to use on port 80/tcp. HTTPHandler http.Handler // HTTPSHandler optionally specifies a handle to use on port 443/tcp. HTTPSHandler http.Handler }
StackConfig contains configuration for creating a new network stack.
Source Files
¶
Directories
¶
Path | Synopsis |
---|---|
Package censor implements common internet censorship techniques for testing.
|
Package censor implements common internet censorship techniques for testing. |
Package models the distributed DNS database.
|
Package models the distributed DNS database. |
Package geolink models a geographic point-to-point link.
|
Package geolink models a geographic point-to-point link. |
Package link models a point-to-point network link.
|
Package link models a point-to-point network link. |
Package packet contains *Packet and the related definitions.
|
Package packet contains *Packet and the related definitions. |
Package router provides network routing capabilities for testing.
|
Package router provides network routing capabilities for testing. |
Package simpki allows to simulate a PKI for testing purposes.
|
Package simpki allows to simulate a PKI for testing purposes. |