predict dst ports while accepting too; inject low-TTL SYN instead of using connect

This commit is contained in:
Christian Ulrich 2020-10-08 00:20:54 +02:00
parent 4cf608459f
commit 37f02bc2ba
No known key found for this signature in database
GPG Key ID: 8241BE099775A097
1 changed files with 20 additions and 30 deletions

View File

@ -225,22 +225,6 @@ proc connect*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress,
except OSError as e: except OSError as e:
raise newException(PunchHoleError, e.msg) raise newException(PunchHoleError, e.msg)
proc prepareAccept(attempt: AcceptAttempt) {.async.} =
for dstPort in attempt.dstPorts:
var sock: AsyncSocket
try:
sock = newAsyncSocket()
sock.setSockOpt(OptReuseAddr, true)
sock.getFd.setSockOptInt(IPPROTO_IP, IP_TTL, 2)
sock.bindAddr(attempt.srcPort, $(attempt.srcIp))
let connectFuture = sock.connect($(attempt.dstIp), dstPort)
await connectFuture or sleepAsync(Timeout)
if connectFuture.finished():
echo "connected during accept phase"
except OSError:
discard
sock.close()
proc doAccept(puncher: TcpSyniPuncher, srcIp: IpAddress, proc doAccept(puncher: TcpSyniPuncher, srcIp: IpAddress,
srcPort: Port) {.async.} = srcPort: Port) {.async.} =
let sock = newAsyncSocket() let sock = newAsyncSocket()
@ -281,24 +265,30 @@ proc accept*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress,
if a.dstIp == dstIp and if a.dstIp == dstIp and
a.dstPorts.any(proc (p: Port): bool = p in dstPorts): a.dstPorts.any(proc (p: Port): bool = p in dstPorts):
raise newException(PunchHoleError, "hole punching for given parameters already active") raise newException(PunchHoleError, "hole punching for given parameters already active")
try:
let rawFd = setupTcpInjectingSocket()
let attempt = AcceptAttempt(srcIp: localIp, srcPort: srcPort, dstIp: dstIp, let attempt = AcceptAttempt(srcIp: localIp, srcPort: srcPort, dstIp: dstIp,
dstPorts: dstPorts, seqNums: seqNums, dstPorts: predictPortRange(dstPorts),
seqNums: seqNums,
future: newFuture[AsyncSocket]("accept")) future: newFuture[AsyncSocket]("accept"))
puncher.acceptAttempts.add(attempt) puncher.acceptAttempts.add(attempt)
await attempt.addFirewallRules() await attempt.addFirewallRules()
await attempt.prepareAccept()
try:
let rawFd = setupTcpInjectingSocket()
for dstPort in attempt.dstPorts: for dstPort in attempt.dstPorts:
let synOut = IpPacket(protocol: tcp, ipAddrSrc: attempt.srcIp,
ipAddrDst: attempt.dstIp, ipTTL: 2,
tcpPortSrc: attempt.srcPort, tcpPortDst: dstPort,
tcpSeqNumber: 0, tcpAckNumber: 0, tcpFlags: {SYN},
tcpWindowSize: 1452 * 10)
await rawFd.injectTcpPacket(synOut)
for seqNum in attempt.seqNums: for seqNum in attempt.seqNums:
let ipPacket = IpPacket(protocol: tcp, ipAddrSrc: attempt.dstIp, let synIn = IpPacket(protocol: tcp, ipAddrSrc: attempt.dstIp,
ipAddrDst: attempt.srcIp, ipTTL: 64, ipAddrDst: attempt.srcIp, ipTTL: 64,
tcpPortSrc: dstPort, tcpPortSrc: dstPort,
tcpPortDst: attempt.srcPort, tcpPortDst: attempt.srcPort,
tcpSeqNumber: seqNum, tcpAckNumber: 0, tcpSeqNumber: seqNum, tcpAckNumber: 0,
tcpFlags: {SYN}, tcpWindowSize: 1452 * 10) tcpFlags: {SYN}, tcpWindowSize: 1452 * 10)
echo &"[{ipPacket.ipAddrSrc}:{ipPacket.tcpPortSrc} -> {ipPacket.ipAddrDst}:{ipPacket.tcpPortDst}, SEQ {ipPacket.tcpSeqNumber}] injecting SYN" echo &"[{synIn.ipAddrSrc}:{synIn.tcpPortSrc} -> {synIn.ipAddrDst}:{synIn.tcpPortDst}, SEQ {synIn.tcpSeqNumber}] injecting SYN"
await rawFd.injectTcpPacket(ipPacket) await rawFd.injectTcpPacket(synIn)
closeSocket(rawFd) closeSocket(rawFd)
await attempt.future or sleepAsync(Timeout) await attempt.future or sleepAsync(Timeout)
await attempt.deleteFirewallRules() await attempt.deleteFirewallRules()