github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/quic/obfuscator.go (about) 1 //go:build !PSIPHON_DISABLE_QUIC 2 // +build !PSIPHON_DISABLE_QUIC 3 4 /* 5 * Copyright (c) 2018, Psiphon Inc. 6 * All rights reserved. 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * 21 */ 22 23 package quic 24 25 import ( 26 "crypto/sha256" 27 std_errors "errors" 28 "io" 29 "net" 30 "sync" 31 "sync/atomic" 32 "time" 33 34 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/Yawning/chacha20" 35 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors" 36 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng" 37 ietf_quic "github.com/Psiphon-Labs/quic-go" 38 "golang.org/x/crypto/hkdf" 39 "golang.org/x/net/ipv4" 40 ) 41 42 const ( 43 44 // MAX_PACKET_SIZE is the largest packet size quic-go will produce, 45 // including post MTU discovery. This value is quic-go 46 // internal/protocol.MaxPacketBufferSize, which is the Ethernet MTU of 47 // 1500 less IPv6 and UDP header sizes. 48 // 49 // Legacy gQUIC quic-go will produce packets no larger than 50 // MAX_PRE_DISCOVERY_PACKET_SIZE_IPV4/IPV6. 51 52 MAX_PACKET_SIZE = 1452 53 54 // MAX_PRE_DISCOVERY_PACKET_SIZE_IPV4/IPV6 are the largest packet sizes 55 // quic-go will produce before MTU discovery, 1280 less IP and UDP header 56 // sizes. These values, which match quic-go 57 // internal/protocol.InitialPacketSizeIPv4/IPv6, are used to calculate 58 // maximum padding sizes. 59 60 MAX_PRE_DISCOVERY_PACKET_SIZE_IPV4 = 1252 61 MAX_PRE_DISCOVERY_PACKET_SIZE_IPV6 = 1232 62 63 // OBFUSCATED_MAX_PACKET_SIZE_ADJUSTMENT is the minimum amount of bytes 64 // required for obfuscation overhead, the nonce and the padding length. 65 // In IETF quic-go, this adjustment value is passed into quic-go and 66 // applied to packet construction so that quic-go produces max packet 67 // sizes reduced by this adjustment value. 68 69 OBFUSCATED_MAX_PACKET_SIZE_ADJUSTMENT = NONCE_SIZE + 1 70 71 // MIN_INITIAL_PACKET_SIZE is the minimum UDP packet payload size for 72 // Initial packets, an anti-amplification measure (see RFC 9000, section 73 // 14.1). To accomodate obfuscation prefix messages within the same 74 // Initial UDP packet, quic-go's enforcement of this size requirement is 75 // disabled and the enforcment is done by ObfuscatedPacketConn. 76 77 MIN_INITIAL_PACKET_SIZE = 1200 78 79 MAX_PADDING_SIZE = 255 80 MAX_GQUIC_PADDING_SIZE = 64 81 82 MIN_DECOY_PACKETS = 0 83 MAX_DECOY_PACKETS = 10 84 85 NONCE_SIZE = 12 86 87 RANDOM_STREAM_LIMIT = 1<<38 - 64 88 ) 89 90 // ObfuscatedPacketConn wraps a QUIC net.PacketConn with an obfuscation layer 91 // that obscures QUIC packets, adding random padding and producing uniformly 92 // random payload. 93 // 94 // The crypto performed by ObfuscatedPacketConn is purely for obfuscation to 95 // frustrate wire-speed DPI and does not add privacy/security. The small 96 // nonce space and single key per server is not cryptographically secure. 97 // 98 // A server-side ObfuscatedPacketConn performs simple QUIC DPI to distinguish 99 // between obfuscated and non-obfsucated peer flows and responds accordingly. 100 // 101 // The header and padding added by ObfuscatedPacketConn on top of the QUIC 102 // payload will increase UDP packets beyond the QUIC max of 1280 bytes, 103 // introducing some risk of fragmentation and/or dropped packets. 104 type ObfuscatedPacketConn struct { 105 ietf_quic.OOBCapablePacketConn 106 isServer bool 107 isIETFClient bool 108 isDecoyClient bool 109 isClosed int32 110 runWaitGroup *sync.WaitGroup 111 stopBroadcast chan struct{} 112 obfuscationKey [32]byte 113 peerModesMutex sync.Mutex 114 peerModes map[string]*peerMode 115 noncePRNG *prng.PRNG 116 paddingPRNG *prng.PRNG 117 decoyPacketCount int32 118 decoyBuffer []byte 119 } 120 121 type peerMode struct { 122 isObfuscated bool 123 isIETF bool 124 lastPacketTime time.Time 125 } 126 127 func (p *peerMode) isStale() bool { 128 return time.Since(p.lastPacketTime) >= SERVER_IDLE_TIMEOUT 129 } 130 131 // NewObfuscatedPacketConn creates a new ObfuscatedPacketConn. 132 func NewObfuscatedPacketConn( 133 conn net.PacketConn, 134 isServer bool, 135 isIETFClient bool, 136 isDecoyClient bool, 137 obfuscationKey string, 138 paddingSeed *prng.Seed) (*ObfuscatedPacketConn, error) { 139 140 oobPacketConn, ok := conn.(ietf_quic.OOBCapablePacketConn) 141 if !ok { 142 return nil, errors.TraceNew("conn must support OOBCapablePacketConn") 143 } 144 145 // There is no replay of obfuscation "encryption", just padding. 146 nonceSeed, err := prng.NewSeed() 147 if err != nil { 148 return nil, errors.Trace(err) 149 } 150 151 packetConn := &ObfuscatedPacketConn{ 152 OOBCapablePacketConn: oobPacketConn, 153 isServer: isServer, 154 isIETFClient: isIETFClient, 155 isDecoyClient: isDecoyClient, 156 peerModes: make(map[string]*peerMode), 157 noncePRNG: prng.NewPRNGWithSeed(nonceSeed), 158 paddingPRNG: prng.NewPRNGWithSeed(paddingSeed), 159 } 160 161 secret := []byte(obfuscationKey) 162 salt := []byte("quic-obfuscation-key") 163 _, err = io.ReadFull( 164 hkdf.New(sha256.New, secret, salt, nil), packetConn.obfuscationKey[:]) 165 if err != nil { 166 return nil, errors.Trace(err) 167 } 168 169 if isDecoyClient { 170 packetConn.decoyPacketCount = int32(packetConn.paddingPRNG.Range( 171 MIN_DECOY_PACKETS, MAX_DECOY_PACKETS)) 172 packetConn.decoyBuffer = make([]byte, MAX_PACKET_SIZE) 173 } 174 175 if isServer { 176 177 packetConn.runWaitGroup = new(sync.WaitGroup) 178 packetConn.stopBroadcast = make(chan struct{}) 179 180 // Reap stale peer mode information to reclaim memory. 181 182 packetConn.runWaitGroup.Add(1) 183 go func() { 184 defer packetConn.runWaitGroup.Done() 185 186 ticker := time.NewTicker(SERVER_IDLE_TIMEOUT / 2) 187 defer ticker.Stop() 188 for { 189 select { 190 case <-ticker.C: 191 packetConn.peerModesMutex.Lock() 192 for address, mode := range packetConn.peerModes { 193 if mode.isStale() { 194 delete(packetConn.peerModes, address) 195 } 196 } 197 packetConn.peerModesMutex.Unlock() 198 case <-packetConn.stopBroadcast: 199 return 200 } 201 } 202 }() 203 } 204 205 return packetConn, nil 206 } 207 208 func (conn *ObfuscatedPacketConn) Close() error { 209 210 // Ensure close channel only called once. 211 if !atomic.CompareAndSwapInt32(&conn.isClosed, 0, 1) { 212 return nil 213 } 214 215 if conn.isServer { 216 close(conn.stopBroadcast) 217 conn.runWaitGroup.Wait() 218 } 219 220 return conn.OOBCapablePacketConn.Close() 221 } 222 223 type temporaryNetError struct { 224 err error 225 } 226 227 func newTemporaryNetError(err error) *temporaryNetError { 228 return &temporaryNetError{err: err} 229 } 230 231 func (e *temporaryNetError) Timeout() bool { 232 return false 233 } 234 235 func (e *temporaryNetError) Temporary() bool { 236 return true 237 } 238 239 func (e *temporaryNetError) Error() string { 240 return e.err.Error() 241 } 242 243 func (conn *ObfuscatedPacketConn) ReadFrom(p []byte) (int, net.Addr, error) { 244 n, _, _, addr, _, err := conn.readPacketWithType(p, nil) 245 // Do not wrap any I/O err returned by conn.OOBCapablePacketConn 246 return n, addr, err 247 } 248 249 func (conn *ObfuscatedPacketConn) WriteTo(p []byte, addr net.Addr) (int, error) { 250 udpAddr, ok := addr.(*net.UDPAddr) 251 if !ok { 252 return 0, errors.TraceNew("unexpected addr type") 253 } 254 n, _, err := conn.writePacket(p, nil, udpAddr) 255 // Do not wrap any I/O err returned by conn.OOBCapablePacketConn 256 return n, err 257 } 258 259 // ReadMsgUDP, and WriteMsgUDP satisfy the ietf_quic.OOBCapablePacketConn 260 // interface. In non-muxListener mode, quic-go will access the 261 // ObfuscatedPacketConn directly and use these functions to set ECN bits. 262 // 263 // ReadBatch implements ietf_quic.batchConn. Providing this implementation 264 // effectively disables the quic-go batch packet reading optimization, which 265 // would otherwise bypass deobfuscation. Note that ipv4.Message is an alias 266 // for x/net/internal/socket.Message and quic-go uses this one type for both 267 // IPv4 and IPv6 packets. 268 // 269 // Read, Write, and RemoteAddr are present to satisfy the net.Conn interface, 270 // to which ObfuscatedPacketConn is converted internally, via quic-go, in 271 // x/net/ipv[4|6] for OOB manipulation. These functions do not need to be 272 // implemented. 273 274 func (conn *ObfuscatedPacketConn) ReadMsgUDP(p, oob []byte) (int, int, int, *net.UDPAddr, error) { 275 n, oobn, flags, addr, _, err := conn.readPacketWithType(p, nil) 276 // Do not wrap any I/O err returned by conn.OOBCapablePacketConn 277 return n, oobn, flags, addr, err 278 } 279 280 func (conn *ObfuscatedPacketConn) WriteMsgUDP(p, oob []byte, addr *net.UDPAddr) (int, int, error) { 281 n, oobn, err := conn.writePacket(p, oob, addr) 282 // Do not wrap any I/O err returned by conn.OOBCapablePacketConn 283 return n, oobn, err 284 } 285 286 func (conn *ObfuscatedPacketConn) ReadBatch(ms []ipv4.Message, _ int) (int, error) { 287 288 // Read a "batch" of 1 message, with any necessary deobfuscation performed 289 // by readPacketWithType. 290 // 291 // TODO: implement proper batch packet reading here, along with batch 292 // deobfuscation. 293 294 if len(ms) < 1 || len(ms[0].Buffers[0]) < 1 { 295 return 0, errors.TraceNew("unexpected message buffer size") 296 } 297 var err error 298 ms[0].N, ms[0].NN, ms[0].Flags, ms[0].Addr, _, err = 299 conn.readPacketWithType(ms[0].Buffers[0], ms[0].OOB) 300 if err != nil { 301 // Do not wrap any I/O err returned by conn.OOBCapablePacketConn 302 return 0, err 303 } 304 return 1, nil 305 } 306 307 var notSupported = std_errors.New("not supported") 308 309 func (conn *ObfuscatedPacketConn) Read(_ []byte) (int, error) { 310 return 0, errors.Trace(notSupported) 311 } 312 313 func (conn *ObfuscatedPacketConn) Write(_ []byte) (int, error) { 314 return 0, errors.Trace(notSupported) 315 } 316 317 func (conn *ObfuscatedPacketConn) RemoteAddr() net.Addr { 318 return nil 319 } 320 321 func (conn *ObfuscatedPacketConn) readPacketWithType( 322 p, oob []byte) (int, int, int, *net.UDPAddr, bool, error) { 323 324 for { 325 n, oobn, flags, addr, isIETF, err := conn.readPacket(p, oob) 326 327 // When enabled, and when a packet is received, sometimes immediately 328 // respond with a decoy packet, which is Sentirely random. Sending a 329 // small number of these packets early in the connection is intended 330 // to frustrate simple traffic fingerprinting which looks for a 331 // certain number of packets client->server, followed by a certain 332 // number of packets server->client, and so on. 333 // 334 // TODO: use a more sophisticated distribution; configure via tactics 335 // parameters; add server-side decoy packet injection. 336 // 337 // See also: 338 // 339 // Tor Project's Sharknado concept: 340 // https://gitlab.torproject.org/legacy/trac/-/issues/30716#note_2326086 341 // 342 // Lantern's OQUIC specification: 343 // https://github.com/getlantern/quicwrapper/blob/master/OQUIC.md 344 if err == nil && conn.isIETFClient && conn.isDecoyClient { 345 count := atomic.LoadInt32(&conn.decoyPacketCount) 346 if count > 0 && conn.paddingPRNG.FlipCoin() { 347 348 if atomic.CompareAndSwapInt32(&conn.decoyPacketCount, count, count-1) { 349 350 packetSize := conn.paddingPRNG.Range( 351 1, getMaxPreDiscoveryPacketSize(addr)) 352 353 // decoyBuffer is all zeros, so the QUIC Fixed Bit is zero. 354 // Ignore any errors when writing decoy packets. 355 _, _ = conn.WriteTo(conn.decoyBuffer[:packetSize], addr) 356 } 357 } 358 } 359 360 // Ignore/drop packets with an invalid QUIC Fixed Bit (see RFC 9000, 361 // Packet Formats). 362 if err == nil && (isIETF || conn.isIETFClient) && n > 0 && (p[0]&0x40) == 0 { 363 continue 364 } 365 366 // Do not wrap any I/O err returned by conn.OOBCapablePacketConn 367 return n, oobn, flags, addr, isIETF, err 368 } 369 } 370 371 func (conn *ObfuscatedPacketConn) readPacket( 372 p, oob []byte) (int, int, int, *net.UDPAddr, bool, error) { 373 374 n, oobn, flags, addr, err := conn.OOBCapablePacketConn.ReadMsgUDP(p, oob) 375 376 // Data is processed even when err != nil, as ReadFrom may return both 377 // a packet and an error, such as io.EOF. 378 // See: https://golang.org/pkg/net/#PacketConn. 379 380 // In client mode, obfuscation is always performed as the client knows it is 381 // using obfuscation. In server mode, DPI is performed to distinguish whether 382 // the QUIC packet for a new flow is obfuscated or not, and whether it's IETF 383 // or gQUIC. The isIETF return value is set only in server mode and is set 384 // only when the function returns no error. 385 386 isObfuscated := true 387 isIETF := true 388 var address string 389 var firstFlowPacket bool 390 var lastPacketTime time.Time 391 392 if n > 0 { 393 394 if conn.isServer { 395 396 // The server handles both plain and obfuscated QUIC packets. 397 // isQUIC performs DPI to determine whether the packet appears to 398 // be QUIC, in which case deobfuscation is not performed. Not all 399 // plain QUIC packets will pass the DPI test, but the initial 400 // packet(s) in a flow are expected to match; so the server 401 // records a peer "mode", referenced by peer address to know when 402 // to skip deobfuscation for later packets. 403 // 404 // It's possible for clients to redial QUIC connections, 405 // transitioning from obfuscated to plain, using the same source 406 // address (IP and port). This is more likely when many clients 407 // are behind NAT. If a packet appears to be QUIC, this will reset 408 // any existing peer "mode" to plain. The obfuscator checks that 409 // its obfuscated packets don't pass the QUIC DPI test. 410 // 411 // TODO: delete peerMode when a packet is a client connection 412 // termination QUIC packet? Will reclaim peerMode memory faster 413 // than relying on reaper. 414 415 lastPacketTime = time.Now() 416 417 // isIETF is not meaningful if not the first packet in a flow and is not 418 // meaningful when first packet is obfuscated. To correctly indicate isIETF 419 // when obfuscated, the isIETFQUICClientHello test is repeated after 420 // deobfuscating the packet. 421 var isQUIC bool 422 isQUIC, isIETF = isQUICClientHello(p[:n]) 423 424 isObfuscated = !isQUIC 425 426 if isObfuscated && isIETF { 427 return n, oobn, flags, addr, false, newTemporaryNetError( 428 errors.Tracef("unexpected isQUIC result")) 429 } 430 431 // Without addr, the mode cannot be determined. 432 if addr == nil { 433 return n, oobn, flags, addr, true, newTemporaryNetError( 434 errors.Tracef("missing addr")) 435 } 436 437 conn.peerModesMutex.Lock() 438 address = addr.String() 439 mode, ok := conn.peerModes[address] 440 if !ok { 441 // This is a new flow. 442 mode = &peerMode{isObfuscated: isObfuscated, isIETF: isIETF} 443 conn.peerModes[address] = mode 444 firstFlowPacket = true 445 } else if mode.isStale() || 446 (isQUIC && (mode.isObfuscated || (mode.isIETF != isIETF))) { 447 // The address for this flow has been seen before, but either (1) it's 448 // stale and not yet reaped; or (2) the client has redialed and switched 449 // from obfuscated to non-obfuscated; or (3) the client has redialed and 450 // switched non-obfuscated gQUIC<-->IETF. These cases are treated like a 451 // new flow. 452 // 453 // Limitation: since the DPI doesn't detect QUIC in post-Hello 454 // non-obfuscated packets, some client redial cases are not identified as 455 // and handled like new flows and the QUIC session will fail. These cases 456 // include the client immediately redialing and switching from 457 // non-obfuscated to obfuscated or switching obfuscated gQUIC<-->IETF. 458 mode.isObfuscated = isObfuscated 459 mode.isIETF = isIETF 460 firstFlowPacket = true 461 } else { 462 isObfuscated = mode.isObfuscated 463 isIETF = mode.isIETF 464 } 465 mode.lastPacketTime = lastPacketTime 466 467 isIETF = mode.isIETF 468 conn.peerModesMutex.Unlock() 469 470 } else { 471 472 isIETF = conn.isIETFClient 473 } 474 475 if isObfuscated { 476 477 // We can use p as a scratch buffer for deobfuscation, and this 478 // avoids allocting a buffer. 479 480 if n < (NONCE_SIZE + 1) { 481 return n, oobn, flags, addr, true, newTemporaryNetError( 482 errors.Tracef("unexpected obfuscated QUIC packet length: %d", n)) 483 } 484 485 cipher, err := chacha20.NewCipher(conn.obfuscationKey[:], p[0:NONCE_SIZE]) 486 if err != nil { 487 return n, oobn, flags, addr, true, errors.Trace(err) 488 } 489 cipher.XORKeyStream(p[NONCE_SIZE:], p[NONCE_SIZE:]) 490 491 // The padding length check allows legacy gQUIC padding to exceed 492 // its 64 byte maximum, as we don't yet know if this is gQUIC or 493 // IETF QUIC. 494 495 paddingLen := int(p[NONCE_SIZE]) 496 if paddingLen > MAX_PADDING_SIZE || paddingLen > n-(NONCE_SIZE+1) { 497 return n, oobn, flags, addr, true, newTemporaryNetError( 498 errors.Tracef("unexpected padding length: %d, %d", paddingLen, n)) 499 } 500 501 n -= (NONCE_SIZE + 1) + paddingLen 502 copy(p[0:n], p[(NONCE_SIZE+1)+paddingLen:n+(NONCE_SIZE+1)+paddingLen]) 503 504 if conn.isServer && firstFlowPacket { 505 isIETF = isIETFQUICClientHello(p[0:n]) 506 507 // When an obfuscated packet looks like neither IETF nor 508 // gQUIC, force it through the IETF code path which will 509 // perform anti-probing check before sending any response 510 // packet. The gQUIC stack may respond with a version 511 // negotiation packet. 512 // 513 // Ensure that mode.isIETF is set to true before returning, 514 // so subsequent packets in the same flow are also forced 515 // through the same anti-probing code path. 516 // 517 // Limitation: the following race condition check is not 518 // consistent with this constraint. This will be resolved by 519 // disabling gQUIC or once gQUIC is ultimatel retired. 520 521 if !isIETF && !isGQUICClientHello(p[0:n]) { 522 isIETF = true 523 } 524 525 conn.peerModesMutex.Lock() 526 mode, ok := conn.peerModes[address] 527 528 // There's a possible race condition between the two instances of locking 529 // peerModesMutex: the client might redial in the meantime. Check that the 530 // mode state is unchanged from when the lock was last held. 531 if !ok || mode.isObfuscated != true || mode.isIETF != false || 532 mode.lastPacketTime != lastPacketTime { 533 conn.peerModesMutex.Unlock() 534 return n, oobn, flags, addr, true, newTemporaryNetError( 535 errors.Tracef("unexpected peer mode")) 536 } 537 538 mode.isIETF = isIETF 539 540 conn.peerModesMutex.Unlock() 541 542 // Enforce the MIN_INITIAL_PACKET_SIZE size requirement for new flows. 543 // 544 // Limitations: 545 // 546 // - The Initial packet may be sent more than once, but we 547 // only check the very first packet. 548 // - For session resumption, the first packet may be a 549 // Handshake packet, not an Initial packet, and can be smaller. 550 551 if isIETF && n < MIN_INITIAL_PACKET_SIZE { 552 return n, oobn, flags, addr, true, newTemporaryNetError(errors.Tracef( 553 "unexpected first QUIC packet length: %d", n)) 554 } 555 } 556 } 557 } 558 559 // Do not wrap any I/O err returned by conn.OOBCapablePacketConn 560 return n, oobn, flags, addr, isIETF, err 561 } 562 563 type obfuscatorBuffer struct { 564 buffer [MAX_PACKET_SIZE]byte 565 } 566 567 var obfuscatorBufferPool = &sync.Pool{ 568 New: func() interface{} { 569 return new(obfuscatorBuffer) 570 }, 571 } 572 573 func (conn *ObfuscatedPacketConn) writePacket( 574 p, oob []byte, addr *net.UDPAddr) (int, int, error) { 575 576 n := len(p) 577 578 isObfuscated := true 579 isIETF := true 580 581 if conn.isServer { 582 583 conn.peerModesMutex.Lock() 584 address := addr.String() 585 mode, ok := conn.peerModes[address] 586 if ok { 587 isObfuscated = mode.isObfuscated 588 isIETF = mode.isIETF 589 } 590 conn.peerModesMutex.Unlock() 591 592 } else { 593 594 isIETF = conn.isIETFClient 595 } 596 597 if isObfuscated { 598 599 if n > MAX_PACKET_SIZE { 600 return 0, 0, newTemporaryNetError(errors.Tracef( 601 "unexpected QUIC packet length: %d", n)) 602 } 603 604 // Note: escape analysis showed a local array escaping to the heap, 605 // so use a buffer pool instead to avoid heap allocation per packet. 606 607 b := obfuscatorBufferPool.Get().(*obfuscatorBuffer) 608 buffer := b.buffer[:] 609 defer obfuscatorBufferPool.Put(b) 610 611 for { 612 613 // Note: this zero-memory pattern is compiler optimized: 614 // https://golang.org/cl/137880043 615 for i := range buffer { 616 buffer[i] = 0 617 } 618 619 nonce := buffer[0:NONCE_SIZE] 620 conn.noncePRNG.Read(nonce) 621 622 maxPadding := getMaxPaddingSize(isIETF, addr, n) 623 624 paddingLen := conn.paddingPRNG.Intn(maxPadding + 1) 625 buffer[NONCE_SIZE] = uint8(paddingLen) 626 627 padding := buffer[(NONCE_SIZE + 1) : (NONCE_SIZE+1)+paddingLen] 628 conn.paddingPRNG.Read(padding) 629 630 copy(buffer[(NONCE_SIZE+1)+paddingLen:], p) 631 dataLen := (NONCE_SIZE + 1) + paddingLen + n 632 633 cipher, err := chacha20.NewCipher(conn.obfuscationKey[:], nonce) 634 if err != nil { 635 return 0, 0, errors.Trace(err) 636 } 637 packet := buffer[NONCE_SIZE:dataLen] 638 cipher.XORKeyStream(packet, packet) 639 640 p = buffer[:dataLen] 641 642 // Don't use obfuscation that looks like QUIC, or the 643 // peer will not treat this packet as obfuscated. 644 isQUIC, _ := isQUICClientHello(p) 645 if !isQUIC { 646 break 647 } 648 } 649 } 650 651 _, oobn, err := conn.OOBCapablePacketConn.WriteMsgUDP(p, oob, addr) 652 653 // quic-go uses OOB to manipulate ECN bits in the IP header; these are not 654 // obfuscated. 655 // 656 // Return n = len(input p) bytes written even when p is an obfuscated 657 // buffer and longer than the input p. 658 659 // Do not wrap any I/O err returned by conn.OOBCapablePacketConn 660 return n, oobn, err 661 } 662 663 func getMaxPreDiscoveryPacketSize(addr net.Addr) int { 664 maxPacketSize := MAX_PRE_DISCOVERY_PACKET_SIZE_IPV4 665 if udpAddr, ok := addr.(*net.UDPAddr); ok && udpAddr.IP.To4() == nil { 666 maxPacketSize = MAX_PRE_DISCOVERY_PACKET_SIZE_IPV6 667 } 668 return maxPacketSize 669 } 670 671 func getMaxPaddingSize(isIETF bool, addr net.Addr, packetSize int) int { 672 673 maxPacketSize := getMaxPreDiscoveryPacketSize(addr) 674 675 maxPadding := 0 676 677 if isIETF { 678 679 // quic-go starts with a maximum packet size of 1280, which is the 680 // IPv6 minimum MTU as well as very commonly supported for IPv4 681 // (quic-go may increase the maximum packet size via MTU discovery). 682 // Do not pad beyond that initial maximum size. As a result, padding 683 // is only added for smaller packets. 684 // OBFUSCATED_PACKET_SIZE_ADJUSTMENT is already factored in via 685 // Client/ServerInitalPacketPaddingAdjustment. 686 687 maxPadding = maxPacketSize - packetSize 688 if maxPadding < 0 { 689 maxPadding = 0 690 } 691 if maxPadding > MAX_PADDING_SIZE { 692 maxPadding = MAX_PADDING_SIZE 693 } 694 695 } else { 696 697 // Legacy gQUIC has a strict maximum packet size of 1280, and legacy 698 // obfuscation adds padding on top of that. 699 700 maxPadding = (maxPacketSize + NONCE_SIZE + 1 + MAX_GQUIC_PADDING_SIZE) - packetSize 701 if maxPadding < 0 { 702 maxPadding = 0 703 } 704 if maxPadding > MAX_GQUIC_PADDING_SIZE { 705 maxPadding = MAX_GQUIC_PADDING_SIZE 706 } 707 } 708 709 return maxPadding 710 } 711 712 func (conn *ObfuscatedPacketConn) serverMaxPacketSizeAdjustment( 713 addr net.Addr) int { 714 715 if !conn.isServer { 716 return 0 717 } 718 719 conn.peerModesMutex.Lock() 720 address := addr.String() 721 mode, ok := conn.peerModes[address] 722 isObfuscated := ok && mode.isObfuscated 723 conn.peerModesMutex.Unlock() 724 725 if isObfuscated { 726 return OBFUSCATED_MAX_PACKET_SIZE_ADJUSTMENT 727 } 728 729 return 0 730 } 731 732 func isQUICClientHello(buffer []byte) (bool, bool) { 733 734 // As this function is called for every packet, it needs to be fast. 735 // 736 // As QUIC header parsing is complex, with many cases, we are not 737 // presently doing that, although this might improve accuracy as we should 738 // be able to identify the precise offset of indicators based on header 739 // values. 740 741 if isIETFQUICClientHello(buffer) { 742 return true, true 743 } else if isGQUICClientHello(buffer) { 744 return true, false 745 } 746 747 return false, false 748 } 749 750 func isGQUICClientHello(buffer []byte) bool { 751 752 // In all currently supported versions, the first client packet contains 753 // the "CHLO" tag at one of the following offsets. The offset can vary for 754 // a single version. 755 // 756 // Note that v44 does not include the "QUIC version" header field in its 757 // first client packet. 758 759 if (len(buffer) >= 33 && 760 buffer[29] == 'C' && 761 buffer[30] == 'H' && 762 buffer[31] == 'L' && 763 buffer[32] == 'O') || 764 (len(buffer) >= 35 && 765 buffer[31] == 'C' && 766 buffer[32] == 'H' && 767 buffer[33] == 'L' && 768 buffer[34] == 'O') || 769 (len(buffer) >= 38 && 770 buffer[34] == 'C' && 771 buffer[35] == 'H' && 772 buffer[36] == 'L' && 773 buffer[37] == 'O') { 774 775 return true 776 } 777 778 return false 779 } 780 781 func isIETFQUICClientHello(buffer []byte) bool { 782 783 // https://tools.ietf.org/html/draft-ietf-quic-transport-23#section-17.2: 784 // 785 // Check 1st nibble of byte 0: 786 // 1... .... = Header Form: Long Header (1) 787 // .1.. .... = Fixed Bit: True 788 // ..00 .... = Packet Type: Initial (0) 789 // 790 // Then check bytes 1..4 for expected version number. 791 792 if len(buffer) < 5 { 793 return false 794 } 795 796 if buffer[0]>>4 != 0x0c { 797 return false 798 } 799 800 // IETF QUIC version 1, RFC 9000 801 802 return buffer[1] == 0 && 803 buffer[2] == 0 && 804 buffer[3] == 0 && 805 buffer[4] == 0x1 806 }