k8s.io/kubernetes@v1.29.3/pkg/proxy/conntrack/conntrack_test.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package conntrack
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"testing"
    23  
    24  	v1 "k8s.io/api/core/v1"
    25  	"k8s.io/utils/exec"
    26  	fakeexec "k8s.io/utils/exec/testing"
    27  	utilnet "k8s.io/utils/net"
    28  )
    29  
    30  func familyParamStr(isIPv6 bool) string {
    31  	if isIPv6 {
    32  		return " -f ipv6"
    33  	}
    34  	return ""
    35  }
    36  
    37  func TestExecConntrackTool(t *testing.T) {
    38  	fcmd := fakeexec.FakeCmd{
    39  		CombinedOutputScript: []fakeexec.FakeAction{
    40  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
    41  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
    42  			func() ([]byte, []byte, error) {
    43  				return []byte(""), nil, fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
    44  			},
    45  		},
    46  	}
    47  	fexec := &fakeexec.FakeExec{
    48  		CommandScript: []fakeexec.FakeCommandAction{
    49  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
    50  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
    51  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
    52  		},
    53  		LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
    54  	}
    55  
    56  	testCases := [][]string{
    57  		{"-L", "-p", "udp"},
    58  		{"-D", "-p", "udp", "-d", "10.0.240.1"},
    59  		{"-D", "-p", "udp", "--orig-dst", "10.240.0.2", "--dst-nat", "10.0.10.2"},
    60  	}
    61  
    62  	expectErr := []bool{false, false, true}
    63  
    64  	for i := range testCases {
    65  		err := Exec(fexec, testCases[i]...)
    66  
    67  		if expectErr[i] {
    68  			if err == nil {
    69  				t.Errorf("expected err, got %v", err)
    70  			}
    71  		} else {
    72  			if err != nil {
    73  				t.Errorf("expected success, got %v", err)
    74  			}
    75  		}
    76  
    77  		execCmd := strings.Join(fcmd.CombinedOutputLog[i], " ")
    78  		expectCmd := fmt.Sprintf("%s %s", "conntrack", strings.Join(testCases[i], " "))
    79  
    80  		if execCmd != expectCmd {
    81  			t.Errorf("expect execute command: %s, but got: %s", expectCmd, execCmd)
    82  		}
    83  	}
    84  }
    85  
    86  func TestClearUDPConntrackForIP(t *testing.T) {
    87  	fcmd := fakeexec.FakeCmd{
    88  		CombinedOutputScript: []fakeexec.FakeAction{
    89  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
    90  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
    91  			func() ([]byte, []byte, error) {
    92  				return []byte(""), nil, fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
    93  			},
    94  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
    95  		},
    96  	}
    97  	fexec := &fakeexec.FakeExec{
    98  		CommandScript: []fakeexec.FakeCommandAction{
    99  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   100  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   101  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   102  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   103  		},
   104  		LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
   105  	}
   106  
   107  	testCases := []struct {
   108  		name string
   109  		ip   string
   110  	}{
   111  		{"IPv4 success", "10.240.0.3"},
   112  		{"IPv4 success", "10.240.0.5"},
   113  		{"IPv4 simulated error", "10.240.0.4"},
   114  		{"IPv6 success", "2001:db8::10"},
   115  	}
   116  
   117  	svcCount := 0
   118  	for _, tc := range testCases {
   119  		if err := ClearEntriesForIP(fexec, tc.ip, v1.ProtocolUDP); err != nil {
   120  			t.Errorf("%s test case:, Unexpected error: %v", tc.name, err)
   121  		}
   122  		expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s -p udp", tc.ip) + familyParamStr(utilnet.IsIPv6String(tc.ip))
   123  		execCommand := strings.Join(fcmd.CombinedOutputLog[svcCount], " ")
   124  		if expectCommand != execCommand {
   125  			t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand)
   126  		}
   127  		svcCount++
   128  	}
   129  	if svcCount != fexec.CommandCalls {
   130  		t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
   131  	}
   132  }
   133  
   134  func TestClearUDPConntrackForPort(t *testing.T) {
   135  	fcmd := fakeexec.FakeCmd{
   136  		CombinedOutputScript: []fakeexec.FakeAction{
   137  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
   138  			func() ([]byte, []byte, error) {
   139  				return []byte(""), nil, fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
   140  			},
   141  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
   142  		},
   143  	}
   144  	fexec := &fakeexec.FakeExec{
   145  		CommandScript: []fakeexec.FakeCommandAction{
   146  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   147  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   148  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   149  		},
   150  		LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
   151  	}
   152  
   153  	testCases := []struct {
   154  		name   string
   155  		port   int
   156  		isIPv6 bool
   157  	}{
   158  		{"IPv4, no error", 8080, false},
   159  		{"IPv4, simulated error", 9090, false},
   160  		{"IPv6, no error", 6666, true},
   161  	}
   162  	svcCount := 0
   163  	for _, tc := range testCases {
   164  		err := ClearEntriesForPort(fexec, tc.port, tc.isIPv6, v1.ProtocolUDP)
   165  		if err != nil {
   166  			t.Errorf("%s test case: Unexpected error: %v", tc.name, err)
   167  		}
   168  		expectCommand := fmt.Sprintf("conntrack -D -p udp --dport %d", tc.port) + familyParamStr(tc.isIPv6)
   169  		execCommand := strings.Join(fcmd.CombinedOutputLog[svcCount], " ")
   170  		if expectCommand != execCommand {
   171  			t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand)
   172  		}
   173  		svcCount++
   174  	}
   175  	if svcCount != fexec.CommandCalls {
   176  		t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
   177  	}
   178  }
   179  
   180  func TestDeleteUDPConnections(t *testing.T) {
   181  	fcmd := fakeexec.FakeCmd{
   182  		CombinedOutputScript: []fakeexec.FakeAction{
   183  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
   184  			func() ([]byte, []byte, error) {
   185  				return []byte(""), nil, fmt.Errorf("conntrack v1.4.2 (conntrack-tools): 0 flow entries have been deleted")
   186  			},
   187  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
   188  		},
   189  	}
   190  	fexec := &fakeexec.FakeExec{
   191  		CommandScript: []fakeexec.FakeCommandAction{
   192  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   193  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   194  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   195  		},
   196  		LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
   197  	}
   198  
   199  	testCases := []struct {
   200  		name   string
   201  		origin string
   202  		dest   string
   203  	}{
   204  		{
   205  			name:   "IPv4 success",
   206  			origin: "1.2.3.4",
   207  			dest:   "10.20.30.40",
   208  		},
   209  		{
   210  			name:   "IPv4 simulated failure",
   211  			origin: "2.3.4.5",
   212  			dest:   "20.30.40.50",
   213  		},
   214  		{
   215  			name:   "IPv6 success",
   216  			origin: "fd00::600d:f00d",
   217  			dest:   "2001:db8::5",
   218  		},
   219  	}
   220  	svcCount := 0
   221  	for i, tc := range testCases {
   222  		err := ClearEntriesForNAT(fexec, tc.origin, tc.dest, v1.ProtocolUDP)
   223  		if err != nil {
   224  			t.Errorf("%s test case: unexpected error: %v", tc.name, err)
   225  		}
   226  		expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s --dst-nat %s -p udp", tc.origin, tc.dest) + familyParamStr(utilnet.IsIPv6String(tc.origin))
   227  		execCommand := strings.Join(fcmd.CombinedOutputLog[i], " ")
   228  		if expectCommand != execCommand {
   229  			t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand)
   230  		}
   231  		svcCount++
   232  	}
   233  	if svcCount != fexec.CommandCalls {
   234  		t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
   235  	}
   236  }
   237  
   238  func TestClearUDPConntrackForPortNAT(t *testing.T) {
   239  	fcmd := fakeexec.FakeCmd{
   240  		CombinedOutputScript: []fakeexec.FakeAction{
   241  			func() ([]byte, []byte, error) { return []byte("1 flow entries have been deleted"), nil, nil },
   242  		},
   243  	}
   244  	fexec := &fakeexec.FakeExec{
   245  		CommandScript: []fakeexec.FakeCommandAction{
   246  			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) },
   247  		},
   248  		LookPathFunc: func(cmd string) (string, error) { return cmd, nil },
   249  	}
   250  	testCases := []struct {
   251  		name string
   252  		port int
   253  		dest string
   254  	}{
   255  		{
   256  			name: "IPv4 success",
   257  			port: 30211,
   258  			dest: "1.2.3.4",
   259  		},
   260  	}
   261  	svcCount := 0
   262  	for i, tc := range testCases {
   263  		err := ClearEntriesForPortNAT(fexec, tc.dest, tc.port, v1.ProtocolUDP)
   264  		if err != nil {
   265  			t.Errorf("%s test case: unexpected error: %v", tc.name, err)
   266  		}
   267  		expectCommand := fmt.Sprintf("conntrack -D -p udp --dport %d --dst-nat %s", tc.port, tc.dest) + familyParamStr(utilnet.IsIPv6String(tc.dest))
   268  		execCommand := strings.Join(fcmd.CombinedOutputLog[i], " ")
   269  		if expectCommand != execCommand {
   270  			t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand)
   271  		}
   272  		svcCount++
   273  	}
   274  	if svcCount != fexec.CommandCalls {
   275  		t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls)
   276  	}
   277  }