Commentaires + docu sur les .py

master
Paul SQUIZZATO 2 years ago
parent a4425c7048
commit 46d4e201df

@ -6,6 +6,11 @@ import scapy.contrib.modbus as mb
from triPacket import triPacket
import getpass
# ========================================================================================
# This decoder is outdated, as it uses a string parser on the packets given by scapy.
# Instead of this script, please use decoderMain.py.
# ========================================================================================
def decode(pkt):
prt=0
addr,value = "",""
@ -115,11 +120,5 @@ if not db_user:
db_password = getpass.getpass('user password : ')
connec=[db_host,db_name,db_user,db_password]
# si register 5 = 55 et coil 3 = 1 et coil 12 = 0 :
# ecriture sur le registre 8 à 72 ou coil 9 à 1 impossibles
# if ['r',5,55] and ['c',3,1] and ['c',12,0] and ecriture ['r',8,72]:
#bloquer ecriture
# ecrire registre 5 72,4,4,55,4
scapy.sniff(iface="lo", prn=decode)

@ -2,44 +2,64 @@ import psycopg2 as psy
import regles
def verifRegle(co):
''' verifRegle takes a connection to a database, from which it'll go through the data in the current transaction
to see if the data correlate to a possible rule violation.
'''
cur=co.cursor()
cur.execute('''SELECT type,addresse,valeur FROM Status ORDER BY type,addresse;''')
res=cur.fetchall()
# res contains all the data from the current transaction. The entirety of the status table is loaded.
dataState={}
for row in res:
dataState[(row[0],int(row[1]))]=int(row[2])
# the dictionnary dataState is a litteral representation of the database, with the key being a tuple of the address and the type of data,
# dataState's values are the values of the statuses.
listRules=regles.getRegles()
# listRules contains all the rules created in regles.py, and getRegles is called to get a copy of the rules' list.
for rule in listRules:
# we check each rule one by one, to see if they aren't violated
ruleWarning=0
condition=len(rule[0])
for i in rule[0]:
if (i[0],i[1]) in dataState:
if dataState[(i[0],i[1])]==i[2]:
ruleWarning+=1
# we first verify if the conditions aren't violated.
if ruleWarning>=condition:
# if all the conditions of the rule are matched, we check to see if the request tries to update the forbidden value.
if (rule[1][0],rule[1][1]) in dataState:
if dataState[(rule[1][0],rule[1][1])]==rule[1][2]:
return False
# The boolean False is returned in the case where one rule is violated.
return True
# If True is returned, it's because there's no rule that is violated, so the request isn't problematic for the system.
def ecritureBDD(lStatus,connec):
''' ecritureBDD is the function that is called to upsert (insert or update) the values of the status given in lStatus
connec contains the information needed to create a connection to the database
'''
co = None
try:
co = psy.connect(host=connec[0],database=connec[1],user=connec[2],password=connec[3])
# the connection to the database is now created in co.
cur = co.cursor()
# cur is a cursor on the connection to the database, it lets us perform actions on co's transaction.
for i in lStatus:
cur.execute("INSERT INTO Status VALUES (%s,%s,%s ) ON CONFLICT (addresse,type) DO UPDATE SET valeur=%s;",(i[1],i[0],i[2],i[2]))
if verifRegle(co):
co.commit()
else:
# each statuses in lStatus is now upserted in the database on the current transaction, until commited, they aren't actually inside the database.
if verifRegle(co)!=True:
# verifRegle is executed with the current connection, so it has access to the transaction in order to verify if rules are violated.
print("A rule has been violated. The system is endangered. The database hasn't been updated.")
co.rollback()
# A message is shown to the user to make him aware of the rule that is violated.
# a co.rollback() would be called if we managed to block the client request in order to prevent the server to be updated.
co.commit()
cur.close()
except(Exception,psy.DatabaseError) as error:
print(error)
# In case of an exception, like the failure of the creation of the connection, details are shown to tell the user about it.
finally:
if co is not None:
co.close()

@ -1,15 +1,22 @@
from ecritureBDD import ecritureBDD
def decoupePacket(lPkt):
''' decoupePacket is a recursive function that takes a list as an argument.
Its purpose is to create lists that shows the updated statuses from the modbus client's requests following the database format.
'''
if type(lPkt)!=list:
# If the list of statuses isn't a list, nothing should be put inside the database.
print('pas liste')
return
if len(lPkt)==0:
# If the list is empty, nothing should be put inside the database as well.
print('liste vide')
return
if len(lPkt)==1:
# If the list has only one element, it is probably another list inside, that's why we call decoupePacket again.
return decoupePacket(lPkt[0])
if len(lPkt)==3 and type(lPkt[0])==str:
# If the list has a size of 3, and it's first element is a string type, we probably have the status we need to use.
return [[lPkt[0],int(lPkt[1]),int(lPkt[2])]]
else:
l=[]
@ -18,5 +25,10 @@ def decoupePacket(lPkt):
return l
def triPacket(lPkt,connec):
'''
triPacket takes the list of statuses obtained from the client's request and the information needed to connect to the database.
'''
lNettoyee=decoupePacket(lPkt)
# decoupePacket is called in order to create a better structured list of statuses.
ecritureBDD(lNettoyee,connec)
# ecritureBDD is now called to update the values inside the database.

Loading…
Cancel
Save