golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/quic/transport_params.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  	"encoding/binary"
    11  	"net/netip"
    12  	"time"
    13  )
    14  
    15  // transportParameters transferred in the quic_transport_parameters TLS extension.
    16  // https://www.rfc-editor.org/rfc/rfc9000.html#section-18.2
    17  type transportParameters struct {
    18  	originalDstConnID              []byte
    19  	maxIdleTimeout                 time.Duration
    20  	statelessResetToken            []byte
    21  	maxUDPPayloadSize              int64
    22  	initialMaxData                 int64
    23  	initialMaxStreamDataBidiLocal  int64
    24  	initialMaxStreamDataBidiRemote int64
    25  	initialMaxStreamDataUni        int64
    26  	initialMaxStreamsBidi          int64
    27  	initialMaxStreamsUni           int64
    28  	ackDelayExponent               int8
    29  	maxAckDelay                    time.Duration
    30  	disableActiveMigration         bool
    31  	preferredAddrV4                netip.AddrPort
    32  	preferredAddrV6                netip.AddrPort
    33  	preferredAddrConnID            []byte
    34  	preferredAddrResetToken        []byte
    35  	activeConnIDLimit              int64
    36  	initialSrcConnID               []byte
    37  	retrySrcConnID                 []byte
    38  }
    39  
    40  const (
    41  	defaultParamMaxUDPPayloadSize       = 65527
    42  	defaultParamAckDelayExponent        = 3
    43  	defaultParamMaxAckDelayMilliseconds = 25
    44  	defaultParamActiveConnIDLimit       = 2
    45  )
    46  
    47  // defaultTransportParameters is initialized to the RFC 9000 default values.
    48  func defaultTransportParameters() transportParameters {
    49  	return transportParameters{
    50  		maxUDPPayloadSize: defaultParamMaxUDPPayloadSize,
    51  		ackDelayExponent:  defaultParamAckDelayExponent,
    52  		maxAckDelay:       defaultParamMaxAckDelayMilliseconds * time.Millisecond,
    53  		activeConnIDLimit: defaultParamActiveConnIDLimit,
    54  	}
    55  }
    56  
    57  const (
    58  	paramOriginalDestinationConnectionID = 0x00
    59  	paramMaxIdleTimeout                  = 0x01
    60  	paramStatelessResetToken             = 0x02
    61  	paramMaxUDPPayloadSize               = 0x03
    62  	paramInitialMaxData                  = 0x04
    63  	paramInitialMaxStreamDataBidiLocal   = 0x05
    64  	paramInitialMaxStreamDataBidiRemote  = 0x06
    65  	paramInitialMaxStreamDataUni         = 0x07
    66  	paramInitialMaxStreamsBidi           = 0x08
    67  	paramInitialMaxStreamsUni            = 0x09
    68  	paramAckDelayExponent                = 0x0a
    69  	paramMaxAckDelay                     = 0x0b
    70  	paramDisableActiveMigration          = 0x0c
    71  	paramPreferredAddress                = 0x0d
    72  	paramActiveConnectionIDLimit         = 0x0e
    73  	paramInitialSourceConnectionID       = 0x0f
    74  	paramRetrySourceConnectionID         = 0x10
    75  )
    76  
    77  func marshalTransportParameters(p transportParameters) []byte {
    78  	var b []byte
    79  	if v := p.originalDstConnID; v != nil {
    80  		b = appendVarint(b, paramOriginalDestinationConnectionID)
    81  		b = appendVarintBytes(b, v)
    82  	}
    83  	if v := uint64(p.maxIdleTimeout / time.Millisecond); v != 0 {
    84  		b = appendVarint(b, paramMaxIdleTimeout)
    85  		b = appendVarint(b, uint64(sizeVarint(v)))
    86  		b = appendVarint(b, uint64(v))
    87  	}
    88  	if v := p.statelessResetToken; v != nil {
    89  		b = appendVarint(b, paramStatelessResetToken)
    90  		b = appendVarintBytes(b, v)
    91  	}
    92  	if v := p.maxUDPPayloadSize; v != defaultParamMaxUDPPayloadSize {
    93  		b = appendVarint(b, paramMaxUDPPayloadSize)
    94  		b = appendVarint(b, uint64(sizeVarint(uint64(v))))
    95  		b = appendVarint(b, uint64(v))
    96  	}
    97  	if v := p.initialMaxData; v != 0 {
    98  		b = appendVarint(b, paramInitialMaxData)
    99  		b = appendVarint(b, uint64(sizeVarint(uint64(v))))
   100  		b = appendVarint(b, uint64(v))
   101  	}
   102  	if v := p.initialMaxStreamDataBidiLocal; v != 0 {
   103  		b = appendVarint(b, paramInitialMaxStreamDataBidiLocal)
   104  		b = appendVarint(b, uint64(sizeVarint(uint64(v))))
   105  		b = appendVarint(b, uint64(v))
   106  	}
   107  	if v := p.initialMaxStreamDataBidiRemote; v != 0 {
   108  		b = appendVarint(b, paramInitialMaxStreamDataBidiRemote)
   109  		b = appendVarint(b, uint64(sizeVarint(uint64(v))))
   110  		b = appendVarint(b, uint64(v))
   111  	}
   112  	if v := p.initialMaxStreamDataUni; v != 0 {
   113  		b = appendVarint(b, paramInitialMaxStreamDataUni)
   114  		b = appendVarint(b, uint64(sizeVarint(uint64(v))))
   115  		b = appendVarint(b, uint64(v))
   116  	}
   117  	if v := p.initialMaxStreamsBidi; v != 0 {
   118  		b = appendVarint(b, paramInitialMaxStreamsBidi)
   119  		b = appendVarint(b, uint64(sizeVarint(uint64(v))))
   120  		b = appendVarint(b, uint64(v))
   121  	}
   122  	if v := p.initialMaxStreamsUni; v != 0 {
   123  		b = appendVarint(b, paramInitialMaxStreamsUni)
   124  		b = appendVarint(b, uint64(sizeVarint(uint64(v))))
   125  		b = appendVarint(b, uint64(v))
   126  	}
   127  	if v := p.ackDelayExponent; v != defaultParamAckDelayExponent {
   128  		b = appendVarint(b, paramAckDelayExponent)
   129  		b = appendVarint(b, uint64(sizeVarint(uint64(v))))
   130  		b = appendVarint(b, uint64(v))
   131  	}
   132  	if v := uint64(p.maxAckDelay / time.Millisecond); v != defaultParamMaxAckDelayMilliseconds {
   133  		b = appendVarint(b, paramMaxAckDelay)
   134  		b = appendVarint(b, uint64(sizeVarint(v)))
   135  		b = appendVarint(b, v)
   136  	}
   137  	if p.disableActiveMigration {
   138  		b = appendVarint(b, paramDisableActiveMigration)
   139  		b = append(b, 0) // 0-length value
   140  	}
   141  	if p.preferredAddrConnID != nil {
   142  		b = append(b, paramPreferredAddress)
   143  		b = appendVarint(b, uint64(4+2+16+2+1+len(p.preferredAddrConnID)+16))
   144  		b = append(b, p.preferredAddrV4.Addr().AsSlice()...)           // 4 bytes
   145  		b = binary.BigEndian.AppendUint16(b, p.preferredAddrV4.Port()) // 2 bytes
   146  		b = append(b, p.preferredAddrV6.Addr().AsSlice()...)           // 16 bytes
   147  		b = binary.BigEndian.AppendUint16(b, p.preferredAddrV6.Port()) // 2 bytes
   148  		b = appendUint8Bytes(b, p.preferredAddrConnID)                 // 1 byte + len(conn_id)
   149  		b = append(b, p.preferredAddrResetToken...)                    // 16 bytes
   150  	}
   151  	if v := p.activeConnIDLimit; v != defaultParamActiveConnIDLimit {
   152  		b = appendVarint(b, paramActiveConnectionIDLimit)
   153  		b = appendVarint(b, uint64(sizeVarint(uint64(v))))
   154  		b = appendVarint(b, uint64(v))
   155  	}
   156  	if v := p.initialSrcConnID; v != nil {
   157  		b = appendVarint(b, paramInitialSourceConnectionID)
   158  		b = appendVarintBytes(b, v)
   159  	}
   160  	if v := p.retrySrcConnID; v != nil {
   161  		b = appendVarint(b, paramRetrySourceConnectionID)
   162  		b = appendVarintBytes(b, v)
   163  	}
   164  	return b
   165  }
   166  
   167  func unmarshalTransportParams(params []byte) (transportParameters, error) {
   168  	p := defaultTransportParameters()
   169  	for len(params) > 0 {
   170  		id, n := consumeVarint(params)
   171  		if n < 0 {
   172  			return p, localTransportError{code: errTransportParameter}
   173  		}
   174  		params = params[n:]
   175  		val, n := consumeVarintBytes(params)
   176  		if n < 0 {
   177  			return p, localTransportError{code: errTransportParameter}
   178  		}
   179  		params = params[n:]
   180  		n = 0
   181  		switch id {
   182  		case paramOriginalDestinationConnectionID:
   183  			p.originalDstConnID = val
   184  			n = len(val)
   185  		case paramMaxIdleTimeout:
   186  			var v uint64
   187  			v, n = consumeVarint(val)
   188  			// If this is unreasonably large, consider it as no timeout to avoid
   189  			// time.Duration overflows.
   190  			if v > 1<<32 {
   191  				v = 0
   192  			}
   193  			p.maxIdleTimeout = time.Duration(v) * time.Millisecond
   194  		case paramStatelessResetToken:
   195  			if len(val) != 16 {
   196  				return p, localTransportError{code: errTransportParameter}
   197  			}
   198  			p.statelessResetToken = val
   199  			n = 16
   200  		case paramMaxUDPPayloadSize:
   201  			p.maxUDPPayloadSize, n = consumeVarintInt64(val)
   202  			if p.maxUDPPayloadSize < 1200 {
   203  				return p, localTransportError{code: errTransportParameter}
   204  			}
   205  		case paramInitialMaxData:
   206  			p.initialMaxData, n = consumeVarintInt64(val)
   207  		case paramInitialMaxStreamDataBidiLocal:
   208  			p.initialMaxStreamDataBidiLocal, n = consumeVarintInt64(val)
   209  		case paramInitialMaxStreamDataBidiRemote:
   210  			p.initialMaxStreamDataBidiRemote, n = consumeVarintInt64(val)
   211  		case paramInitialMaxStreamDataUni:
   212  			p.initialMaxStreamDataUni, n = consumeVarintInt64(val)
   213  		case paramInitialMaxStreamsBidi:
   214  			p.initialMaxStreamsBidi, n = consumeVarintInt64(val)
   215  			if p.initialMaxStreamsBidi > maxStreamsLimit {
   216  				return p, localTransportError{code: errTransportParameter}
   217  			}
   218  		case paramInitialMaxStreamsUni:
   219  			p.initialMaxStreamsUni, n = consumeVarintInt64(val)
   220  			if p.initialMaxStreamsUni > maxStreamsLimit {
   221  				return p, localTransportError{code: errTransportParameter}
   222  			}
   223  		case paramAckDelayExponent:
   224  			var v uint64
   225  			v, n = consumeVarint(val)
   226  			if v > 20 {
   227  				return p, localTransportError{code: errTransportParameter}
   228  			}
   229  			p.ackDelayExponent = int8(v)
   230  		case paramMaxAckDelay:
   231  			var v uint64
   232  			v, n = consumeVarint(val)
   233  			if v >= 1<<14 {
   234  				return p, localTransportError{code: errTransportParameter}
   235  			}
   236  			p.maxAckDelay = time.Duration(v) * time.Millisecond
   237  		case paramDisableActiveMigration:
   238  			p.disableActiveMigration = true
   239  		case paramPreferredAddress:
   240  			if len(val) < 4+2+16+2+1 {
   241  				return p, localTransportError{code: errTransportParameter}
   242  			}
   243  			p.preferredAddrV4 = netip.AddrPortFrom(
   244  				netip.AddrFrom4(*(*[4]byte)(val[:4])),
   245  				binary.BigEndian.Uint16(val[4:][:2]),
   246  			)
   247  			val = val[4+2:]
   248  			p.preferredAddrV6 = netip.AddrPortFrom(
   249  				netip.AddrFrom16(*(*[16]byte)(val[:16])),
   250  				binary.BigEndian.Uint16(val[16:][:2]),
   251  			)
   252  			val = val[16+2:]
   253  			var nn int
   254  			p.preferredAddrConnID, nn = consumeUint8Bytes(val)
   255  			if nn < 0 {
   256  				return p, localTransportError{code: errTransportParameter}
   257  			}
   258  			val = val[nn:]
   259  			if len(val) != 16 {
   260  				return p, localTransportError{code: errTransportParameter}
   261  			}
   262  			p.preferredAddrResetToken = val
   263  			val = nil
   264  		case paramActiveConnectionIDLimit:
   265  			p.activeConnIDLimit, n = consumeVarintInt64(val)
   266  			if p.activeConnIDLimit < 2 {
   267  				return p, localTransportError{code: errTransportParameter}
   268  			}
   269  		case paramInitialSourceConnectionID:
   270  			p.initialSrcConnID = val
   271  			n = len(val)
   272  		case paramRetrySourceConnectionID:
   273  			p.retrySrcConnID = val
   274  			n = len(val)
   275  		default:
   276  			n = len(val)
   277  		}
   278  		if n != len(val) {
   279  			return p, localTransportError{code: errTransportParameter}
   280  		}
   281  	}
   282  	return p, nil
   283  }