2020-10-14 20:52:20 +02:00
|
|
|
import asyncdispatch, asyncnet, strformat
|
|
|
|
from net import IpAddress, Port, `$`, `==`
|
2020-10-23 01:15:37 +02:00
|
|
|
import message
|
2020-10-15 19:20:44 +02:00
|
|
|
import port_prediction
|
2020-10-14 20:52:20 +02:00
|
|
|
import puncher
|
|
|
|
import utils
|
|
|
|
|
2020-10-23 01:15:37 +02:00
|
|
|
export Puncher, Responder, PunchHoleError, cleanup, respond
|
2020-10-14 20:52:20 +02:00
|
|
|
|
|
|
|
type
|
2020-10-23 01:15:37 +02:00
|
|
|
TcpNutssResponder* = ref object of Responder
|
|
|
|
|
|
|
|
Request = object
|
2020-10-14 20:52:20 +02:00
|
|
|
dstIp: IpAddress
|
|
|
|
dstPorts: seq[Port]
|
2020-10-23 01:15:37 +02:00
|
|
|
srcIp: IpAddress
|
|
|
|
srcPorts: seq[Port]
|
|
|
|
extraData: string
|
2020-10-14 20:52:20 +02:00
|
|
|
|
2020-10-23 01:15:37 +02:00
|
|
|
method cleanup*(puncher: TcpNutssResponder) {.async.} =
|
2020-10-15 19:52:28 +02:00
|
|
|
discard
|
2020-10-14 20:52:20 +02:00
|
|
|
|
|
|
|
proc initTcpNutssResponder*(): TcpNutssResponder =
|
|
|
|
TcpNutssResponder()
|
|
|
|
|
|
|
|
proc connect(srcIp: IpAddress, srcPort: Port, dstIp: IpAddress, dstPort: Port,
|
|
|
|
future: Future[AsyncSocket]) {.async.} =
|
|
|
|
let sock = newAsyncSocket()
|
|
|
|
sock.setSockOpt(OptReuseAddr, true)
|
|
|
|
echo &"connect {srcIp}:{srcPort} -> {dstIp}:{dstPort}"
|
|
|
|
sock.bindAddr(srcPort, $srcIp)
|
|
|
|
try:
|
|
|
|
await sock.connect($dstIp, dstPort)
|
|
|
|
future.complete(sock)
|
|
|
|
except OSError as e:
|
|
|
|
echo &"connection {srcIP}:{srcPort.int} -> {dstIp}:{dstPort.int} failed: ", e.msg
|
|
|
|
sock.close()
|
|
|
|
|
2020-10-23 01:15:37 +02:00
|
|
|
method respond*(puncher: TcpNutssResponder, args: string): Future[AsyncSocket] {.async.} =
|
|
|
|
let req = parseMessage[Request](args)
|
|
|
|
let localIp = getPrimaryIPAddr(req.dstIp)
|
2020-10-14 20:52:20 +02:00
|
|
|
try:
|
|
|
|
let connectFuture = newFuture[AsyncSocket]("respond")
|
2020-10-23 01:15:37 +02:00
|
|
|
let portRange = predictPortRange(req.dstPorts)
|
2020-10-15 19:20:44 +02:00
|
|
|
for dstPort in portRange:
|
2020-10-23 01:15:37 +02:00
|
|
|
asyncCheck connect(localIp, req.srcPorts[0], req.dstIp, req.dstPorts[0],
|
|
|
|
connectFuture)
|
2020-10-14 20:52:20 +02:00
|
|
|
await connectFuture or sleepAsync(Timeout)
|
|
|
|
if connectFuture.finished():
|
|
|
|
result = connectFuture.read()
|
|
|
|
else:
|
|
|
|
raise newException(PunchHoleError, "timeout")
|
|
|
|
except OSError as e:
|
|
|
|
raise newException(PunchHoleError, e.msg)
|