istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tools/istio-iptables/pkg/capture/run_test.go (about)

     1  // Copyright Istio 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 capture
    16  
    17  import (
    18  	"net/netip"
    19  	"path/filepath"
    20  	"reflect"
    21  	"strings"
    22  	"testing"
    23  
    24  	testutil "istio.io/istio/pilot/test/util"
    25  	"istio.io/istio/tools/istio-iptables/pkg/config"
    26  	"istio.io/istio/tools/istio-iptables/pkg/constants"
    27  	dep "istio.io/istio/tools/istio-iptables/pkg/dependencies"
    28  )
    29  
    30  func constructTestConfig() *config.Config {
    31  	return &config.Config{
    32  		ProxyPort:               "15001",
    33  		InboundCapturePort:      "15006",
    34  		InboundTunnelPort:       "15008",
    35  		ProxyUID:                constants.DefaultProxyUID,
    36  		ProxyGID:                constants.DefaultProxyUID,
    37  		InboundTProxyMark:       "1337",
    38  		InboundTProxyRouteTable: "133",
    39  		OwnerGroupsInclude:      constants.OwnerGroupsInclude.DefaultValue,
    40  		HostIPv4LoopbackCidr:    constants.HostIPv4LoopbackCidr.DefaultValue,
    41  		RestoreFormat:           false,
    42  	}
    43  }
    44  
    45  func TestIptables(t *testing.T) {
    46  	cases := []struct {
    47  		name   string
    48  		config func(cfg *config.Config)
    49  	}{
    50  		{
    51  			"ipv6-empty-inbound-ports",
    52  			func(cfg *config.Config) {
    53  				cfg.InboundPortsInclude = ""
    54  				cfg.EnableIPv6 = true
    55  			},
    56  		},
    57  		{
    58  			"ip-range",
    59  			func(cfg *config.Config) {
    60  				cfg.OutboundIPRangesExclude = "1.1.0.0/16"
    61  				cfg.OutboundIPRangesInclude = "9.9.0.0/16"
    62  				cfg.DryRun = true
    63  				cfg.RedirectDNS = true
    64  				cfg.EnableIPv6 = false
    65  				cfg.ProxyGID = "1,2"
    66  				cfg.ProxyUID = "3,4"
    67  				cfg.DNSServersV4 = []string{"127.0.0.53"}
    68  			},
    69  		},
    70  		{
    71  			"tproxy",
    72  			func(cfg *config.Config) {
    73  				cfg.InboundInterceptionMode = constants.TPROXY
    74  				cfg.InboundPortsInclude = "*"
    75  				cfg.OutboundIPRangesExclude = "1.1.0.0/16"
    76  				cfg.OutboundIPRangesInclude = "9.9.0.0/16"
    77  				cfg.DryRun = true
    78  				cfg.RedirectDNS = true
    79  				cfg.DNSServersV4 = []string{"127.0.0.53"}
    80  				cfg.ProxyGID = "1337"
    81  				cfg.ProxyUID = "1337"
    82  				cfg.ExcludeInterfaces = "not-istio-nic"
    83  				cfg.EnableIPv6 = true
    84  			},
    85  		},
    86  		{
    87  			"ipv6-inbound-ports",
    88  			func(cfg *config.Config) {
    89  				cfg.InboundPortsInclude = "4000,5000"
    90  				cfg.EnableIPv6 = true
    91  			},
    92  		},
    93  		{
    94  			"ipv6-virt-interfaces",
    95  			func(cfg *config.Config) {
    96  				cfg.InboundPortsInclude = "4000,5000"
    97  				cfg.KubeVirtInterfaces = "eth0,eth1"
    98  				cfg.EnableIPv6 = true
    99  			},
   100  		},
   101  		{
   102  			"ipv6-ipnets",
   103  			func(cfg *config.Config) {
   104  				cfg.InboundPortsInclude = "4000,5000"
   105  				cfg.InboundPortsExclude = "6000,7000,"
   106  				cfg.KubeVirtInterfaces = "eth0,eth1"
   107  				cfg.OutboundIPRangesExclude = "2001:db8::/32"
   108  				cfg.OutboundIPRangesInclude = "2001:db8::/32"
   109  				cfg.EnableIPv6 = true
   110  			},
   111  		},
   112  		{
   113  			"ipv6-uid-gid",
   114  			func(cfg *config.Config) {
   115  				cfg.InboundPortsInclude = "4000,5000"
   116  				cfg.InboundPortsExclude = "6000,7000"
   117  				cfg.KubeVirtInterfaces = "eth0,eth1"
   118  				cfg.ProxyGID = "1,2"
   119  				cfg.ProxyUID = "3,4"
   120  				cfg.EnableIPv6 = true
   121  				cfg.OutboundIPRangesExclude = "2001:db8::/32"
   122  				cfg.OutboundIPRangesInclude = "2001:db8::/32"
   123  			},
   124  		},
   125  		{
   126  			"ipv6-outbound-ports",
   127  			func(cfg *config.Config) {
   128  				cfg.InboundPortsInclude = ""
   129  				cfg.OutboundPortsInclude = "32000,31000"
   130  				cfg.EnableIPv6 = true
   131  			},
   132  		},
   133  		{
   134  			"empty",
   135  			func(cfg *config.Config) {},
   136  		},
   137  		{
   138  			"kube-virt-interfaces",
   139  			func(cfg *config.Config) {
   140  				cfg.KubeVirtInterfaces = "eth1,eth2"
   141  				cfg.OutboundIPRangesInclude = "*"
   142  			},
   143  		},
   144  		{
   145  			"ipnets",
   146  			func(cfg *config.Config) {
   147  				cfg.OutboundIPRangesInclude = "10.0.0.0/8"
   148  			},
   149  		},
   150  		{
   151  			"ipnets-with-kube-virt-interfaces",
   152  			func(cfg *config.Config) {
   153  				cfg.KubeVirtInterfaces = "eth1,eth2"
   154  				cfg.OutboundIPRangesInclude = "10.0.0.0/8"
   155  			},
   156  		},
   157  		{
   158  			"inbound-ports-include",
   159  			func(cfg *config.Config) {
   160  				cfg.InboundPortsInclude = "32000,31000"
   161  			},
   162  		},
   163  		{
   164  			"inbound-ports-wildcard",
   165  			func(cfg *config.Config) {
   166  				cfg.InboundPortsInclude = "*"
   167  			},
   168  		},
   169  		{
   170  			"inbound-ports-tproxy",
   171  			func(cfg *config.Config) {
   172  				cfg.InboundPortsInclude = "32000,31000"
   173  				cfg.InboundInterceptionMode = constants.TPROXY
   174  			},
   175  		},
   176  		{
   177  			"inbound-ports-wildcard-tproxy",
   178  			func(cfg *config.Config) {
   179  				cfg.InboundPortsInclude = "*"
   180  				cfg.InboundInterceptionMode = constants.TPROXY
   181  			},
   182  		},
   183  		{
   184  			"dns-uid-gid",
   185  			func(cfg *config.Config) {
   186  				cfg.RedirectDNS = true
   187  				cfg.DNSServersV4 = []string{"127.0.0.53"}
   188  				cfg.DNSServersV6 = []string{"::127.0.0.53"}
   189  				cfg.ProxyGID = "1,2"
   190  				cfg.ProxyUID = "3,4"
   191  				cfg.EnableIPv6 = true
   192  			},
   193  		},
   194  		{
   195  			"ipv6-dns-uid-gid",
   196  			func(cfg *config.Config) {
   197  				cfg.EnableIPv6 = true
   198  				cfg.RedirectDNS = true
   199  				cfg.ProxyGID = "1,2"
   200  				cfg.ProxyUID = "3,4"
   201  			},
   202  		},
   203  		{
   204  			"outbound-owner-groups",
   205  			func(cfg *config.Config) {
   206  				cfg.OwnerGroupsInclude = "java,202"
   207  			},
   208  		},
   209  		{
   210  			"outbound-owner-groups-exclude",
   211  			func(cfg *config.Config) {
   212  				cfg.OwnerGroupsExclude = "888,ftp"
   213  			},
   214  		},
   215  		{
   216  			"ipv6-dns-outbound-owner-groups",
   217  			func(cfg *config.Config) {
   218  				cfg.EnableIPv6 = true
   219  				cfg.RedirectDNS = true
   220  				cfg.OwnerGroupsInclude = "java,202"
   221  			},
   222  		},
   223  		{
   224  			"ipv6-dns-outbound-owner-groups-exclude",
   225  			func(cfg *config.Config) {
   226  				cfg.EnableIPv6 = true
   227  				cfg.RedirectDNS = true
   228  				cfg.OwnerGroupsExclude = "888,ftp"
   229  			},
   230  		},
   231  		{
   232  			"outbound-ports-include",
   233  			func(cfg *config.Config) {
   234  				cfg.OutboundPortsInclude = "32000,31000"
   235  			},
   236  		},
   237  		{
   238  			"loopback-outbound-iprange",
   239  			func(cfg *config.Config) {
   240  				cfg.OutboundIPRangesInclude = "127.1.2.3/32"
   241  				cfg.DryRun = true
   242  				cfg.RedirectDNS = true
   243  				cfg.DNSServersV4 = []string{"127.0.0.53"}
   244  				cfg.EnableIPv6 = false
   245  				cfg.ProxyGID = "1,2"
   246  				cfg.ProxyUID = "3,4"
   247  			},
   248  		},
   249  		{
   250  			"basic-exclude-nic",
   251  			func(cfg *config.Config) {
   252  				cfg.ExcludeInterfaces = "not-istio-nic"
   253  			},
   254  		},
   255  		{
   256  			"logging",
   257  			func(cfg *config.Config) {
   258  				cfg.TraceLogging = true
   259  			},
   260  		},
   261  		{
   262  			"drop-invalid",
   263  			func(cfg *config.Config) {
   264  				cfg.DropInvalid = true
   265  			},
   266  		},
   267  		{
   268  			"host-ipv4-loopback-cidr",
   269  			func(cfg *config.Config) {
   270  				cfg.HostIPv4LoopbackCidr = "127.0.0.1/8"
   271  			},
   272  		},
   273  	}
   274  	for _, tt := range cases {
   275  		t.Run(tt.name, func(t *testing.T) {
   276  			cfg := constructTestConfig()
   277  			tt.config(cfg)
   278  
   279  			ext := &dep.DependenciesStub{}
   280  			iptConfigurator := NewIptablesConfigurator(cfg, ext)
   281  			iptConfigurator.Run()
   282  			compareToGolden(t, tt.name, ext.ExecutedAll)
   283  		})
   284  	}
   285  }
   286  
   287  func TestSeparateV4V6(t *testing.T) {
   288  	mkIPList := func(ips ...string) []netip.Prefix {
   289  		ret := []netip.Prefix{}
   290  		for _, ip := range ips {
   291  			ipp, err := netip.ParsePrefix(ip)
   292  			if err != nil {
   293  				panic(err.Error())
   294  			}
   295  			ret = append(ret, ipp)
   296  		}
   297  		return ret
   298  	}
   299  	cases := []struct {
   300  		name string
   301  		cidr string
   302  		v4   NetworkRange
   303  		v6   NetworkRange
   304  	}{
   305  		{
   306  			name: "wildcard",
   307  			cidr: "*",
   308  			v4:   NetworkRange{IsWildcard: true},
   309  			v6:   NetworkRange{IsWildcard: true},
   310  		},
   311  		{
   312  			name: "v4 only",
   313  			cidr: "10.0.0.0/8,172.16.0.0/16",
   314  			v4:   NetworkRange{CIDRs: mkIPList("10.0.0.0/8", "172.16.0.0/16")},
   315  		},
   316  		{
   317  			name: "v6 only",
   318  			cidr: "fd04:3e42:4a4e:3381::/64,ffff:ffff:ac10:ac10::/64",
   319  			v6:   NetworkRange{CIDRs: mkIPList("fd04:3e42:4a4e:3381::/64", "ffff:ffff:ac10:ac10::/64")},
   320  		},
   321  	}
   322  	for _, tt := range cases {
   323  		t.Run(tt.name, func(t *testing.T) {
   324  			cfg := constructTestConfig()
   325  			iptConfigurator := NewIptablesConfigurator(cfg, &dep.DependenciesStub{})
   326  			v4Range, v6Range, err := iptConfigurator.separateV4V6(tt.cidr)
   327  			if err != nil {
   328  				t.Fatal(err)
   329  			}
   330  			if !reflect.DeepEqual(v4Range, tt.v4) {
   331  				t.Fatalf("expected %v, got %v", tt.v4, v4Range)
   332  			}
   333  			if !reflect.DeepEqual(v6Range, tt.v6) {
   334  				t.Fatalf("expected %v, got %v", tt.v6, v6Range)
   335  			}
   336  		})
   337  	}
   338  }
   339  
   340  func compareToGolden(t *testing.T, name string, actual []string) {
   341  	t.Helper()
   342  	gotBytes := []byte(strings.Join(actual, "\n"))
   343  	goldenFile := filepath.Join("testdata", name+".golden")
   344  	testutil.CompareContent(t, gotBytes, goldenFile)
   345  }