• Créez un tampon DNS avec votre fichier /etc/hosts en python

    Tampon DNS

    Ce premier article traite d'un script python permettant de mettre à jour mon fichier hosts (sous Linux). J'utilise ce fichier hosts comme 'tampon DNS' afin d'accélérer ma navigation internet, et en même temps pour filtrer un peu certains trackers et autres sites qui se régalent de nos données de navigation. Attention, je ne gère ici que l'IPV4 !

    Avant toute requête DNS, le navigateur va regarder dans ce fichier hosts si l'URL y est présente et utilisera dans ce cas l'adresse IP correspondante. L'expérience montre que l'on gagne énormément en vitesse de navigation par cette méthode, le principal problème étant que certains sites changent régulièrement d'adresse IP...

    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.

     

    Fichier hosts type :

      1 127.0.0.1 localhost
      2 127.0.0.1 tawr6o.vkcache.com
      3 127.0.0.1 todqjw.vkcache.com
      4 127.0.0.1 www.meilleursoldes.com
      5 127.0.0.1 M_adam-desktop
      6 127.0.0.1 M_This
      7 ###BEGIN myLocal DNS Server
      8 216.58.206.13 accounts.google.com
      9 194.187.168.100 www.qwant.com
     10 212.82.100.150 www.yahoo.fr
     11 ###END myLocal DNS Server
     12 # The following lines are desirable for IPv6 capable hosts
     13 # ::1 ip6-localhost ip6-loopback
     14 # fe00::0 ip6-localnet
     15 # ff00::0 ip6-mcastprefix
     16 # ff02::1 ip6-allnodes
     17 # ff02::2 ip6-allrouters

     

     

    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
    

    Tags Tags : , , , ,
  • Commentaires

    Aucun commentaire pour le moment

    Suivre le flux RSS des commentaires


    Ajouter un commentaire

    Nom / Pseudo :

    E-mail (facultatif) :

    Site Web (facultatif) :

    Commentaire :