golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/transport_params_test.go (about)

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.21
     6  
     7  package quic
     8  
     9  import (
    10  	"bytes"
    11  	"math"
    12  	"net/netip"
    13  	"reflect"
    14  	"testing"
    15  	"time"
    16  )
    17  
    18  func TestTransportParametersMarshalUnmarshal(t *testing.T) {
    19  	for _, test := range []struct {
    20  		params func(p *transportParameters)
    21  		enc    []byte
    22  	}{{
    23  		params: func(p *transportParameters) {
    24  			p.originalDstConnID = []byte("connid")
    25  		},
    26  		enc: []byte{
    27  			0x00, // original_destination_connection_id
    28  			byte(len("connid")),
    29  			'c', 'o', 'n', 'n', 'i', 'd',
    30  		},
    31  	}, {
    32  		params: func(p *transportParameters) {
    33  			p.maxIdleTimeout = 10 * time.Millisecond
    34  		},
    35  		enc: []byte{
    36  			0x01, // max_idle_timeout
    37  			1,    // length
    38  			10,   // varint msecs
    39  		},
    40  	}, {
    41  		params: func(p *transportParameters) {
    42  			p.statelessResetToken = []byte("0123456789abcdef")
    43  		},
    44  		enc: []byte{
    45  			0x02, // stateless_reset_token
    46  			16,   // length
    47  			'0', '1', '2', '3', '4', '5', '6', '7',
    48  			'8', '9', 'a', 'b', 'c', 'd', 'e', 'f', // reset token
    49  		},
    50  	}, {
    51  		params: func(p *transportParameters) {
    52  			p.maxUDPPayloadSize = 1200
    53  		},
    54  		enc: []byte{
    55  			0x03,       // max_udp_payload_size
    56  			2,          // length
    57  			0x44, 0xb0, // varint value
    58  		},
    59  	}, {
    60  		params: func(p *transportParameters) {
    61  			p.initialMaxData = 10
    62  		},
    63  		enc: []byte{
    64  			0x04, // initial_max_data
    65  			1,    // length
    66  			10,   // varint value
    67  		},
    68  	}, {
    69  		params: func(p *transportParameters) {
    70  			p.initialMaxStreamDataBidiLocal = 10
    71  		},
    72  		enc: []byte{
    73  			0x05, // initial_max_stream_data_bidi_local
    74  			1,    // length
    75  			10,   // varint value
    76  		},
    77  	}, {
    78  		params: func(p *transportParameters) {
    79  			p.initialMaxStreamDataBidiRemote = 10
    80  		},
    81  		enc: []byte{
    82  			0x06, // initial_max_stream_data_bidi_remote
    83  			1,    // length
    84  			10,   // varint value
    85  		},
    86  	}, {
    87  		params: func(p *transportParameters) {
    88  			p.initialMaxStreamDataUni = 10
    89  		},
    90  		enc: []byte{
    91  			0x07, // initial_max_stream_data_uni
    92  			1,    // length
    93  			10,   // varint value
    94  		},
    95  	}, {
    96  		params: func(p *transportParameters) {
    97  			p.initialMaxStreamsBidi = 10
    98  		},
    99  		enc: []byte{
   100  			0x08, // initial_max_streams_bidi
   101  			1,    // length
   102  			10,   // varint value
   103  		},
   104  	}, {
   105  		params: func(p *transportParameters) {
   106  			p.initialMaxStreamsUni = 10
   107  		},
   108  		enc: []byte{
   109  			0x09, // initial_max_streams_uni
   110  			1,    // length
   111  			10,   // varint value
   112  		},
   113  	}, {
   114  		params: func(p *transportParameters) {
   115  			p.ackDelayExponent = 4
   116  		},
   117  		enc: []byte{
   118  			0x0a, // ack_delay_exponent
   119  			1,    // length
   120  			4,    // varint value
   121  		},
   122  	}, {
   123  		params: func(p *transportParameters) {
   124  			p.maxAckDelay = 10 * time.Millisecond
   125  		},
   126  		enc: []byte{
   127  			0x0b, // max_ack_delay
   128  			1,    // length
   129  			10,   // varint value
   130  		},
   131  	}, {
   132  		params: func(p *transportParameters) {
   133  			p.disableActiveMigration = true
   134  		},
   135  		enc: []byte{
   136  			0x0c, // disable_active_migration
   137  			0,    // length
   138  		},
   139  	}, {
   140  		params: func(p *transportParameters) {
   141  			p.preferredAddrV4 = netip.MustParseAddrPort("127.0.0.1:80")
   142  			p.preferredAddrV6 = netip.MustParseAddrPort("[fe80::1]:1024")
   143  			p.preferredAddrConnID = []byte("connid")
   144  			p.preferredAddrResetToken = []byte("0123456789abcdef")
   145  		},
   146  		enc: []byte{
   147  			0x0d, // preferred_address
   148  			byte(4 + 2 + 16 + 2 + 1 + len("connid") + 16), // length
   149  			127, 0, 0, 1, // v4 address
   150  			0, 80, // v4 port
   151  			0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // v6 address
   152  			0x04, 0x00, // v6 port,
   153  			6,                            // connection id length
   154  			'c', 'o', 'n', 'n', 'i', 'd', // connection id
   155  			'0', '1', '2', '3', '4', '5', '6', '7',
   156  			'8', '9', 'a', 'b', 'c', 'd', 'e', 'f', // reset token
   157  		},
   158  	}, {
   159  		params: func(p *transportParameters) {
   160  			p.activeConnIDLimit = 10
   161  		},
   162  		enc: []byte{
   163  			0x0e, // active_connection_id_limit
   164  			1,    // length
   165  			10,   // varint value
   166  		},
   167  	}, {
   168  		params: func(p *transportParameters) {
   169  			p.initialSrcConnID = []byte("connid")
   170  		},
   171  		enc: []byte{
   172  			0x0f, // initial_source_connection_id
   173  			byte(len("connid")),
   174  			'c', 'o', 'n', 'n', 'i', 'd',
   175  		},
   176  	}, {
   177  		params: func(p *transportParameters) {
   178  			p.retrySrcConnID = []byte("connid")
   179  		},
   180  		enc: []byte{
   181  			0x10, // retry_source_connection_id
   182  			byte(len("connid")),
   183  			'c', 'o', 'n', 'n', 'i', 'd',
   184  		},
   185  	}} {
   186  		wantParams := defaultTransportParameters()
   187  		test.params(&wantParams)
   188  		gotBytes := marshalTransportParameters(wantParams)
   189  		if !bytes.Equal(gotBytes, test.enc) {
   190  			t.Errorf("marshalTransportParameters(%#v):\n got: %x\nwant: %x", wantParams, gotBytes, test.enc)
   191  		}
   192  		gotParams, err := unmarshalTransportParams(test.enc)
   193  		if err != nil {
   194  			t.Errorf("unmarshalTransportParams(%x): unexpected error: %v", test.enc, err)
   195  		} else if !reflect.DeepEqual(gotParams, wantParams) {
   196  			t.Errorf("unmarshalTransportParams(%x):\n got: %#v\nwant: %#v", test.enc, gotParams, wantParams)
   197  		}
   198  	}
   199  }
   200  
   201  func TestTransportParametersErrors(t *testing.T) {
   202  	for _, test := range []struct {
   203  		desc string
   204  		enc  []byte
   205  	}{{
   206  		desc: "invalid id",
   207  		enc: []byte{
   208  			0x40, // too short
   209  		},
   210  	}, {
   211  		desc: "parameter too short",
   212  		enc: []byte{
   213  			0x00,    // original_destination_connection_id
   214  			0x04,    // length
   215  			1, 2, 3, // not enough data
   216  		},
   217  	}, {
   218  		desc: "extra data in parameter",
   219  		enc: []byte{
   220  			0x01, // max_idle_timeout
   221  			2,    // length
   222  			10,   // varint msecs
   223  			0,    // extra junk
   224  		},
   225  	}, {
   226  		desc: "invalid varint in parameter",
   227  		enc: []byte{
   228  			0x01, // max_idle_timeout
   229  			1,    // length
   230  			0x40, // incomplete varint
   231  		},
   232  	}, {
   233  		desc: "stateless_reset_token not 16 bytes",
   234  		enc: []byte{
   235  			0x02, // stateless_reset_token,
   236  			15,   // length
   237  			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
   238  		},
   239  	}, {
   240  		desc: "initial_max_streams_bidi is too large",
   241  		enc: []byte{
   242  			0x08, // initial_max_streams_bidi,
   243  			8,    // length,
   244  			0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   245  		},
   246  	}, {
   247  		desc: "initial_max_streams_uni is too large",
   248  		enc: []byte{
   249  			0x08, // initial_max_streams_uni,
   250  			9,    // length,
   251  			0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
   252  		},
   253  	}, {
   254  		desc: "preferred_address is too short",
   255  		enc: []byte{
   256  			0x0d, // preferred_address
   257  			byte(3),
   258  			127, 0, 0,
   259  		},
   260  	}, {
   261  		desc: "preferred_address reset token too short",
   262  		enc: []byte{
   263  			0x0d, // preferred_address
   264  			byte(4 + 2 + 16 + 2 + 1 + len("connid") + 15), // length
   265  			127, 0, 0, 1, // v4 address
   266  			0, 80, // v4 port
   267  			0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // v6 address
   268  			0x04, 0x00, // v6 port,
   269  			6,                            // connection id length
   270  			'c', 'o', 'n', 'n', 'i', 'd', // connection id
   271  			'0', '1', '2', '3', '4', '5', '6', '7',
   272  			'8', '9', 'a', 'b', 'c', 'd', 'e', // reset token, one byte too short
   273  
   274  		},
   275  	}, {
   276  		desc: "preferred_address conn id too long",
   277  		enc: []byte{
   278  			0x0d, // preferred_address
   279  			byte(4 + 2 + 16 + 2 + 1 + len("connid") + 16), // length
   280  			127, 0, 0, 1, // v4 address
   281  			0, 80, // v4 port
   282  			0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, // v6 address
   283  			0x04, 0x00, // v6 port,
   284  			byte(len("connid")) + 16 + 1, // connection id length, too long
   285  			'c', 'o', 'n', 'n', 'i', 'd', // connection id
   286  			'0', '1', '2', '3', '4', '5', '6', '7',
   287  			'8', '9', 'a', 'b', 'c', 'd', 'e', 'f', // reset token
   288  
   289  		},
   290  	}} {
   291  		_, err := unmarshalTransportParams(test.enc)
   292  		if err == nil {
   293  			t.Errorf("%v:\nunmarshalTransportParams(%x): unexpectedly succeeded", test.desc, test.enc)
   294  		}
   295  	}
   296  }
   297  
   298  func TestTransportParametersRangeErrors(t *testing.T) {
   299  	for _, test := range []struct {
   300  		desc   string
   301  		params func(p *transportParameters)
   302  	}{{
   303  		desc: "max_udp_payload_size < 1200",
   304  		params: func(p *transportParameters) {
   305  			p.maxUDPPayloadSize = 1199
   306  		},
   307  	}, {
   308  		desc: "ack_delay_exponent > 20",
   309  		params: func(p *transportParameters) {
   310  			p.ackDelayExponent = 21
   311  		},
   312  	}, {
   313  		desc: "max_ack_delay > 1^14 ms",
   314  		params: func(p *transportParameters) {
   315  			p.maxAckDelay = (1 << 14) * time.Millisecond
   316  		},
   317  	}, {
   318  		desc: "active_connection_id_limit < 2",
   319  		params: func(p *transportParameters) {
   320  			p.activeConnIDLimit = 1
   321  		},
   322  	}} {
   323  		p := defaultTransportParameters()
   324  		test.params(&p)
   325  		enc := marshalTransportParameters(p)
   326  		_, err := unmarshalTransportParams(enc)
   327  		if err == nil {
   328  			t.Errorf("%v: unmarshalTransportParams unexpectedly succeeded", test.desc)
   329  		}
   330  	}
   331  }
   332  
   333  func TestTransportParameterMaxIdleTimeoutOverflowsDuration(t *testing.T) {
   334  	tooManyMS := 1 + (math.MaxInt64 / uint64(time.Millisecond))
   335  
   336  	var enc []byte
   337  	enc = appendVarint(enc, paramMaxIdleTimeout)
   338  	enc = appendVarint(enc, uint64(sizeVarint(tooManyMS)))
   339  	enc = appendVarint(enc, uint64(tooManyMS))
   340  
   341  	dec, err := unmarshalTransportParams(enc)
   342  	if err != nil {
   343  		t.Fatalf("unmarshalTransportParameters(enc) = %v", err)
   344  	}
   345  	if got, want := dec.maxIdleTimeout, time.Duration(0); got != want {
   346  		t.Errorf("max_idle_timeout=%v, got maxIdleTimeout=%v; want %v", tooManyMS, got, want)
   347  	}
   348  }
   349  
   350  func TestTransportParametersSkipUnknownParameters(t *testing.T) {
   351  	enc := []byte{
   352  		0x20, // unknown transport parameter
   353  		1,    // length
   354  		0,    // varint value
   355  
   356  		0x04, // initial_max_data
   357  		1,    // length
   358  		10,   // varint value
   359  
   360  		0x21, // unknown transport parameter
   361  		1,    // length
   362  		0,    // varint value
   363  	}
   364  	dec, err := unmarshalTransportParams(enc)
   365  	if err != nil {
   366  		t.Fatalf("unmarshalTransportParameters(enc) = %v", err)
   367  	}
   368  	if got, want := dec.initialMaxData, int64(10); got != want {
   369  		t.Errorf("got initial_max_data=%v; want %v", got, want)
   370  	}
   371  }
   372  
   373  func FuzzTransportParametersMarshalUnmarshal(f *testing.F) {
   374  	f.Fuzz(func(t *testing.T, in []byte) {
   375  		p1, err := unmarshalTransportParams(in)
   376  		if err != nil {
   377  			return
   378  		}
   379  		out := marshalTransportParameters(p1)
   380  		p2, err := unmarshalTransportParams(out)
   381  		if err != nil {
   382  			t.Fatalf("round trip unmarshal/remarshal: unmarshal error: %v\n%x", err, in)
   383  		}
   384  		if !reflect.DeepEqual(p1, p2) {
   385  			t.Fatalf("round trip unmarshal/remarshal: parameters differ:\n%x\n%#v\n%#v", in, p1, p2)
   386  		}
   387  	})
   388  }