adapt punchd messages to README
This commit is contained in:
parent
239ddd64b1
commit
0f21a63a81
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
96
punchd.nim
96
punchd.nim
|
@ -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()
|
||||
|
|
|
@ -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()
|
|
@ -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
|
Loading…
Reference in New Issue