gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/iptables/iptables_test.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package iptables
    16  
    17  import (
    18  	"context"
    19  	"errors"
    20  	"fmt"
    21  	"net"
    22  	"slices"
    23  	"sync"
    24  	"testing"
    25  
    26  	"gvisor.dev/gvisor/pkg/log"
    27  	"gvisor.dev/gvisor/pkg/test/dockerutil"
    28  	"gvisor.dev/gvisor/pkg/test/testutil"
    29  )
    30  
    31  // singleTest runs a TestCase. Each test follows a pattern:
    32  //   - Create a container.
    33  //   - Get the container's IP.
    34  //   - Send the container our IP.
    35  //   - Start a new goroutine running the local action of the test.
    36  //   - Wait for both the container and local actions to finish.
    37  //
    38  // Container output is logged to $TEST_UNDECLARED_OUTPUTS_DIR if it exists, or
    39  // to stderr.
    40  func singleTest(t *testing.T, test TestCase) {
    41  	for _, tc := range []bool{false, true} {
    42  		subtest := "IPv4"
    43  		if tc {
    44  			subtest = "IPv6"
    45  		}
    46  		t.Run(subtest, func(t *testing.T) {
    47  			iptablesTest(t, test, tc)
    48  		})
    49  	}
    50  }
    51  
    52  func iptablesTest(t *testing.T, test TestCase, ipv6 bool) {
    53  	if _, ok := Tests[test.Name()]; !ok {
    54  		log.Infof("no test found with name %q. Has it been registered?", test.Name())
    55  		t.FailNow()
    56  	}
    57  
    58  	// Wait for the local and container goroutines to finish.
    59  	var wg sync.WaitGroup
    60  	defer wg.Wait()
    61  
    62  	ctx, cancel := context.WithTimeout(context.Background(), TestTimeout)
    63  	defer cancel()
    64  
    65  	d := dockerutil.MakeContainer(ctx, t)
    66  	defer func() {
    67  		if logs, err := d.Logs(context.Background()); err != nil {
    68  			log.Infof("Failed to retrieve container logs.")
    69  		} else {
    70  			log.Infof("=== Container logs: ===\n%s", logs)
    71  		}
    72  		// Use a new context, as cleanup should run even when we
    73  		// timeout.
    74  		d.CleanUp(context.Background())
    75  	}()
    76  
    77  	// Create and start the container.
    78  	opts := dockerutil.RunOpts{
    79  		Image:  "iptables",
    80  		CapAdd: []string{"NET_ADMIN"},
    81  	}
    82  	d.CopyFiles(&opts, "/runner", "test/iptables/runner/runner")
    83  	args := []string{"/runner/runner", "-name", test.Name()}
    84  	if ipv6 {
    85  		args = append(args, "-ipv6")
    86  	}
    87  	if err := d.Spawn(ctx, opts, args...); err != nil {
    88  		log.Infof("docker run failed: %v", err)
    89  		t.FailNow()
    90  	}
    91  
    92  	// Get the container IP.
    93  	ip, err := d.FindIP(ctx, ipv6)
    94  	if err != nil {
    95  		// If ipv6 is not configured, don't fail.
    96  		if ipv6 && err == dockerutil.ErrNoIP {
    97  			log.Infof("No ipv6 address is available.")
    98  			t.Skip()
    99  		}
   100  		log.Infof("failed to get container IP: %v", err)
   101  		t.FailNow()
   102  	}
   103  
   104  	// Give the container our IP.
   105  	if err := sendIP(ip); err != nil {
   106  		log.Infof("failed to send IP to container: %v", err)
   107  		t.FailNow()
   108  	}
   109  
   110  	// Run our side of the test.
   111  	errCh := make(chan error, 2)
   112  	wg.Add(1)
   113  	go func() {
   114  		defer wg.Done()
   115  		if err := test.LocalAction(ctx, ip, ipv6); err != nil && !errors.Is(err, context.Canceled) {
   116  			errCh <- fmt.Errorf("LocalAction failed: %v", err)
   117  		} else {
   118  			errCh <- nil
   119  		}
   120  		if test.LocalSufficient() {
   121  			errCh <- nil
   122  		}
   123  	}()
   124  
   125  	// Run the container side.
   126  	wg.Add(1)
   127  	go func() {
   128  		defer wg.Done()
   129  		// Wait for the final statement. This structure has the side
   130  		// effect that all container logs will appear within the
   131  		// individual test context.
   132  		if _, err := d.WaitForOutput(ctx, TerminalStatement, TestTimeout); err != nil && !errors.Is(err, context.Canceled) {
   133  			errCh <- fmt.Errorf("ContainerAction failed: %v", err)
   134  		} else {
   135  			errCh <- nil
   136  		}
   137  		if test.ContainerSufficient() {
   138  			errCh <- nil
   139  		}
   140  	}()
   141  
   142  	for i := 0; i < 2; i++ {
   143  		select {
   144  		case err := <-errCh:
   145  			if err != nil {
   146  				t.Fatal(err)
   147  			}
   148  		}
   149  	}
   150  }
   151  
   152  func sendIP(ip net.IP) error {
   153  	contAddr := net.TCPAddr{
   154  		IP:   ip,
   155  		Port: IPExchangePort,
   156  	}
   157  	var conn *net.TCPConn
   158  	// The container may not be listening when we first connect, so retry
   159  	// upon error.
   160  	cb := func() error {
   161  		c, err := net.DialTCP("tcp", nil, &contAddr)
   162  		conn = c
   163  		return err
   164  	}
   165  	if err := testutil.Poll(cb, TestTimeout); err != nil {
   166  		return fmt.Errorf("timed out waiting to send IP, most recent error: %v", err)
   167  	}
   168  	if _, err := conn.Write([]byte{0}); err != nil {
   169  		return fmt.Errorf("error writing to container: %v", err)
   170  	}
   171  	return nil
   172  }
   173  
   174  func TestFilterInputDropUDP(t *testing.T) {
   175  	singleTest(t, &FilterInputDropUDP{})
   176  }
   177  
   178  func TestFilterInputDropUDPPort(t *testing.T) {
   179  	singleTest(t, &FilterInputDropUDPPort{})
   180  }
   181  
   182  func TestFilterInputDropDifferentUDPPort(t *testing.T) {
   183  	singleTest(t, &FilterInputDropDifferentUDPPort{})
   184  }
   185  
   186  func TestFilterInputDropAll(t *testing.T) {
   187  	singleTest(t, &FilterInputDropAll{})
   188  }
   189  
   190  func TestFilterInputDropOnlyUDP(t *testing.T) {
   191  	singleTest(t, &FilterInputDropOnlyUDP{})
   192  }
   193  
   194  func TestFilterInputDropTCPDestPort(t *testing.T) {
   195  	singleTest(t, &FilterInputDropTCPDestPort{})
   196  }
   197  
   198  func TestFilterInputDropTCPSrcPort(t *testing.T) {
   199  	singleTest(t, &FilterInputDropTCPSrcPort{})
   200  }
   201  
   202  func TestFilterInputCreateUserChain(t *testing.T) {
   203  	singleTest(t, &FilterInputCreateUserChain{})
   204  }
   205  
   206  func TestFilterInputDefaultPolicyAccept(t *testing.T) {
   207  	singleTest(t, &FilterInputDefaultPolicyAccept{})
   208  }
   209  
   210  func TestFilterInputDefaultPolicyDrop(t *testing.T) {
   211  	singleTest(t, &FilterInputDefaultPolicyDrop{})
   212  }
   213  
   214  func TestFilterInputReturnUnderflow(t *testing.T) {
   215  	singleTest(t, &FilterInputReturnUnderflow{})
   216  }
   217  
   218  func TestFilterOutputDropTCPDestPort(t *testing.T) {
   219  	singleTest(t, &FilterOutputDropTCPDestPort{})
   220  }
   221  
   222  func TestFilterOutputDropTCPSrcPort(t *testing.T) {
   223  	singleTest(t, &FilterOutputDropTCPSrcPort{})
   224  }
   225  
   226  func TestFilterOutputAcceptTCPOwner(t *testing.T) {
   227  	singleTest(t, &FilterOutputAcceptTCPOwner{})
   228  }
   229  
   230  func TestFilterOutputDropTCPOwner(t *testing.T) {
   231  	singleTest(t, &FilterOutputDropTCPOwner{})
   232  }
   233  
   234  func TestFilterOutputAcceptUDPOwner(t *testing.T) {
   235  	singleTest(t, &FilterOutputAcceptUDPOwner{})
   236  }
   237  
   238  func TestFilterOutputDropUDPOwner(t *testing.T) {
   239  	singleTest(t, &FilterOutputDropUDPOwner{})
   240  }
   241  
   242  func TestFilterOutputOwnerFail(t *testing.T) {
   243  	singleTest(t, &FilterOutputOwnerFail{})
   244  }
   245  
   246  func TestFilterOutputAcceptGIDOwner(t *testing.T) {
   247  	singleTest(t, &FilterOutputAcceptGIDOwner{})
   248  }
   249  
   250  func TestFilterOutputDropGIDOwner(t *testing.T) {
   251  	singleTest(t, &FilterOutputDropGIDOwner{})
   252  }
   253  
   254  func TestFilterOutputInvertGIDOwner(t *testing.T) {
   255  	singleTest(t, &FilterOutputInvertGIDOwner{})
   256  }
   257  
   258  func TestFilterOutputInvertUIDOwner(t *testing.T) {
   259  	singleTest(t, &FilterOutputInvertUIDOwner{})
   260  }
   261  
   262  func TestFilterOutputInvertUIDAndGIDOwner(t *testing.T) {
   263  	singleTest(t, &FilterOutputInvertUIDAndGIDOwner{})
   264  }
   265  
   266  func TestFilterOutputInterfaceAccept(t *testing.T) {
   267  	singleTest(t, &FilterOutputInterfaceAccept{})
   268  }
   269  
   270  func TestFilterOutputInterfaceDrop(t *testing.T) {
   271  	singleTest(t, &FilterOutputInterfaceDrop{})
   272  }
   273  
   274  func TestFilterOutputInterface(t *testing.T) {
   275  	singleTest(t, &FilterOutputInterface{})
   276  }
   277  
   278  func TestFilterOutputInterfaceBeginsWith(t *testing.T) {
   279  	singleTest(t, &FilterOutputInterfaceBeginsWith{})
   280  }
   281  
   282  func TestFilterOutputInterfaceInvertDrop(t *testing.T) {
   283  	singleTest(t, &FilterOutputInterfaceInvertDrop{})
   284  }
   285  
   286  func TestFilterOutputInterfaceInvertAccept(t *testing.T) {
   287  	singleTest(t, &FilterOutputInterfaceInvertAccept{})
   288  }
   289  
   290  func TestFilterOutputInvertSportAccept(t *testing.T) {
   291  	singleTest(t, &FilterOutputInvertSportAccept{})
   292  }
   293  
   294  func TestFilterOutputInvertSportDrop(t *testing.T) {
   295  	singleTest(t, &FilterOutputInvertSportDrop{})
   296  }
   297  
   298  func TestJumpSerialize(t *testing.T) {
   299  	singleTest(t, &FilterInputSerializeJump{})
   300  }
   301  
   302  func TestJumpBasic(t *testing.T) {
   303  	singleTest(t, &FilterInputJumpBasic{})
   304  }
   305  
   306  func TestJumpReturn(t *testing.T) {
   307  	singleTest(t, &FilterInputJumpReturn{})
   308  }
   309  
   310  func TestJumpReturnDrop(t *testing.T) {
   311  	singleTest(t, &FilterInputJumpReturnDrop{})
   312  }
   313  
   314  func TestJumpBuiltin(t *testing.T) {
   315  	singleTest(t, &FilterInputJumpBuiltin{})
   316  }
   317  
   318  func TestJumpTwice(t *testing.T) {
   319  	singleTest(t, &FilterInputJumpTwice{})
   320  }
   321  
   322  func TestInputDestination(t *testing.T) {
   323  	singleTest(t, &FilterInputDestination{})
   324  }
   325  
   326  func TestInputInvertDestination(t *testing.T) {
   327  	singleTest(t, &FilterInputInvertDestination{})
   328  }
   329  
   330  func TestFilterOutputDestination(t *testing.T) {
   331  	singleTest(t, &FilterOutputDestination{})
   332  }
   333  
   334  func TestFilterOutputInvertDestination(t *testing.T) {
   335  	singleTest(t, &FilterOutputInvertDestination{})
   336  }
   337  
   338  func TestNATPreRedirectUDPPort(t *testing.T) {
   339  	singleTest(t, &NATPreRedirectUDPPort{})
   340  }
   341  
   342  func TestNATPreRedirectTCPPort(t *testing.T) {
   343  	singleTest(t, &NATPreRedirectTCPPort{})
   344  }
   345  
   346  func TestNATPreRedirectTCPOutgoing(t *testing.T) {
   347  	singleTest(t, &NATPreRedirectTCPOutgoing{})
   348  }
   349  
   350  func TestNATOutRedirectTCPIncoming(t *testing.T) {
   351  	singleTest(t, &NATOutRedirectTCPIncoming{})
   352  }
   353  func TestNATOutRedirectUDPPort(t *testing.T) {
   354  	singleTest(t, &NATOutRedirectUDPPort{})
   355  }
   356  
   357  func TestNATOutRedirectTCPPort(t *testing.T) {
   358  	singleTest(t, &NATOutRedirectTCPPort{})
   359  }
   360  
   361  func TestNATDropUDP(t *testing.T) {
   362  	singleTest(t, &NATDropUDP{})
   363  }
   364  
   365  func TestNATAcceptAll(t *testing.T) {
   366  	singleTest(t, &NATAcceptAll{})
   367  }
   368  
   369  func TestNATOutRedirectIP(t *testing.T) {
   370  	singleTest(t, &NATOutRedirectIP{})
   371  }
   372  
   373  func TestNATOutDontRedirectIP(t *testing.T) {
   374  	singleTest(t, &NATOutDontRedirectIP{})
   375  }
   376  
   377  func TestNATOutRedirectInvert(t *testing.T) {
   378  	singleTest(t, &NATOutRedirectInvert{})
   379  }
   380  
   381  func TestNATOutDNAT(t *testing.T) {
   382  	singleTest(t, &NATOutDNAT{})
   383  }
   384  
   385  func TestNATOutDNATAddrOnly(t *testing.T) {
   386  	singleTest(t, &NATOutDNATAddrOnly{})
   387  }
   388  
   389  func TestNATOutDNATPortOnly(t *testing.T) {
   390  	singleTest(t, &NATOutDNATPortOnly{})
   391  }
   392  
   393  func TestNATPreRedirectIP(t *testing.T) {
   394  	singleTest(t, &NATPreRedirectIP{})
   395  }
   396  
   397  func TestNATPreDontRedirectIP(t *testing.T) {
   398  	singleTest(t, &NATPreDontRedirectIP{})
   399  }
   400  
   401  func TestNATPreRedirectInvert(t *testing.T) {
   402  	singleTest(t, &NATPreRedirectInvert{})
   403  }
   404  
   405  func TestNATRedirectRequiresProtocol(t *testing.T) {
   406  	singleTest(t, &NATRedirectRequiresProtocol{})
   407  }
   408  
   409  func TestNATLoopbackSkipsPrerouting(t *testing.T) {
   410  	singleTest(t, &NATLoopbackSkipsPrerouting{})
   411  }
   412  
   413  func TestInputSource(t *testing.T) {
   414  	singleTest(t, &FilterInputSource{})
   415  }
   416  
   417  func TestInputInvertSource(t *testing.T) {
   418  	singleTest(t, &FilterInputInvertSource{})
   419  }
   420  
   421  func TestInputInterfaceAccept(t *testing.T) {
   422  	singleTest(t, &FilterInputInterfaceAccept{})
   423  }
   424  
   425  func TestInputInterfaceDrop(t *testing.T) {
   426  	singleTest(t, &FilterInputInterfaceDrop{})
   427  }
   428  
   429  func TestInputInterface(t *testing.T) {
   430  	singleTest(t, &FilterInputInterface{})
   431  }
   432  
   433  func TestInputInterfaceBeginsWith(t *testing.T) {
   434  	singleTest(t, &FilterInputInterfaceBeginsWith{})
   435  }
   436  
   437  func TestInputInterfaceInvertDrop(t *testing.T) {
   438  	singleTest(t, &FilterInputInterfaceInvertDrop{})
   439  }
   440  
   441  func TestInputInterfaceInvertAccept(t *testing.T) {
   442  	singleTest(t, &FilterInputInterfaceInvertAccept{})
   443  }
   444  
   445  func TestFilterInputInvertDportAccept(t *testing.T) {
   446  	singleTest(t, &FilterInputInvertDportAccept{})
   447  }
   448  
   449  func TestFilterInputInvertDportDrop(t *testing.T) {
   450  	singleTest(t, &FilterInputInvertDportDrop{})
   451  }
   452  
   453  func TestFilterAddrs(t *testing.T) {
   454  	tcs := []struct {
   455  		ipv6  bool
   456  		addrs []string
   457  		want  []string
   458  	}{
   459  		{
   460  			ipv6:  false,
   461  			addrs: []string{"192.168.0.1", "192.168.0.2/24", "::1", "::2/128"},
   462  			want:  []string{"192.168.0.1", "192.168.0.2"},
   463  		},
   464  		{
   465  			ipv6:  true,
   466  			addrs: []string{"192.168.0.1", "192.168.0.2/24", "::1", "::2/128"},
   467  			want:  []string{"::1", "::2"},
   468  		},
   469  	}
   470  
   471  	for _, tc := range tcs {
   472  		if got := filterAddrs(tc.addrs, tc.ipv6); !slices.Equal(got, tc.want) {
   473  			t.Errorf("%v with IPv6 %t: got %v, but wanted %v", tc.addrs, tc.ipv6, got, tc.want)
   474  		}
   475  	}
   476  }
   477  
   478  func TestNATPreOriginalDst(t *testing.T) {
   479  	singleTest(t, &NATPreOriginalDst{})
   480  }
   481  
   482  func TestNATOutOriginalDst(t *testing.T) {
   483  	singleTest(t, &NATOutOriginalDst{})
   484  }
   485  
   486  func TestNATPreRECVORIGDSTADDR(t *testing.T) {
   487  	singleTest(t, &NATPreRECVORIGDSTADDR{})
   488  }
   489  
   490  func TestNATOutRECVORIGDSTADDR(t *testing.T) {
   491  	singleTest(t, &NATOutRECVORIGDSTADDR{})
   492  }
   493  
   494  func TestNATPostSNATUDP(t *testing.T) {
   495  	singleTest(t, &NATPostSNATUDP{})
   496  }
   497  
   498  func TestNATPostSNATTCP(t *testing.T) {
   499  	singleTest(t, &NATPostSNATTCP{})
   500  }