Guest User

Simulation (simplistic) of TCP/IP encapsulation

a guest
Jan 14th, 2019
468
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.59 KB | None | 0 0
  1. exercice    = "TP 1"
  2. title       = "Simulation d'encapsulation"
  3. author      = "Équipe : ..."
  4. date        = "2019-01-12"
  5. description = "Simulation d'encapsulation des protocoles réseau en Python, avec journalisation"
  6.  
  7. def info():
  8.     print("---------------------")
  9.     print(exercice, ":", title)
  10.     print(author)
  11.     print(date)
  12.     print("---------------------")
  13.     print(description)
  14.     print("---------------------")
  15.  
  16. import abc          # Pour des classes abstraites
  17. import logging      # Pour journalisation
  18. import binascii     # Pour calculation de CRC
  19. import re           # Pour recherche dans listes
  20.  
  21. #les diffents types d'entetes
  22. class Header:
  23.     def Header(self):
  24.         pass
  25.  
  26. class Ethernet(Header):
  27.     def __init__(self, macsource, macdestination):
  28.         self.macsource=macsource
  29.         self.macdestination=macdestination
  30.     def __str__(self):
  31.         # return "Ethernet " + str(self.Header())
  32.         return "Ethernet {} -> {}".format(self.macsource, self.macdestination)
  33.     def Header(self):
  34.         return [self.macsource,self.macdestination]
  35.  
  36. class IP(Ethernet):
  37.     def __init__(self,macsource, macdestination, IPsource, IPdestination):
  38.         Ethernet.__init__(self,macsource,macdestination)
  39.         self.IPsource=IPsource
  40.         self.IPdestination=IPdestination
  41.     def __str__(self):
  42.         # return "IP " + str(self.Header())
  43.         return "IP {} ({}) -> {} ({})".format(self.IPsource, self.macsource, self.IPdestination, self.macdestination)
  44.     def Header(self):
  45.         # Version originale ne va pas marcher ! https://stackoverflow.com/a/7507308/6123418
  46.         # return Ethernet.Header(self).extend([self.IPsource,self.IPdestination])
  47.         # Alors :
  48.         return [self.IPsource,self.IPdestination] + Ethernet.Header(self)
  49.    
  50. class TCP(IP):
  51.     def __init__(self, macsource, macdestination, IPsource, IPdestination, portsource, portdestination):
  52.         IP.__init__(self, macsource, macdestination, IPsource, IPdestination)
  53.         self.portsource = portsource
  54.         self.portdestination = portdestination
  55.     def __str__(self):
  56.         # return "TCP " + str(self.Header())
  57.         return "TCP {}:{} ({}) -> {}:{} ({})".format(self.IPsource, self.portsource, self.macsource, self.IPdestination, self.portdestination, self.macdestination)
  58.     def Header(self):
  59.         return [self.portsource, self.portdestination] + IP.Header(self)
  60.  
  61. #le paquet
  62. class Paquet:
  63.     def __init__(self, header, data, checksum):
  64.         self.header = header        #strategy pattern
  65.         self.data = data
  66.         self.checksum = checksum    #strategy pattern
  67.     def Paquet(self):
  68.         return [self.header.Header(),self.data,self.checksum.checksumAlgorithm(self.header.Header(),self.data)]
  69.  
  70. #les differents types de checksum algorithms
  71. class Checksum(metaclass=abc.ABCMeta):              # Question 5 : Checksum strategie
  72.     @abc.abstractmethod
  73.     def checksumAlgorithm(self, entete, donnees):
  74.         pass
  75.  
  76. class CRC(Checksum):
  77.     def checksumAlgorithm(self, entete, donnees):
  78.         # Algorithm de crc32
  79.         crc_source = ""                             # Préparer une variable
  80.         for token in entete:                        # Y ajouter toutes les entêtes
  81.             crc_source = crc_source + str(token)
  82.         crc_source = crc_source + str(donnees)      # Ajouter les données
  83.         # Convertir string en bytearray et en calculer la CRC :
  84.         # crc_calculated = binascii.crc32(bytearray(crc_source, 'utf-8'))
  85.         return binascii.crc32(bytearray(crc_source, 'utf-8'))
  86.  
  87. class Paritybit(Checksum):
  88.     def checksumAlgorithm(self, entete, donnees):
  89.         #algorithm de bit de parite
  90.         crc_source = ""                             # Préparer une variable
  91.         for token in entete:                        # Y ajouter toutes les entêtes
  92.             crc_source = crc_source + str(token)
  93.         crc_source = crc_source + str(donnees)      # Ajouter les données
  94.         # Calculer parité
  95.         x = int(0)
  96.         for i in range(0, len(crc_source)):
  97.             x ^= ord(crc_source[i])
  98.         shiftamount = 1
  99.         while x >> shiftamount:
  100.             x ^= x >> shiftamount
  101.             shiftamount <<= 1
  102.         return x & 1
  103.  
  104. # Calculer parité d'un int
  105. # https://stackoverflow.com/a/49934659/6123418
  106. def parity_of_int(x):
  107.     shiftamount = 1
  108.     while x >> shiftamount:
  109.         x ^= x >> shiftamount
  110.         shiftamount <<= 1
  111.     return x & 1
  112.  
  113. # Calculer parité d'une ligne de texte
  114. def parity(texte):
  115.     x = int(0)
  116.     for i in range(0, len(texte)):
  117.         x ^= ord(texte[i])
  118.     shiftamount = 1
  119.     while x >> shiftamount:
  120.         x ^= x >> shiftamount
  121.         shiftamount <<= 1
  122.     return x & 1
  123.  
  124. # La classe Event (événement) pour le patron observateur
  125. class Event(object):
  126.     pass
  127.  
  128. # Calculer CRC
  129. def crc(texte):
  130.     return binascii.crc32(bytearray(texte, 'utf-8'))
  131.  
  132. #la class firewall observable
  133. class Firewall(object):
  134.     paquets = []
  135.     blacklist = []
  136.     observateurs = []
  137.     #les donnees de la classe observable
  138.     @classmethod
  139.     def ajouter(cls, paquet):
  140.         #implementation
  141.         cls.paquets.append(paquet)
  142.     @classmethod
  143.     def supprimer(cls, index = 0):
  144.         cls.paquets.pop(index)
  145.     @classmethod
  146.     def verifier(cls):
  147.         # Implementation
  148.         if cls.paquets:             # Seulement si la ligne d'attente n'est pas vide
  149.             blocked = False
  150.             for address in cls.blacklist:
  151.                 # Compiler un pattern regex selon les adresses dans blacklist
  152.                 mask = re.compile(address)
  153.                 # L'adresse IP source : cls.paquets[0].Paquet()[0][2]
  154.                 if re.match(mask, cls.paquets[0].Paquet()[0][2]):
  155.                     blocked = True
  156.                 # Revérifier CRC ou Paritybit : cls.paquets[0].Paquet()[2]
  157.                 crc_source = ""                                 # Préparer une variable
  158.                 for token in cls.paquets[0].Paquet()[0]:        # Y ajouter toutes les entêtes
  159.                     crc_source += str(token)
  160.                 crc_source += str(cls.paquets[0].Paquet()[1])   # Ajouter les données
  161.                 if len(str(cls.paquets[0].Paquet()[2])) == 1:
  162.                     # Vérifier Paritybit
  163.                     if cls.paquets[0].Paquet()[2] != parity(crc_source):
  164.                         print("Checking parity: {}".format(crc_source))
  165.                         blocked = True
  166.                 else:
  167.                     # Vérifier plutôt CRC
  168.                     if cls.paquets[0].Paquet()[2] != crc(crc_source):
  169.                         print("Checking CRC: {}".format(crc_source))
  170.                         blocked = True
  171.             if blocked:
  172.                 cls.dispatch("Block", cls.paquets[0])
  173.             else:
  174.                 cls.dispatch("Pass", cls.paquets[0])
  175.             cls.supprimer()         # Finalement, supprimer le paquet de la ligne d'attente
  176.     @classmethod
  177.     def bloquer(cls, IPsource):
  178.         cls.blacklist.append(IPsource)
  179.     @classmethod
  180.     def register(cls, who, callback = None):
  181.         if callback == None:
  182.             callback = getattr(who, 'update')
  183.         cls.observateurs.append(callback)
  184.     @classmethod
  185.     def dispatch(cls, status, paquet):
  186.         for callback in cls.observateurs:
  187.             callback(status, paquet)
  188.  
  189. # La classe réseau observatrice
  190. class reseau:
  191.     # les données de la classe réseau (observateur)
  192.     def __init__(self):
  193.         self.paquets = []
  194.         Firewall.register(self, self.update)
  195.     def update(self, status, paquet):
  196.         if status == "Pass":
  197.             self.paquets.append(paquet)
  198.             logging.debug("Paquet passed (IPsrc {}, IPdst {})".format(paquet.Paquet()[0][2], paquet.Paquet()[0][3]))
  199.             print("Passed (IPsrc {}, IPdst {}, checksum {})".format(paquet.Paquet()[0][2], paquet.Paquet()[0][3], paquet.Paquet()[2]))
  200.  
  201. #la classe logfile observatrice
  202. class logfile:
  203.     # les donnees de la classe logfile (observateur)
  204.     def __init__(self):
  205.         logging.basicConfig(filename='tp1.log',level=logging.DEBUG, format='%(asctime)s [%(levelname)s] %(message)s')
  206.         logging.debug("----- >8 -----")     # Ça sert juste à délimiter les tests
  207.         Firewall.register(self, self.update)
  208.     def update(self, status, paquet):
  209.         if status == "Block":
  210.             logging.warning("Paquet blocked (IPsrc {}, IPdst {})".format(paquet.Paquet()[0][2], paquet.Paquet()[0][3]))
  211.             print("Blocked (IP src {}, IPdst {}, checksum {})".format(paquet.Paquet()[0][2], paquet.Paquet()[0][3], paquet.Paquet()[2]))
  212.  
  213. # =========================================================================
  214. # Testing ground
  215. # =========================================================================
  216. info()
  217.  
  218. # Ici on teste les ajouts de plusieurs paquets au Firewall. Format:
  219. #   Firewall.ajouter(Paquet)
  220. # Le Paquet ici est une liste de 3 elements : entête, données et checksum.
  221. # L'entête peut être de niveau Ethernet, IP ou (normallement) TCP. Pour TCP :
  222. #   TCP(MAC_src, MAC_dst, IP_source, IP_destination, Port_src, Port_dst)
  223. # Données = une ligne de texte
  224. # Checksum spécifie un de deux algorithmes de calcule de checksum : CRC() ou Paritybit()
  225. print()
  226. print("Test: appending paquets to firewall")
  227. for i in range(1, 6):       # Générer 5 paquets avec differentes données, qui seront acceptés
  228.     Firewall.ajouter(Paquet(TCP("AAAA", "BBBB", "192.168.1.{}".format(i), "192.168.1.20{}".format(i), "21", "2021"), "Test_{}".format(i), CRC() ))
  229. for i in range(1, 3):       # Générer 2 autres paquets, qui seront refusés par le Firewall
  230.     Firewall.ajouter(Paquet(TCP("AAAA", "BBBB", "192.155.23.{}".format(i), "192.168.1.200", "21", "2021"), "Test_{}".format(i), CRC() ))
  231.  
  232. for t in Firewall.paquets:
  233.     print(t.Paquet())
  234.  
  235. print()
  236. print("Test: registering net and log as observers for Firewall")
  237. net = reseau()
  238. log = logfile()
  239. print("...")
  240.    
  241. print()
  242. print("Test: setting up firewall blacklist")
  243. Firewall.bloquer("192.168.*.3")     # Ajouter une adresse dans blacklist du Firewall
  244. Firewall.bloquer("192.155.23.*")    # L'adresse à bloquer selon l'énoncé
  245. for mask in Firewall.blacklist:
  246.     print("Blacklisted: {}".format(mask))
  247.  
  248. print()
  249. print("Test: verifying paquets by firewall")
  250. while Firewall.paquets:             # Processer tous les paquets dans la liste d'attente
  251.     # print(Firewall.paquets[0].Paquet())       # Pour debugging
  252.     Firewall.verifier()             # Vérifier !
  253.  
  254. print()
  255. print("Test: verifyting the log file")
  256. print("Le fichier tp1.log devrait contenir une ligne [DEBUG] sur chaque paquet accepté,")
  257. print("aussi bien qu'une ligne [WARNING] pour chaque paquet bloqué.")
Advertisement
Add Comment
Please, Sign In to add comment