k8s.io/kubernetes@v1.29.3/pkg/util/iptables/testing/fake_test.go (about)

     1  /*
     2  Copyright 2022 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  	"strings"
    22  	"testing"
    23  
    24  	"github.com/lithammer/dedent"
    25  
    26  	"k8s.io/kubernetes/pkg/util/iptables"
    27  )
    28  
    29  func TestFakeIPTables(t *testing.T) {
    30  	fake := NewFake()
    31  	buf := bytes.NewBuffer(nil)
    32  
    33  	err := fake.SaveInto("", buf)
    34  	if err != nil {
    35  		t.Fatalf("unexpected error from SaveInto: %v", err)
    36  	}
    37  	expected := dedent.Dedent(strings.Trim(`
    38  		*nat
    39  		:PREROUTING - [0:0]
    40  		:INPUT - [0:0]
    41  		:OUTPUT - [0:0]
    42  		:POSTROUTING - [0:0]
    43  		COMMIT
    44  		*filter
    45  		:INPUT - [0:0]
    46  		:FORWARD - [0:0]
    47  		:OUTPUT - [0:0]
    48  		COMMIT
    49  		*mangle
    50  		COMMIT
    51  		`, "\n"))
    52  	if buf.String() != expected {
    53  		t.Fatalf("bad initial dump. expected:\n%s\n\ngot:\n%s\n", expected, buf.Bytes())
    54  	}
    55  
    56  	// EnsureChain
    57  	existed, err := fake.EnsureChain(iptables.Table("blah"), iptables.Chain("KUBE-TEST"))
    58  	if err == nil {
    59  		t.Errorf("did not get expected error creating chain in non-existent table")
    60  	} else if existed {
    61  		t.Errorf("wrong return value from EnsureChain with non-existent table")
    62  	}
    63  	existed, err = fake.EnsureChain(iptables.TableNAT, iptables.Chain("KUBE-TEST"))
    64  	if err != nil {
    65  		t.Errorf("unexpected error creating chain: %v", err)
    66  	} else if existed {
    67  		t.Errorf("wrong return value from EnsureChain with non-existent chain")
    68  	}
    69  	existed, err = fake.EnsureChain(iptables.TableNAT, iptables.Chain("KUBE-TEST"))
    70  	if err != nil {
    71  		t.Errorf("unexpected error creating chain: %v", err)
    72  	} else if !existed {
    73  		t.Errorf("wrong return value from EnsureChain with existing chain")
    74  	}
    75  
    76  	// ChainExists
    77  	exists, err := fake.ChainExists(iptables.TableNAT, iptables.Chain("KUBE-TEST"))
    78  	if err != nil {
    79  		t.Errorf("unexpected error checking chain: %v", err)
    80  	} else if !exists {
    81  		t.Errorf("wrong return value from ChainExists with existing chain")
    82  	}
    83  	exists, err = fake.ChainExists(iptables.TableNAT, iptables.Chain("KUBE-TEST-NOT"))
    84  	if err != nil {
    85  		t.Errorf("unexpected error checking chain: %v", err)
    86  	} else if exists {
    87  		t.Errorf("wrong return value from ChainExists with non-existent chain")
    88  	}
    89  
    90  	// EnsureRule
    91  	existed, err = fake.EnsureRule(iptables.Append, iptables.Table("blah"), iptables.Chain("KUBE-TEST"), "-j", "ACCEPT")
    92  	if err == nil {
    93  		t.Errorf("did not get expected error creating rule in non-existent table")
    94  	} else if existed {
    95  		t.Errorf("wrong return value from EnsureRule with non-existent table")
    96  	}
    97  	existed, err = fake.EnsureRule(iptables.Append, iptables.TableNAT, iptables.Chain("KUBE-TEST-NOT"), "-j", "ACCEPT")
    98  	if err == nil {
    99  		t.Errorf("did not get expected error creating rule in non-existent chain")
   100  	} else if existed {
   101  		t.Errorf("wrong return value from EnsureRule with non-existent chain")
   102  	}
   103  	existed, err = fake.EnsureRule(iptables.Append, iptables.TableNAT, iptables.Chain("KUBE-TEST"), "-j", "ACCEPT")
   104  	if err != nil {
   105  		t.Errorf("unexpected error creating rule: %v", err)
   106  	} else if existed {
   107  		t.Errorf("wrong return value from EnsureRule with non-existent rule")
   108  	}
   109  	existed, err = fake.EnsureRule(iptables.Prepend, iptables.TableNAT, iptables.Chain("KUBE-TEST"), "-j", "DROP")
   110  	if err != nil {
   111  		t.Errorf("unexpected error creating rule: %v", err)
   112  	} else if existed {
   113  		t.Errorf("wrong return value from EnsureRule with non-existent rule")
   114  	}
   115  	existed, err = fake.EnsureRule(iptables.Append, iptables.TableNAT, iptables.Chain("KUBE-TEST"), "-j", "DROP")
   116  	if err != nil {
   117  		t.Errorf("unexpected error creating rule: %v", err)
   118  	} else if !existed {
   119  		t.Errorf("wrong return value from EnsureRule with already-existing rule")
   120  	}
   121  
   122  	// Sanity-check...
   123  	buf.Reset()
   124  	err = fake.SaveInto("", buf)
   125  	if err != nil {
   126  		t.Fatalf("unexpected error from SaveInto: %v", err)
   127  	}
   128  	expected = dedent.Dedent(strings.Trim(`
   129  		*nat
   130  		:PREROUTING - [0:0]
   131  		:INPUT - [0:0]
   132  		:OUTPUT - [0:0]
   133  		:POSTROUTING - [0:0]
   134  		:KUBE-TEST - [0:0]
   135  		-A KUBE-TEST -j DROP
   136  		-A KUBE-TEST -j ACCEPT
   137  		COMMIT
   138  		*filter
   139  		:INPUT - [0:0]
   140  		:FORWARD - [0:0]
   141  		:OUTPUT - [0:0]
   142  		COMMIT
   143  		*mangle
   144  		COMMIT
   145  		`, "\n"))
   146  	if buf.String() != expected {
   147  		t.Fatalf("bad sanity-check dump. expected:\n%s\n\ngot:\n%s\n", expected, buf.Bytes())
   148  	}
   149  
   150  	// DeleteRule
   151  	err = fake.DeleteRule(iptables.Table("blah"), iptables.Chain("KUBE-TEST"), "-j", "DROP")
   152  	if err == nil {
   153  		t.Errorf("did not get expected error deleting rule in non-existent table")
   154  	}
   155  	err = fake.DeleteRule(iptables.TableNAT, iptables.Chain("KUBE-TEST-NOT"), "-j", "DROP")
   156  	if err == nil {
   157  		t.Errorf("did not get expected error deleting rule in non-existent chain")
   158  	}
   159  	err = fake.DeleteRule(iptables.TableNAT, iptables.Chain("KUBE-TEST"), "-j", "DROPLET")
   160  	if err != nil {
   161  		t.Errorf("unexpected error deleting non-existent rule: %v", err)
   162  	}
   163  	err = fake.DeleteRule(iptables.TableNAT, iptables.Chain("KUBE-TEST"), "-j", "DROP")
   164  	if err != nil {
   165  		t.Errorf("unexpected error deleting rule: %v", err)
   166  	}
   167  
   168  	// Restore
   169  	rules := dedent.Dedent(strings.Trim(`
   170  		*nat
   171  		:KUBE-RESTORED - [0:0]
   172  		:KUBE-MISC-CHAIN - [0:0]
   173  		:KUBE-MISC-TWO - [0:0]
   174  		:KUBE-EMPTY - [0:0]
   175  		-A KUBE-RESTORED -m comment --comment "restored chain" -j ACCEPT
   176  		-A KUBE-MISC-CHAIN -s 1.2.3.4 -j KUBE-MISC-TWO
   177  		-A KUBE-MISC-CHAIN -d 5.6.7.8 -j MASQUERADE
   178  		-A KUBE-MISC-TWO -j ACCEPT
   179  		COMMIT
   180  		`, "\n"))
   181  	err = fake.Restore(iptables.TableNAT, []byte(rules), iptables.NoFlushTables, iptables.NoRestoreCounters)
   182  	if err != nil {
   183  		t.Fatalf("unexpected error from Restore: %v", err)
   184  	}
   185  
   186  	// We used NoFlushTables, so this should leave KUBE-TEST unchanged
   187  	buf.Reset()
   188  	err = fake.SaveInto("", buf)
   189  	if err != nil {
   190  		t.Fatalf("unexpected error from SaveInto: %v", err)
   191  	}
   192  	expected = dedent.Dedent(strings.Trim(`
   193  		*nat
   194  		:PREROUTING - [0:0]
   195  		:INPUT - [0:0]
   196  		:OUTPUT - [0:0]
   197  		:POSTROUTING - [0:0]
   198  		:KUBE-TEST - [0:0]
   199  		:KUBE-RESTORED - [0:0]
   200  		:KUBE-MISC-CHAIN - [0:0]
   201  		:KUBE-MISC-TWO - [0:0]
   202  		:KUBE-EMPTY - [0:0]
   203  		-A KUBE-TEST -j ACCEPT
   204  		-A KUBE-RESTORED -m comment --comment "restored chain" -j ACCEPT
   205  		-A KUBE-MISC-CHAIN -s 1.2.3.4 -j KUBE-MISC-TWO
   206  		-A KUBE-MISC-CHAIN -d 5.6.7.8 -j MASQUERADE
   207  		-A KUBE-MISC-TWO -j ACCEPT
   208  		COMMIT
   209  		*filter
   210  		:INPUT - [0:0]
   211  		:FORWARD - [0:0]
   212  		:OUTPUT - [0:0]
   213  		COMMIT
   214  		*mangle
   215  		COMMIT
   216  		`, "\n"))
   217  	if buf.String() != expected {
   218  		t.Fatalf("bad post-restore dump. expected:\n%s\n\ngot:\n%s\n", expected, buf.Bytes())
   219  	}
   220  
   221  	// Trying to use Restore to delete a chain that another chain jumps to will fail
   222  	rules = dedent.Dedent(strings.Trim(`
   223  		*nat
   224  		:KUBE-MISC-TWO - [0:0]
   225  		-X KUBE-MISC-TWO
   226  		COMMIT
   227  		`, "\n"))
   228  	err = fake.Restore(iptables.TableNAT, []byte(rules), iptables.NoFlushTables, iptables.RestoreCounters)
   229  	if err == nil || !strings.Contains(err.Error(), "referenced by existing rules") {
   230  		t.Fatalf("Expected 'referenced by existing rules' error from Restore, got %v", err)
   231  	}
   232  
   233  	// Trying to use Restore to add a jump to a non-existent chain will fail
   234  	rules = dedent.Dedent(strings.Trim(`
   235  		*nat
   236  		:KUBE-MISC-TWO - [0:0]
   237  		-A KUBE-MISC-TWO -j KUBE-MISC-THREE
   238  		COMMIT
   239  		`, "\n"))
   240  	err = fake.Restore(iptables.TableNAT, []byte(rules), iptables.NoFlushTables, iptables.RestoreCounters)
   241  	if err == nil || !strings.Contains(err.Error(), "non-existent chain") {
   242  		t.Fatalf("Expected 'non-existent chain' error from Restore, got %v", err)
   243  	}
   244  
   245  	// more Restore; empty out one chain and delete another, but also update its counters
   246  	rules = dedent.Dedent(strings.Trim(`
   247  		*nat
   248  		:KUBE-RESTORED - [0:0]
   249  		:KUBE-TEST - [99:9999]
   250  		-X KUBE-RESTORED
   251  		COMMIT
   252  		`, "\n"))
   253  	err = fake.Restore(iptables.TableNAT, []byte(rules), iptables.NoFlushTables, iptables.RestoreCounters)
   254  	if err != nil {
   255  		t.Fatalf("unexpected error from Restore: %v", err)
   256  	}
   257  
   258  	buf.Reset()
   259  	err = fake.SaveInto("", buf)
   260  	if err != nil {
   261  		t.Fatalf("unexpected error from SaveInto: %v", err)
   262  	}
   263  	expected = dedent.Dedent(strings.Trim(`
   264  		*nat
   265  		:PREROUTING - [0:0]
   266  		:INPUT - [0:0]
   267  		:OUTPUT - [0:0]
   268  		:POSTROUTING - [0:0]
   269  		:KUBE-TEST - [99:9999]
   270  		:KUBE-MISC-CHAIN - [0:0]
   271  		:KUBE-MISC-TWO - [0:0]
   272  		:KUBE-EMPTY - [0:0]
   273  		-A KUBE-MISC-CHAIN -s 1.2.3.4 -j KUBE-MISC-TWO
   274  		-A KUBE-MISC-CHAIN -d 5.6.7.8 -j MASQUERADE
   275  		-A KUBE-MISC-TWO -j ACCEPT
   276  		COMMIT
   277  		*filter
   278  		:INPUT - [0:0]
   279  		:FORWARD - [0:0]
   280  		:OUTPUT - [0:0]
   281  		COMMIT
   282  		*mangle
   283  		COMMIT
   284  		`, "\n"))
   285  	if buf.String() != expected {
   286  		t.Fatalf("bad post-second-restore dump. expected:\n%s\n\ngot:\n%s\n", expected, buf.Bytes())
   287  	}
   288  
   289  	// RestoreAll, FlushTables
   290  	rules = dedent.Dedent(strings.Trim(`
   291  		*filter
   292  		:INPUT - [0:0]
   293  		:FORWARD - [0:0]
   294  		:OUTPUT - [0:0]
   295  		:KUBE-TEST - [0:0]
   296  		-A KUBE-TEST -m comment --comment "filter table KUBE-TEST" -j ACCEPT
   297  		COMMIT
   298  		*nat
   299  		:PREROUTING - [0:0]
   300  		:INPUT - [0:0]
   301  		:OUTPUT - [0:0]
   302  		:POSTROUTING - [0:0]
   303  		:KUBE-TEST - [88:8888]
   304  		:KUBE-NEW-CHAIN - [0:0]
   305  		-A KUBE-NEW-CHAIN -d 172.30.0.1 -j DNAT --to-destination 10.0.0.1
   306  		-A KUBE-NEW-CHAIN -d 172.30.0.2 -j DNAT --to-destination 10.0.0.2
   307  		-A KUBE-NEW-CHAIN -d 172.30.0.3 -j DNAT --to-destination 10.0.0.3
   308  		COMMIT
   309  		`, "\n"))
   310  	err = fake.RestoreAll([]byte(rules), iptables.FlushTables, iptables.NoRestoreCounters)
   311  	if err != nil {
   312  		t.Fatalf("unexpected error from RestoreAll: %v", err)
   313  	}
   314  
   315  	buf.Reset()
   316  	err = fake.SaveInto("", buf)
   317  	if err != nil {
   318  		t.Fatalf("unexpected error from SaveInto: %v", err)
   319  	}
   320  	expected = dedent.Dedent(strings.Trim(`
   321  		*nat
   322  		:PREROUTING - [0:0]
   323  		:INPUT - [0:0]
   324  		:OUTPUT - [0:0]
   325  		:POSTROUTING - [0:0]
   326  		:KUBE-TEST - [88:8888]
   327  		:KUBE-NEW-CHAIN - [0:0]
   328  		-A KUBE-NEW-CHAIN -d 172.30.0.1 -j DNAT --to-destination 10.0.0.1
   329  		-A KUBE-NEW-CHAIN -d 172.30.0.2 -j DNAT --to-destination 10.0.0.2
   330  		-A KUBE-NEW-CHAIN -d 172.30.0.3 -j DNAT --to-destination 10.0.0.3
   331  		COMMIT
   332  		*filter
   333  		:INPUT - [0:0]
   334  		:FORWARD - [0:0]
   335  		:OUTPUT - [0:0]
   336  		:KUBE-TEST - [0:0]
   337  		-A KUBE-TEST -m comment --comment "filter table KUBE-TEST" -j ACCEPT
   338  		COMMIT
   339  		*mangle
   340  		COMMIT
   341  		`, "\n"))
   342  	if buf.String() != expected {
   343  		t.Fatalf("bad post-restore-all dump. expected:\n%s\n\ngot:\n%s\n", expected, buf.Bytes())
   344  	}
   345  }