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