refactor: create raw sockets where they are used
This commit is contained in:
parent
9caca83dd6
commit
1116d06e82
66
tcp_syni.nim
66
tcp_syni.nim
|
@ -94,13 +94,13 @@ proc injectTcpPacket(rawFd: AsyncFD, ipPacket: IpPacket) {.async.} =
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise newException(PunchHoleError, e.msg)
|
raise newException(PunchHoleError, e.msg)
|
||||||
|
|
||||||
proc captureSeqNumbers(attempt: ConnectAttempt, rawFd: AsyncFD,
|
proc captureSeqNumbers(attempt: ConnectAttempt, cb: PunchProgressCb) {.async.} =
|
||||||
cb: PunchProgressCb) {.async.} =
|
|
||||||
# FIXME: timeout?
|
# FIXME: timeout?
|
||||||
# FIXME: create raw socket here
|
let iface = fromIpAddress(attempt.srcIp)
|
||||||
|
let captureFd = setupEthernetCapturingSocket(iface)
|
||||||
var seqNums = newSeq[uint32]()
|
var seqNums = newSeq[uint32]()
|
||||||
while seqNums.len < attempt.dstPorts.len:
|
while seqNums.len < attempt.dstPorts.len:
|
||||||
let packet = await rawFd.recv(4000)
|
let packet = await captureFd.recv(4000)
|
||||||
if packet == "":
|
if packet == "":
|
||||||
break
|
break
|
||||||
let parsed = parseEthernetPacket(packet)
|
let parsed = parseEthernetPacket(packet)
|
||||||
|
@ -113,12 +113,13 @@ proc captureSeqNumbers(attempt: ConnectAttempt, rawFd: AsyncFD,
|
||||||
if parsed.tcpPortDst.int == port.int:
|
if parsed.tcpPortDst.int == port.int:
|
||||||
seqNums.add(parsed.tcpSeqNumber)
|
seqNums.add(parsed.tcpSeqNumber)
|
||||||
break
|
break
|
||||||
closeSocket(rawFd)
|
closeSocket(captureFd)
|
||||||
await cb(seqNums)
|
await cb(seqNums)
|
||||||
|
|
||||||
proc captureAndResendAck(attempt: ConnectAttempt, captureFd: AsyncFD,
|
proc captureAndResendAck(attempt: ConnectAttempt) {.async.} =
|
||||||
injectFd: AsyncFD) {.async.} =
|
let iface = fromIpAddress(attempt.srcIp)
|
||||||
# FIXME: create raw socket here
|
let captureFd = setupEthernetCapturingSocket(iface)
|
||||||
|
let injectFd = setupTcpInjectingSocket()
|
||||||
block loops:
|
block loops:
|
||||||
while true:
|
while true:
|
||||||
let packet = await captureFd.recv(4000)
|
let packet = await captureFd.recv(4000)
|
||||||
|
@ -208,12 +209,8 @@ proc connect*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress,
|
||||||
dstPorts: predictPortRange(dstPorts))
|
dstPorts: predictPortRange(dstPorts))
|
||||||
puncher.connectAttempts.add(attempt)
|
puncher.connectAttempts.add(attempt)
|
||||||
await attempt.addFirewallRules()
|
await attempt.addFirewallRules()
|
||||||
let iface = fromIpAddress(attempt.srcIp)
|
asyncCheck attempt.captureSeqNumbers(progressCb)
|
||||||
let captureSeqFd = setupEthernetCapturingSocket(iface)
|
asyncCheck attempt.captureAndResendAck()
|
||||||
let captureAckFd = setupEthernetCapturingSocket(iface)
|
|
||||||
let injectAckFd = setupTcpInjectingSocket()
|
|
||||||
asyncCheck attempt.captureSeqNumbers(captureSeqFd, progressCb)
|
|
||||||
asyncCheck attempt.captureAndResendAck(captureAckFd, injectAckFd)
|
|
||||||
try:
|
try:
|
||||||
let connectFuture = newFuture[AsyncSocket]("connect")
|
let connectFuture = newFuture[AsyncSocket]("connect")
|
||||||
for dstPort in attempt.dstPorts:
|
for dstPort in attempt.dstPorts:
|
||||||
|
@ -256,6 +253,27 @@ proc doAccept(puncher: TcpSyniPuncher, srcIp: IpAddress,
|
||||||
break
|
break
|
||||||
sock.close()
|
sock.close()
|
||||||
|
|
||||||
|
proc injectSynPackets(attempt: AcceptAttempt) {.async.} =
|
||||||
|
let rawFd = setupTcpInjectingSocket()
|
||||||
|
for dstPort in attempt.dstPorts:
|
||||||
|
let synOut = IpPacket(protocol: tcp, ipAddrSrc: attempt.srcIp,
|
||||||
|
ipAddrDst: attempt.dstIp, ipTTL: 2,
|
||||||
|
tcpPortSrc: attempt.srcPort, tcpPortDst: dstPort,
|
||||||
|
tcpSeqNumber: rand(uint32), tcpAckNumber: 0,
|
||||||
|
tcpFlags: {SYN}, tcpWindowSize: 1452 * 10)
|
||||||
|
echo &"[{synOut.ipAddrSrc}:{synOut.tcpPortSrc} -> {synOut.ipAddrDst}:{synOut.tcpPortDst}, SEQ {synOut.tcpSeqNumber}] injecting outgoing SYN"
|
||||||
|
await rawFd.injectTcpPacket(synOut)
|
||||||
|
for seqNum in attempt.seqNums:
|
||||||
|
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 incoming SYN"
|
||||||
|
await rawFd.injectTcpPacket(synIn)
|
||||||
|
closeSocket(rawFd)
|
||||||
|
|
||||||
proc accept*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress,
|
proc accept*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress,
|
||||||
dstPorts: seq[Port],
|
dstPorts: seq[Port],
|
||||||
seqNums: seq[uint32]): Future[AsyncSocket] {.async.} =
|
seqNums: seq[uint32]): Future[AsyncSocket] {.async.} =
|
||||||
|
@ -270,31 +288,13 @@ proc accept*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress,
|
||||||
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:
|
try:
|
||||||
let rawFd = setupTcpInjectingSocket()
|
|
||||||
let attempt = AcceptAttempt(srcIp: localIp, srcPort: srcPort, dstIp: dstIp,
|
let attempt = AcceptAttempt(srcIp: localIp, srcPort: srcPort, dstIp: dstIp,
|
||||||
dstPorts: predictPortRange(dstPorts),
|
dstPorts: predictPortRange(dstPorts),
|
||||||
seqNums: seqNums,
|
seqNums: seqNums,
|
||||||
future: newFuture[AsyncSocket]("accept"))
|
future: newFuture[AsyncSocket]("accept"))
|
||||||
puncher.acceptAttempts.add(attempt)
|
puncher.acceptAttempts.add(attempt)
|
||||||
await attempt.addFirewallRules()
|
await attempt.addFirewallRules()
|
||||||
for dstPort in attempt.dstPorts:
|
await attempt.injectSynPackets()
|
||||||
let synOut = IpPacket(protocol: tcp, ipAddrSrc: attempt.srcIp,
|
|
||||||
ipAddrDst: attempt.dstIp, ipTTL: 2,
|
|
||||||
tcpPortSrc: attempt.srcPort, tcpPortDst: dstPort,
|
|
||||||
tcpSeqNumber: rand(uint32), tcpAckNumber: 0,
|
|
||||||
tcpFlags: {SYN}, tcpWindowSize: 1452 * 10)
|
|
||||||
echo &"[{synOut.ipAddrSrc}:{synOut.tcpPortSrc} -> {synOut.ipAddrDst}:{synOut.tcpPortDst}, SEQ {synOut.tcpSeqNumber}] injecting outgoing SYN"
|
|
||||||
await rawFd.injectTcpPacket(synOut)
|
|
||||||
for seqNum in attempt.seqNums:
|
|
||||||
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 incoming SYN"
|
|
||||||
await rawFd.injectTcpPacket(synIn)
|
|
||||||
closeSocket(rawFd)
|
|
||||||
await attempt.future or sleepAsync(Timeout)
|
await attempt.future or sleepAsync(Timeout)
|
||||||
await attempt.deleteFirewallRules()
|
await attempt.deleteFirewallRules()
|
||||||
puncher.acceptAttempts.del(puncher.acceptAttempts.find(attempt))
|
puncher.acceptAttempts.del(puncher.acceptAttempts.find(attempt))
|
||||||
|
|
Loading…
Reference in New Issue