I have a problem with running a python code in pox controller...
I have a code that use ping3 to ping between a pox controller and two servers.
However, every time the ping returns (None) as a result and I can't figure out why.
I have tried to go through the code of the icmp pinger and I find out that this line:
whatReady = select.select([mySocket], [], [], timeLeft)
always return this result: [],[],[]
and because of this ping always return (None) instead of numerical number.
The icmp pinger code:
from socket import *
import socket
import os
import sys
import struct
import time
import select
import binascii
ICMP_ECHO_REQUEST = 8
def checksum(str):
csum = 0
countTo = (len(str) / 2) * 2
count = 0
while count < countTo:
thisVal = ord(str[count+1]) * 256 + ord(str[count])
csum = csum + thisVal
csum = csum & 0xffffffffL
count = count + 2
if countTo < len(str):
csum = csum + ord(str[len(str) - 1])
csum = csum & 0xffffffffL
csum = (csum >> 16) + (csum & 0xffff)
csum = csum + (csum >> 16)
answer = ~csum
answer = answer & 0xffff
answer = answer >> 8 | (answer << 8 & 0xff00)
return answer
def receiveOnePing(mySocket, ID, timeout, destAddr):
timeLeft = timeout
while 1:
startedSelect = time.time()
whatReady = select.select([mySocket], [], [], timeLeft)
howLongInSelect = (time.time() - startedSelect)
if whatReady[0] == []: #Timeout
return "Request timed out."
timeReceived = time.time()
recPacket, addr = mySocket.recvfrom(1024)
#Fill in start
#Fetch the ICMP header from the IP packet
ICMPHeader = recPacket[20:28]
Type, Code, Checksum, packetID, Sequence = struct.unpack('bbHHh', ICMPHeader)
if packetID == ID:
BytesInDouble = struct.calcsize('d')
timeSent = struct.unpack('d',recPacket[28:28 + BytesInDouble])[0]
return timeReceived - timeSent
else:
return 'Different ID'
#Fill in end
timeLeft = timeLeft - howLongInSelect
if timeLeft <= 0:
return "Request timed out"
def sendOnePing(mySocket, destAddr, ID):
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
myChecksum = 0
# Make a dummy header with a 0 checksum
# struct -- Interpret strings as packed binary data
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
data = struct.pack("d", time.time())
# Calculate the checksum on the data and the dummy header.
myChecksum = checksum(header + data)
# Get the right checksum, and put in the header
if sys.platform == 'darwin':
myChecksum = socket.htons(myChecksum) & 0xffff
#Convert 16-bit integers from host to network byte order.
else:
myChecksum = socket.htons(myChecksum)
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
packet = header + data
mySocket.sendto(packet, (destAddr, 1)) # AF_INET address must be tuple, not str
#Both LISTS and TUPLES consist of a number of objects
#which can be referenced by their position within the object
def doOnePing(destAddr, timeout):
icmp = socket.getprotobyname("icmp")
#SOCK_RAW is a powerful socket type. For more details see: http://sock-raw.ord/papers/sock_raw
#Fill in start
#Create Socket here
try:
mySocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
except socket.error, (errno, msg):
if errno == 1:
raise socket.error(msg)
#Fill in end
myID = os.getpid() & 0xFFFF #Return the current process i
sendOnePing(mySocket, destAddr, myID)
delay = receiveOnePing(mySocket, myID, timeout, destAddr)
mySocket.close()
return delay
ping("www.google.com") # USA - North America
# ping('www.china.org.cn') # China - Asia
# ping('www.thepiratebay.se') # Sweden - Europe
Can anyone help to understand what is the actual problem and how I can fix it...
Related
i keep having a problem in my code coming back as Test Failed: unsupported operand type(s) for +: 'int' and 'tuple'.
i am a super beginner who is not very good at coding, so i cannot figure out what the issue is.
here is the full code.
i am making a simple icmp pinger program.
thanks everyone for your help!!!
(this is my first question here so please let me know if i need to edit anything)
from socket import *
import os
import sys
import struct
import time
import select
import statistics
import binascii
# Should use stdev
ICMP_ECHO_REQUEST = 8
def checksum(string):
csum = 0
countTo = (len(string) // 2) * 2
count = 0
while count < countTo:
thisVal = (string[count + 1]) * 256 + (string[count])
csum += thisVal
csum &= 0xffffffff
count += 2
if countTo < len(string):
csum += (string[len(string) - 1])
csum &= 0xffffffff
csum = (csum >> 16) + (csum & 0xffff)
csum = csum + (csum >> 16)
answer = ~csum
answer = answer & 0xffff
answer = answer >> 8 | (answer << 8 & 0xff00)
return answer
def receiveOnePing(mySocket, ID, timeout, destAddr):
timeLeft = timeout
while 1:
startedSelect = time.time()
whatReady = select.select([mySocket], [], [], timeLeft)
howLongInSelect = (time.time() - startedSelect)
if whatReady[0] == []: # Timeout
return "Request timed out."
timeReceived = time.time()
recPacket, addr = mySocket.recvfrom(1024)
# Fetch the ICMP header from the IP packet
header = recPacket[20:28]
type, code, checksum, packID, seqNo = struct.unpack("bbHHh", header)
if type == 0 and packID == ID:
bytesInDouble = struct.calcsize("d")
timeSent = struct.unpack("d", recPacket[28:28 + bytesInDouble])[0]
ttls = struct.unpack("c", recPacket[8:9])[0]
rtt = timeReceived - timeSent
return (rtt, ttls)
timeLeft = timeLeft - howLongInSelect
if timeLeft <= 0:
return "Request timed out."
def sendOnePing(mySocket, destAddr, ID):
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
myChecksum = 0
# Make a dummy header with a 0 checksum
# struct -- Interpret strings as packed binary data
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
data = struct.pack("d", time.time())
# Calculate the checksum on the data and the dummy header.
myChecksum = checksum(header + data)
# Get the right checksum, and put in the header
if sys.platform == 'darwin':
# Convert 16-bit integers from host to network byte order
myChecksum = htons(myChecksum) & 0xffff
else:
myChecksum = htons(myChecksum)
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
packet = header + data
mySocket.sendto(packet, (destAddr, 1)) # AF_INET address must be tuple, not str
# Both LISTS and TUPLES consist of a number of objects
# which can be referenced by their position number within the object.
def doOnePing(destAddr, timeout):
icmp = getprotobyname("icmp")
# SOCK_RAW is a powerful socket type. For more details: http://sockraw.org/papers/sock_raw
mySocket = socket(AF_INET, SOCK_RAW, icmp)
myID = os.getpid() & 0xFFFF # Return the current process i
sendOnePing(mySocket, destAddr, myID)
delay = receiveOnePing(mySocket, myID, timeout, destAddr)
mySocket.close()
return delay
def ping(host, timeout=1):
# timeout=1 means: If one second goes by without a reply from the server, # the client assumes that either the client's ping or the server's pong is lost
dest = gethostbyname(host)
# print("Pinging " + dest + " using Python:")
# print("")
# Calculate vars values and return them
count = 0
val = []
# Send ping requests to a server separated by approximately one second
for i in range(0,4):
delay = doOnePing(dest, timeout)
val.append(delay)
# print(delay)
time.sleep(1) # one second
if len(val) > 0:
packet_min = min(val) * 1000
packet_avg = sum(val) / len(val) * 1000
packet_max = max(val) * 1000
stdev_var = list(val) * 1000
vars = [str(round(packet_min, 2)), str(round(packet_avg, 2)), str(round(packet_max, 2)),str(round(stdev(stdev_var), 2))]
else:
vars = ['0', '0.0', '0', '0.0']
return vars
if __name__ == '__main__':
ping("google.co.il")
You have return (rtt, ttls) in function receiveOnePing and then you return the same tuple from function doOnePing. After that, you append this tuple to list and are trying to sum this list of tuples. This leads to the error you mentioned.
You need val.append(delay[0]) in ping function (line 122).
You also use undefined function stdev. Should be statistics.stdev.
Please note that your script will crash in case of timeout because you return a string in this.
Also the code is runnable only by root.
UPD
Below is fixed code.
rom socket import *
import os
import sys
import struct
import time
import select
import statistics
import binascii
# Should use stdev
ICMP_ECHO_REQUEST = 8
def checksum(string):
csum = 0
countTo = (len(string) // 2) * 2
count = 0
while count < countTo:
thisVal = (string[count + 1]) * 256 + (string[count])
csum += thisVal
csum &= 0xffffffff
count += 2
if countTo < len(string):
csum += (string[len(string) - 1])
csum &= 0xffffffff
csum = (csum >> 16) + (csum & 0xffff)
csum = csum + (csum >> 16)
answer = ~csum
answer = answer & 0xffff
answer = answer >> 8 | (answer << 8 & 0xff00)
return answer
def receiveOnePing(mySocket, ID, timeout, destAddr):
timeLeft = timeout
while 1:
startedSelect = time.time()
whatReady = select.select([mySocket], [], [], timeLeft)
howLongInSelect = (time.time() - startedSelect)
if whatReady[0] == []: # Timeout
return "Request timed out."
timeReceived = time.time()
recPacket, addr = mySocket.recvfrom(1024)
# Fetch the ICMP header from the IP packet
header = recPacket[20:28]
type, code, checksum, packID, seqNo = struct.unpack("bbHHh", header)
if type == 0 and packID == ID:
bytesInDouble = struct.calcsize("d")
timeSent = struct.unpack("d", recPacket[28:28 + bytesInDouble])[0]
ttls = struct.unpack("c", recPacket[8:9])[0]
rtt = timeReceived - timeSent
return (rtt, ttls)
timeLeft = timeLeft - howLongInSelect
if timeLeft <= 0:
return "Request timed out."
def sendOnePing(mySocket, destAddr, ID):
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
myChecksum = 0
# Make a dummy header with a 0 checksum
# struct -- Interpret strings as packed binary data
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
data = struct.pack("d", time.time())
# Calculate the checksum on the data and the dummy header.
myChecksum = checksum(header + data)
# Get the right checksum, and put in the header
if sys.platform == 'darwin':
# Convert 16-bit integers from host to network byte order
myChecksum = htons(myChecksum) & 0xffff
else:
myChecksum = htons(myChecksum)
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
packet = header + data
mySocket.sendto(packet, (destAddr, 1)) # AF_INET address must be tuple, not str
# Both LISTS and TUPLES consist of a number of objects
# which can be referenced by their position number within the object.
def doOnePing(destAddr, timeout):
icmp = getprotobyname("icmp")
# SOCK_RAW is a powerful socket type. For more details: http://sockraw.org/papers/sock_raw
mySocket = socket(AF_INET, SOCK_RAW, icmp)
myID = os.getpid() & 0xFFFF # Return the current process i
sendOnePing(mySocket, destAddr, myID)
delay = receiveOnePing(mySocket, myID, timeout, destAddr)
mySocket.close()
return delay
def ping(host, timeout=1):
# timeout=1 means: If one second goes by without a reply from the server, # the client assumes that either the client's ping or the server's pong is lost
dest = gethostbyname(host)
# print("Pinging " + dest + " using Python:")
# print("")
# Calculate vars values and return them
count = 0
val = []
# Send ping requests to a server separated by approximately one second
for i in range(0,4):
delay = doOnePing(dest, timeout)
val.append(delay[0])
# print(delay)
time.sleep(1) # one second
print(val)
if len(val) > 0:
packet_min = min(val) * 1000
packet_avg = sum(val) / len(val) * 1000
packet_max = max(val) * 1000
stdev_var = list(val) * 1000
vars = [str(round(packet_min, 2)), str(round(packet_avg, 2)), str(round(packet_max, 2)),str(round(statistics.stdev(stdev_var), 2))]
else:
vars = ['0', '0.0', '0', '0.0']
return vars
if __name__ == '__main__':
ping("google.co.il")
>sudo python3 ping.py
[0.0778355598449707, 0.07866811752319336, 0.07798004150390625, 0.07628297805786133]
The error occurs in this line:
packet_avg = sum(val) / len(val) * 1000
Therefore val is suspect. Follow the logic back through doOnePing to receiveOnePing and you will find that function does not return suitable types.
You have a few issues. What I can see:
you are trying to checksum but in python, using an index returns a string, not a character, so this generates a string, not a number:
thisVal = (string[count + 1]) * 256 + (string[count])
What you probably want in this case is:
thisVal = ord(string[count + 1]) * 256 + ord(string[count])
and also on this line:
csum += (string[len(string) - 1])
to
csum += ord(string[len(string) - 1])
Then, you are putting tuples and possibly strings into your val array.
You need to decide how you want to handle the errors/time out of the ping.
You could just ignore them for now:
for i in range(0,4):
delay = doOnePing(dest, timeout)
if isinstance(delay, tuple):
val.append(delay[0])
time.sleep(1) # one second
That will only add if you received a tuple, and only add the first member of the tuple, which appears to be the delay you want.
ERROR : TypeError: ord() expected string of length 1, but int found
I am getting this error while compiling the program.
File "C:\Users\Administrator\Desktop\tracer1.py", line 129, in <module>
get_route("www.google.com")
File "C:\Users\Administrator\Desktop\tracer1.py", line 85, in get_route
d = build_packet()
File "C:\Users\Administrator\Desktop\tracer1.py", line 62, in build_packet
myChecksum = checksum(header + data)
File "C:\Users\Administrator\Desktop\tracer1.py", line 28, in checksum
thisVal = ord(str[count+1]) * 256 + ord(str[count])
**TypeError: ord() expected string of length 1, but int found**
the program is to find the traceroute using ICMP
from socket import *
import socket
import os
import sys
import struct
import time
import select
import binascii
import ctypes
ICMP_ECHO_REQUEST = 8
MAX_HOPS = 30
TIMEOUT = 2.0
TRIES = 2
# The packet that we shall send to each router along the path is the ICMP echo
# request packet, which is exactly what we had used in the ICMP ping exercise.
# We shall use the same packet that we built in the Ping exercise
ctypes.windll.shell32.IsUserAnAdmin()
print (ctypes.windll.shell32.IsUserAnAdmin())
def checksum(str):
csum = 0
countTo = (len(str) / 2) * 2
count = 0
while count < countTo:
thisVal = ord(str[count+1]) * 256 + ord(str[count])
csum = csum + thisVal
csum = csum & 0xffffffff
count = count + 2
if countTo < len(str):
csum = csum + ord(str[len(str) - 1])
csum = csum & 0xffffffff
csum = (csum >> 16) + (csum & 0xffff)
csum = csum + (csum >> 16)
answer = ~csum
answer = answer & 0xffff
answer = answer >> 8 | (answer << 8 & 0xff00)
return answer
def build_packet():
# In the sendOnePing() method of the ICMP Ping exercise ,firstly the header of our
# packet to be sent was made, secondly the checksum was appended to the header and
# then finally the complete packet was sent to the destination.
# Make the header in a similar way to the ping exercise.
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
myChecksum = 0
pid = os.getpid() & 0xFFFF
# Make a dummy header with a 0 checksum.
# struct -- Interpret strings as packed binary data
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, pid, 1)
#header = struct.pack("!HHHHH", ICMP_ECHO_REQUEST, 0, myChecksum, pid, 1)
data = struct.pack("d", time.time())
# Calculate the checksum on the data and the dummy header.
# Append checksum to the header.
myChecksum = checksum(header + data)
if sys.platform == 'darwin':
myChecksum = socket.htons(myChecksum) & 0xffff
#Convert 16-bit integers from host to network byte order.
else:
myChecksum = htons(myChecksum)
packet = header + data
return packet
def get_route(hostname):
timeLeft = TIMEOUT
for ttl in range(1,MAX_HOPS):
for tries in range(TRIES):
destAddr = socket.gethostbyname(hostname)
#Fill in start
# Make a raw socket named mySocket
mySocket = socket.socket(AF_INET, SOCK_RAW, getprotobyname("icmp"))
mySocket.bind(("", 12000));
#Fill in end
mySocket.setsockopt(socket.IPPROTO_IP, socket.IP_TTL, struct.pack('I', ttl))
mySocket.settimeout(TIMEOUT)
try:
d = build_packet()
mySocket.sendto(d, (hostname, 0))
t = time.time()
startedSelect = time.time()
whatReady = select.select([mySocket], [], [], timeLeft)
howLongInSelect = (time.time() - startedSelect)
if whatReady[0] == []: # Timeout
print ("* * * Request timed out.")
recvPacket, addr = mySocket.recvfrom(1024)
print ("addr")
timeReceived = time.time()
timeLeft = timeLeft - howLongInSelect
if timeLeft <= 0:
print ("* * * Request timed out.")
except socket.timeout:
continue
else:
#Fill in start
# Fetch the icmp type from the IP packet
print( struct.calcsize("bbHHhd"))
request_code, request_type, checksum, packet_id, \
sequence, timeSent, data = struct.unpack("bbHHhd", recvPacket,0)
#Fill in end
if request_type == 11:
bytes = struct.calcsize("d")
timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0]
print (" %d rtt=%.0f ms %s" % (ttl,(timeReceived -t)*1000, addr[0]))
elif request_type == 3:
bytes = struct.calcsize("d")
timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0]
print (" %d rtt=%.0f ms %s" % (ttl,(timeReceived -t)*1000, addr[0]))
elif request_type == 0:
bytes = struct.calcsize("d")
timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0]
print (" %d rtt=%.0f ms %s" % (ttl,(timeReceived -timeSent)*1000, addr[0]))
return
else:
print ("error")
break
finally:
mySocket.close()
get_route("www.google.com")
You are running the script using Python 3 where indexing a bytes object returns an integer:
>>> b"abc"[1]
98
Remove the ord() calls. They are redundant in this case.
I encountered today a similar type of error. I added this answer here to highlight certain observations. The main API to focus here is triple_des. If the input is qqq, then it will cause the error. If the input is sMAC, then there is no error. Interestingly, qqq == sMAC is true. Furthermore, both variable's print via binascii shows similar value. Variable qqq came from bytearray.fromhex('7A414086D86A4BF5554AE6FBC4AC0465') and variable sMAC came from "7A414086D86A4BF5554AE6FBC4AC0465",decode('hex').
>>> qqq[0]
122
>>> sMAC[0]
'z'
>>> qqq == sMAC
True
>>> binascii.hexlify(sMAC)
'7a414086d86a4bf5554ae6fbc4ac0465'
>>> binascii.hexlify(qqq)
'7a414086d86a4bf5554ae6fbc4ac0465'
>>> qqq == sMAC
True
>>> repr(qqq)
"bytearray(b'zA#\\x86\\xd8jK\\xf5UJ\\xe6\\xfb\\xc4\\xac\\x04e')"
>>> repr(sMAC)
"'zA#\\x86\\xd8jK\\xf5UJ\\xe6\\xfb\\xc4\\xac\\x04e'"
>>> cipher1 = triple_des(qqq,CBC,"\0\0\0\0\0\0\0\0",pad=None,padmode=PAD_PKCS5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/john/.local/lib/python2.7/site-packages/pyDes.py", line 710, in __init__
self.setKey(key)
File "/home/john/.local/lib/python2.7/site-packages/pyDes.py", line 727, in setKey
self._padding, self._padmode)
File "/home/john/.local/lib/python2.7/site-packages/pyDes.py", line 409, in __init__
self.setKey(key)
File "/home/john/.local/lib/python2.7/site-packages/pyDes.py", line 414, in setKey
self.__create_sub_keys()
File "/home/john/.local/lib/python2.7/site-packages/pyDes.py", line 462, in __create_sub_keys
key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey()))
File "/home/john/.local/lib/python2.7/site-packages/pyDes.py", line 421, in __String_to_BitList
data = [ord(c) for c in data]
TypeError: ord() expected string of length 1, but int found
>>> cipher1 = triple_des(sMAC,CBC,"\0\0\0\0\0\0\0\0",pad=None,padmode=PAD_PKCS5)
>>>
Hope this additional detail helps.
The for loop for ttl in xrange(1,MAX_HOPS): in get_route function is executing just once. it is supposed to run for values in range 1 to 30. I am posting my entire code. Please help.
import socket
import os
import sys
import struct
import time
import select
import binascii
ICMP_ECHO_REQUEST = 8
MAX_HOPS = 30
TIMEOUT = 2.0
TRIES = 2
def checksum(str):
csum = 0
countTo = (len(str) / 2) * 2
count = 0
while count < countTo:
thisVal = ord(str[count+1]) * 256 + ord(str[count])
csum = csum + thisVal
csum = csum & 0xffffffffL
count = count + 2
if countTo < len(str):
csum = csum + ord(str[len(str) - 1])
csum = csum & 0xffffffffL
csum = (csum >> 16) + (csum & 0xffff)
csum = csum + (csum >> 16)
answer = ~csum
answer = answer & 0xffff
answer = answer >> 8 | (answer << 8 & 0xff00)
return answer
def build_packet():
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
myChecksum = 0
ID = os.getpid() & 0xFFFF
# Make a dummy header with a 0 checksum.
# struct -- Interpret strings as packed binary data
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
data = struct.pack("d", time.time())
# Calculate the checksum on the data and the dummy header.
myChecksum = checksum(header + data)
# Get the right checksum, and put in the header
if sys.platform == 'darwin':
myChecksum = socket.htons(myChecksum) & 0xffff
#Convert 16-bit integers from host to network byte order.
else:
myChecksum = socket.htons(myChecksum)
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
packet = header + data
return packet
def get_route(hostname):
timeLeft = TIMEOUT
for ttl in xrange(1,MAX_HOPS):
for tries in xrange(TRIES):
destAddr = socket.gethostbyname(hostname)
#Fill in start
# Make a raw socket named mySocket
try:
mySocket = socket.socket(socket.AF_INET, socket.SOCK_RAW,socket.getprotobyname("icmp"))
except socket.error, (errno, msg):
if errno == 1:
raise socket.error(msg)
#Fill in end
mySocket.setsockopt(socket.IPPROTO_IP, socket.IP_TTL, struct.pack('I', ttl))
mySocket.settimeout(TIMEOUT)
try:
d = build_packet()
mySocket.sendto(d, (hostname, 0))
t = time.time()
startedSelect = time.time()
whatReady = select.select([mySocket], [], [], timeLeft)
howLongInSelect = (time.time() - startedSelect)
if whatReady[0] == []: # Timeout
print "* * * Request timed out."
recvPacket, addr = mySocket.recvfrom(1024)
print addr
timeReceived = time.time()
timeLeft = timeLeft - howLongInSelect
if timeLeft <= 0:
print "* * * Request timed out."
except socket.timeout:
continue
else:
#Fill in start
# Fetch the icmp type from the IP packet
unpackedPacket = struct.unpack_from("bbHHhd", recvPacket, 0)
(request_code, request_type, checksum, packet_id, sequence, timeSent) = unpackedPacket
#Fill in end
if request_type == 11:
bytes = struct.calcsize("d")
timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0]
print " %d rtt=%.0f ms %s" % (ttl,(timeReceived -t)*1000, addr[0])
elif request_type == 3:
bytes = struct.calcsize("d")
timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0]
print " %d rtt=%.0f ms %s" % (ttl,(timeReceived -t)*1000, addr[0])
elif request_type == 0:
bytes = struct.calcsize("d")
timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0]
print " %d rtt=%.0f ms %s" % (ttl,(timeReceived -timeSent)*1000, addr[0])
return
else:
print "error"
break
finally:
mySocket.close()
get_route("www.google.com")
I am working on a ICMP pinger program and have run into a problem. When i run the program i first do sudo su in the terminal so i have root access since we're required to use raw sockets and then when i run the program i get this traceback
sh-3.2# python3 icmp.py
Pinging 31.13.66.112 using Python:
Traceback (most recent call last):
File "icmp.py", line 149, in <module>
ping("www.facebook.com")
File "icmp.py", line 141, in ping
delay = doOnePing(dest,timeout)
File "icmp.py", line 123, in doOnePing
sendOnePing(mySocket,destAddr,myID)
File "icmp.py", line 111, in sendOnePing
mySocket.sendto(packet,(destAddr,1))
OSError: [Errno 56] Socket is already connected
here is the code I am running
import os
from socket import *
from sys import *
from struct import *
from time import *
from select import *
from binascii import *
ICMP_ECHO_REQUEST = 8
def checksum (val):
csum = 0
countTo = (len(val) // 2) * 2
count = 0
while count < countTo:
thisVal = val[count+1] * 256 + val[count]
csum = csum + thisVal
csum = csum & 0xffffffff
count = count + 2
if countTo < len(val):
csum = csum + val[len(val) - 1]
csum = csum & 0xffffffff
csum = (csum >> 16) + (csum & 0xffff)
csum = csum + (csum >> 16)
answer = ~csum
answer = answer & 0xffff
answer = answer >> 8 | (answer << 8 & 0xff00)
return answer
def receiveOnePing(mySocket,ID,timeout,destAddr):
timeLeft = timeout
while 1:
startedSelect = time()
whatReady = select([mySocket],[],[],timeLeft)
howLongInSelect = (time() - startedSelect)
if whatReady[0] == []: #Timeout
return "Request timed out."
timeReceived = time()
recPacket, addr = mySocket.recvfrom(1024)
icmpHeader = recPacket[20:28]
kind,code,checksum,idNum,sequence = unpack("bbHHh",icmpHeader)
if idNum == ID:
sizeofdouble = calcsize("d")
timeSent = unpack("d",recPacket[28:28+sizeofdouble])[0]
print(("TYPE: %d CODE: %d CHECKSUM: 0x%08x ID: %d SEQ: %d TIME: %d ms\n" % (kind,code,checksum,idNum,sequence,timeReceived - timeSent)*1000))
timeLeft = timeLeft - howLongInSelect
if timeLeft <= 0:
return "Request timed out."
else:
return "Reply from %s successfully." % destAddr
def sendOnePing(mySocket, destAddr, ID):
myChecksum = 0
header = pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
data = pack("d",time())
myChecksum = checksum(header + data)
if platform == 'darwin':
myChecksum = htons(myChecksum) & 0xffff
else:
myChecksum = htons(myChecksum)
header = pack("bbHHh", ICMP_ECHO_REQUEST,0,myChecksum,ID,1)
packet = header + data
mySocket.sendto(packet,(destAddr,1))
def doOnePing(destAddr,timeout):
icmp = getprotobyname("icmp")
mySocket = socket(AF_INET,SOCK_RAW,icmp)
mySocket.connect((destAddr,80))
myID = os.getpid() & 0xFFFF
sendOnePing(mySocket,destAddr,myID)
delay = receiveOnePing(mySocket,myID,timeout,destAddr)
mySocket.close()
return delay
def ping(host,timeout = 1):
dest = gethostbyname(host)
print("Pinging " + dest + " using Python:")
print()
while 1:
delay = doOnePing(dest,timeout)
print(delay)
sleep(1)
return delay
ping("www.facebook.com")
we were given a lab sheet with the "skeleton" program and we had to fill in the missing parts so Here is the lab sheet where the skeleton code was given
note: the skeleton and my program wont match perfectly due to the fact that i had to change things to fix other errors that occurred before this one.
I thank you for your help in advance,
Tyler
You should use "bind", instead of "connect". Then this program you should run as root like "sudo python3 icmp.py" for Linux or Mac OS.
Hope this help.
Thanks
So, you connect the socket (that is, tell it the peer address to send data to), and then call sendto providing a peer address again. The socket gets confused even if those two addresses are identical.
Either do not connect, or call send.
For my Computer Networking class, I'm trying to implement Traceroute using raw sockets with the ICMP protocol. I need to build a packet and then unpack the response packet using the Python struct class. Here is the code for building the packet:
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, pid, 1)
data = struct.pack("d", time.time())
packet = header + data
Later, I receive an ICMP packet in the same format with the confirmation. Here is the code for unpacking the packet:
request_code, request_type, checksum, packet_id, \
sequence, timeSent, data = struct.unpack("bbHHhd", recvPacket)
But I'm getting the following error: struct.error: unpack requires a string argument of length 16.
I don't understand because when I check struct.calcsize() for the format string, it returns 16.
Here is my full program if you would like to run it on your machine
from socket import *
import socket
import os
import sys
import struct
import time
import select
import binascii
ICMP_ECHO_REQUEST = 8
MAX_HOPS = 30
TIMEOUT = 2.0
TRIES = 2
# The packet that we shall send to each router along the path is the ICMP echo
# request packet, which is exactly what we had used in the ICMP ping exercise.
# We shall use the same packet that we built in the Ping exercise
def checksum(str):
csum = 0
countTo = (len(str) / 2) * 2
count = 0
while count < countTo:
thisVal = ord(str[count+1]) * 256 + ord(str[count])
csum = csum + thisVal
csum = csum & 0xffffffffL
count = count + 2
if countTo < len(str):
csum = csum + ord(str[len(str) - 1])
csum = csum & 0xffffffffL
csum = (csum >> 16) + (csum & 0xffff)
csum = csum + (csum >> 16)
answer = ~csum
answer = answer & 0xffff
answer = answer >> 8 | (answer << 8 & 0xff00)
return answer
def build_packet():
# In the sendOnePing() method of the ICMP Ping exercise ,firstly the header of our
# packet to be sent was made, secondly the checksum was appended to the header and
# then finally the complete packet was sent to the destination.
# Make the header in a similar way to the ping exercise.
# Header is type (8), code (8), checksum (16), id (16), sequence (16)
myChecksum = 0
pid = os.getpid() & 0xFFFF
# Make a dummy header with a 0 checksum.
# struct -- Interpret strings as packed binary data
header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, pid, 1)
#header = struct.pack("!HHHHH", ICMP_ECHO_REQUEST, 0, myChecksum, pid, 1)
data = struct.pack("d", time.time())
# Calculate the checksum on the data and the dummy header.
# Append checksum to the header.
myChecksum = checksum(header + data)
if sys.platform == 'darwin':
myChecksum = socket.htons(myChecksum) & 0xffff
#Convert 16-bit integers from host to network byte order.
else:
myChecksum = htons(myChecksum)
packet = header + data
return packet
def get_route(hostname):
timeLeft = TIMEOUT
for ttl in xrange(1,MAX_HOPS):
for tries in xrange(TRIES):
destAddr = socket.gethostbyname(hostname)
#Fill in start
# Make a raw socket named mySocket
mySocket = socket.socket(AF_INET, SOCK_RAW, getprotobyname("icmp"))
mySocket.bind(("", 12000));
#Fill in end
mySocket.setsockopt(socket.IPPROTO_IP, socket.IP_TTL, struct.pack('I', ttl))
mySocket.settimeout(TIMEOUT)
try:
d = build_packet()
mySocket.sendto(d, (hostname, 0))
t = time.time()
startedSelect = time.time()
whatReady = select.select([mySocket], [], [], timeLeft)
howLongInSelect = (time.time() - startedSelect)
if whatReady[0] == []: # Timeout
print "* * * Request timed out."
recvPacket, addr = mySocket.recvfrom(1024)
print addr
timeReceived = time.time()
timeLeft = timeLeft - howLongInSelect
if timeLeft <= 0:
print "* * * Request timed out."
except socket.timeout:
continue
else:
#Fill in start
# Fetch the icmp type from the IP packet
print struct.calcsize("bbHHhd")
request_code, request_type, checksum, packet_id, \
sequence, timeSent, data = struct.unpack("bbHHhd", recvPacket)
#Fill in end
if request_type == 11:
bytes = struct.calcsize("d")
timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0]
print " %d rtt=%.0f ms %s" % (ttl,(timeReceived -t)*1000, addr[0])
elif request_type == 3:
bytes = struct.calcsize("d")
timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0]
print " %d rtt=%.0f ms %s" % (ttl,(timeReceived -t)*1000, addr[0])
elif request_type == 0:
bytes = struct.calcsize("d")
timeSent = struct.unpack("d", recvPacket[28:28 + bytes])[0]
print " %d rtt=%.0f ms %s" % (ttl,(timeReceived -timeSent)*1000, addr[0])
return
else:
print "error"
break
finally:
mySocket.close()
get_route("www.google.com")
The struct.unpack function requires that the data you pass to it match the format string's length exactly.
If you have a large buffer and you only want to decode part of it, consider using the struct.unpack_from function instead. It takes an additional argument specifying the offset to begin decoding at, and accepts buffers larger than the format string describes:
(request_code, request_type, checksum, packet_id, sequence,
timeSent, data) = struct.unpack_from("bbHHhd", recvPacket, 0)
You may find this function useful if you want to decode other parts of the packet data after parsing the header.
recvPacket is bigger than your structure. If your structure is the first part of the data, unpack just the bytes of the structure:
pktFormat = 'bbHHhd'
pktSize = struct.calcsize(pktFormat)
... = struct.unpack(pktFormat, recvPacket[:pktSize])