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  }