adapt punchd messages to README

This commit is contained in:
Christian Ulrich 2020-10-22 00:22:11 +02:00
parent 239ddd64b1
commit 0f21a63a81
No known key found for this signature in database
GPG Key ID: 8241BE099775A097
5 changed files with 86 additions and 74 deletions

View File

@ -94,10 +94,10 @@ progress|ID|TECHNIQUE|IP_FROM|PORTS_FROM|IP_TO|PORTS_TO|EXTRA_ARGS
error|ID|ERROR_MSG
```
The fields in the "progress" message are the same that can be found in "respond"
message described above. This is because the application is expected to forward
them to the other peer through the rendezvous server so the other peer can call
"respond" on its ``punchd`` instance.
The fields in the "progress" message are the same that can be found in the
"respond" message described above. This is because the application is expected
to forward them to the other peer through the rendezvous server so the other
peer can call "respond" on its ``punchd`` instance.
## Example

View File

@ -41,12 +41,12 @@ type
NotifyPeer* = object
sender: string
recipient: string
command: string
technique: string
srcIp: IpAddress
srcPorts: seq[Port]
dstIp: IpAddress
dstPorts: seq[Port]
#seqNumbers: seq[uint32]
extraArgs: string
# Exceptions
PunchdError = object of ValueError # FIXME: not used yet
@ -141,15 +141,14 @@ proc handlePeerNotifications(serverConn: ServerConnection,
echo "received message from ", msg.sender
let srcPorts = msg.srcPorts.join(",")
let dstPorts = msg.dstPorts.join(",")
#let seqNumbers = msg.seqNumbers.join(",")
let req = &"{msg.srcIp}|{srcPorts}|{msg.dstIp}|{dstPorts}"
let req = &"{msg.srcIp}|{srcPorts}|{msg.dstIp}|{dstPorts}|{msg.extraData}"
asyncCheck acceptConnection(punchdConn, msg.command, req)
except ValueError as e:
echo e.msg
discard
proc punchHole(punchdConn: PunchdConnection, serverConn: ServerConnection,
peerId: string, otherPeerId: string):
peerId: string, otherPeerId: string, technique: string):
Future[AsyncSocket] {.async.} =
let sResp = await serverConn.sendRequest("get-peerinfo", otherPeerId)
let peerInfo = parseMessage[OkGetPeerinfo](sResp)
@ -164,8 +163,8 @@ proc punchHole(punchdConn: PunchdConnection, serverConn: ServerConnection,
future.fail(e)
let myPorts = serverConn.publicPorts.join(",")
let peerPorts = peerInfo.ports.join(",")
let req = &"{serverConn.publicIp}|{myPorts}|{peerInfo.ip}|{peerPorts}"
let pResp = await punchdConn.sendRequest("tcp-nutss-initiate", req, progressCb)
let req = &"{technique}|{serverConn.publicIp}|{myPorts}|{peerInfo.ip}|{peerPorts}"
let pResp = await punchdConn.sendRequest("initiate", req, progressCb)
result = pResp.sock
proc initServerConnection(serverHostname: string, serverPort: Port,
@ -239,7 +238,8 @@ proc runApp(serverHostname: string, serverPort: Port, peerId: string,
var serverConn = await initServerConnection(serverHostname, serverPort,
srcPort)
asyncCheck handleServerMessages(serverConn)
let sock = await punchHole(punchdConn, serverConn, peerId, otherPeerId)
let sock = await punchHole(punchdConn, serverConn, peerId, otherPeerId,
"tcp-nutss")
echo "connected!"
await sock.send("ping")
let msg = await sock.recv(4)

View File

@ -3,8 +3,8 @@ from nativesockets import Domain, SockType, Protocol
from net import IpAddress, Port, `$`
import asyncutils
import message
import tcp_syni_connect
import tcp_syni_accept
import tcp_syni_initiator
import tcp_syni_responder
import tcp_nutss_initiator
import tcp_nutss_responder
@ -14,38 +14,39 @@ from nativesockets import setSockOptInt
type
Punchd = ref object
unixSocket: AsyncSocket
tcpSyniCP: TcpSyniConnectPuncher
tcpSyniAP: TcpSyniAcceptPuncher
tcpSyniInitiator: TcpSyniInitiator
tcpSyniResponder: TcpSyniResponder
tcpNutssInitiator: TcpNutssInitiator
tcpNutssResponder: TcpNutssResponder
Sigint = object of CatchableError
# Requests
TcpSyniConnect = object
InitiateTcpSyni = object
srcIp: IpAddress
srcPorts: seq[Port]
dstIp: IpAddress
dstPorts: seq[Port]
TcpSyniAccept = object
RespondTcpSyni = object
dstIp: IpAddress
dstPorts: seq[Port]
srcIp: IpAddress
srcPorts: seq[Port]
seqNums: seq[uint32]
TcpNutssInitiate = object
InitiateTcpNutss = object
srcIp: IpAddress
srcPorts: seq[Port]
dstIp: IpAddress
dstPorts: seq[Port]
TcpNutssRespond = object
RespondTcpNutss = object
dstIp: IpAddress
dstPorts: seq[Port]
srcIp: IpAddress
srcPorts: seq[Port]
extraData: string
const PunchdSocket = "/tmp/punchd.socket"
@ -63,41 +64,52 @@ proc handleRequest(punchd: Punchd, line: string,
var id: string
var sock: AsyncSocket
try:
let args = line.parseArgs(3)
let args = line.parseArgs(4)
id = args[1]
case args[0]:
of "tcp-syni-connect":
let req = parseMessage[TcpSyniConnect](args[2])
proc progress(seqNumbers: seq[uint32]) {.async.} =
echo "progress! seqNumbers: ", seqNumbers
let content = @["tcp-syni-accept", $req.srcIp, req.srcPorts.join(","),
$req.dstIp, req.dstPorts.join(","),
seqNumbers.join(",")].join("|")
await sendToClient(unixSock, &"progress|{id}|{content}\n")
sock = await punchd.tcpSyniCP.connect(req.srcPorts[0], req.dstIp,
req.dstPorts, progress)
of "initiate":
case args[2]:
of "tcp-syni":
let req = parseMessage[InitiateTcpSyni](args[3])
proc progress(seqNumbers: seq[uint32]) {.async.} =
echo "progress! seqNumbers: ", seqNumbers
let content = @["tcp-syni", $req.srcIp, req.srcPorts.join(","),
$req.dstIp, req.dstPorts.join(","),
seqNumbers.join(",")].join("|")
await sendToClient(unixSock, &"progress|{id}|{content}\n")
sock = await punchd.tcpSyniInitiator.initiate(req.srcPorts[0], req.dstIp,
req.dstPorts, progress)
of "tcp-syni-accept":
let req = parseMessage[TcpSyniAccept](args[2])
sock = await punchd.tcpSyniAP.accept(req.srcPorts[0], req.dstIp,
req.dstPorts, req.seqNums)
of "tcp-nutss":
let req = parseMessage[InitiateTcpNutss](args[3])
proc progress() {.async.} =
echo "progress!"
let content = @["tcp-nutss", $req.srcIp, req.srcPorts.join(","),
$req.dstIp, req.dstPorts.join(",")].join("|")
await sendToClient(unixSock, &"progress|{id}|{content}\n")
sock = await punchd.tcpNutssInitiator.initiate(req.srcPorts[0], req.dstIp,
req.dstPorts, progress)
of "tcp-nutss-initiate":
let req = parseMessage[TcpNutssInitiate](args[2])
proc progress() {.async.} =
echo "progress!"
let content = @["tcp-nutss-respond", $req.srcIp, req.srcPorts.join(","),
$req.dstIp, req.dstPorts.join(",")].join("|")
await sendToClient(unixSock, &"progress|{id}|{content}\n")
sock = await punchd.tcpNutssInitiator.initiate(req.srcPorts[0], req.dstIp,
req.dstPorts, progress)
else:
raise newException(ValueError, "invalid request")
of "respond":
case args[2]:
of "tcp-syni":
let req = parseMessage[RespondTcpSyni](args[3])
sock = await punchd.tcpSyniResponder.respond(req.srcPorts[0], req.dstIp,
req.dstPorts, req.seqNums)
of "tcp-nutss":
let req = parseMessage[RespondTcpNutss](args[3])
sock = await punchd.tcpNutssResponder.respond(req.srcPorts[0],
req.dstIp, req.dstPorts)
else:
raise newException(ValueError, "invalid request")
of "tcp-nutss-respond":
let req = parseMessage[TcpNutssRespond](args[2])
sock = await punchd.tcpNutssResponder.respond(req.srcPorts[0], req.dstIp,
req.dstPorts)
else:
raise newException(ValueError, "invalid request")
@ -134,8 +146,8 @@ proc main() =
{fpUserRead, fpUserWrite, fpGroupRead, fpGroupWrite,
fpOthersRead, fpOthersWrite})
let punchd = Punchd(unixSocket: unixSocket,
tcpSyniCP: initTcpSyniConnectPuncher(),
tcpSyniAP: initTcpSyniAcceptPuncher(),
tcpSyniInitiator: initTcpSyniInitiator(),
tcpSyniResponder: initTcpSyniResponder(),
tcpNutssInitiator: initTcpNutssInitiator(),
tcpNutssResponder: initTcpNutssResponder())
asyncCheck handleUsers(punchd)
@ -143,8 +155,8 @@ proc main() =
runForever()
except Sigint:
waitFor punchd.tcpSyniCP.cleanup()
waitFor punchd.tcpSyniAP.cleanup()
waitFor punchd.tcpSyniInitiator.cleanup()
waitFor punchd.tcpSyniResponder.cleanup()
waitFor punchd.tcpNutssInitiator.cleanup()
waitFor punchd.tcpNutssResponder.cleanup()
punchd.unixSocket.close()

View File

@ -17,19 +17,19 @@ type
dstIp: IpAddress
dstPorts: seq[Port]
TcpSyniConnectPuncher* = Puncher[Attempt]
TcpSyniInitiator* = Puncher[Attempt]
PunchProgressCb* = proc(seqNums: seq[uint32]) {.async.}
var IPPROTO_IP {.importc: "IPPROTO_IP", header: "<netinet/in.h>".}: cint
var IP_TTL {.importc: "IP_TTL", header: "<netinet/in.h>".}: cint
proc cleanup*(puncher: TcpSyniConnectPuncher) {.async.} =
proc cleanup*(puncher: TcpSyniInitiator) {.async.} =
while puncher.attempts.len() != 0:
await puncher.attempts.pop().deleteFirewallRules()
proc initTcpSyniConnectPuncher*(): TcpSyniConnectPuncher =
TcpSyniConnectPuncher()
proc initTcpSyniInitiator*(): TcpSyniInitiator =
TcpSyniInitiator()
proc captureSeqNumbers(attempt: Attempt, cb: PunchProgressCb) {.async.} =
# FIXME: timeout?
@ -77,12 +77,12 @@ proc captureAndResendAck(attempt: Attempt) {.async.} =
closeSocket(captureFd)
closeSocket(injectFd)
proc doConnect(srcIp: IpAddress, srcPort: Port, dstIp: IpAddress, dstPort: Port,
proc connect(srcIp: IpAddress, srcPort: Port, dstIp: IpAddress, dstPort: Port,
future: Future[AsyncSocket]) {.async.} =
let sock = newAsyncSocket()
sock.setSockOpt(OptReuseAddr, true)
sock.getFd.setSockOptInt(IPPROTO_IP, IP_TTL, 2)
echo &"doConnect {srcIp}:{srcPort} -> {dstIp}:{dstPort}"
echo &"connect {srcIp}:{srcPort} -> {dstIp}:{dstPort}"
sock.bindAddr(srcPort, $srcIp)
try:
await sock.connect($dstIp, dstPort)
@ -92,9 +92,9 @@ proc doConnect(srcIp: IpAddress, srcPort: Port, dstIp: IpAddress, dstPort: Port,
echo &"connection {srcIP}:{srcPort.int} -> {dstIp}:{dstPort.int} failed: ", e.msg
sock.close()
proc connect*(puncher: TcpSyniConnectPuncher, srcPort: Port, dstIp: IpAddress,
dstPorts: seq[Port],
progressCb: PunchProgressCb): Future[AsyncSocket] {.async.} =
proc initiate*(puncher: TcpSyniInitiator, srcPort: Port, dstIp: IpAddress,
dstPorts: seq[Port],
progressCb: PunchProgressCb): Future[AsyncSocket] {.async.} =
let localIp = getPrimaryIPAddr(dstIp)
if puncher.findAttempt(localIp, srcPort, dstIp, dstPorts) != -1:
raise newException(PunchHoleError, "hole punching for given parameters already active")
@ -107,7 +107,7 @@ proc connect*(puncher: TcpSyniConnectPuncher, srcPort: Port, dstIp: IpAddress,
try:
let connectFuture = newFuture[AsyncSocket]("connect")
for dstPort in attempt.dstPorts:
asyncCheck doConnect(attempt.srcIp, attempt.srcPort, attempt.dstIp,
asyncCheck connect(attempt.srcIp, attempt.srcPort, attempt.dstIp,
dstPort, connectFuture)
await connectFuture or sleepAsync(Timeout)
await attempt.deleteFirewallRules()

View File

@ -19,15 +19,15 @@ type
seqNums: seq[uint32]
future: Future[AsyncSocket]
TcpSyniAcceptPuncher* = Puncher[Attempt]
TcpSyniResponder* = Puncher[Attempt]
proc cleanup*(puncher: TcpSyniAcceptPuncher) {.async.} =
proc cleanup*(puncher: TcpSyniResponder) {.async.} =
while puncher.attempts.len() != 0:
await puncher.attempts.pop().deleteFirewallRules()
proc initTcpSyniAcceptPuncher*(): TcpSyniAcceptPuncher =
proc initTcpSyniResponder*(): TcpSyniResponder =
randomize()
TcpSyniAcceptPuncher()
TcpSyniResponder()
proc injectSynPackets(attempt: Attempt) {.async.} =
let injectFd = setupTcpInjectingSocket()
@ -50,8 +50,8 @@ proc injectSynPackets(attempt: Attempt) {.async.} =
await injectFd.injectTcpPacket(synIn)
closeSocket(injectFd)
proc doAccept(puncher: TcpSyniAcceptPuncher, srcIp: IpAddress,
srcPort: Port) {.async.} =
proc accept(puncher: TcpSyniResponder, srcIp: IpAddress,
srcPort: Port) {.async.} =
let sock = newAsyncSocket()
sock.setSockOpt(OptReuseAddr, true)
sock.bindAddr(srcPort, $srcIp)
@ -77,14 +77,14 @@ proc doAccept(puncher: TcpSyniAcceptPuncher, srcIp: IpAddress,
break
sock.close()
proc accept*(puncher: TcpSyniAcceptPuncher, srcPort: Port, dstIp: IpAddress,
dstPorts: seq[Port],
seqNums: seq[uint32]): Future[AsyncSocket] {.async.} =
proc respond*(puncher: TcpSyniResponder, srcPort: Port, dstIp: IpAddress,
dstPorts: seq[Port],
seqNums: seq[uint32]): Future[AsyncSocket] {.async.} =
let localIp = getPrimaryIPAddr(dstIp)
let existingAttempts = puncher.findAttemptsByLocalAddr(localIp, srcPort)
if existingAttempts.len() == 0:
echo &"accepting connections from {dstIp}:{dstPorts[0].int}"
asyncCheck puncher.doAccept(localIp, srcPort)
asyncCheck puncher.accept(localIp, srcPort)
else:
for a in existingAttempts:
if a.dstIp == dstIp and