[Pkg-privacy-commits] [obfs4proxy] 56/151: Add support for IAT obfuscation (disabled by default).

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 12:59:38 UTC 2015


This is an automated email from the git hooks/post-receive script.

infinity0 pushed a commit to branch master
in repository obfs4proxy.

commit e77ddddf4d10dbd3387c2e4714c287c546c70512
Author: Yawning Angel <yawning at schwanenlied.me>
Date:   Fri May 23 05:23:36 2014 +0000

    Add support for IAT obfuscation (disabled by default).
    
    When enabled, inter-packet delay will be randomized between 0 and 10
    ms in 100 usec intervals.  As experiences from ScrambleSuit (and back
    of the envelope math based on how networks work) show, this is
    extremely expensive and artificially limits the throughput of the link.
    
    When enabled, bulk transfer throughput will be limited to an average of
    278 KiB/s.
---
 obfs4.go                 | 54 ++++++++++++++++++++++++++++++++++++++++--------
 obfs4proxy/obfs4proxy.go |  7 +++++--
 packet.go                |  3 +++
 3 files changed, 53 insertions(+), 11 deletions(-)

diff --git a/obfs4.go b/obfs4.go
index f32c222..3bbccb3 100644
--- a/obfs4.go
+++ b/obfs4.go
@@ -50,6 +50,8 @@ const (
 
 	maxCloseDelayBytes = maxHandshakeLength
 	maxCloseDelay      = 60
+
+	maxIatDelay        = 100
 )
 
 type connState int
