You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
6.2 KiB
156 lines
6.2 KiB
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#https://scapy.readthedocs.io/en/latest/api/scapy.packet.html#scapy.packet.Packet
|
|
#https://scapy.readthedocs.io/en/latest/api/scapy.contrib.modbus.html
|
|
|
|
import getpass
|
|
import scapy.all as scapy
|
|
import scapy.contrib.modbus as mb
|
|
|
|
from triPacket import triPacket
|
|
|
|
def BytesToBits(value):
|
|
status = []
|
|
for i in range(len(value)):
|
|
#Transform the i'th byte into 1 binary string
|
|
val = str(bin(value[i]))
|
|
#Delete the '0x' header
|
|
val = val[2:]
|
|
#Fill with '0' to have 8 values
|
|
val = val.rjust(8,'0')
|
|
#Revert the list to get into the growing order
|
|
val = val[::-1]
|
|
#Add the 8 values on `status`
|
|
status.extend(j for j in [*val])
|
|
return status
|
|
|
|
|
|
def decode(pkt):
|
|
'''Insert the packet's `pkt` the [type_call,address,status] informations into the `connec` database '''
|
|
if "ModbusADU" in pkt:
|
|
global miniL
|
|
modpkt = pkt["ModbusADU"]
|
|
type_call = ""
|
|
|
|
#Multiple Coils/Registers request-> else: Single request
|
|
if "Multiple" in modpkt.payload.name:
|
|
type_call += "m"
|
|
else:
|
|
type_call += "s"
|
|
|
|
#Coils or Registers request
|
|
if "Coil" in modpkt.payload.name:
|
|
type_call += "C"
|
|
else:
|
|
type_call += "R"
|
|
|
|
|
|
miniL[0] = type_call
|
|
|
|
#Read request (read request are all "Multiple request")
|
|
if "Read" in modpkt.payload.name:
|
|
type_call += "r"
|
|
#Response for a read request packet's
|
|
if "Response" in modpkt.payload.name:
|
|
#Number of byte that have been read
|
|
#byte_count = modpkt.payload.getfieldval("byteCount")
|
|
status = []
|
|
#Response for a read coils request packet's
|
|
if "C" in type_call:
|
|
#Get the list of byte's values that have been read
|
|
value = modpkt.payload.getfieldval("coilStatus")
|
|
|
|
#Transform the byte's values into a list of bits values for each byte
|
|
status = BytesToBits(value)
|
|
#Response for a read registers request packet's
|
|
else:
|
|
#Get the list of byte's values that have been read
|
|
status = modpkt.payload.getfieldval("registerVal")
|
|
|
|
#Fill the list of the values/address that have been read
|
|
LPackets = []
|
|
for j in range(len(status)):
|
|
LPackets.append([str.lower(miniL[0][1]),miniL[2]+j,status[j]])
|
|
|
|
#Add the read's status into the `connect` database
|
|
triPacket(LPackets,connec)
|
|
#Reset the globalization's list
|
|
####miniL = [0,0,0]
|
|
|
|
#First request for a read packet's : Get the starting address and globalize it before getting the response
|
|
else:
|
|
addr = modpkt.payload.getfieldval("startAddr")
|
|
miniL[2] = addr
|
|
|
|
#Write request
|
|
else:
|
|
type_call += "w"
|
|
#Write request needed information aren't on the Response packet's
|
|
if "Response" in modpkt.payload.name:
|
|
#Reset of the globalization
|
|
miniL = [0,0,0]
|
|
else:
|
|
#Multiple write request
|
|
if "m" in type_call:
|
|
#Get the starting address
|
|
addr = modpkt.payload.getfieldval("startAddr")
|
|
#Get the list of values that have been read
|
|
value = modpkt.payload.getfieldval("outputsValue")
|
|
status = []
|
|
#Multiple write coils request (register's values are already on the good format)
|
|
LPackets = []
|
|
#Get the number of bytes to be write in order to not reset to 0, address on the same bytes of the written one's
|
|
if "C" in type_call:
|
|
#Transform the byte's values into a list of bits values for each byte
|
|
status = BytesToBits(value)
|
|
byte_count = modpkt.payload.getfieldval("quantityOutput")
|
|
#Fill the list of the values/address that while be write
|
|
else:
|
|
byte_count = modpkt.payload.getfieldval("quantityRegisters")
|
|
status=value
|
|
for j in range(byte_count):
|
|
if miniL[0][1]=='C' and status[j]==65280:
|
|
status[j]=1
|
|
LPackets.append([str.lower(miniL[0][1]),addr+j,status[j]])
|
|
|
|
#Add and check the write's status into the `connect` database
|
|
triPacket(LPackets,connec)
|
|
#Single write request
|
|
else:
|
|
#Single write coil request
|
|
if "C" in type_call:
|
|
addr = modpkt.payload.getfieldval("outputAddr")
|
|
value = modpkt.payload.getfieldval("outputValue")
|
|
if value==65280:
|
|
value=1
|
|
#Single write register request
|
|
else:
|
|
addr = modpkt.payload.getfieldval("registerAddr")
|
|
value = modpkt.payload.getfieldval("registerValue")
|
|
#Add the write's status into the `connect` database
|
|
triPacket([str.lower(miniL[0][1]),addr,value],connec)
|
|
|
|
|
|
|
|
#Connection to the database
|
|
print("In order for data sniffed to be stored inside the database, please register the following :")
|
|
DB_HOST = input('host of the database server : ')
|
|
if not DB_HOST:
|
|
DB_HOST = '192.168.128.141'
|
|
DB_NAME = input('name of the database : ')
|
|
if not DB_NAME:
|
|
DB_NAME = 'dblodufour1'
|
|
DB_USER = input('login of the user : ')
|
|
if not DB_USER:
|
|
DB_USER = 'lodufour1'
|
|
DB_PASSWORD = getpass.getpass('user password : ')
|
|
connec=[DB_HOST,DB_NAME,DB_USER,DB_PASSWORD]
|
|
|
|
#Initialization in order globalize the First Packet with his response
|
|
miniL = [0,0,0]
|
|
|
|
#Sniff the packets received on the localhost's network interface and call the decode() function for each of them
|
|
scapy.sniff(iface="lo", prn=decode)
|
|
|