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 }