Skip to content

Instantly share code, notes, and snippets.

@onemouth
Created February 5, 2018 07:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save onemouth/67cb276d15d3b064ee4cf5ce8b70663c to your computer and use it in GitHub Desktop.
Save onemouth/67cb276d15d3b064ee4cf5ce8b70663c to your computer and use it in GitHub Desktop.
Use ttl=1 Ping to find first router device's ip
import socket
import struct
import sys
import select
class PingProtocolData(object):
def __init__(self):
self.seq_number = 0
@property
def ICMP_ECHO(self):
return 8
@property
def seq_number(self):
return self.__seq_number
@property
def identifier(self):
return 0
@seq_number.setter
def seq_number(self, seq_number):
self.__seq_number = seq_number
def generate_ping_packet(self):
checksum = 0
header = struct.pack("!BBHHH", self.ICMP_ECHO, 0, checksum, self.identifier,
self.seq_number)
padBytes = "abcdefghijk"
data = bytes(padBytes)
#print data
checksum = self.calculate_checksum(header+data)
header = struct.pack("!BBHHH", self.ICMP_ECHO, 0, checksum, self.identifier,
self.seq_number)
packet = header + data
print packet
return packet
def calculate_checksum(self, source_string):
"""
A port of the functionality of in_cksum() from ping.c
Ideally this would act on the string as a series of 16-bit ints (host
packed), but this works.
Network data is big-endian, hosts are typically little-endian
"""
countTo = (int(len(source_string) / 2)) * 2
sum = 0
count = 0
# Handle bytes in pairs (decoding as short ints)
loByte = 0
hiByte = 0
while count < countTo:
if (sys.byteorder == "little"):
loByte = source_string[count]
hiByte = source_string[count + 1]
else:
loByte = source_string[count + 1]
hiByte = source_string[count]
loByte = ord(loByte)
hiByte = ord(hiByte)
sum = sum + (hiByte * 256 + loByte)
count += 2
# Handle last byte if applicable (odd-number of bytes)
# Endianness should be irrelevant in this case
if countTo < len(source_string): # Check for odd length
loByte = source_string[len(source_string) - 1]
loByte = ord(loByte)
sum += loByte
sum &= 0xffffffff # Truncate sum to 32 bits (a variance from ping.c, which
# uses signed ints, but overflow is unlikely in ping)
sum = (sum >> 16) + (sum & 0xffff) # Add high 16 bits to low 16 bits
sum += (sum >> 16) # Add carry from above (if any)
answer = ~sum & 0xffff # Invert and truncate to 16 bits
answer = socket.htons(answer)
return answer
class Pinger(object):
def __init__(self, ppd):
self.ppd = ppd
def _send_ping(self, s, target):
ping_packet = self.ppd.generate_ping_packet()
s.sendto(ping_packet, (target, 1))
def _receive_ping(self, s):
timeout = 2.5
select.select([s], [], [], timeout)
packet_data, address = s.recvfrom(2048)
print packet_data, address
def do(self):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.getprotobyname("icmp"))
s.setsockopt(socket.IPPROTO_IP, socket.IP_TTL, 1)
self._send_ping(s, "8.8.8.8")
self._receive_ping(s)
s.close()
def main():
pinger = Pinger(PingProtocolData())
pinger.do()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment