refactor: create raw sockets where they are used

This commit is contained in:
Christian Ulrich 2020-10-10 12:30:14 +02:00
parent 9caca83dd6
commit 1116d06e82
No known key found for this signature in database
GPG Key ID: 8241BE099775A097
1 changed files with 33 additions and 33 deletions

View File

@ -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,27 +253,8 @@ proc doAccept(puncher: TcpSyniPuncher, srcIp: IpAddress,
break break
sock.close() sock.close()
proc accept*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress, proc injectSynPackets(attempt: AcceptAttempt) {.async.} =
dstPorts: seq[Port],
seqNums: seq[uint32]): Future[AsyncSocket] {.async.} =
let localIp = getPrimaryIPAddr(dstIp)
let existingAttempts = puncher.findAcceptAttemptsByLocalAddr(localIp, srcPort)
if existingAttempts.len() == 0:
echo &"accepting connections from {dstIp}:{dstPorts[0].int}"
asyncCheck puncher.doAccept(localIp, srcPort)
else:
for a in existingAttempts:
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")
try:
let rawFd = setupTcpInjectingSocket() 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: for dstPort in attempt.dstPorts:
let synOut = IpPacket(protocol: tcp, ipAddrSrc: attempt.srcIp, let synOut = IpPacket(protocol: tcp, ipAddrSrc: attempt.srcIp,
ipAddrDst: attempt.dstIp, ipTTL: 2, ipAddrDst: attempt.dstIp, ipTTL: 2,
@ -295,6 +273,28 @@ proc accept*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress,
echo &"[{synIn.ipAddrSrc}:{synIn.tcpPortSrc} -> {synIn.ipAddrDst}:{synIn.tcpPortDst}, SEQ {synIn.tcpSeqNumber}] injecting incoming SYN" echo &"[{synIn.ipAddrSrc}:{synIn.tcpPortSrc} -> {synIn.ipAddrDst}:{synIn.tcpPortDst}, SEQ {synIn.tcpSeqNumber}] injecting incoming SYN"
await rawFd.injectTcpPacket(synIn) await rawFd.injectTcpPacket(synIn)
closeSocket(rawFd) closeSocket(rawFd)
proc accept*(puncher: TcpSyniPuncher, srcPort: Port, dstIp: IpAddress,
dstPorts: seq[Port],
seqNums: seq[uint32]): Future[AsyncSocket] {.async.} =
let localIp = getPrimaryIPAddr(dstIp)
let existingAttempts = puncher.findAcceptAttemptsByLocalAddr(localIp, srcPort)
if existingAttempts.len() == 0:
echo &"accepting connections from {dstIp}:{dstPorts[0].int}"
asyncCheck puncher.doAccept(localIp, srcPort)
else:
for a in existingAttempts:
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")
try:
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()
await attempt.injectSynPackets()
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))