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