Skip to content

Commit

Permalink
dialers/desync: on tracert failures, assume max desync ttl
Browse files Browse the repository at this point in the history
  • Loading branch information
ignoramous committed Aug 10, 2024
1 parent 8d7b1d9 commit 2cd475c
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 6 deletions.
2 changes: 1 addition & 1 deletion intra/dialers/rdial.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func desyncIpConnect(d *protect.RDial, proto string, ip netip.Addr, port int) (n
case "tcp", "tcp4", "tcp6":
if !ip.IsPrivate() {
payload := []byte(Http1_1String)
return DialWithSplitAndDesyncSmart(d, netip.AddrPortFrom(ip, uint16(port)), 20 /*some fixed max ttl*/, payload)
return DialWithSplitAndDesyncSmart(d, netip.AddrPortFrom(ip, uint16(port)), payload)
}
return d.DialTCP(proto, nil, tcpaddr(ip, port))
case "udp", "udp4", "udp6":
Expand Down
21 changes: 16 additions & 5 deletions intra/dialers/split_and_desync.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ import (
const (
probeSize = 8
Http1_1String = "POST / HTTP/1.1\r\nHost: 10.0.0.1\r\nContent-Type: application/octet-stream\r\nContent-Length: 9999999\r\n\r\n"

DESYNC_MAX_TTL = 24 // some arbitrary value
DESYNC_NOOP_TTL = DESYNC_MAX_TTL
)

// ttlcache stores the TTL for a given IP address for a limited time.
Expand Down Expand Up @@ -93,9 +96,10 @@ func exceedsTTL(cmsgs []unix.SocketControlMessage) bool {
// If `payload` is smaller than the initial upstream segment, it launches the attack and splits.
// This traceroute is not accurate, because of time limit (TCP handshake).
// Note: The path the UDP packet took to reach the destination may differ from the path the TCP packet took.
func DialWithSplitAndDesyncTraceroute(d *protect.RDial, ipp netip.AddrPort, maxTTL int, payload []byte) (*overwriteSplitter, error) {
func DialWithSplitAndDesyncTraceroute(d *protect.RDial, ipp netip.AddrPort, payload []byte) (*overwriteSplitter, error) {
udpAddr := net.UDPAddrFromAddrPort(ipp)
udpAddr.Port = 1 // unset port
maxTTL := DESYNC_MAX_TTL

isIPv6 := ipp.Addr().Is6()

Expand Down Expand Up @@ -225,6 +229,10 @@ func DialWithSplitAndDesyncTraceroute(d *protect.RDial, ipp netip.AddrPort, maxT
}
}
}
if split1.ttl == 1 {
split1.ttl = DESYNC_NOOP_TTL
}

log.D("split-desync: addr: %v, ttl: %d", ipp, split1.ttl)

return split1, nil
Expand All @@ -248,12 +256,12 @@ func DialWithSplitAndDesyncFixedTtl(d *protect.RDial, addr netip.AddrPort, initi
// DialWithSplitAndDesyncSmart estimates the TTL with UDP traceroute,
// then returns a TCP connection that may launch TCB Desynchronization
// and split the initial upstream segment.
func DialWithSplitAndDesyncSmart(d *protect.RDial, ipp netip.AddrPort, maxTTL int, payload []byte) (DuplexConn, error) {
func DialWithSplitAndDesyncSmart(d *protect.RDial, ipp netip.AddrPort, payload []byte) (DuplexConn, error) {
ttl, ok := ttlcache.Get(ipp.Addr())
if ok {
return DialWithSplitAndDesyncFixedTtl(d, ipp, ttl, payload)
}
conn, err := DialWithSplitAndDesyncTraceroute(d, ipp, maxTTL, payload)
conn, err := DialWithSplitAndDesyncTraceroute(d, ipp, payload)
if err == nil && conn != nil { // go vet (incorrectly) complains about conn being nil when err is nil
ttlcache.Put(ipp.Addr(), conn.ttl)
}
Expand Down Expand Up @@ -309,8 +317,11 @@ func (s *overwriteSplitter) Write(b []byte) (int, error) {
return conn.Write(b)
}

// set `Used` to ensure this code only runs once per conn.
s.used.Store(true)
// set `used` to ensure this code only runs once per conn.
if !s.used.CompareAndSwap(false, true) {
return conn.Write(b)
}

if len(b) <= len(s.payload) {
return conn.Write(b)
}
Expand Down

1 comment on commit 2cd475c

@ignoramous
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#81

Please sign in to comment.