k8s.io/kubernetes@v1.29.3/pkg/util/iptables/testing/fake.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 testing 18 19 import ( 20 "bytes" 21 "fmt" 22 "strings" 23 "time" 24 25 "k8s.io/apimachinery/pkg/util/sets" 26 "k8s.io/kubernetes/pkg/util/iptables" 27 ) 28 29 // FakeIPTables is no-op implementation of iptables Interface. 30 type FakeIPTables struct { 31 hasRandomFully bool 32 protocol iptables.Protocol 33 34 Dump *IPTablesDump 35 } 36 37 // NewFake returns a no-op iptables.Interface 38 func NewFake() *FakeIPTables { 39 f := &FakeIPTables{ 40 protocol: iptables.ProtocolIPv4, 41 Dump: &IPTablesDump{ 42 Tables: []Table{ 43 { 44 Name: iptables.TableNAT, 45 Chains: []Chain{ 46 {Name: iptables.ChainPrerouting}, 47 {Name: iptables.ChainInput}, 48 {Name: iptables.ChainOutput}, 49 {Name: iptables.ChainPostrouting}, 50 }, 51 }, 52 { 53 Name: iptables.TableFilter, 54 Chains: []Chain{ 55 {Name: iptables.ChainInput}, 56 {Name: iptables.ChainForward}, 57 {Name: iptables.ChainOutput}, 58 }, 59 }, 60 { 61 Name: iptables.TableMangle, 62 Chains: []Chain{}, 63 }, 64 }, 65 }, 66 } 67 68 return f 69 } 70 71 // NewIPv6Fake returns a no-op iptables.Interface with IsIPv6() == true 72 func NewIPv6Fake() *FakeIPTables { 73 f := NewFake() 74 f.protocol = iptables.ProtocolIPv6 75 return f 76 } 77 78 // SetHasRandomFully sets f's return value for HasRandomFully() 79 func (f *FakeIPTables) SetHasRandomFully(can bool) *FakeIPTables { 80 f.hasRandomFully = can 81 return f 82 } 83 84 // EnsureChain is part of iptables.Interface 85 func (f *FakeIPTables) EnsureChain(table iptables.Table, chain iptables.Chain) (bool, error) { 86 t, err := f.Dump.GetTable(table) 87 if err != nil { 88 return false, err 89 } 90 if c, _ := f.Dump.GetChain(table, chain); c != nil { 91 return true, nil 92 } 93 t.Chains = append(t.Chains, Chain{Name: chain}) 94 return false, nil 95 } 96 97 // FlushChain is part of iptables.Interface 98 func (f *FakeIPTables) FlushChain(table iptables.Table, chain iptables.Chain) error { 99 if c, _ := f.Dump.GetChain(table, chain); c != nil { 100 c.Rules = nil 101 } 102 return nil 103 } 104 105 // DeleteChain is part of iptables.Interface 106 func (f *FakeIPTables) DeleteChain(table iptables.Table, chain iptables.Chain) error { 107 t, err := f.Dump.GetTable(table) 108 if err != nil { 109 return err 110 } 111 for i := range t.Chains { 112 if t.Chains[i].Name == chain { 113 t.Chains = append(t.Chains[:i], t.Chains[i+1:]...) 114 return nil 115 } 116 } 117 return nil 118 } 119 120 // ChainExists is part of iptables.Interface 121 func (f *FakeIPTables) ChainExists(table iptables.Table, chain iptables.Chain) (bool, error) { 122 if _, err := f.Dump.GetTable(table); err != nil { 123 return false, err 124 } 125 if c, _ := f.Dump.GetChain(table, chain); c != nil { 126 return true, nil 127 } 128 return false, nil 129 } 130 131 // EnsureRule is part of iptables.Interface 132 func (f *FakeIPTables) EnsureRule(position iptables.RulePosition, table iptables.Table, chain iptables.Chain, args ...string) (bool, error) { 133 c, err := f.Dump.GetChain(table, chain) 134 if err != nil { 135 return false, err 136 } 137 138 rule := "-A " + string(chain) + " " + strings.Join(args, " ") 139 for _, r := range c.Rules { 140 if r.Raw == rule { 141 return true, nil 142 } 143 } 144 145 parsed, err := ParseRule(rule, false) 146 if err != nil { 147 return false, err 148 } 149 150 if position == iptables.Append { 151 c.Rules = append(c.Rules, parsed) 152 } else { 153 c.Rules = append([]*Rule{parsed}, c.Rules...) 154 } 155 return false, nil 156 } 157 158 // DeleteRule is part of iptables.Interface 159 func (f *FakeIPTables) DeleteRule(table iptables.Table, chain iptables.Chain, args ...string) error { 160 c, err := f.Dump.GetChain(table, chain) 161 if err != nil { 162 return err 163 } 164 165 rule := "-A " + string(chain) + " " + strings.Join(args, " ") 166 for i, r := range c.Rules { 167 if r.Raw == rule { 168 c.Rules = append(c.Rules[:i], c.Rules[i+1:]...) 169 break 170 } 171 } 172 return nil 173 } 174 175 // IsIPv6 is part of iptables.Interface 176 func (f *FakeIPTables) IsIPv6() bool { 177 return f.protocol == iptables.ProtocolIPv6 178 } 179 180 // Protocol is part of iptables.Interface 181 func (f *FakeIPTables) Protocol() iptables.Protocol { 182 return f.protocol 183 } 184 185 func (f *FakeIPTables) saveTable(table iptables.Table, buffer *bytes.Buffer) error { 186 t, err := f.Dump.GetTable(table) 187 if err != nil { 188 return err 189 } 190 191 fmt.Fprintf(buffer, "*%s\n", table) 192 for _, c := range t.Chains { 193 fmt.Fprintf(buffer, ":%s - [%d:%d]\n", c.Name, c.Packets, c.Bytes) 194 } 195 for _, c := range t.Chains { 196 for _, r := range c.Rules { 197 fmt.Fprintf(buffer, "%s\n", r.Raw) 198 } 199 } 200 fmt.Fprintf(buffer, "COMMIT\n") 201 return nil 202 } 203 204 // SaveInto is part of iptables.Interface 205 func (f *FakeIPTables) SaveInto(table iptables.Table, buffer *bytes.Buffer) error { 206 if table == "" { 207 // As a secret extension to the API, FakeIPTables treats table="" as 208 // meaning "all tables" 209 for i := range f.Dump.Tables { 210 err := f.saveTable(f.Dump.Tables[i].Name, buffer) 211 if err != nil { 212 return err 213 } 214 } 215 return nil 216 } 217 218 return f.saveTable(table, buffer) 219 } 220 221 // This is not a complete list but it's enough to pass the unit tests 222 var builtinTargets = sets.NewString("ACCEPT", "DROP", "RETURN", "REJECT", "DNAT", "SNAT", "MASQUERADE", "MARK") 223 224 func (f *FakeIPTables) restoreTable(newDump *IPTablesDump, newTable *Table, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error { 225 oldTable, err := f.Dump.GetTable(newTable.Name) 226 if err != nil { 227 return err 228 } 229 230 backupChains := make([]Chain, len(oldTable.Chains)) 231 copy(backupChains, oldTable.Chains) 232 233 // Update internal state 234 if flush == iptables.FlushTables { 235 oldTable.Chains = make([]Chain, 0, len(newTable.Chains)) 236 } 237 for _, newChain := range newTable.Chains { 238 oldChain, _ := f.Dump.GetChain(newTable.Name, newChain.Name) 239 switch { 240 case oldChain == nil && newChain.Deleted: 241 // no-op 242 case oldChain == nil && !newChain.Deleted: 243 oldTable.Chains = append(oldTable.Chains, newChain) 244 case oldChain != nil && newChain.Deleted: 245 _ = f.DeleteChain(newTable.Name, newChain.Name) 246 case oldChain != nil && !newChain.Deleted: 247 // replace old data with new 248 oldChain.Rules = newChain.Rules 249 if counters == iptables.RestoreCounters { 250 oldChain.Packets = newChain.Packets 251 oldChain.Bytes = newChain.Bytes 252 } 253 } 254 } 255 256 // Now check that all old/new jumps are valid 257 for _, chain := range oldTable.Chains { 258 for _, rule := range chain.Rules { 259 if rule.Jump == nil { 260 continue 261 } 262 if builtinTargets.Has(rule.Jump.Value) { 263 continue 264 } 265 266 jumpedChain, _ := f.Dump.GetChain(oldTable.Name, iptables.Chain(rule.Jump.Value)) 267 if jumpedChain == nil { 268 newChain, _ := newDump.GetChain(oldTable.Name, iptables.Chain(rule.Jump.Value)) 269 if newChain != nil { 270 // rule is an old rule that jumped to a chain which 271 // was deleted by newDump. 272 oldTable.Chains = backupChains 273 return fmt.Errorf("deleted chain %q is referenced by existing rules", newChain.Name) 274 } else { 275 // rule is a new rule that jumped to a chain that was 276 // neither created nor pre-existing 277 oldTable.Chains = backupChains 278 return fmt.Errorf("rule %q jumps to a non-existent chain", rule.Raw) 279 } 280 } 281 } 282 } 283 284 return nil 285 } 286 287 // Restore is part of iptables.Interface 288 func (f *FakeIPTables) Restore(table iptables.Table, data []byte, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error { 289 dump, err := ParseIPTablesDump(string(data)) 290 if err != nil { 291 return err 292 } 293 294 newTable, err := dump.GetTable(table) 295 if err != nil { 296 return err 297 } 298 299 return f.restoreTable(dump, newTable, flush, counters) 300 } 301 302 // RestoreAll is part of iptables.Interface 303 func (f *FakeIPTables) RestoreAll(data []byte, flush iptables.FlushFlag, counters iptables.RestoreCountersFlag) error { 304 dump, err := ParseIPTablesDump(string(data)) 305 if err != nil { 306 return err 307 } 308 309 for i := range dump.Tables { 310 err = f.restoreTable(dump, &dump.Tables[i], flush, counters) 311 if err != nil { 312 return err 313 } 314 } 315 return nil 316 } 317 318 // Monitor is part of iptables.Interface 319 func (f *FakeIPTables) Monitor(canary iptables.Chain, tables []iptables.Table, reloadFunc func(), interval time.Duration, stopCh <-chan struct{}) { 320 } 321 322 // HasRandomFully is part of iptables.Interface 323 func (f *FakeIPTables) HasRandomFully() bool { 324 return f.hasRandomFully 325 } 326 327 func (f *FakeIPTables) Present() bool { 328 return true 329 } 330 331 var _ = iptables.Interface(&FakeIPTables{})