summaryrefslogtreecommitdiffhomepage
path: root/test/iptables/iptables_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'test/iptables/iptables_test.go')
-rw-r--r--test/iptables/iptables_test.go137
1 files changed, 121 insertions, 16 deletions
diff --git a/test/iptables/iptables_test.go b/test/iptables/iptables_test.go
index 340f9426e..834f7615f 100644
--- a/test/iptables/iptables_test.go
+++ b/test/iptables/iptables_test.go
@@ -15,8 +15,12 @@
package iptables
import (
+ "context"
+ "errors"
"fmt"
"net"
+ "reflect"
+ "sync"
"testing"
"gvisor.dev/gvisor/pkg/test/dockerutil"
@@ -33,12 +37,40 @@ import (
// Container output is logged to $TEST_UNDECLARED_OUTPUTS_DIR if it exists, or
// to stderr.
func singleTest(t *testing.T, test TestCase) {
+ for _, tc := range []bool{false, true} {
+ subtest := "IPv4"
+ if tc {
+ subtest = "IPv6"
+ }
+ t.Run(subtest, func(t *testing.T) {
+ iptablesTest(t, test, tc)
+ })
+ }
+}
+
+func iptablesTest(t *testing.T, test TestCase, ipv6 bool) {
if _, ok := Tests[test.Name()]; !ok {
t.Fatalf("no test found with name %q. Has it been registered?", test.Name())
}
- d := dockerutil.MakeDocker(t)
- defer d.CleanUp()
+ // Wait for the local and container goroutines to finish.
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ ctx, cancel := context.WithTimeout(context.Background(), TestTimeout)
+ defer cancel()
+
+ d := dockerutil.MakeContainer(ctx, t)
+ defer func() {
+ if logs, err := d.Logs(context.Background()); err != nil {
+ t.Logf("Failed to retrieve container logs.")
+ } else {
+ t.Logf("=== Container logs: ===\n%s", logs)
+ }
+ // Use a new context, as cleanup should run even when we
+ // timeout.
+ d.CleanUp(context.Background())
+ }()
// Create and start the container.
opts := dockerutil.RunOpts{
@@ -46,12 +78,16 @@ func singleTest(t *testing.T, test TestCase) {
CapAdd: []string{"NET_ADMIN"},
}
d.CopyFiles(&opts, "/runner", "test/iptables/runner/runner")
- if err := d.Spawn(opts, "/runner/runner", "-name", test.Name()); err != nil {
+ args := []string{"/runner/runner", "-name", test.Name()}
+ if ipv6 {
+ args = append(args, "-ipv6")
+ }
+ if err := d.Spawn(ctx, opts, args...); err != nil {
t.Fatalf("docker run failed: %v", err)
}
// Get the container IP.
- ip, err := d.FindIP()
+ ip, err := d.FindIP(ctx, ipv6)
if err != nil {
t.Fatalf("failed to get container IP: %v", err)
}
@@ -62,15 +98,44 @@ func singleTest(t *testing.T, test TestCase) {
}
// Run our side of the test.
- if err := test.LocalAction(ip); err != nil {
- t.Fatalf("LocalAction failed: %v", err)
- }
-
- // Wait for the final statement. This structure has the side effect
- // that all container logs will appear within the individual test
- // context.
- if _, err := d.WaitForOutput(TerminalStatement, TestTimeout); err != nil {
- t.Fatalf("test failed: %v", err)
+ errCh := make(chan error, 2)
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ if err := test.LocalAction(ctx, ip, ipv6); err != nil && !errors.Is(err, context.Canceled) {
+ errCh <- fmt.Errorf("LocalAction failed: %v", err)
+ } else {
+ errCh <- nil
+ }
+ if test.LocalSufficient() {
+ errCh <- nil
+ }
+ }()
+
+ // Run the container side.
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ // Wait for the final statement. This structure has the side
+ // effect that all container logs will appear within the
+ // individual test context.
+ if _, err := d.WaitForOutput(ctx, TerminalStatement, TestTimeout); err != nil && !errors.Is(err, context.Canceled) {
+ errCh <- fmt.Errorf("ContainerAction failed: %v", err)
+ } else {
+ errCh <- nil
+ }
+ if test.ContainerSufficient() {
+ errCh <- nil
+ }
+ }()
+
+ for i := 0; i < 2; i++ {
+ select {
+ case err := <-errCh:
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
}
}
@@ -83,7 +148,7 @@ func sendIP(ip net.IP) error {
// The container may not be listening when we first connect, so retry
// upon error.
cb := func() error {
- c, err := net.DialTCP("tcp4", nil, &contAddr)
+ c, err := net.DialTCP("tcp", nil, &contAddr)
conn = c
return err
}
@@ -244,11 +309,11 @@ func TestInputInvertDestination(t *testing.T) {
singleTest(t, FilterInputInvertDestination{})
}
-func TestOutputDestination(t *testing.T) {
+func TestFilterOutputDestination(t *testing.T) {
singleTest(t, FilterOutputDestination{})
}
-func TestOutputInvertDestination(t *testing.T) {
+func TestFilterOutputInvertDestination(t *testing.T) {
singleTest(t, FilterOutputInvertDestination{})
}
@@ -260,6 +325,13 @@ func TestNATPreRedirectTCPPort(t *testing.T) {
singleTest(t, NATPreRedirectTCPPort{})
}
+func TestNATPreRedirectTCPOutgoing(t *testing.T) {
+ singleTest(t, NATPreRedirectTCPOutgoing{})
+}
+
+func TestNATOutRedirectTCPIncoming(t *testing.T) {
+ singleTest(t, NATOutRedirectTCPIncoming{})
+}
func TestNATOutRedirectUDPPort(t *testing.T) {
singleTest(t, NATOutRedirectUDPPort{})
}
@@ -315,3 +387,36 @@ func TestInputSource(t *testing.T) {
func TestInputInvertSource(t *testing.T) {
singleTest(t, FilterInputInvertSource{})
}
+
+func TestFilterAddrs(t *testing.T) {
+ tcs := []struct {
+ ipv6 bool
+ addrs []string
+ want []string
+ }{
+ {
+ ipv6: false,
+ addrs: []string{"192.168.0.1", "192.168.0.2/24", "::1", "::2/128"},
+ want: []string{"192.168.0.1", "192.168.0.2"},
+ },
+ {
+ ipv6: true,
+ addrs: []string{"192.168.0.1", "192.168.0.2/24", "::1", "::2/128"},
+ want: []string{"::1", "::2"},
+ },
+ }
+
+ for _, tc := range tcs {
+ if got := filterAddrs(tc.addrs, tc.ipv6); !reflect.DeepEqual(got, tc.want) {
+ t.Errorf("%v with IPv6 %t: got %v, but wanted %v", tc.addrs, tc.ipv6, got, tc.want)
+ }
+ }
+}
+
+func TestNATPreOriginalDst(t *testing.T) {
+ singleTest(t, NATPreOriginalDst{})
+}
+
+func TestNATOutOriginalDst(t *testing.T) {
+ singleTest(t, NATOutOriginalDst{})
+}