Просмотр исходного кода

Obfuscated QUIC fixes:

- Test entire obfuscated packet to see if it matches QUIC DPI.

- Zero buffer obtained from pool to ensure no chance of
  data cross over.
Rod Hynes 7 лет назад
Родитель
Сommit
4492d3c806
1 измененных файлов с 41 добавлено и 34 удалено
  1. 41 34
      psiphon/common/quic/obfuscator.go

+ 41 - 34
psiphon/common/quic/obfuscator.go

@@ -299,55 +299,62 @@ func (conn *ObfuscatedPacketConn) WriteTo(p []byte, addr net.Addr) (int, error)
 		buffer := b.buffer[:]
 		defer obfuscatorBufferPool.Put(b)
 
-		nonce := buffer[0:NONCE_SIZE]
 		for {
+
+			// Note: this zero-memory pattern is compiler optimized:
+			// https://golang.org/cl/137880043
+			for i := range buffer {
+				buffer[i] = 0
+			}
+
+			nonce := buffer[0:NONCE_SIZE]
 			err := conn.getRandomBytes(nonce)
 			if err != nil {
 				return 0, common.ContextError(err)
 			}
 
-			// Don't use a random nonce that looks like QUIC, or the
-			// peer will not treat this packet as obfuscated.
-			if !isQUIC(buffer[:]) {
-				break
+			// Obfuscated QUIC padding results in packets that exceed the
+			// QUIC max packet size of 1280.
+
+			maxPaddingLen := maxObfuscatedPacketSize - (n + (NONCE_SIZE + 1))
+			if maxPaddingLen < 0 {
+				maxPaddingLen = 0
+			}
+			if maxPaddingLen > MAX_PADDING {
+				maxPaddingLen = MAX_PADDING
 			}
-		}
 
-		// Obfuscated QUIC padding results in packets that exceed the
-		// QUIC max packet size of 1280.
+			paddingLen, err := conn.getRandomPaddingLen(maxPaddingLen)
+			if err != nil {
+				return 0, common.ContextError(err)
+			}
 
-		maxPaddingLen := maxObfuscatedPacketSize - (n + (NONCE_SIZE + 1))
-		if maxPaddingLen < 0 {
-			maxPaddingLen = 0
-		}
-		if maxPaddingLen > MAX_PADDING {
-			maxPaddingLen = MAX_PADDING
-		}
+			buffer[NONCE_SIZE] = uint8(paddingLen)
 
-		paddingLen, err := conn.getRandomPaddingLen(maxPaddingLen)
-		if err != nil {
-			return 0, common.ContextError(err)
-		}
+			padding := buffer[(NONCE_SIZE + 1) : (NONCE_SIZE+1)+paddingLen]
+			err = conn.getRandomBytes(padding)
+			if err != nil {
+				return 0, common.ContextError(err)
+			}
 
-		buffer[NONCE_SIZE] = uint8(paddingLen)
+			copy(buffer[(NONCE_SIZE+1)+paddingLen:], p)
+			dataLen := (NONCE_SIZE + 1) + paddingLen + n
 
-		padding := buffer[(NONCE_SIZE + 1) : (NONCE_SIZE+1)+paddingLen]
-		err = conn.getRandomBytes(padding)
-		if err != nil {
-			return 0, common.ContextError(err)
-		}
+			cipher, err := chacha20.NewCipher(conn.obfuscationKey[:], nonce)
+			if err != nil {
+				return 0, common.ContextError(err)
+			}
+			packet := buffer[NONCE_SIZE:dataLen]
+			cipher.XORKeyStream(packet, packet)
 
-		copy(buffer[(NONCE_SIZE+1)+paddingLen:], p)
-		dataLen := (NONCE_SIZE + 1) + paddingLen + n
+			p = buffer[:dataLen]
 
-		cipher, err := chacha20.NewCipher(conn.obfuscationKey[:], nonce)
-		if err != nil {
-			return 0, common.ContextError(err)
+			// Don't use obfuscation that looks like QUIC, or the
+			// peer will not treat this packet as obfuscated.
+			if !isQUIC(p) {
+				break
+			}
 		}
-		packet := buffer[NONCE_SIZE:dataLen]
-		cipher.XORKeyStream(packet, packet)
-
-		p = buffer[:dataLen]
 	}
 
 	_, err := conn.PacketConn.WriteTo(p, addr)