An application that can sniff packets in a local network and display protocol information.
Requirements:
– Linux
– Windows
– Python 2.7
Feature List:
+ Sniff packets in a local network.
+ Filter packets by specific protocol in real time.
+ Extract specific attributes from a filtered protocol in real time.
+ Calculate maximum diameter, maximum packet length, average diameter, and average packet size.
Protocol Support:
– Linux: Ethernet (MAC), ARP, IP, ICMP, TCP, UDP
– Windows: IP, ICMP, TCP, UDP
Sniffer-txt.py Script:
Sniffer-gui.py Script:
import socket, sys, time, platform, struct
from PyQt4 import QtGui, QtCore
class SniffThread(QtCore.QThread):
def eth(self, packet, extractedAttIndex, printKey):
# Header lengths.
ethHeaderLength = 14
# Get Ethernet header using begin and end.
# No need for windows calibration, Ethernet support under Linux only.
begin = 0
end = begin + ethHeaderLength
ethHeader = packet[begin:end]
# Unpack the header because it originally in hex.
# The regular expression helps unpack the header.
# ! signifies we are unpacking a network endian.
# 6s signifies we are unpacking a string of size 6 bytes.
# H signifies we are unpacking an integer of size 2 bytes.
ethHeaderUnpacked = struct.unpack('!6s6sH', ethHeader)
# The first 6s is 6 bytes and contains the destination address.
ethDestAddress = ethHeaderUnpacked[0]
# The second 6s is 6 bytes and contains the source address.
ethSourceAddress = ethHeaderUnpacked[1]
# The first H is 2 bytes and contains the packet length.
ethType = socket.ntohs(ethHeaderUnpacked[2])
# Properly unpack and format the destination address.
ethDestAddress = '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % (ord(ethDestAddress[0]), ord(ethDestAddress[1]), ord(ethDestAddress[2]), ord(ethDestAddress[3]), ord(ethDestAddress[4]), ord(ethDestAddress[5]))
# Properly unpack and format the source address.
ethSourceAddress = '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % (ord(ethSourceAddress[0]), ord(ethSourceAddress[1]), ord(ethSourceAddress[2]), ord(ethSourceAddress[3]), ord(ethSourceAddress[4]), ord(ethSourceAddress[5]))
# Check if the print key is 0.
# If true, header information will be printed.
# Check if the user selected extracted attribute index is 0.
# If true, all attributes will be printed.
# If false, the attribute the user selected extracted attribute index corresponds to will be printed.
# If false, the attribute the user selected attribute index corresponds to will be returned.
if printKey == 0:
# Print Ethernet Header
self.unpackedInfo.append('\n********************\n** Ethernet (MAC) **\n********************')
if (extractedAttIndex == 1) or (extractedAttIndex == 0):
self.unpackedInfo.append('Destination Address: ' + str(ethDestAddress))
if (extractedAttIndex == 2) or (extractedAttIndex == 0):
self.unpackedInfo.append('Source Address: ' + str(ethSourceAddress))
if (extractedAttIndex == 3) or (extractedAttIndex == 0):
self.unpackedInfo.append('EtherType: ' + str(ethType))
else:
if (extractedAttIndex == 1):
return str(ethDestAddress)
if (extractedAttIndex == 2):
return str(ethSourceAddress)
if (extractedAttIndex == 3):
return str(ethType)
def arp(self, packet, extractedAttIndex, printKey):
# Header lengths.
ethHeaderLength = 14
arpHeaderLength = 28
# Get ARP header using begin and end.
begin = ethHeaderLength
end = begin + arpHeaderLength
arpHeader = packet[begin:end]
# Unpack the header because it originally in hex.
# The regular expression helps unpack the header.
# ! signifies we are unpacking a network endian.
# H signifies we are unpacking an integer of size 2 bytes.
# B signifies we are unpacking an integer of size 1 byte.
# 6s signifies we are unpacking a string of size 6 bytes.
# 4s signifies we are unpacking a string of size 4 bytes.
arpHeaderUnpacked = struct.unpack('!HHBBH6s4s6s4s', arpHeader)
# The first H is 2 bytes and contains the hardware type.
arpHardwareType = socket.ntohs(arpHeaderUnpacked[0])
# The second H is 2 bytes and contains the protocol type.
arpProtocolType = socket.ntohs(arpHeaderUnpacked[1])
# The first B is 1 byte and contains the hardware address length.
arpHardAddressLength = arpHeaderUnpacked[2]
# The second B is 1 byte and contains the protocol address length.
arpProtAddressLength = arpHeaderUnpacked[3]
# The third H is 2 bytes and contains the operation.
arpOperation = arpHeaderUnpacked[4]
# The first 6s is 6 bytes and contains the sender hardware address.
arpSenderHardAddress = arpHeaderUnpacked[5]
# The first 4s is 4 bytes and contains the sender protocol address.
arpSenderProtAddress = socket.inet_ntoa(arpHeaderUnpacked[6])
# The second 6s is 6 bytes and contains the target hardware address.
arpTargetHardAddress = arpHeaderUnpacked[7]
# The second 4s is 4 bytes and contains the target protocol address.
arpTargetProtAddress = socket.inet_ntoa(arpHeaderUnpacked[8])
# Properly unpack and format the source MAC address.
arpSenderHardAddress = '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % (ord(arpSenderHardAddress[0]), ord(arpSenderHardAddress[1]), ord(arpSenderHardAddress[2]), ord(arpSenderHardAddress[3]), ord(arpSenderHardAddress[4]), ord(arpSenderHardAddress[5]))
# Properly unpack and format the destination MAC address.
arpTargetHardAddress = '%.2x:%.2x:%.2x:%.2x:%.2x:%.2x' % (ord(arpTargetHardAddress[0]), ord(arpTargetHardAddress[1]), ord(arpTargetHardAddress[2]), ord(arpTargetHardAddress[3]), ord(arpTargetHardAddress[4]), ord(arpTargetHardAddress[5]))
# Check if the print key is 0.
# If true, header information will be printed.
# Check if the user selected extracted attribute index is 0.
# If true, all attributes will be printed.
# If false, the attribute the user selected extracted attribute index corresponds to will be printed.
# If false, the attribute the user selected attribute index corresponds to will be returned.
if printKey == 0:
# Print ARP Header
self.unpackedInfo.append('\n*******************\n******* ARP *******\n*******************')
if (extractedAttIndex == 1) or (extractedAttIndex == 0):
self.unpackedInfo.append('Hardware Type: ' + str(arpHardwareType))
if (extractedAttIndex == 2) or (extractedAttIndex == 0):
self.unpackedInfo.append('Protocol Type: ' + str(arpProtocolType))
if (extractedAttIndex == 3) or (extractedAttIndex == 0):
self.unpackedInfo.append('Hardware Address Length: ' + str(arpHardAddressLength))
if (extractedAttIndex == 4) or (extractedAttIndex == 0):
self.unpackedInfo.append('Protocol Address Length: ' + str(arpProtAddressLength))
if (extractedAttIndex == 5) or (extractedAttIndex == 0):
self.unpackedInfo.append('Operation: ' + str(arpOperation))
if (extractedAttIndex == 6) or (extractedAttIndex == 0):
self.unpackedInfo.append('Sender Hardware Address: ' + str(arpSenderHardAddress))
if (extractedAttIndex == 7) or (extractedAttIndex == 0):
self.unpackedInfo.append('Sender Protocol Address: ' + str(arpSenderProtAddress))
if (extractedAttIndex == 8) or (extractedAttIndex == 0):
self.unpackedInfo.append('Target Hardware Address: ' + str(arpTargetHardAddress))
if (extractedAttIndex == 9) or (extractedAttIndex == 0):
self.unpackedInfo.append('Target Protocol Address: ' + str(arpTargetProtAddress))
# Separator
self.unpackedInfo.append('\n----------------------------------------')
else:
if (extractedAttIndex == 1):
return str(arpHardwareType)
if (extractedAttIndex == 2):
return str(arpProtocolType)
if (extractedAttIndex == 3):
return str(arpHardAddressLength)
if (extractedAttIndex == 4):
return str(arpProtAddressLength)
if (extractedAttIndex == 5):
return str(arpOperation)
if (extractedAttIndex == 6):
return str(arpSenderHardAddress)
if (extractedAttIndex == 7):
return str(arpSenderProtAddress)
if (extractedAttIndex == 8):
return str(arpTargetHardAddress)
if (extractedAttIndex == 9):
return str(arpTargetProtAddress)
def ip(self, packet, extractedAttIndex, printKey):
# Header lengths.
ethHeaderLength = 14
ipHeaderLength = 20
# Get IP header using begin and end.
# Specific Linux and Windows calibration is needed.
if self.os == self.linux:
begin = ethHeaderLength
end = begin + ipHeaderLength
elif self.os == self.windows:
begin = 0
end = begin + ipHeaderLength
ipHeader = packet[begin:end]
# Unpack the header because it originally in hex.
# The regular expression helps unpack the header.
# ! signifies we are unpacking a network endian.
# B signifies we are unpacking an integer of size 1 byte.
# H signifies we are unpacking an integer of size 2 bytes.
# 4s signifies we are unpacking a string of size 4 bytes.
ipHeaderUnpacked = struct.unpack('!BBHHHBBH4s4s' , ipHeader)
# The first B is 1 byte and contains the version and header length.
# Both are 4 bits each, split ipHeaderUnpacked[0] in "half".
ipVersionAndHeaderLength = ipHeaderUnpacked[0]
ipVersion = ipVersionAndHeaderLength >> 4
ipHeaderLength = ipVersionAndHeaderLength & 0xF
# The second B is 1 byte and contains the service type and ECN.
ipDSCPAndECN = ipHeaderUnpacked[1]
ipDSCP = ipDSCPAndECN >> 2
ipECN = ipDSCPAndECN & 0x3
# The first H is 2 bytes and contains the total length.
ipTotalLength = ipHeaderUnpacked[2]
# The second H is 2 bytes and contains the total length.
ipIdentification = ipHeaderUnpacked[3]
# The third H is 2 bytes and contains the flags and fragment offset.
# Flags is 3 bits and fragment offset is 13 bits.
# Split ipHeaderUnpacked[4].
ipFlagsAndFragmentOffset = ipHeaderUnpacked[4]
ipFlags = ipFlagsAndFragmentOffset >> 13
ipFragmentOffset = ipFlagsAndFragmentOffset & 0x1FFF
# The third B is 1 byte and contains the time to live.
ipTimeToLive = ipHeaderUnpacked[5]
# Our fourth B is 1 byte and contains the protocol.
ipProtocol = ipHeaderUnpacked[6]
# The fourth H is 2 bytes and contains the header checksum.
ipHeaderChecksum = ipHeaderUnpacked[7]
# The first 4s is 4 bytes and contains the source address.
ipSourceAddress = socket.inet_ntoa(ipHeaderUnpacked[8]);
# The second 4s is 4 bytes and contains the dest address.
ipDestAddress = socket.inet_ntoa(ipHeaderUnpacked[9]);
# Check if the print key is 0.
# If true, header information will be printed.
# Check if the user selected extracted attribute index is 0.
# If true, all attributes will be printed.
# If false, the attribute the user selected extracted attribute index corresponds to will be printed.
# If false, the attribute the user selected attribute index corresponds to will be returned.
if printKey == 0:
# Print IP Header
# Some segments of the header are switched back to hex form because that
# is the format wireshark has it.
self.unpackedInfo.append('\n********************\n******** IP ********\n********************')
if (extractedAttIndex == 1) or (extractedAttIndex == 0):
self.unpackedInfo.append('Version: ' + str(ipVersion))
if (extractedAttIndex == 2) or (extractedAttIndex == 0):
self.unpackedInfo.append('Header Length: ' + str(ipHeaderLength) + ' 32-bit words')
if (extractedAttIndex == 3) or (extractedAttIndex == 0):
self.unpackedInfo.append('Differentiated Services Code Point: ' + format(ipDSCP, '#04X') + ' , ' + str(ipDSCP))
if (extractedAttIndex == 4) or (extractedAttIndex == 0):
self.unpackedInfo.append('Explicit Congestion Notification: ' + format(ipECN, '#04X') + ' , ' + str(ipECN))
if (extractedAttIndex == 5) or (extractedAttIndex == 0):
self.unpackedInfo.append('Total Length: ' + str(ipTotalLength) + ' bytes')
if (extractedAttIndex == 6) or (extractedAttIndex == 0):
self.unpackedInfo.append('Identification: ' + format(ipIdentification, '#04X') + ' , ' + str(ipI