From 37f02bc2bac260b1e5e0de110f107f1690fcd10a Mon Sep 17 00:00:00 2001 From: Christian Ulrich Date: Thu, 8 Oct 2020 00:20:54 +0200 Subject: [PATCH] predict dst ports while accepting too; inject low-TTL SYN instead of using connect --- tcp_syni.nim | 50 ++++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/tcp_syni.nim b/tcp_syni.nim index bce5907..e74e6b3 100644 --- a/tcp_syni.nim +++ b/tcp_syni.nim @@ -225,22 +225,6 @@ proc connect*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress, except OSError as e: 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, srcPort: Port) {.async.} = let sock = newAsyncSocket() @@ -281,24 +265,30 @@ proc accept*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress, if a.dstIp == dstIp and a.dstPorts.any(proc (p: Port): bool = p in dstPorts): raise newException(PunchHoleError, "hole punching for given parameters already active") - let attempt = AcceptAttempt(srcIp: localIp, srcPort: srcPort, dstIp: dstIp, - dstPorts: dstPorts, seqNums: seqNums, - future: newFuture[AsyncSocket]("accept")) - puncher.acceptAttempts.add(attempt) - await attempt.addFirewallRules() - await attempt.prepareAccept() try: let rawFd = setupTcpInjectingSocket() + let attempt = AcceptAttempt(srcIp: localIp, srcPort: srcPort, dstIp: dstIp, + dstPorts: predictPortRange(dstPorts), + seqNums: seqNums, + future: newFuture[AsyncSocket]("accept")) + puncher.acceptAttempts.add(attempt) + await attempt.addFirewallRules() 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: - let ipPacket = IpPacket(protocol: tcp, ipAddrSrc: attempt.dstIp, - ipAddrDst: attempt.srcIp, ipTTL: 64, - tcpPortSrc: dstPort, - tcpPortDst: attempt.srcPort, - tcpSeqNumber: seqNum, tcpAckNumber: 0, - tcpFlags: {SYN}, tcpWindowSize: 1452 * 10) - echo &"[{ipPacket.ipAddrSrc}:{ipPacket.tcpPortSrc} -> {ipPacket.ipAddrDst}:{ipPacket.tcpPortDst}, SEQ {ipPacket.tcpSeqNumber}] injecting SYN" - await rawFd.injectTcpPacket(ipPacket) + let synIn = IpPacket(protocol: tcp, ipAddrSrc: attempt.dstIp, + ipAddrDst: attempt.srcIp, ipTTL: 64, + tcpPortSrc: dstPort, + tcpPortDst: attempt.srcPort, + tcpSeqNumber: seqNum, tcpAckNumber: 0, + tcpFlags: {SYN}, tcpWindowSize: 1452 * 10) + echo &"[{synIn.ipAddrSrc}:{synIn.tcpPortSrc} -> {synIn.ipAddrDst}:{synIn.tcpPortDst}, SEQ {synIn.tcpSeqNumber}] injecting SYN" + await rawFd.injectTcpPacket(synIn) closeSocket(rawFd) await attempt.future or sleepAsync(Timeout) await attempt.deleteFirewallRules()