github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/iptables/iptables_test.go (about)

     1  package iptables
     2  
     3  import (
     4  	"net"
     5  	"os/exec"
     6  	"strconv"
     7  	"strings"
     8  	"sync"
     9  	"testing"
    10  
    11  	_ "github.com/docker/libnetwork/testutils"
    12  )
    13  
    14  const chainName = "DOCKEREST"
    15  
    16  var natChain *ChainInfo
    17  var filterChain *ChainInfo
    18  var bridgeName string
    19  
    20  func TestNewChain(t *testing.T) {
    21  	var err error
    22  
    23  	bridgeName = "lo"
    24  	natChain, err = NewChain(chainName, Nat, false)
    25  	err = ProgramChain(natChain, bridgeName, false, true)
    26  	if err != nil {
    27  		t.Fatal(err)
    28  	}
    29  
    30  	filterChain, err = NewChain(chainName, Filter, false)
    31  	err = ProgramChain(filterChain, bridgeName, false, true)
    32  	if err != nil {
    33  		t.Fatal(err)
    34  	}
    35  }
    36  
    37  func TestForward(t *testing.T) {
    38  	ip := net.ParseIP("192.168.1.1")
    39  	port := 1234
    40  	dstAddr := "172.17.0.1"
    41  	dstPort := 4321
    42  	proto := "tcp"
    43  
    44  	bridgeName := "lo"
    45  	err := natChain.Forward(Insert, ip, port, proto, dstAddr, dstPort, bridgeName)
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	dnatRule := []string{
    51  		"-d", ip.String(),
    52  		"-p", proto,
    53  		"--dport", strconv.Itoa(port),
    54  		"-j", "DNAT",
    55  		"--to-destination", dstAddr + ":" + strconv.Itoa(dstPort),
    56  		"!", "-i", bridgeName,
    57  	}
    58  
    59  	if !Exists(natChain.Table, natChain.Name, dnatRule...) {
    60  		t.Fatalf("DNAT rule does not exist")
    61  	}
    62  
    63  	filterRule := []string{
    64  		"!", "-i", bridgeName,
    65  		"-o", bridgeName,
    66  		"-d", dstAddr,
    67  		"-p", proto,
    68  		"--dport", strconv.Itoa(dstPort),
    69  		"-j", "ACCEPT",
    70  	}
    71  
    72  	if !Exists(filterChain.Table, filterChain.Name, filterRule...) {
    73  		t.Fatalf("filter rule does not exist")
    74  	}
    75  
    76  	masqRule := []string{
    77  		"-d", dstAddr,
    78  		"-s", dstAddr,
    79  		"-p", proto,
    80  		"--dport", strconv.Itoa(dstPort),
    81  		"-j", "MASQUERADE",
    82  	}
    83  
    84  	if !Exists(natChain.Table, "POSTROUTING", masqRule...) {
    85  		t.Fatalf("MASQUERADE rule does not exist")
    86  	}
    87  }
    88  
    89  func TestLink(t *testing.T) {
    90  	var err error
    91  
    92  	bridgeName := "lo"
    93  	ip1 := net.ParseIP("192.168.1.1")
    94  	ip2 := net.ParseIP("192.168.1.2")
    95  	port := 1234
    96  	proto := "tcp"
    97  
    98  	err = filterChain.Link(Append, ip1, ip2, port, proto, bridgeName)
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  
   103  	rule1 := []string{
   104  		"-i", bridgeName,
   105  		"-o", bridgeName,
   106  		"-p", proto,
   107  		"-s", ip1.String(),
   108  		"-d", ip2.String(),
   109  		"--dport", strconv.Itoa(port),
   110  		"-j", "ACCEPT"}
   111  
   112  	if !Exists(filterChain.Table, filterChain.Name, rule1...) {
   113  		t.Fatalf("rule1 does not exist")
   114  	}
   115  
   116  	rule2 := []string{
   117  		"-i", bridgeName,
   118  		"-o", bridgeName,
   119  		"-p", proto,
   120  		"-s", ip2.String(),
   121  		"-d", ip1.String(),
   122  		"--sport", strconv.Itoa(port),
   123  		"-j", "ACCEPT"}
   124  
   125  	if !Exists(filterChain.Table, filterChain.Name, rule2...) {
   126  		t.Fatalf("rule2 does not exist")
   127  	}
   128  }
   129  
   130  func TestPrerouting(t *testing.T) {
   131  	args := []string{
   132  		"-i", "lo",
   133  		"-d", "192.168.1.1"}
   134  
   135  	err := natChain.Prerouting(Insert, args...)
   136  	if err != nil {
   137  		t.Fatal(err)
   138  	}
   139  
   140  	if !Exists(natChain.Table, "PREROUTING", args...) {
   141  		t.Fatalf("rule does not exist")
   142  	}
   143  
   144  	delRule := append([]string{"-D", "PREROUTING", "-t", string(Nat)}, args...)
   145  	if _, err = Raw(delRule...); err != nil {
   146  		t.Fatal(err)
   147  	}
   148  }
   149  
   150  func TestOutput(t *testing.T) {
   151  	args := []string{
   152  		"-o", "lo",
   153  		"-d", "192.168.1.1"}
   154  
   155  	err := natChain.Output(Insert, args...)
   156  	if err != nil {
   157  		t.Fatal(err)
   158  	}
   159  
   160  	if !Exists(natChain.Table, "OUTPUT", args...) {
   161  		t.Fatalf("rule does not exist")
   162  	}
   163  
   164  	delRule := append([]string{"-D", "OUTPUT", "-t",
   165  		string(natChain.Table)}, args...)
   166  	if _, err = Raw(delRule...); err != nil {
   167  		t.Fatal(err)
   168  	}
   169  }
   170  
   171  func TestConcurrencyWithWait(t *testing.T) {
   172  	RunConcurrencyTest(t, true)
   173  }
   174  
   175  func TestConcurrencyNoWait(t *testing.T) {
   176  	RunConcurrencyTest(t, false)
   177  }
   178  
   179  // Runs 10 concurrent rule additions. This will fail if iptables
   180  // is actually invoked simultaneously without --wait.
   181  // Note that if iptables does not support the xtable lock on this
   182  // system, then allowXlock has no effect -- it will always be off.
   183  func RunConcurrencyTest(t *testing.T, allowXlock bool) {
   184  	var wg sync.WaitGroup
   185  
   186  	if !allowXlock && supportsXlock {
   187  		supportsXlock = false
   188  		defer func() { supportsXlock = true }()
   189  	}
   190  
   191  	ip := net.ParseIP("192.168.1.1")
   192  	port := 1234
   193  	dstAddr := "172.17.0.1"
   194  	dstPort := 4321
   195  	proto := "tcp"
   196  
   197  	for i := 0; i < 10; i++ {
   198  		wg.Add(1)
   199  		go func() {
   200  			defer wg.Done()
   201  			err := natChain.Forward(Append, ip, port, proto, dstAddr, dstPort, "lo")
   202  			if err != nil {
   203  				t.Fatal(err)
   204  			}
   205  		}()
   206  	}
   207  	wg.Wait()
   208  }
   209  
   210  func TestCleanup(t *testing.T) {
   211  	var err error
   212  	var rules []byte
   213  
   214  	// Cleanup filter/FORWARD first otherwise output of iptables-save is dirty
   215  	link := []string{"-t", string(filterChain.Table),
   216  		string(Delete), "FORWARD",
   217  		"-o", bridgeName,
   218  		"-j", filterChain.Name}
   219  	if _, err = Raw(link...); err != nil {
   220  		t.Fatal(err)
   221  	}
   222  	filterChain.Remove()
   223  
   224  	err = RemoveExistingChain(chainName, Nat)
   225  	if err != nil {
   226  		t.Fatal(err)
   227  	}
   228  
   229  	rules, err = exec.Command("iptables-save").Output()
   230  	if err != nil {
   231  		t.Fatal(err)
   232  	}
   233  	if strings.Contains(string(rules), chainName) {
   234  		t.Fatalf("Removing chain failed. %s found in iptables-save", chainName)
   235  	}
   236  }
   237  
   238  func TestExistsRaw(t *testing.T) {
   239  	testChain1 := "ABCD"
   240  	testChain2 := "EFGH"
   241  
   242  	_, err := NewChain(testChain1, Filter, false)
   243  	if err != nil {
   244  		t.Fatal(err)
   245  	}
   246  	defer func() {
   247  		RemoveExistingChain(testChain1, Filter)
   248  	}()
   249  
   250  	_, err = NewChain(testChain2, Filter, false)
   251  	if err != nil {
   252  		t.Fatal(err)
   253  	}
   254  	defer func() {
   255  		RemoveExistingChain(testChain2, Filter)
   256  	}()
   257  
   258  	// Test detection over full and truncated rule string
   259  	input := []struct{ rule []string }{
   260  		{[]string{"-s", "172.8.9.9/32", "-j", "ACCEPT"}},
   261  		{[]string{"-d", "172.8.9.0/24", "-j", "DROP"}},
   262  		{[]string{"-s", "172.0.3.0/24", "-d", "172.17.0.0/24", "-p", "tcp", "-m", "tcp", "--dport", "80", "-j", testChain2}},
   263  		{[]string{"-j", "RETURN"}},
   264  	}
   265  
   266  	for i, r := range input {
   267  		ruleAdd := append([]string{"-t", string(Filter), "-A", testChain1}, r.rule...)
   268  		err = RawCombinedOutput(ruleAdd...)
   269  		if err != nil {
   270  			t.Fatalf("i=%d, err: %v", i, err)
   271  		}
   272  		if !existsRaw(Filter, testChain1, r.rule...) {
   273  			t.Fatalf("Failed to detect rule. i=%d", i)
   274  		}
   275  		// Truncate the rule
   276  		trg := r.rule[len(r.rule)-1]
   277  		trg = trg[:len(trg)-2]
   278  		r.rule[len(r.rule)-1] = trg
   279  		if existsRaw(Filter, testChain1, r.rule...) {
   280  			t.Fatalf("Invalid detection. i=%d", i)
   281  		}
   282  	}
   283  }
   284  
   285  func TestGetVersion(t *testing.T) {
   286  	mj, mn, mc := parseVersionNumbers("iptables v1.4.19.1-alpha")
   287  	if mj != 1 || mn != 4 || mc != 19 {
   288  		t.Fatalf("Failed to parse version numbers")
   289  	}
   290  }
   291  
   292  func TestSupportsCOption(t *testing.T) {
   293  	input := []struct {
   294  		mj int
   295  		mn int
   296  		mc int
   297  		ok bool
   298  	}{
   299  		{1, 4, 11, true},
   300  		{1, 4, 12, true},
   301  		{1, 5, 0, true},
   302  		{0, 4, 11, false},
   303  		{0, 5, 12, false},
   304  		{1, 3, 12, false},
   305  		{1, 4, 10, false},
   306  	}
   307  	for ind, inp := range input {
   308  		if inp.ok != supportsCOption(inp.mj, inp.mn, inp.mc) {
   309  			t.Fatalf("Incorrect check: %d", ind)
   310  		}
   311  	}
   312  }