Increase SYN packet sending rate in the python script - python

I am using raw sockets in python to send SYN packets repeatedly at high rate for a project. I am able to send SYN at a rate of 120 Mb/S using below python Script. Is there a way to optimize it to increase the rate of the packets?
I think CPU is the bottleneck, as my NIC supports upto 1 Gbps. I am even constructing the packet once and just resending it repeatedly.
# some imports
import thread
import socket, sys
from struct import *
import time
import datetime as dt
def sendFunc(s, packet, dest_ip, sizeOfPacket):
start_time = time.time()
i = 0
while(1):
time_diff = time.time() - start_time
i = i + 1
if time_diff > 1:
start_time = time.time()
print i*sizeOfPacket
i = 0
s.sendto(packet, (dest_ip , 0 )) # put this in a loop if you want to flood the target
# checksum functions needed for calculation checksum
def checksum(msg):
s = 0
# loop taking 2 characters at a time
for i in range(0, len(msg), 2):
w = (ord(msg[i]) << 8) + (ord(msg[i+1]) )
s = s + w
s = (s>>16) + (s & 0xffff);
#s = s + (s >> 16);
#complement and mask to 4 byte short
s = ~s & 0xffff
return s
#create a raw socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
except socket.error , msg:
print 'Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
# tell kernel not to put in headers, since we are providing it
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# now start constructing the packet
packet = '';
source_ip = 'x.x.x.x'
dest_ip = 'y.y.y.y' # or socket.gethostbyname('www.google.com')
# ip header fields
ihl = 5
version = 4
tos = 0
tot_len = 20 + 20 # python seems to correctly fill the total length, dont know how ??
id = 54321 #Id of this packet
frag_off = 0
ttl = 255
protocol = socket.IPPROTO_TCP
check = 10 # python seems to correctly fill the checksum
saddr = socket.inet_aton ( source_ip ) #Spoof the source ip address if you want to
daddr = socket.inet_aton ( dest_ip )
ihl_version = (version << 4) + ihl
# the ! in the pack format string means network order
ip_header = pack('!BBHHHBBH4s4s' , ihl_version, tos, tot_len, id, frag_off, ttl, protocol, check, saddr, daddr)
# tcp header fields
source = 1234 # source port
dest = 80 # destination port
seq = 0
ack_seq = 0
doff = 5 #4 bit field, size of tcp header, 5 * 4 = 20 bytes
#tcp flags
fin = 0
syn = 1
rst = 0
psh = 0
ack = 0
urg = 0
window = socket.htons (5840) # maximum allowed window size
check = 0
urg_ptr = 0
offset_res = (doff << 4) + 0
tcp_flags = fin + (syn << 1) + (rst << 2) + (psh <<3) + (ack << 4) + (urg << 5)
# the ! in the pack format string means network order
tcp_header = pack('!HHLLBBHHH' , source, dest, seq, ack_seq, offset_res, tcp_flags, window, check, urg_ptr)
# pseudo header fields
source_address = socket.inet_aton( source_ip )
dest_address = socket.inet_aton(dest_ip)
placeholder = 0
protocol = socket.IPPROTO_TCP
tcp_length = len(tcp_header)
psh = pack('!4s4sBBH' , source_address , dest_address , placeholder , protocol , tcp_length);
psh = psh + tcp_header;
tcp_checksum = checksum(psh)
# make the tcp header again and fill the correct checksum
tcp_header = pack('!HHLLBBHHH' , source, dest, seq, ack_seq, offset_res, tcp_flags, window, tcp_checksum , urg_ptr)
# final full packet - syn packets dont have any data
packet = ip_header + tcp_header
#Send the packet finally - the port specified has no effect
print "size of packet", len(packet)
sendFunc(s, packet, dest_ip, len(packet))

Related

