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