En-tête IPV4

Afin de s'habituer aux manipulations de listes, de caractères, d'entiers dans différentes bases, il vous est demandé de créer une fonction Haskell qui vérifie la somme de contrôle (cheksum) de l'en-tête IPv4 d'une capture effectuée avec wireShark.

Vous pourrez par exemple utiliser les fonctions intToDigit, digitToInt du module Data.Char ainsi que les fonctions take et drop du module Data.List.

Par exemple, après avoir capturé l'en-tête 4500 003c 1c46 4000 4006 b1e6 ac10 0a63 ac10 0a0c :

Haskell
*IPV4> let s = "4500003c1c4640004006b1e6ac100a63ac100a0c"
*IPV4> verifIPheader s
True

Vous pourrez par exemple utiliser une structure ressemblant à :

Haskell
module IPV4 where
 
import qualified Data.Char as C 
 
decoupeBlock :: String -> [String]
???  
 
sumBlock :: [Int] -> Int
???
 
toHex :: Int -> String
???
 
checkSum :: [String] -> String
???
 
verifIPheader :: String -> Bool 
???

Une proposition de corrigé (mais bon, l'important, c'est de chercher...) :

Haskell
module IPV4 where
 
import qualified Data.Char as C 
 
-- découpe une chaîne en blocs de longueur 4
decoupeBlock :: String -> [String]
decoupeBlock ""    = [] 
decoupeBlock chaine = (take 4 chaine) : (decoupeBlock (drop 4 chaine)) 
  
-- on fait la somme des éléments d'une liste d'entiers en base 16
-- on commence par la droite, dans le sens des puissances croissantes de 16.
sumBlock :: [Int] -> Int
sumBlock [] = 0
sumBlock b = (last b) + 16 * (sumBlock (init b))
 
-- on écrit un entier, donné en base 10, en base 16.
-- on concatène à droite le reste de chaque résidu modulo 16.
toHex :: Int -> String
toHex x
  | x < 16 = [C.intToDigit x]
  | otherwise =  (toHex (div x 16)) ++ [C.intToDigit (mod x 16)] 
 
-- s2d convertit l'en-tête base 16 en liste d'entiers écrits en base 10 
-- on fait la somme (avec l'addition en base 10) des blocs déjà sommés
-- on ajoute éventuellement les retenus aux unités
checkSum :: [String] -> String
checkSum s =
   let s2d = map (\ bloc -> map (\c -> C.digitToInt c) bloc) s in
   let som = sum (map sumBlock s2d) in
   let r = (mod som (2^16)) +  (div som (2^16)) in
   toHex r
 
-- on récupère dans l'en-tête sa longueur utile
-- on ne prend que la longueur utile (il peut y avoir des parties optionnelles)
-- on applique checksum à cette chaîne : on doit trouver "ffff" qui est 1111111111111111
verifIPheader :: String -> Bool 
verifIPheader s =
  let h = decoupeBlock s in
  let ncs = C.digitToInt (head (tail (head h))) in
  let iph = take (2*ncs) h in
  checkSum iph == "ffff"