TCP model , implementing seq_number [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I use TCP for transmission layer.But may be my payload is bigger than my buffer, So I have to implement seq_number of TCP in my payloads. Do you know some class or module or some way to do it?
UPDATE:
My packet contains header+payload.
If you would like to implement the TCP seq_number logic by yourself theres this github repository called "TCP Emulator":
https://github.com/ohEmily/tcp-emulator-python
If you want only to create tcp packet header with seq_number i'de use the Python socket module
#!/usr/bin/python
import socket
import struct
class TCPPacket:
def __init__(self, dport = 80, sport = 65535, dst='127.0.0.1', src='192.168.1.101', data = 'Nothing'):
self.dport = dport
self.sport = sport
self.src_ip = src
self.dst_ip = dst
self.data = data
self.raw = None
self.create_tcp_feilds()
def assemble_tcp_feilds(self):
self.raw = struct.pack('!HHLLBBHHH', # Data Structure Representation
self.tcp_src, # Source IP
self.tcp_dst, # Destination IP
self.tcp_seq, # Sequence
self.tcp_ack_seq, # Acknownlegment Sequence
self.tcp_hdr_len, # Header Length
self.tcp_flags , # TCP Flags
self.tcp_wdw, # TCP Windows
self.tcp_chksum, # TCP cheksum
self.tcp_urg_ptr # TCP Urgent Pointer
)
self.calculate_chksum() # Call Calculate CheckSum
return
def reassemble_tcp_feilds(self):
self.raw = struct.pack('!HHLLBBH',
self.tcp_src,
self.tcp_dst,
self.tcp_seq,
self.tcp_ack_seq,
self.tcp_hdr_len,
self.tcp_flags ,
self.tcp_wdw
)+
struct.pack("H",
self.tcp_chksum
)+
struct.pack('!H',
self.tcp_urg_ptr
)
return
def calculate_chksum(self):
src_addr = socket.inet_aton( self.src_ip )
dest_addr = socket.inet_aton( self.dst_ip )
placeholder = 0
protocol = socket.IPPROTO_TCP
tcp_len = len(self.raw) + len(self.data)
psh = struct.pack('!4s4sBBH' ,
src_addr ,
dest_addr ,
placeholder ,
protocol ,
tcp_len
)
psh = psh + self.raw + self.data
self.tcp_chksum = self.chksum(psh)
self.reassemble_tcp_feilds()
return
def chksum(self, msg):
s = 0 # Binary Sum
# loop taking 2 characters at a time
for i in range(0, len(msg), 2):
a = ord(msg[i])
b = ord(msg[i+1])
s = s + (a+(b << 8))
# One's Complement
s = s + (s >> 16)
s = ~s & 0xffff
return s
def create_tcp_feilds(self):
# ---- [ Source Port ]
self.tcp_src = self.sport
# ---- [ Destination Port ]
self.tcp_dst = self.dport
# ---- [ TCP Sequence Number]
self.tcp_seq = 0
# ---- [ TCP Acknowledgement Number]
self.tcp_ack_seq = 0
# ---- [ Header Length ]
self.tcp_hdr_len = 80
# ---- [ TCP Flags ]
tcp_flags_rsv = (0 << 9)
tcp_flags_noc = (0 << 8)
tcp_flags_cwr = (0 << 7)
tcp_flags_ecn = (0 << 6)
tcp_flags_urg = (0 << 5)
tcp_flags_ack = (0 << 4)
tcp_flags_psh = (0 << 3)
tcp_flags_rst = (0 << 2)
tcp_flags_syn = (1 << 1)
tcp_flags_fin = (0)
self.tcp_flags = tcp_flags_rsv + tcp_flags_noc + tcp_flags_cwr + \
tcp_flags_ecn + tcp_flags_urg + tcp_flags_ack + \
tcp_flags_psh + tcp_flags_rst + tcp_flags_syn + tcp_flags_fin
# ---- [ TCP Window Size ]
self.tcp_wdw = socket.htons (5840)
# ---- [ TCP CheckSum ]
self.tcp_chksum = 0
# ---- [ TCP Urgent Pointer ]
self.tcp_urg_ptr = 0
return
In order to run it:
if __name__=='__main__':
# Create Raw Socket
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
tcp = TCPPacket()
tcp.assemble_tcp_feilds()
s.sendto(tcp.raw, ('127.0.0.1' , 0 ))
Source: http://www.bitforestinfo.com/2017/12/code-to-create-tcp-packet-header-with-python-socket-module.html

struct.pack raises "struct.error: required argument is not an integer"

I am trying to make a network proxy which will forward packets to another IP. I can sniff a packet, unpack it, and view, print, and manipulate its contents. But when I want to pack the bytes to forward it to some other IP, it gives this error:
struct.error: required argument is not an integer
The error is raised on this line of code:
ip_header = struct.pack('!BBHHHBBH4s4s' ,version_IHL, TOS, totalLength, ID,flags, TTL,protocolNR, checksum,sourceAddress,destinationAddress)
Here is the code. Bold stuff in code are comments in my code.
import socket
import sys
import struct
import re
import logging
import struct
from scapy.all import *
import Functions
logging.basicConfig(filename='example.log',level=logging.DEBUG)
hold = "192.168.0.125"
print ("\n\t\t\t**************************")
print ("\t\t\t*****SettingUp Server*****")
print ("\t\t\t**************************\n\n")
print("\t*****Implementing DHKE")
print ("\t*****Generating server public & private keypairs now . . .")
(e,n), private = Functions.generate_keypair(7, 11)
print ("*****Public Key: {} , {} ", e,n)
print ("*****Private key: {} ", private)
public = (e,n)
ip = '192.168.0.125'
port = 5001
# the public network interface
#HOST = socket.gethostbyname(socket.gethostname())
#..............................................................................................
# create a raw socket and bind it to the public interface
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind(('192.168.0.117',5001))
# Include IP headers
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('format=%(asctime)s %(message)s')
# receive all packages
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
#..............................................................................................
data = Functions.recievedata(s)
logging.info('**Packet Recieved')
print("Packet Recieved")
#function_data = tuple(struct.unpack(data))
unpacked_data = struct.unpack('!BBHHHBBH4s4s',data[:20])
listunpacked = list(unpacked_data)
logging.info('--> Unpacking packet')
version_IHL = unpacked_data[0]
version = version_IHL >>4
IHL = version_IHL & 0xF
TOS = unpacked_data[1]
totalLength = unpacked_data[2]
ID = unpacked_data[3]
flags = unpacked_data[4]
fragmentOffset = unpacked_data[4] & 0x1FFF
TTL = unpacked_data[5]
protocolNR = unpacked_data[6]
checksum = unpacked_data[7]
sourceAddress = socket.inet_ntoa(unpacked_data[8])
destinationAddress = socket.inet_ntoa(unpacked_data[9])
#..............................................................................................
print("An IP packet with the size %i is captured.", (totalLength))
print("Raw data: "+ str(data))
print("\nParsed data")
print("Version:\t\t"+ str(version))
print("Header length:\t\t"+ str(IHL*4)+'bytes')
print("Type of service:\t\t" + str(Functions.getTOS(TOS)))
print("Length:\t\t\t"+str(totalLength))
print("ID:\t\t\t"+str(hex(ID)) + ' {' + str(ID) + '}')
print("Flags:\t\t\t" + Functions.getFlags(flags))
print("Fragment offset:\t" + str(fragmentOffset))
print( "TTL:\t\t\t"+str(TTL))
print("Protocol:\t\t" + Functions.getProtocol(protocolNR))
print("Checksum:\t\t" + str(checksum))
print("Source:\t\t\t" + sourceAddress)
print("Destination:\t\t" + destinationAddress)
print("Payload:\n"+str(data[20:]))
# receive a package
#print(s.recvfrom(65565))
#IP = input("Enter IP address to send: ")
#port = int(input("Port: "))
#..............................................................................................
print("\tOld Destination: "+ destinationAddress)
listunpacked[9] = hold
unpacked_data = tuple(listunpacked)
print("\n\t\tNew Address is: "+ unpacked_data[9])
print()
#s.inet_aton(unpacked_data[9]) = hold
#unpacked_data = tuple(listunpacked)
#unpacked_data = bytes(unpacked_data)
#destinationAddress = socket.inet_ntoa(unpacked_data[9])
#..............................................................................................
# tcp header fields
tcp_source = 80 # source port
tcp_dest = 5001 # destination port
tcp_seq = 454
tcp_ack_seq = 0
tcp_doff = 5 # 4 bit field, size of tcp header, 5 * 4 = 20 bytes
# tcp flags
tcp_fin = 0
tcp_syn = 1
tcp_rst = 0
tcp_psh = 0
tcp_ack = 0
tcp_urg = 0
tcp_window = socket.htons(5840) # maximum allowed window size
tcp_check = 0
tcp_urg_ptr = 0
tcp_offset_res = (tcp_doff << 4) + 0
tcp_flags = tcp_fin + (tcp_syn << 1) + (tcp_rst << 2) + (tcp_psh << 3) + (tcp_ack << 4) + (tcp_urg << 5)
# the ! in the pack format string means network order
tcp_header = tuple(struct.pack('!HHLLBBHHH', tcp_source, tcp_dest, tcp_seq, tcp_ack_seq, tcp_offset_res, tcp_flags, tcp_window,tcp_check, tcp_urg_ptr))
#p =(data+tcp_header)
#hold = bytes(hold,"utf-8")
#hold = socket.inet_aton ( hold )
#checksum = bytes(checksum,"utf-8")
#destinationAddress = c_int(listunpacked[9])
checksum = bytes(str(checksum),"utf-8")
#ip_header = struct.pack('!BBHHHBBH4s4s' , version_IHL, TOS, totalLength, ID,flags, TTL,protocolNR, checksum,sourceAddress,destinationAddress)
#tcp_header = struct.pack('!HHLLBBH' , tcp_source, tcp_dest, tcp_seq, tcp_ack_seq, tcp_offset_res, tcp_flags, tcp_window) + struct.pack('H' , tcp_check) + struct.pack('!H' , tcp_urg_ptr)
#packet = ip_header + tcp_header + str(data[20:])
message = "How are you"
#data = bytes(unpacked_data,"utf-8") + tcp_header + message
ip_header = struct.pack('!BBHHHBBH4s4s' ,version_IHL, TOS, totalLength, ID,flags, TTL,protocolNR, checksum,sourceAddress,destinationAddress)
data = bytes(unpacked_data) + data[20:]
s.sendto(data, ("192.168.0.125" , 5001))
print("Packet sent")
# disabled promiscuous mode
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
ip_header = struct.pack('!BBHHHBBH4s4s' ,version_IHL, TOS, totalLength, ID,flags, TTL,protocolNR, checksum,sourceAddress,destinationAddress)
Both the B and H formats require integer arguments (or non-integer objects that implement the __index__ method) (see Format Characters).
The checksum argument is now of type bytes because you set it here before packing:
checksum = bytes(str(checksum),"utf-8")
And bytes objects do not implement the __index__ method.
You can check this using dir(checksum).
That's why you're getting the struct.error exception.
When packing a value x using one of the integer formats ('b', 'B',
'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'), if x is outside the valid
range for that format then struct.error is raised.
Either:
Use a different variable for the bytes(str(checksum),"utf-8") output
Pass an int type object for the checksum value

Socket Error when using socket.sendto()

So, I have a problem where when I use s.sendto(). Once I arrange all the information to be put into the packet and I try to send it, it ends up telling me there is something wrong with my arguments.
The code below is the code I'm using (admittedly from this website).
# some imports
import socket, sys
from struct import *
# checksum functions needed for calculation checksum
def checksum(msg):
s = 0
# loop taking 2 characters at a time
for i in range(0, len(msg), 2):
w = (ord(msg[i]) << 8) + (ord(msg[i+1]) )
s = s + w
s = (s>>16) + (s & 0xffff);
#s = s + (s >> 16);
#complement and mask to 4 byte short
s = ~s & 0xffff
return s
#create a raw socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
except socket.error , msg:
print 'Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
# tell kernel not to put in headers, since we are providing it
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
# now start constructing the packet
packet = '';
source_ip = '192.168.0.13'
dest_ip = '192.168.0.1' # or socket.gethostbyname('www.google.com')
# ip header fields
ihl = 5
version = 4
tos = 0
tot_len = 20 + 20 # python seems to correctly fill the total length, dont know how ??
id = 54321 #Id of this packet
frag_off = 0
ttl = 255
protocol = socket.IPPROTO_TCP
check = 10 # python seems to correctly fill the checksum
saddr = socket.inet_aton ( source_ip ) #Spoof the source ip address if you want to
daddr = socket.inet_aton ( dest_ip )
ihl_version = (version << 4) + ihl
# the ! in the pack format string means network order
ip_header = pack('!BBHHHBBH4s4s' , ihl_version, tos, tot_len, id, frag_off, ttl, protocol, check, saddr, daddr)
# tcp header fields
source = 1234 # source port
dest = 80 # destination port
seq = 0
ack_seq = 0
doff = 5 #4 bit field, size of tcp header, 5 * 4 = 20 bytes
#tcp flags
fin = 0
syn = 1
rst = 0
psh = 0
ack = 0
urg = 0
window = socket.htons (5840) # maximum allowed window size
check = 0
urg_ptr = 0
offset_res = (doff << 4) + 0
tcp_flags = fin + (syn << 1) + (rst << 2) + (psh <<3) + (ack << 4) + (urg << 5)
# the ! in the pack format string means network order
tcp_header = pack('!HHLLBBHHH' , source, dest, seq, ack_seq, offset_res, tcp_flags, window, check, urg_ptr)
# pseudo header fields
source_address = socket.inet_aton( source_ip )
dest_address = socket.inet_aton(dest_ip)
placeholder = 0
protocol = socket.IPPROTO_TCP
tcp_length = len(tcp_header)
psh = pack('!4s4sBBH' , source_address , dest_address , placeholder , protocol , tcp_length);
psh = psh + tcp_header;
tcp_checksum = checksum(psh)
# make the tcp header again and fill the correct checksum
tcp_header = pack('!HHLLBBHHH' , source, dest, seq, ack_seq, offset_res, tcp_flags, window, tcp_checksum , urg_ptr)
# final full packet - syn packets dont have any data
packet = ip_header + tcp_header
#Send the packet finally - the port specified has no effect
while True:
s.sendto(packet, (dest_ip , 80))
And when I run it, I get this error:
File "tcp-syn.py", line 98, in <module>
s.sendto(packet, (dest_ip , 80))
socket.error: [Errno 22] Invalid argument
Any help would be appreciated!

Why my TCP packet doesn't seems like a TCP packet for protocol analyzers?

I am trying to use raw sockets to send a GET request to a server. I am using raw sockets so I can edit the Packet window size. Here is my code.
import socket, sys
from struct import *
def checksum(msg):
s = 0
for i in range(0, len(msg), 2):
w = ord(msg[i]) + (ord(msg[i+1]) << 8 )
s = s + w
s = (s>>16) + (s & 0xffff);
s = s + (s >> 16);
s = ~s & 0xffff
return s
#create a raw socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
except socket.error , msg:
print 'Socket could not be created. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
# tell kernel not to put in headers, since we are providing it, when using IPPROTO_RAW this is not necessary
# s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
packet = '';
source_ip = '192.168.2.7'
dest_ip = '216.86.145.50' # or socket.gethostbyname('www.google.com')
# ip header fields
ip_ihl = 5
ip_ver = 4
ip_tos = 0
ip_tot_len = 0 # kernel will fill the correct total length
ip_id = 54321 #Id of this packet
ip_frag_off = 0
ip_ttl = 255
ip_proto = socket.IPPROTO_TCP
ip_check = 0 # kernel will fill the correct checksum
ip_saddr = socket.inet_aton ( source_ip ) #Spoof the source ip address if you want to
ip_daddr = socket.inet_aton ( dest_ip )
ip_ihl_ver = (ip_ver << 4) + ip_ihl
ip_header = pack('!BBHHHBBH4s4s' , ip_ihl_ver, ip_tos, ip_tot_len, ip_id, ip_frag_off, ip_ttl, ip_proto, ip_check, ip_saddr, ip_daddr)
# tcp header fields
tcp_source = 1234 # source port
tcp_dest = 80 # destination port
tcp_seq = 454
tcp_ack_seq = 0
tcp_doff = 5
#tcp flags
tcp_fin = 0
tcp_syn = 1
tcp_rst = 0
tcp_psh = 0
tcp_ack = 0
tcp_urg = 0
tcp_window = socket.htons (2048)
tcp_check = 0
tcp_urg_ptr = 0
tcp_offset_res = (tcp_doff << 4) + 0
tcp_flags = tcp_fin + (tcp_syn << 1) + (tcp_rst << 2) + (tcp_psh <<3) + (tcp_ack << 4) + (tcp_urg << 5)
tcp_header = pack('!HHLLBBHHH' , tcp_source, tcp_dest, tcp_seq, tcp_ack_seq, tcp_offset_res, tcp_flags, tcp_window, tcp_check, tcp_urg_ptr)
user_data = "GET / HTTP/1.1\r\nHost:www.example.com\n\nUser-Agent:Mozilla 5.0\r\n\r\n"
source_address = socket.inet_aton( source_ip )
dest_address = socket.inet_aton(dest_ip)
placeholder = 0
protocol = socket.IPPROTO_TCP
tcp_length = len(tcp_header) + len(user_data)
psh = pack('!4s4sBBH' , source_address , dest_address , placeholder , protocol , tcp_length);
psh = psh + tcp_header + user_data;
tcp_check = checksum(psh)
tcp_header = pack('!HHLLBBH' , tcp_source, tcp_dest, tcp_seq, tcp_ack_seq, tcp_offset_res, tcp_flags, tcp_window) + pack('H' , tcp_check) + pack('!H' , tcp_urg_ptr)
packet = ip_header + tcp_header + user_data
s.sendto(packet, (dest_ip , 0 ))
I am using Wireshark to view the packet being sent. The problem is the output is not a TCP GET request packet. In wire shark the output is the white in colour, under protocol it says IPv4 and info says: 144 Unknown(255). How do I fix this?
Like #Sivir said you need to establish a three way handshake because you want to use the TCP protocol. In theory the handshake should look like this
YourProgram: sends a SYN packet
Server: sends SYNACK packet
YourProgram: sends a ACK packet
More information regarding this can be found here.
It's because you send one single packet, but in TCP you have to setup connection first (3 ways handshake), then send request and then close connection.
Although it is possible to implement it using raw socket, there is a few parameters that you need to control during connection. If you tell why do you need to control window size, may be there is way to do it without TCP protocol implementation.

struct: unpack Requires String Argument of Length 16

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])

Categories

Resources