@@ -67,6 +69,7 @@ type Obfs4Conn struct {
 	conn net.Conn
 
 	lenProbDist *wDist
+	iatProbDist *wDist
 
 	encoder *framing.Encoder
 	decoder *framing.Decoder
@@ -444,13 +447,38 @@ func (c *Obfs4Conn) Write(b []byte) (n int, err error) {
 		return 0, err
 	}
 
-	// Send the frame(s).
-	_, err = c.conn.Write(frameBuf.Bytes())
-	if err != nil {
-		// Partial writes are fatal because the frame encoder state is advanced
-		// at this point.  It's possible to keep frameBuf around, but fuck it.
-		// Someone that wants write timeouts can change this.
-		return 0, err
+	// Spit frame(s) onto the network.
+	//
+	// Partial writes are fatal because the frame encoder state is advanced
+	// at this point.  It's possible to keep frameBuf around, but fuck it.
+	// Someone that wants write timeouts can change this.
+	if c.iatProbDist != nil {
+		var iatFrame [framing.MaximumSegmentLength]byte
+		for frameBuf.Len() > 0 {
+			iatWrLen := 0
+			iatWrLen, err = frameBuf.Read(iatFrame[:])
+			if err != nil {
+				return 0, err
+			} else if iatWrLen == 0 {
+				panic(fmt.Sprintf("BUG: Write(), iat length was 0"))
+			}
+
+			// Calculate the delay.  The delay resolution is 100 usec, leading
+			// to a maximum delay of 10 msec.
+			iatDelta := time.Duration(c.iatProbDist.sample() * 100)
+
+			// Write then sleep.
+			_, err = c.conn.Write(iatFrame[:iatWrLen])
+			if err != nil {
+				return 0, err
+			}
+		    time.Sleep(iatDelta * time.Microsecond)
+		}
+	} else {
+		_, err = c.conn.Write(frameBuf.Bytes())
+		if err != nil {
+			return 0, err
+		}
 	}
 
 	return
@@ -508,7 +536,7 @@ func (c *Obfs4Conn) SetWriteDeadline(t time.Time) error {
 // DialObfs4 connects to the remote address on the network, and handshakes with
 // the peer's obfs4 Node ID and Identity Public Key.  nodeID and publicKey are
 // expected as strings containing the Base64 encoded values.
-func DialObfs4(network, address, nodeID, publicKey string) (*Obfs4Conn, error) {
+func DialObfs4(network, address, nodeID, publicKey string, iatObfuscation bool) (*Obfs4Conn, error) {
 	// Decode the node_id/public_key.
 	pub, err := ntor.PublicKeyFromBase64(publicKey)
 	if err != nil {
@@ -528,6 +556,9 @@ func DialObfs4(network, address, nodeID, publicKey string) (*Obfs4Conn, error) {
 	// Connect to the peer.
 	c := new(Obfs4Conn)
 	c.lenProbDist = newWDist(seed, 0, framing.MaximumSegmentLength)
+	if iatObfuscation {
+		c.iatProbDist = newWDist(seed, 0, maxIatDelay)
+	}
 	c.conn, err = net.Dial(network, address)
 	if err != nil {
 		return nil, err
@@ -554,6 +585,7 @@ type Obfs4Listener struct {
 	nodeID  *ntor.NodeID
 
 	seed *DrbgSeed
+	iatObfuscation bool
 
 	closeDelayBytes int
 	closeDelay      int
@@ -587,6 +619,9 @@ func (l *Obfs4Listener) AcceptObfs4() (*Obfs4Conn, error) {
 	cObfs.isServer = true
 	cObfs.listener = l
 	cObfs.lenProbDist = newWDist(l.seed, 0, framing.MaximumSegmentLength)
+	if l.iatObfuscation {
+		cObfs.iatProbDist = newWDist(l.seed, 0, maxIatDelay)
+	}
 	if err != nil {
 		c.Close()
 		return nil, err
@@ -629,7 +664,7 @@ func (l *Obfs4Listener) NodeID() string {
 // ListenObfs4 annnounces on the network and address, and returns and
 // Obfs4Listener. nodeId, privateKey and seed are expected as strings
 // containing the Base64 encoded values.
-func ListenObfs4(network, laddr, nodeID, privateKey, seed string) (*Obfs4Listener, error) {
+func ListenObfs4(network, laddr, nodeID, privateKey, seed string, iatObfuscation bool) (*Obfs4Listener, error) {
 	var err error
 
 	// Decode node_id/private_key.
@@ -655,6 +690,7 @@ func ListenObfs4(network, laddr, nodeID, privateKey, seed string) (*Obfs4Listene
 	rng := rand.New(newHashDrbg(l.seed))
 	l.closeDelayBytes = rng.Intn(maxCloseDelayBytes)
 	l.closeDelay = rng.Intn(maxCloseDelay)
+	l.iatObfuscation = iatObfuscation
 
 	// Start up the listener.
 	l.listener, err = net.Listen(network, laddr)
diff --git a/obfs4proxy/obfs4proxy.go b/obfs4proxy/obfs4proxy.go
index 3ad8785..86589bb 100644
--- a/obfs4proxy/obfs4proxy.go
+++ b/obfs4proxy/obfs4proxy.go
@@ -70,6 +70,7 @@ const (
 )
 
 var unsafeLogging bool
+var iatObfuscation bool
 var ptListeners []net.Listener
 
 // When a connection handler starts, +1 is written to this channel; when it
@@ -194,7 +195,7 @@ func serverSetup() bool {
 
 			// Initialize the listener.
 			ln, err := obfs4.ListenObfs4("tcp", bindaddr.Addr.String(), nodeID,
-				privateKey, seed)
+				privateKey, seed, iatObfuscation)
 			if err != nil {
 				pt.SmethodError(bindaddr.MethodName, err.Error())
 				break
@@ -249,7 +250,8 @@ func clientHandler(conn *pt.SocksConn) error {
 	}()
 
 	defer logAndRecover(nil)
-	remote, err := obfs4.DialObfs4("tcp", conn.Req.Target, nodeID, publicKey)
+	remote, err := obfs4.DialObfs4("tcp", conn.Req.Target, nodeID, publicKey,
+		iatObfuscation)
 	if err != nil {
 		log.Printf("[ERROR] client: %p: Handshake failed: %s", remote, err)
 		conn.Reject()
@@ -395,6 +397,7 @@ func main() {
 	// Some command line args.
 	genParams := flag.String("genServerParams", "", "Generate server params given a bridge fingerprint.")
 	doLogging := flag.Bool("enableLogging", false, "Log to TOR_PT_STATE_LOCATION/obfs4proxy.log")
+	flag.BoolVar(&iatObfuscation, "iatObfuscation", false, "Enable IAT obufscation (EXPENSIVE)")
 	flag.BoolVar(&unsafeLogging, "unsafeLogging", false, "Disable the address scrubber")
 	flag.Parse()
 	if *genParams != "" {
diff --git a/packet.go b/packet.go
index 4112c9b..78f6697 100644
--- a/packet.go
+++ b/packet.go
@@ -181,6 +181,9 @@ func (c *Obfs4Conn) consumeFramedPackets(w io.Writer) (n int, err error) {
 					break
 				}
 				c.lenProbDist.reset(seed)
+				if c.iatProbDist != nil {
+					c.iatProbDist.reset(seed)
+				}
 			}
 		default:
 			// Ignore unrecognised packet types.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/obfs4proxy.git



More information about the Pkg-privacy-commits mailing list