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 }