resend SYN+ACK with normal TTL
This commit is contained in:
parent
0f622c0953
commit
acfcb79108
|
@ -58,10 +58,11 @@ type
|
|||
URG
|
||||
|
||||
IpPacket* = object
|
||||
ipAddrSrc*: IpAddress
|
||||
ipAddrDst*: IpAddress
|
||||
ipTTL*: uint8
|
||||
case protocol*: Protocol
|
||||
of tcp:
|
||||
tcpIpSrc*: IpAddress
|
||||
tcpIpDst*: IpAddress
|
||||
tcpPortSrc*: Port
|
||||
tcpPortDst*: Port
|
||||
tcpSeqNumber*: uint32
|
||||
|
@ -87,8 +88,9 @@ proc parseEthernetPacket*(input: string): IpPacket =
|
|||
let tcpHeader = cast[ptr Tcphdr](cast[int](ipHeader) + ipHeader.ip_hl.int * 4)
|
||||
|
||||
result = IpPacket(protocol: tcp,
|
||||
tcpIpSrc: ipSrc,
|
||||
tcpIpDst: ipDst,
|
||||
ipAddrSrc: ipSrc,
|
||||
ipAddrDst: ipDst,
|
||||
ipTTL: ipHeader.ip_ttl,
|
||||
tcpPortSrc: Port(ntohs(tcpHeader.th_sport)),
|
||||
tcpPortDst: Port(ntohs(tcpHeader.th_dport)),
|
||||
tcpSeqNumber: ntohl(tcpHeader.th_seq),
|
||||
|
@ -132,8 +134,8 @@ proc serialize*(packet: IpPacket): string =
|
|||
of tcp:
|
||||
result = newString(sizeof(Ip) + sizeof(Tcphdr))
|
||||
zeroMem(result.cstring, result.len)
|
||||
let srcIp = InAddr(s_addr: cast[uint32](packet.tcpIpSrc.address_v4))
|
||||
let dstIp = InAddr(s_addr: cast[uint32](packet.tcpIpDst.address_v4))
|
||||
let srcIp = InAddr(s_addr: cast[uint32](packet.ipAddrSrc.address_v4))
|
||||
let dstIp = InAddr(s_addr: cast[uint32](packet.ipAddrDst.address_v4))
|
||||
|
||||
let ipHeader = cast[ptr Ip](addr result[0])
|
||||
ipHeader.ip_hl = 5
|
||||
|
@ -142,7 +144,7 @@ proc serialize*(packet: IpPacket): string =
|
|||
ipHeader.ip_len = htons(sizeof(Ip).uint16 + sizeof(TcpHdr).uint16)
|
||||
ipHeader.ip_id = htons(54321) # FIXME = random number
|
||||
ipHeader.ip_off = 0
|
||||
ipHeader.ip_ttl = 64
|
||||
ipHeader.ip_ttl = packet.ipTTL
|
||||
ipHeader.ip_p = 6.cuchar
|
||||
ipHeader.ip_src = srcIp
|
||||
ipHeader.ip_dst = dstIp
|
||||
|
|
84
tcp_syni.nim
84
tcp_syni.nim
|
@ -45,6 +45,20 @@ proc iptablesDelete(chain: string, rule: string) {.async.} =
|
|||
let firewall_cmd = fmt"iptables -D {chain} {rule}"
|
||||
discard await asyncExecCmd(firewall_cmd)
|
||||
|
||||
proc injectTcpPacket(rawFd: AsyncFD, ipPacket: IpPacket) {.async.} =
|
||||
assert(ipPacket.protocol == tcp)
|
||||
try:
|
||||
let packet = serialize(ipPacket)
|
||||
var sockaddr: Sockaddr_storage
|
||||
var sockaddrLen: SockLen
|
||||
toSockAddr(ipPacket.ipAddrDst, ipPacket.tcpPortDst, sockaddr, sockaddrLen)
|
||||
await rawFd.sendTo(packet.cstring, packet.len,
|
||||
cast[ptr SockAddr](addr sockaddr), sockaddrLen)
|
||||
echo &"injected {ipPacket.ipAddrSrc}:{ipPacket.tcpPortSrc.int} -> {ipPacket.ipAddrDst}:{ipPacket.tcpPortDst.int} (seq {ipPacket.tcpSeqNumber})"
|
||||
except OSError as e:
|
||||
echo &"cannot inject {ipPacket.ipAddrSrc}:{ipPacket.tcpPortSrc.int} -> {ipPacket.ipAddrDst}:{ipPacket.tcpPortDst.int} (seq {ipPacket.tcpSeqNumber})", e.msg
|
||||
raise newException(PunchHoleError, e.msg)
|
||||
|
||||
proc captureSeqNumbers(puncher: TcpSyniPuncher, rawFd: AsyncFD,
|
||||
cb: PunchProgressCb) {.async.} =
|
||||
# FIXME: every sequence number is captured twice (RST too?)
|
||||
|
@ -54,40 +68,41 @@ proc captureSeqNumbers(puncher: TcpSyniPuncher, rawFd: AsyncFD,
|
|||
let packet = await rawFd.recv(4000)
|
||||
if packet == "":
|
||||
break
|
||||
echo "packet len: ", packet.len
|
||||
let parsed = parseEthernetPacket(packet)
|
||||
if parsed.protocol == tcp and
|
||||
parsed.tcpIpSrc == puncher.srcIp and
|
||||
parsed.ipAddrSrc == puncher.srcIp and
|
||||
parsed.tcpPortSrc.int == puncher.srcPort.int and
|
||||
parsed.tcpIpDst == puncher.dstIp and
|
||||
parsed.ipAddrDst == puncher.dstIp and
|
||||
parsed.tcpFlags == {SYN}:
|
||||
for i, port in puncher.dstPorts.pairs:
|
||||
for port in puncher.dstPorts:
|
||||
if parsed.tcpPortDst.int == port.int:
|
||||
seqNums.add(parsed.tcpSeqNumber)
|
||||
break
|
||||
await cb(seqNums)
|
||||
|
||||
proc injectSyns(rawFd: AsyncFD, srcIp: IpAddress, srcPort: Port,
|
||||
dstIp: IpAddress, dstPort: Port,
|
||||
seqNums: seq[uint32]) {.async.} =
|
||||
for seqNum in seqNums:
|
||||
let ipPacket = IpPacket(protocol: tcp,
|
||||
tcpIpSrc: srcIp,
|
||||
tcpIpDst: dstIp,
|
||||
tcpPortSrc: srcPort,
|
||||
tcpPortDst: dstPort,
|
||||
tcpSeqNumber: seqNum,
|
||||
tcpFlags: {SYN})
|
||||
try:
|
||||
let packet = serialize(ipPacket)
|
||||
var sockaddr: Sockaddr_storage
|
||||
var sockaddrLen: SockLen
|
||||
toSockAddr(dstIp, dstPort, sockaddr, sockaddrLen)
|
||||
await rawFd.sendTo(packet.cstring, packet.len,
|
||||
cast[ptr SockAddr](addr sockaddr), sockaddrLen)
|
||||
echo &"injected {srcIP}:{srcPort.int} -> {dstIp}:{dstPort.int} (seq {seqNum})"
|
||||
except OSError as e:
|
||||
echo "cannot inject {srcIp}:{srcPort.int} -> {dstIp}:{dstPort.int} (seq {seqNum}): ", e.msg
|
||||
proc captureAndResendSynAck(puncher: TcpSyniPuncher, rawFd: AsyncFD) {.async.} =
|
||||
while true:
|
||||
let packet = await rawFd.recv(4000)
|
||||
if packet == "":
|
||||
break
|
||||
let parsed = parseEthernetPacket(packet)
|
||||
if parsed.protocol == tcp and
|
||||
parsed.ipAddrSrc == puncher.srcIp and
|
||||
parsed.tcpPortSrc.int == puncher.srcPort.int and
|
||||
parsed.ipAddrDst == puncher.dstIp and
|
||||
parsed.tcpFlags == {SYN, ACK}:
|
||||
for port in puncher.dstPorts:
|
||||
if parsed.tcpPortDst.int == port.int:
|
||||
let ipPacket = IpPacket(protocol: tcp,
|
||||
ipAddrSrc: puncher.srcIp,
|
||||
ipAddrDst: puncher.dstIp,
|
||||
ipTTL: 64,
|
||||
tcpPortSrc: puncher.srcPort,
|
||||
tcpPortDst: parsed.tcpPortDst,
|
||||
tcpSeqNumber: parsed.tcpSeqNumber,
|
||||
tcpFlags: parsed.tcpFlags)
|
||||
await rawFd.injectTcpPacket(ipPacket)
|
||||
break
|
||||
|
||||
proc initPuncher*(srcPort: Port, dstIp: IpAddress, dstPorts: array[3, Port],
|
||||
seqNums: seq[uint32] = @[]): TcpSyniPuncher =
|
||||
|
@ -128,6 +143,7 @@ proc doConnect(srcIp: IpAddress, srcPort: Port, dstIp: IpAddress, dstPort: Port,
|
|||
sock.bindAddr(srcPort, $srcIp)
|
||||
try:
|
||||
await sock.connect($dstIp, dstPort)
|
||||
sock.getFd.setSockOptInt(IPPROTO_IP, IP_TTL, 64)
|
||||
future.complete(sock)
|
||||
except OSError as e:
|
||||
echo &"connection {srcIP}:{srcPort.int} -> {dstIp}:{dstPort.int} failed: ", e.msg
|
||||
|
@ -141,8 +157,10 @@ proc connectParallel(puncher: TcpSyniPuncher): Future[AsyncSocket] =
|
|||
proc connect*(puncher: TcpSyniPuncher,
|
||||
progressCb: PunchProgressCb): Future[AsyncSocket] {.async.} =
|
||||
let iface = fromIpAddress(puncher.srcIp)
|
||||
let rawFd = setupEthernetCapturingSocket(iface)
|
||||
asyncCheck puncher.captureSeqNumbers(rawFd, progressCb)
|
||||
let captureSeqFd = setupEthernetCapturingSocket(iface)
|
||||
let captureSynAckFd = setupEthernetCapturingSocket(iface)
|
||||
asyncCheck puncher.captureSeqNumbers(captureSeqFd, progressCb)
|
||||
asyncCheck puncher.captureAndResendSynAck(captureSynAckFd)
|
||||
await puncher.addFirewallRules()
|
||||
try:
|
||||
result = await puncher.connectParallel()
|
||||
|
@ -171,8 +189,16 @@ proc accept*(puncher: TcpSyniPuncher): Future[AsyncSocket] {.async.} =
|
|||
# FIXME: timeout
|
||||
let rawFd = setupTcpInjectingSocket()
|
||||
for dstPort in puncher.dstPorts:
|
||||
asyncCheck injectSyns(rawFd, puncher.dstIp, dstPort, puncher.srcIp,
|
||||
puncher.srcPort, puncher.seqNums)
|
||||
for seqNum in puncher.seqNums:
|
||||
let ipPacket = IpPacket(protocol: tcp,
|
||||
ipAddrSrc: puncher.dstIp,
|
||||
ipAddrDst: puncher.srcIp,
|
||||
ipTTL: 64,
|
||||
tcpPortSrc: dstPort,
|
||||
tcpPortDst: puncher.srcPort,
|
||||
tcpSeqNumber: seqNum,
|
||||
tcpFlags: {SYN})
|
||||
asyncCheck rawFd.injectTcpPacket(ipPacket)
|
||||
let sock = newAsyncSocket()
|
||||
sock.setSockOpt(OptReuseAddr, true)
|
||||
sock.bindAddr(puncher.srcPort, $(puncher.srcIp))
|
||||
|
|
Loading…
Reference in New Issue