Blog traitant d'informatique, de programmation, de python, de golang, de linux...
1/ Le fichier hosts (/etc/hosts)
Ce fichier hosts devra donc être mis à jour assez régulièrement (globalement, je lance une mise à jour par semaine, parfois plus, parfois moins), ou au moins à chaque fois que le navigateur affiche un message comme quoi il ne trouve pas le site en question.
Pour faciliter un peu les choses, j'ai légèrement modifié le fichier hosts, en lui ajoutant 2 lignes :
###BEGIN myLocal DNS Server
et
###END myLocal DNS Server
qui me serviront de repères pour la section à modifier / mettre à jour. Tout ce qui se trouve avant la ligne ###BEGIN... sert à définir le localhost, l'adresse de votre machine sur le réseau local, ainsi que tous les sites que vous voulez filtrer en les redirigeant vers 127.0.0.1 (ou autre n° d'IP si besoin). Tout ce qui se trouve après ###END... sert à définir les adresses utiles en IPV6. J'ai laissé cette section IPV6 comme à l'origine, je ne l'utilise pas. Enfin, tout ce qui se trouve entre les lignes ###BEGIN... et ###END... contient la partie 'tampon DNS' (myLocal DNS Server), la liste des IP et URL qui nous intéresse.
Attention, pour diverses raisons liées au script python, on ne devra plus utiliser le caractère # pour mettre un commentaire ailleurs que dans la section IPV6 ! L'effet en serait qu'une ligne commençant par # ne serait pas recopiée dans la liste finale, et serait donc purement oubliée et supprimée du fichier hosts après mise à jour. Pour le cas ou un commentaire serait placé dans la section myLocal DNS en fin de ligne comme ceci :
172.217.18.202 youtube.googleapis.com # Mon commentaire ici
--> toute la partie ' # Mon commentaire ici' disparaîtrait simplement de la version mise à jour.
2/ Le fichier python pyHosts.py
Ce fichier python contient le script permettant de mettre à jour le fichier hosts. Pour que ce script fonctionne, il faut d'abord installer la librairie python3-dnspython qui permettra au programme d'aller interroger un vrai serveur DNS pour la mise à jour.
Dans un premier temps, ce script vérifie si il existe un fichier nommé 'history.json' dans le répertoire courant. Pour plus de détails, voir directement les commentaires explicatifs dans le script à partir de la ligne 20.
Dans un deuxième temps, pyHosts.py va alors regarder si il existe un fichier tcpdump.log (Voir les détails dans les commentaires du script à partir de la ligne 27).
Enfin, le script va charger le fichier hosts actuel (voir commentaires ligne 13 dans le code) puis procéder à la mise à jour de l'ensemble des DNS de ce fichier, en y ajoutant si nécessaires les nouvelles URLs provenant de l'historique du navigateur Brave d'un côté, et de la surveillance effectuée au préalable par tcpdump de l'autre. Vous pouvez jetez un oeil au code ci-dessous. Le zip de ce script est téléchargeable directement ici. Dans une précédente version de cette article, j'ai eu quelques soucis de nommage de cette archive. Je n'ai pas bien compris ce qui s'est passé mais le problème est résolu. Ce zip contient un répertoire /pyHosts/ qui contient le fichier pyHosts.py. Attention, ce script n'a été testé que sous python3.6 ! Je ne peux pas garantir son bon fonctionnement sous une autre version pour le moment. Pour le lancer, placez-vous en console dans le répertoire ../pyHosts, puis lancez tout simplement la commande :
you@yourComputer:~/pyHosts$ python3 pyHosts.py
Script pyHosts.py :
1 #!/usr/bin/env python3 2 # -*- coding: utf-8 -*- 3 # Version 0.2 du 24/05/2019 4 5 6 #### 7 # NB : Ce script est prévu pour fonctionner sous Linux essentiellement (mais doit être adaptable 8 # assez facilement pour d'autres OS...) 9 # 10 # Pré-requis : installation de python3-dnspython (sudo apt-get install python3-dnspython sur 11 # debian et dérivées) 12 # 13 # Ce script permet de mettre à jour toutes les entrées présentes dans le fichier hosts du 14 # répertoire .../pyHosts 15 # Attention, ce fichier est une copie du fichier /etc/hosts réellement utilisé par le système. 16 # Une fois la mise à jour effectuée, il faudra remplacer manuellement le fichier /etc/hosts 17 # par le fichier .../pyHosts/hosts, à moins qu'un lien symbolique de .../pyHosts/hosts vers 18 # /etc/hosts n'ai été créé avec les droits d'écriture qui vont bien... 19 # 20 # Ce script permettra aussi l'ajout de l'historique de navigation du navigateur Brave au 21 # fichier hosts. Cet historique est obtenu avec l'extension 'History Export' : 22 # --> https://chrome.google.com/webstore/detail/history-export/lpmoaclacdaofhlijejogfldmgkdlglj 23 # Cette extension permet de sauver l'historique dans un fichier history.json. Il faut sauver ce 24 # fichier dans le répertoire .../pyHosts 25 # A la fin du script, ce fichier history.json sera effacé. 26 # 27 # pyHosts.py peut aussi ajouter les entrées des connexions vues par tcpdump. Au préalable, avant 28 # de lancer le script pyHosts.py, il faudra démarrer le process tcpdump dans un terminal, à 29 # partir du répertoire .../pyHosts 31 # --> sudo tcpdump -tq tcp > tcpdump.log 32 # Cela produira le fichier .../pyHosts/tcpdump.log, qui mémorisera toutes les connexions de 33 # votre navigation internet tant que vous n'arrêterez pas ce process. Quand vous déciderez de 34 # l'arrêter, vous pourrez alors mettre à jour le fichier hosts en lançant le script 35 # .../pyHosts/pyHosts.py. Attention, pour lancer le script pyHosts.py, tcpdump doit 36 # impérativement être arrêté ! A la fin du script, le fichier tcpdum.log sera effacé. 37 # 38 # NB : Ce script a été testé sous python3.6. 39 #### 40 41 42 43 44 import os 45 import time 46 import dns.resolver 47 48 49 50 def removeRNFromListe(listName): 51 ''' Permet de supprimer les \r\n des fins de lignes avant ajout à la stringlist ''' 52 newList = [] 53 for oneLine in listName: 54 if oneLine.endswith("\r\n"): 55 oneLine = oneLine[0:(len(oneLine)-2)] 56 if oneLine.endswith("\n"): 57 oneLine = oneLine[0:(len(oneLine)-1)] 58 if len(oneLine) >0: 59 newList.append(oneLine) 60 return newList 61 62 63 def readFileLines(filename): 64 ''' Ouverture du fichier filename et stockage des lignes lues dans newList''' 65 if os.path.exists(filename): 66 myFile = open(filename, 'r') 67 oneStringList = myFile.readlines() 68 myFile.close() 69 newList = removeRNFromListe(oneStringList) 70 return newList 71 else: 72 return ("Le fichier "+filename+" n'existe pas!") 73 74 75 def writeFile(filename, lines): 76 ''' Ecriture des lignes lines dans le fichier filename ''' 77 myFile = open(filename, 'w') 78 for line in lines: 79 oneStr = line + "\r\n" 80 myFile.write(oneStr) 81 myFile.close() 82 return ("Écriture du fichier hosts OK") 83 84 85 86 87 ###################### Lancement du programme principal 88 # 89 if __name__ == "__main__": 90 91 tDepart = time.time() 92 currentWorkingDir = os.getcwd() 93 currentHostsFilePath = currentWorkingDir + '/hosts' 94 currentBraveHistoryFilePath = currentWorkingDir + '/history.json' 95 currentTcpdumpFilePath = currentWorkingDir + '/tcpdump.log' 96 97 #### Lecture/chargement du fichier history.json -> Historique de navigation du navigateur Brave 98 # 99 returnedObject = readFileLines(currentBraveHistoryFilePath) 100 braveUrlList = [] 101 if "<class 'list'>" in str(type(returnedObject)): 102 for oneLine in returnedObject: 103 if 'https://' in oneLine: 104 sep1 = oneLine.split('https://') 105 myUrl = sep1[1].split('/')[0] 106 if len(myUrl.split('.')) != 4: 107 braveUrlList.append(myUrl) 108 else: 109 try: 110 nb1 = int(myUrl.split('.')[0]) 111 nb2 = int(myUrl.split('.')[1]) 112 nb3 = int(myUrl.split('.')[2]) 113 nb4 = int(myUrl.split('.')[3]) 114 except: 115 braveUrlList.append(myUrl) 116 if 'http://' in oneLine: 117 sep1 = oneLine.split('http://') 118 myUrl = sep1[1].split('/')[0] 119 if len(myUrl.split('.')) != 4: 120 braveUrlList.append(myUrl) 121 else: 122 try: 123 nb1 = int(myUrl.split('.')[0]) 124 nb2 = int(myUrl.split('.')[1]) 125 nb3 = int(myUrl.split('.')[2]) 126 nb4 = int(myUrl.split('.')[3]) 127 except: 128 braveUrlList.append(myUrl) 129 braveUrlSet = set(braveUrlList) 130 braveUrlList = list(braveUrlSet) 131 132 #### Lecture/chargement du fichier tcpdump.log - Ce fichier aura eventuellement été 133 # créé par la commande "sudo tcpdump -tq tcp > tcpdump.log" à partir du répertoire 134 # courant .../pyHosts 135 # 136 returnedObject = readFileLines(currentTcpdumpFilePath) 137 print(type(returnedObject)) 138 tcpdumpUrlList = [] 139 if "<class 'list'>" in str(type(returnedObject)): 140 for oneLine in returnedObject: 141 if not 'IP This.' in oneLine: 142 sep1 = oneLine.split('.http') 143 myUrl = sep1[0][3:] 144 if len(myUrl.split('.')) != 4 and not ' > ' in myUrl: 145 tcpdumpUrlList.append(myUrl) 146 else: 147 try: 148 nb1 = int(myUrl.split('.')[0]) 149 nb2 = int(myUrl.split('.')[1]) 150 nb3 = int(myUrl.split('.')[2]) 151 nb4 = int(myUrl.split('.')[3]) 152 except: 153 if not ' > ' in myUrl: 154 tcpdumpUrlList.append(myUrl) 155 tcpdumpUrlSet = set(tcpdumpUrlList) 156 tcpdumpUrlList = list(tcpdumpUrlSet) 157 158 #### Chargement du fichier hosts -> Attention, ce fichier hosts est une copie du fichier 159 # /etc/hosts (attention aux droits d'écriture) ! CE FICHIER DOIT TOUJOURS EXISTER !!! 160 # 161 hostsUrlList = [] 162 listIPV4_127 = [] 163 listIPV6 = [] 164 newLines = [] 165 myLines = readFileLines(currentHostsFilePath) 166 for oneLine in myLines: 167 myIP = oneLine.split()[0] 168 myHost = oneLine.split()[1] 169 if '127.0.0.1' in myIP or '127.0.1.1' in myIP or '###BEGIN' in myIP: 170 listIPV4_127.append(oneLine) 171 if '###END' in oneLine or '# ' in oneLine: 172 listIPV6.append(oneLine) 173 if not '127.0.0.' in myIP and not '127.0.1.' in myIP and not '#' in myIP: 174 hostsUrlList.append(myHost) 175 176 #### Ajouts des nouvelles entrées en provenance de l'historique de Brave et de tcpdump à la 177 # liste des DNS à mettre à jour dans hostsUrlList - Suppression des URLs déjà présentes 178 # dans listIPV4_127 de la liste hostsUrlList (si ces URLs sont dans listIPV4_127, c'est 179 # que l'on souhaite les filtrer, il ne faut pas qu'elle soit dans la liste des adresses 180 # à mettre à jour!) 181 # 182 nbLinesBeforeUpdate = len(hostsUrlList) 183 hostsUrlList.extend(braveUrlList) 184 hostsUrlList.extend(tcpdumpUrlList) 185 hostsUrlSet = set(hostsUrlList) 186 hostsUrlList = list(hostsUrlSet) 187 hostsUrlList.sort() 188 toRemoveIndex = [] 189 for oneL127 in listIPV4_127: 190 try: 191 myHost127 = oneL127.split()[1] 192 for theIndex, oneLUrlList in enumerate(hostsUrlList): 193 myHostUrlList = oneLUrlList.split()[1] 194 if myHost127 in myHostUrlList and myHostUrlList in myHost127: 195 toRemoveIndex.append(theIndex) 196 except: 197 pass 198 toRemoveIndex.sort(reverse=True) 199 for iddx in toRemoveIndex: 200 del myHostUrlList[iddx] 201 nbLines = len(hostsUrlList) 202 newEntriesInHosts = nbLines - nbLinesBeforeUpdate 203 listIPV4_127.sort() 204 listIPV4_127.append(listIPV4_127[0]) 205 del listIPV4_127[0] 206 newLines.extend(listIPV4_127) 207 208 #### Mise à jour des DNS et sauvegarde du fichier hosts 209 # 210 for index, oneHost in enumerate(hostsUrlList): 211 try: 212 answ = dns.resolver.query(oneHost, 'A') 213 rdata = answ[0] 214 newLines.append(str(rdata.address)+' '+oneHost) 215 print (index,'/', nbLines, ": ", rdata.address, oneHost) 216 except: 217 print('Erreur sur résolution DNS de :', oneHost) 218 newLines.extend(listIPV6) 219 print() 220 print('Mise à jour du fichier hosts terminée.', str(newEntriesInHosts), 221 'entrées ont été ajoutées au fichier hosts') 222 print() 223 status = writeFile(currentHostsFilePath, newLines) 224 print(status) 225 print() 226 tUpdate = int(time.time() - tDepart) 227 nbMin = int(tUpdate / 60) 228 nbSec = int(tUpdate % 60) 229 print('Mise à jour effectuée en', str(nbMin), 'min et', str(nbSec), 'sec') 230 print() 231 print() 232 try: 233 os.remove(currentBraveHistoryFilePath) 234 os.remove(currentTcpdumpFilePath) 235 except: 236 '''Rien à faire, les fichiers history.json et/ou tcpdump.log auront été 237 effacés si besoin''' 238 pass