github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/transport/tcpconntrack/tcp_conntrack_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tcpconntrack_test
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/FlowerWrong/netstack/tcpip/header"
    21  	"github.com/FlowerWrong/netstack/tcpip/transport/tcpconntrack"
    22  )
    23  
    24  // connected creates a connection tracker TCB and sets it to a connected state
    25  // by performing a 3-way handshake.
    26  func connected(t *testing.T, iss, irs uint32, isw, irw uint16) *tcpconntrack.TCB {
    27  	// Send SYN.
    28  	tcp := make(header.TCP, header.TCPMinimumSize)
    29  	tcp.Encode(&header.TCPFields{
    30  		SeqNum:     iss,
    31  		AckNum:     0,
    32  		DataOffset: header.TCPMinimumSize,
    33  		Flags:      header.TCPFlagSyn,
    34  		WindowSize: irw,
    35  	})
    36  
    37  	tcb := tcpconntrack.TCB{}
    38  	tcb.Init(tcp)
    39  
    40  	// Receive SYN-ACK.
    41  	tcp.Encode(&header.TCPFields{
    42  		SeqNum:     irs,
    43  		AckNum:     iss + 1,
    44  		DataOffset: header.TCPMinimumSize,
    45  		Flags:      header.TCPFlagSyn | header.TCPFlagAck,
    46  		WindowSize: isw,
    47  	})
    48  
    49  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultAlive {
    50  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
    51  	}
    52  
    53  	// Send ACK.
    54  	tcp.Encode(&header.TCPFields{
    55  		SeqNum:     iss + 1,
    56  		AckNum:     irs + 1,
    57  		DataOffset: header.TCPMinimumSize,
    58  		Flags:      header.TCPFlagAck,
    59  		WindowSize: irw,
    60  	})
    61  
    62  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultAlive {
    63  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
    64  	}
    65  
    66  	return &tcb
    67  }
    68  
    69  func TestConnectionRefused(t *testing.T) {
    70  	// Send SYN.
    71  	tcp := make(header.TCP, header.TCPMinimumSize)
    72  	tcp.Encode(&header.TCPFields{
    73  		SeqNum:     1234,
    74  		AckNum:     0,
    75  		DataOffset: header.TCPMinimumSize,
    76  		Flags:      header.TCPFlagSyn,
    77  		WindowSize: 30000,
    78  	})
    79  
    80  	tcb := tcpconntrack.TCB{}
    81  	tcb.Init(tcp)
    82  
    83  	// Receive RST.
    84  	tcp.Encode(&header.TCPFields{
    85  		SeqNum:     789,
    86  		AckNum:     1235,
    87  		DataOffset: header.TCPMinimumSize,
    88  		Flags:      header.TCPFlagRst | header.TCPFlagAck,
    89  		WindowSize: 50000,
    90  	})
    91  
    92  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultReset {
    93  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultReset)
    94  	}
    95  }
    96  
    97  func TestConnectionRefusedInSynRcvd(t *testing.T) {
    98  	// Send SYN.
    99  	tcp := make(header.TCP, header.TCPMinimumSize)
   100  	tcp.Encode(&header.TCPFields{
   101  		SeqNum:     1234,
   102  		AckNum:     0,
   103  		DataOffset: header.TCPMinimumSize,
   104  		Flags:      header.TCPFlagSyn,
   105  		WindowSize: 30000,
   106  	})
   107  
   108  	tcb := tcpconntrack.TCB{}
   109  	tcb.Init(tcp)
   110  
   111  	// Receive SYN.
   112  	tcp.Encode(&header.TCPFields{
   113  		SeqNum:     789,
   114  		AckNum:     0,
   115  		DataOffset: header.TCPMinimumSize,
   116  		Flags:      header.TCPFlagSyn,
   117  		WindowSize: 50000,
   118  	})
   119  
   120  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultAlive {
   121  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   122  	}
   123  
   124  	// Receive RST with no ACK.
   125  	tcp.Encode(&header.TCPFields{
   126  		SeqNum:     790,
   127  		AckNum:     0,
   128  		DataOffset: header.TCPMinimumSize,
   129  		Flags:      header.TCPFlagRst,
   130  		WindowSize: 50000,
   131  	})
   132  
   133  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultReset {
   134  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultReset)
   135  	}
   136  }
   137  
   138  func TestConnectionResetInSynRcvd(t *testing.T) {
   139  	// Send SYN.
   140  	tcp := make(header.TCP, header.TCPMinimumSize)
   141  	tcp.Encode(&header.TCPFields{
   142  		SeqNum:     1234,
   143  		AckNum:     0,
   144  		DataOffset: header.TCPMinimumSize,
   145  		Flags:      header.TCPFlagSyn,
   146  		WindowSize: 30000,
   147  	})
   148  
   149  	tcb := tcpconntrack.TCB{}
   150  	tcb.Init(tcp)
   151  
   152  	// Receive SYN.
   153  	tcp.Encode(&header.TCPFields{
   154  		SeqNum:     789,
   155  		AckNum:     0,
   156  		DataOffset: header.TCPMinimumSize,
   157  		Flags:      header.TCPFlagSyn,
   158  		WindowSize: 50000,
   159  	})
   160  
   161  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultAlive {
   162  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   163  	}
   164  
   165  	// Send RST with no ACK.
   166  	tcp.Encode(&header.TCPFields{
   167  		SeqNum:     1235,
   168  		AckNum:     0,
   169  		DataOffset: header.TCPMinimumSize,
   170  		Flags:      header.TCPFlagRst,
   171  	})
   172  
   173  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultReset {
   174  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultReset)
   175  	}
   176  }
   177  
   178  func TestRetransmitOnSynSent(t *testing.T) {
   179  	// Send initial SYN.
   180  	tcp := make(header.TCP, header.TCPMinimumSize)
   181  	tcp.Encode(&header.TCPFields{
   182  		SeqNum:     1234,
   183  		AckNum:     0,
   184  		DataOffset: header.TCPMinimumSize,
   185  		Flags:      header.TCPFlagSyn,
   186  		WindowSize: 30000,
   187  	})
   188  
   189  	tcb := tcpconntrack.TCB{}
   190  	tcb.Init(tcp)
   191  
   192  	// Retransmit the same SYN.
   193  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultConnecting {
   194  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultConnecting)
   195  	}
   196  }
   197  
   198  func TestRetransmitOnSynRcvd(t *testing.T) {
   199  	// Send initial SYN.
   200  	tcp := make(header.TCP, header.TCPMinimumSize)
   201  	tcp.Encode(&header.TCPFields{
   202  		SeqNum:     1234,
   203  		AckNum:     0,
   204  		DataOffset: header.TCPMinimumSize,
   205  		Flags:      header.TCPFlagSyn,
   206  		WindowSize: 30000,
   207  	})
   208  
   209  	tcb := tcpconntrack.TCB{}
   210  	tcb.Init(tcp)
   211  
   212  	// Receive SYN. This will cause the state to go to SYN-RCVD.
   213  	tcp.Encode(&header.TCPFields{
   214  		SeqNum:     789,
   215  		AckNum:     0,
   216  		DataOffset: header.TCPMinimumSize,
   217  		Flags:      header.TCPFlagSyn,
   218  		WindowSize: 50000,
   219  	})
   220  
   221  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultAlive {
   222  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   223  	}
   224  
   225  	// Retransmit the original SYN.
   226  	tcp.Encode(&header.TCPFields{
   227  		SeqNum:     1234,
   228  		AckNum:     0,
   229  		DataOffset: header.TCPMinimumSize,
   230  		Flags:      header.TCPFlagSyn,
   231  		WindowSize: 30000,
   232  	})
   233  
   234  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultAlive {
   235  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   236  	}
   237  
   238  	// Transmit a SYN-ACK.
   239  	tcp.Encode(&header.TCPFields{
   240  		SeqNum:     1234,
   241  		AckNum:     790,
   242  		DataOffset: header.TCPMinimumSize,
   243  		Flags:      header.TCPFlagSyn | header.TCPFlagAck,
   244  		WindowSize: 30000,
   245  	})
   246  
   247  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultAlive {
   248  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   249  	}
   250  }
   251  
   252  func TestClosedBySelf(t *testing.T) {
   253  	tcb := connected(t, 1234, 789, 30000, 50000)
   254  
   255  	// Send FIN.
   256  	tcp := make(header.TCP, header.TCPMinimumSize)
   257  	tcp.Encode(&header.TCPFields{
   258  		SeqNum:     1235,
   259  		AckNum:     790,
   260  		DataOffset: header.TCPMinimumSize,
   261  		Flags:      header.TCPFlagAck | header.TCPFlagFin,
   262  		WindowSize: 30000,
   263  	})
   264  
   265  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultAlive {
   266  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   267  	}
   268  
   269  	// Receive FIN/ACK.
   270  	tcp.Encode(&header.TCPFields{
   271  		SeqNum:     790,
   272  		AckNum:     1236,
   273  		DataOffset: header.TCPMinimumSize,
   274  		Flags:      header.TCPFlagAck | header.TCPFlagFin,
   275  		WindowSize: 50000,
   276  	})
   277  
   278  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultAlive {
   279  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   280  	}
   281  
   282  	// Send ACK.
   283  	tcp.Encode(&header.TCPFields{
   284  		SeqNum:     1236,
   285  		AckNum:     791,
   286  		DataOffset: header.TCPMinimumSize,
   287  		Flags:      header.TCPFlagAck,
   288  		WindowSize: 30000,
   289  	})
   290  
   291  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultClosedBySelf {
   292  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultClosedBySelf)
   293  	}
   294  }
   295  
   296  func TestClosedByPeer(t *testing.T) {
   297  	tcb := connected(t, 1234, 789, 30000, 50000)
   298  
   299  	// Receive FIN.
   300  	tcp := make(header.TCP, header.TCPMinimumSize)
   301  	tcp.Encode(&header.TCPFields{
   302  		SeqNum:     790,
   303  		AckNum:     1235,
   304  		DataOffset: header.TCPMinimumSize,
   305  		Flags:      header.TCPFlagAck | header.TCPFlagFin,
   306  		WindowSize: 50000,
   307  	})
   308  
   309  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultAlive {
   310  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   311  	}
   312  
   313  	// Send FIN/ACK.
   314  	tcp.Encode(&header.TCPFields{
   315  		SeqNum:     1235,
   316  		AckNum:     791,
   317  		DataOffset: header.TCPMinimumSize,
   318  		Flags:      header.TCPFlagAck | header.TCPFlagFin,
   319  		WindowSize: 30000,
   320  	})
   321  
   322  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultAlive {
   323  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   324  	}
   325  
   326  	// Receive ACK.
   327  	tcp.Encode(&header.TCPFields{
   328  		SeqNum:     791,
   329  		AckNum:     1236,
   330  		DataOffset: header.TCPMinimumSize,
   331  		Flags:      header.TCPFlagAck,
   332  		WindowSize: 50000,
   333  	})
   334  
   335  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultClosedByPeer {
   336  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultClosedByPeer)
   337  	}
   338  }
   339  
   340  func TestSendAndReceiveDataClosedBySelf(t *testing.T) {
   341  	sseq := uint32(1234)
   342  	rseq := uint32(789)
   343  	tcb := connected(t, sseq, rseq, 30000, 50000)
   344  	sseq++
   345  	rseq++
   346  
   347  	// Send some data.
   348  	tcp := make(header.TCP, header.TCPMinimumSize+1024)
   349  
   350  	for i := uint32(0); i < 10; i++ {
   351  		// Send some data.
   352  		tcp.Encode(&header.TCPFields{
   353  			SeqNum:     sseq,
   354  			AckNum:     rseq,
   355  			DataOffset: header.TCPMinimumSize,
   356  			Flags:      header.TCPFlagAck,
   357  			WindowSize: 30000,
   358  		})
   359  		sseq += uint32(len(tcp)) - header.TCPMinimumSize
   360  
   361  		if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultAlive {
   362  			t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   363  		}
   364  
   365  		// Receive ack for data.
   366  		tcp.Encode(&header.TCPFields{
   367  			SeqNum:     rseq,
   368  			AckNum:     sseq,
   369  			DataOffset: header.TCPMinimumSize,
   370  			Flags:      header.TCPFlagAck,
   371  			WindowSize: 50000,
   372  		})
   373  
   374  		if r := tcb.UpdateStateInbound(tcp[:header.TCPMinimumSize]); r != tcpconntrack.ResultAlive {
   375  			t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   376  		}
   377  	}
   378  
   379  	for i := uint32(0); i < 10; i++ {
   380  		// Receive some data.
   381  		tcp.Encode(&header.TCPFields{
   382  			SeqNum:     rseq,
   383  			AckNum:     sseq,
   384  			DataOffset: header.TCPMinimumSize,
   385  			Flags:      header.TCPFlagAck,
   386  			WindowSize: 50000,
   387  		})
   388  		rseq += uint32(len(tcp)) - header.TCPMinimumSize
   389  
   390  		if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultAlive {
   391  			t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   392  		}
   393  
   394  		// Send ack for data.
   395  		tcp.Encode(&header.TCPFields{
   396  			SeqNum:     sseq,
   397  			AckNum:     rseq,
   398  			DataOffset: header.TCPMinimumSize,
   399  			Flags:      header.TCPFlagAck,
   400  			WindowSize: 30000,
   401  		})
   402  
   403  		if r := tcb.UpdateStateOutbound(tcp[:header.TCPMinimumSize]); r != tcpconntrack.ResultAlive {
   404  			t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   405  		}
   406  	}
   407  
   408  	// Send FIN.
   409  	tcp = tcp[:header.TCPMinimumSize]
   410  	tcp.Encode(&header.TCPFields{
   411  		SeqNum:     sseq,
   412  		AckNum:     rseq,
   413  		DataOffset: header.TCPMinimumSize,
   414  		Flags:      header.TCPFlagAck | header.TCPFlagFin,
   415  		WindowSize: 30000,
   416  	})
   417  	sseq++
   418  
   419  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultAlive {
   420  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   421  	}
   422  
   423  	// Receive FIN/ACK.
   424  	tcp.Encode(&header.TCPFields{
   425  		SeqNum:     rseq,
   426  		AckNum:     sseq,
   427  		DataOffset: header.TCPMinimumSize,
   428  		Flags:      header.TCPFlagAck | header.TCPFlagFin,
   429  		WindowSize: 50000,
   430  	})
   431  	rseq++
   432  
   433  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultAlive {
   434  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   435  	}
   436  
   437  	// Send ACK.
   438  	tcp.Encode(&header.TCPFields{
   439  		SeqNum:     sseq,
   440  		AckNum:     rseq,
   441  		DataOffset: header.TCPMinimumSize,
   442  		Flags:      header.TCPFlagAck,
   443  		WindowSize: 30000,
   444  	})
   445  
   446  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultClosedBySelf {
   447  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultClosedBySelf)
   448  	}
   449  }
   450  
   451  func TestIgnoreBadResetOnSynSent(t *testing.T) {
   452  	// Send SYN.
   453  	tcp := make(header.TCP, header.TCPMinimumSize)
   454  	tcp.Encode(&header.TCPFields{
   455  		SeqNum:     1234,
   456  		AckNum:     0,
   457  		DataOffset: header.TCPMinimumSize,
   458  		Flags:      header.TCPFlagSyn,
   459  		WindowSize: 30000,
   460  	})
   461  
   462  	tcb := tcpconntrack.TCB{}
   463  	tcb.Init(tcp)
   464  
   465  	// Receive a RST with a bad ACK, it should not cause the connection to
   466  	// be reset.
   467  	acks := []uint32{1234, 1236, 1000, 5000}
   468  	flags := []uint8{header.TCPFlagRst, header.TCPFlagRst | header.TCPFlagAck}
   469  	for _, a := range acks {
   470  		for _, f := range flags {
   471  			tcp.Encode(&header.TCPFields{
   472  				SeqNum:     789,
   473  				AckNum:     a,
   474  				DataOffset: header.TCPMinimumSize,
   475  				Flags:      f,
   476  				WindowSize: 50000,
   477  			})
   478  
   479  			if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultConnecting {
   480  				t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   481  			}
   482  		}
   483  	}
   484  
   485  	// Complete the handshake.
   486  	// Receive SYN-ACK.
   487  	tcp.Encode(&header.TCPFields{
   488  		SeqNum:     789,
   489  		AckNum:     1235,
   490  		DataOffset: header.TCPMinimumSize,
   491  		Flags:      header.TCPFlagSyn | header.TCPFlagAck,
   492  		WindowSize: 50000,
   493  	})
   494  
   495  	if r := tcb.UpdateStateInbound(tcp); r != tcpconntrack.ResultAlive {
   496  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   497  	}
   498  
   499  	// Send ACK.
   500  	tcp.Encode(&header.TCPFields{
   501  		SeqNum:     1235,
   502  		AckNum:     790,
   503  		DataOffset: header.TCPMinimumSize,
   504  		Flags:      header.TCPFlagAck,
   505  		WindowSize: 30000,
   506  	})
   507  
   508  	if r := tcb.UpdateStateOutbound(tcp); r != tcpconntrack.ResultAlive {
   509  		t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive)
   510  	}
   511  }