I am trying to implement UDP stop-and-wait protocol using python socket programming. I have been trying out my code with different retransmission times. And sometimes I get all the files correctly received at the receiver, but sometimes some packets get lost. For example when I ran it with 40ms five times, twice the file was received correctly and three times incorrectly. Why is this variability happening?
Here is my code for the sender and receiver:
senderSocket = socket(AF_INET, SOCK_DGRAM) # Create UDP socket for sender
r = 0 # Number of retransmissions
for i in range(0, len(messages)):
senderSocket.settimeout(retryTimeout) # After the message is sent, set retransmission timeout to listen for acknowledgement
while True:
senderSocket.sendto(messages[i], (hostName, portNumber))
acknowledged = False
while not acknowledged:
try:
ack, receiverAddress = senderSocket.recvfrom(2) # Receive ACK
acknowledged = True
except: # Socket timeout exception occurs when timeout expires but no ACK received
senderSocket.sendto(messages[i], (hostName, portNumber)) # Retransmit the message
r = r + 1 # Increment the number of retransmissions
break # On to the next message
senderSocket.close()
while True:
message, senderAddress = receiverSocket.recvfrom(1027) # Read from UDP socket into message, getting sender's address (sender IP and port)
header = message[:3] # Header is the first 3 bytes (index 0, 1, 2)
data = message[3:] # Rest is the data
first_byte = '{0:08b}'.format(header[0])
second_byte = '{0:08b}'.format(header[1])
seq_num = int(first_byte + second_byte, 2) # Convert bytes to decimal
if seq_num not in seq_nums: # Detect duplicates
seq_nums.append(seq_num)
file_content.extend(data)
ack = header[:2] # ACK is the receipt of the received message (sequence number)
receiverSocket.sendto(ack, senderAddress) # Send ACK
if header[2] == 1: # Sent multiple ACKs at lat message to make sure it receives and the sender closes
receiverSocket.sendto(ack, senderAddress)
receiverSocket.sendto(ack, senderAddress)
receiverSocket.sendto(ack, senderAddress)
break
receiverSocket.close()
I am trying to do these steps :
read pcap file
analyze the packets and show connections that have not been set up properly
is it possible to extract information like this ?
i have write Python classes to extract Packet Header , Packet's Ethernet , Packet IP , Packet TCP information. i need guidance that is it possible to extract information like this ? hva_pcao.py , hva_pckt
rdr = pcap.open_offline('xsupport.pcap')
i = 0
for hdr, data in rdr:
if i ==2:
print(hdr)
eth = Eth.decode(data)
if eth is None: continue
print(str(eth))
ip = Ip.decode(eth.pl)
if ip is None: continue
print(str(ip))
tcp = Tcp.decode(ip.pl)
if tcp is None: continue
print(str(tcp))
print((repr(tcp.flags) + " - " + repr(tcp.kFlags_FIN) + " * " + repr(tcp.kFlags_ACK)))
# break
My expected output is : analyze the packets and show connections that have not been set up properly
How can I find with scapy wireless networks around? If I do sniff() and if pkt.haslayer(Dot11) and then if pkt.info then I collect them but very slow, for example my Android phone do it in seconds and this script in minutes or even more...
The reason for the difference is that your phone is actively looking for WiFi points by sending out requests to any access points nearby - sniff is listening for any passing traffic.
You might find is a lot quicker to:
Specifically select your network adapter - so you are not sniffing all adapters.
Do some digging to find out how to actively query for wifi networks and use sr with such packets, read the IEEE 802.11 specification to find out more, I would especially look for "Probe request frame".
The example on how to send WiFi packets from packet header may well help, (not my code and not tested by me):
#!/usr/bin/env python
"""
802.11 Scapy Packet Example
Author: Joff Thyer, 2014
"""
# if we set logging to ERROR level, it supresses the warning message
# from Scapy about ipv6 routing
# WARNING: No route found for IPv6 destination :: (no default route?)
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import *
class Scapy80211():
def __init__(self,intf='wlan0',ssid='test',\
source='00:00:de:ad:be:ef',\
bssid='00:11:22:33:44:55',srcip='10.10.10.10'):
self.rates = "\x03\x12\x96\x18\x24\x30\x48\x60"
self.ssid = ssid
self.source = source
self.srcip = srcip
self.bssid = bssid
self.intf = intf
self.intfmon = intf + 'mon'
# set Scapy conf.iface
conf.iface = self.intfmon
# create monitor interface using iw
cmd = '/sbin/iw dev %s interface add %s type monitor >/dev/null 2>&1' \
% (self.intf, self.intfmon)
try:
os.system(cmd)
except:
raise
def Beacon(self,count=10,ssid='',dst='ff:ff:ff:ff:ff:ff'):
if not ssid: ssid=self.ssid
beacon = Dot11Beacon(cap=0x2104)
essid = Dot11Elt(ID='SSID',info=ssid)
rates = Dot11Elt(ID='Rates',info=self.rates)
dsset = Dot11Elt(ID='DSset',info='\x01')
tim = Dot11Elt(ID='TIM',info='\x00\x01\x00\x00')
pkt = RadioTap()\
/Dot11(type=0,subtype=8,addr1=dst,addr2=self.source,addr3=self.bssid)\
/beacon/essid/rates/dsset/tim
print '[*] 802.11 Beacon: SSID=[%s], count=%d' % (ssid,count)
try:
sendp(pkt,iface=self.intfmon,count=count,inter=0.1,verbose=0)
except:
raise
def ProbeReq(self,count=10,ssid='',dst='ff:ff:ff:ff:ff:ff'):
if not ssid: ssid=self.ssid
param = Dot11ProbeReq()
essid = Dot11Elt(ID='SSID',info=ssid)
rates = Dot11Elt(ID='Rates',info=self.rates)
dsset = Dot11Elt(ID='DSset',info='\x01')
pkt = RadioTap()\
/Dot11(type=0,subtype=4,addr1=dst,addr2=self.source,addr3=self.bssid)\
/param/essid/rates/dsset
print '[*] 802.11 Probe Request: SSID=[%s], count=%d' % (ssid,count)
try:
sendp(pkt,count=count,inter=0.1,verbose=0)
except:
raise
def ARP(self,targetip,count=1,toDS=False):
if not targetip: return
arp = LLC()/SNAP()/ARP(op='who-has',psrc=self.srcip,pdst=targetip,hwsrc=self.source)
if toDS:
pkt = RadioTap()\
/Dot11(type=2,subtype=32,FCfield='to-DS',\
addr1=self.bssid,addr2=self.source,addr3='ff:ff:ff:ff:ff:ff')\
/arp
else:
pkt = RadioTap()\
/Dot11(type=2,subtype=32,\
addr1='ff:ff:ff:ff:ff:ff',addr2=self.source,addr3=self.bssid)\
/arp
print '[*] ARP Req: who-has %s' % (targetip)
try:
sendp(pkt,inter=0.1,verbose=0,count=count)
except:
raise
ans = sniff(lfilter = lambda x: x.haslayer(ARP) and x.op == 2,
store=1,count=1,timeout=1)
if len(ans) > 0:
return ans[0][ARP].hwsrc
else:
return None
def DNSQuery(self,query='www.google.com',qtype='A',ns=None,count=1,toDS=False):
if ns == None: return
dstmac = self.ARP(ns)
dns = LLC()/SNAP()/IP(src=self.srcip,dst=ns)/\
UDP(sport=random.randint(49152,65535),dport=53)/\
DNS(qd=DNSQR(qname=query,qtype=qtype))
if toDS:
pkt = RadioTap()\
/Dot11(type=2,subtype=32,FCfield='to-DS',\
addr1=self.bssid,addr2=self.source,addr3=dstmac)/dns
else:
pkt = RadioTap()\
/Dot11(type=2,subtype=32,\
addr1=dstmac,addr2=self.source,addr3=self.bssid)/dns
print '[*] DNS query %s (%s) -> %s?' % (query,qtype,ns)
try:
sendp(pkt,count=count,verbose=0)
except:
raise
# main routine
if __name__ == "__main__":
print """
[*] 802.11 Scapy Packet Crafting Example
[*] Assumes 'wlan0' is your wireless NIC!
[*] Author: Joff Thyer, 2014
"""
sdot11 = Scapy80211(intf='wlan0')
sdot11.Beacon()
sdot11.ProbeReq()
sdot11.DNSQuery(ns='10.10.10.2')
I once wrote a script that could scan wireless network .
Its simple to use :
python rs.py mon0
Here mon0 is our interface. There are comments in the code to understand it properly.
#Implementation of a wireless scanner using Scapy library
#!/usr/bin/env python
# rs.py - Wireless AP scanner
#author rahil sharma
# date 15/3/2013 #rs
#usage python rs.py mon0
#where mon0 is your monitoring interface
#used this using my alfa card in bactrack
import sys, os, signal
from multiprocessing import Process
from scapy.all import *
interface='' # monitor interface
aps = {} # dictionary to store unique APs
# process unique sniffed Beacons and ProbeResponses.
#haslayer packet has Dot11 layer present
#ord() string to integer ex ord('a) will give 97
def sniffAP(p):
if ( (p.haslayer(Dot11Beacon))):
ssid = p[Dot11Elt].info
bssid = p[Dot11].addr3
channel = int( ord(p[Dot11Elt:3].info))
capability = p.sprintf("{Dot11Beacon:%Dot11Beacon.cap%}\
{Dot11ProbeResp:%Dot11ProbeResp.cap%}")
# Check for encrypted networks
#now we put Dot11Beacon.cap info in capability and using regular expression search inbuilt function in python we search for privacy if it is present then the network is encrypted
#output of the above cap file is somewhat like this short-slot+DSSS-OFDM+res15+ESS
if re.search("privacy", capability): enc = 'Y'
else: enc = 'N'
# Save discovered AP
aps[p[Dot11].addr3] = enc
# Display discovered AP
print "%02d %s %s %s" % (int(channel), enc, bssid, ssid)
# Channel hopper - we are making a channel hopper because we want to scan the whole wireless spectrum.
#first choose a random channel using randrange function
#use system to run the shell command iw dev wlan0 set channel 1
#exit when a keyboard interrupt is given CTrl+c
def channel_hopper():
while True:
try:
channel = random.randrange(1,15)
os.system("iw dev %s set channel %d" % (interface, channel))
time.sleep(1)
except KeyboardInterrupt:
break
# Capture interrupt signal and cleanup before exiting
#terminate is used to end the child process
#before exiting the program we will be displaying number of aps found etc.
#here Cntrl+c is used to
#signal_handler used to do clean up before the program exits
def signal_handler(signal, frame):
p.terminate()
p.join()
print "\n-=-=-=-=-= STATISTICS =-=-=-=-=-=-"
print "Total APs found: %d" % len(aps)
print "Encrypted APs : %d" % len([ap for ap in aps if aps[ap] =='Y'])
print "Unencrypted APs: %d" % len([ap for ap in aps if aps[ap] =='N'])
sys.exit(0)
#use this for command line variables
#for checking the number of command line variables and if they are in right order
if __name__ == "__main__":
if len(sys.argv) != 2:
print "Usage %s monitor_interface" % sys.argv[0]
sys.exit(1)
interface = sys.argv[1]
#take mon0 as interface given in the fist command line variable
# Print the program header
print "-=-=-=-=-=-= rs_scan.py =-=-=-=-=-=-"
print "CH ENC BSSID SSID"
# Start the channel hopper
#In multiprocessing, processes are spawned by creating a Process object and then calling its start() method
p = Process(target = channel_hopper)
p.start()
# Capture CTRL-C
#this will call the signal handler CTRL+C comes under the SIGINT
signal.signal(signal.SIGINT, signal_handler)
# Start the sniffer
sniff(iface=interface,prn=sniffAP)
#inbuit scapy function to start sniffing calls a function which defines the criteria and we need to give the interface`enter code here`
I'm using Python 2.7.5 to send a message to a modbus tcp simulator. What I do not understand is why python is sending the last byte twice on sendall:
This is what the python script prints out per my code (below)...
S: 00020000000c1110000400030600790083008d
R: 000200000006111000040003
R: 8d0000000003d8f603
The simulator logs this where (TX is received from script and RX is sent to script)...
TX: 00020000000c1110000400030600790083008d
RX: 000200000006111000040003
TX: 8d
Modbus message in error x03
RX: 8d0000000003d8f603
So question is...why is 8d sent twice (according to the modbus simulator listening)? The simulator is throwing an error because of it...
Code excerpt:
def writeMultipleHoldingRegister(socket, transactionid, unitid, address,valuesToWrite):
TRANSACT_ID_BYTES = convertIntToBytes(int(transactionid))
DATA_ADDRESS_BYTES = convertIntToBytes(int(address))
FUNCTIONCODE_BYTES = '10'
NUMREGISTERS_BYTES = convertIntToBytes(len(valuesToWrite))
NUMBYTES = len(valuesToWrite)*2
NUMBYTES_BYTES = str(('%04X' % NUMBYTES)[2:4])
MESSAGE_LENGTH_BYTES = convertIntToBytes(int(6+(len(valuesToWrite)*2)))
modbustcp_write = (TRANSACT_ID_BYTES + '0000' + MESSAGE_LENGTH_BYTES + unitid + FUNCTIONCODE_BYTES + DATA_ADDRESS_BYTES + NUMREGISTERS_BYTES + NUMBYTES_BYTES).decode('hex')
for value in valuesToWrite:
modbustcp_write = modbustcp_write + convertIntToBytes(int(value)).decode('hex')
print 'S:', binascii.hexlify(modbustcp_write)
socket.sendall(modbustcp_write) #modbus tcp
data = socket.recv(12)
print 'R:', binascii.hexlify(data)
HOST = 'localhost'
PORT = 502
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
writeMultipleHoldingRegister(s, 2, '11', 4, [121, 131, 141])
print 'R:', binascii.hexlify(s.recv(100))
s.close()
Followed advice left in comment. Process Monitor showed me the traffic but not the bytes themselves. So I downloaded and ran RawCAP and viewed the output in Wireshark. To paraphrase...where 'S' is sent by simulator and 'R' is received by simulator...
R: 00020000000c1110000400030600790083008d (modbus request recv)
S: 000200000006111000040003 (modbus ack good request sent)
S: 8d0000000003d8f603 (modbus error notification sent...wtf)
I never see a '8d' received twice...so I don't know what's going on here. Maybe a bug in the simulator... http://www.plcsimulator.org/
How can I parse a ICMP packet (using dpkt) to check if it is a request or a response coming from A to B?
I found some examples for TCP and UDP packets (below) but I can't find anything for IP packets.
import dpkt
f = open('test.pcap')
pcap = dpkt.pcap.Reader(f)
for ts, buf in pcap:
eth = dpkt.ethernet.Ethernet(buf)
ip = eth.data
tcp = ip.data
if tcp.dport == 80 and len(tcp.data) > 0:
http = dpkt.http.Request(tcp.data)
print http.uri
f.close()
Also, is there any good tutorial for dpkt?
This is an old question but for folks coming across this, I've added an ICMP example to the dpkt repo. The docs can be found here: http://dpkt.readthedocs.io/en/latest/print_icmp.html and the example code can be found in dpkt/examples/print_icmp.py
# For each packet in the pcap process the contents
for timestamp, buf in pcap:
# Unpack the Ethernet frame (mac src/dst, ethertype)
eth = dpkt.ethernet.Ethernet(buf)
# Make sure the Ethernet data contains an IP packet
if not isinstance(eth.data, dpkt.ip.IP):
print 'Non IP Packet type not supported %s\n' % eth.data.__class__.__name__
continue
# Now grab the data within the Ethernet frame (the IP packet)
ip = eth.data
# Now check if this is an ICMP packet
if isinstance(ip.data, dpkt.icmp.ICMP):
icmp = ip.data
# Pull out fragment information
do_not_fragment = bool(ip.off & dpkt.ip.IP_DF)
more_fragments = bool(ip.off & dpkt.ip.IP_MF)
fragment_offset = ip.off & dpkt.ip.IP_OFFMASK
# Print out the info
print 'Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp))
print 'Ethernet Frame: ', mac_addr(eth.src), mac_addr(eth.dst), eth.type
print 'IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)' % \
(inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl,
do_not_fragment, more_fragments, fragment_offset)
print 'ICMP: type:%d code:%d checksum:%d data: %s\n' % (icmp.type,
icmp.code, icmp.sum, repr(icmp.data))
Example Output
Timestamp: 2013-05-30 22:45:17.283187
Ethernet Frame: 60:33:4b:13:c5:58 02:1a:11:f0:c8:3b 2048
IP: 192.168.43.9 -> 8.8.8.8 (len=84 ttl=64 DF=0 MF=0 offset=0)
ICMP: type:8 code:0 checksum:48051 data: Echo(id=55099, data='Q\xa7\xd6}\x00\x04Q\xe4\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567')
Timestamp: 2013-05-30 22:45:17.775391
Ethernet Frame: 02:1a:11:f0:c8:3b 60:33:4b:13:c5:58 2048
IP: 8.8.8.8 -> 192.168.43.9 (len=84 ttl=40 DF=0 MF=0 offset=0)
ICMP: type:0 code:0 checksum:50099 data: Echo(id=55099, data='Q\xa7\xd6}\x00\x04Q\xe4\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567')