
    |iXC                     8   d Z ddlZddlZddlZddlZddlmZmZmZm	Z	m
Z
 dZdddddddddZ ej        d	          Zd
edefdZd
ede	e         fdZdefdZd)dededededeeef         f
dZd
ededeeeef         fdZdededefdZd
edefdZd
edefdZd*d
ededefdZd
edefdZd
edefdZd
edefd Zd
ed!ee         defd"Zd
edefd#Zd*d
ed$edeeef         fd%Z deeef         fd&Z!d'eeef         deee
eef         f         fd(Z"dS )+u[   
Service d'analyse DNS sécurisé.
Vérifie SPF, DKIM, DMARC, DNSSEC, MTA-STS, DANE, BIMI.
    N)DictTupleListOptionalUniond         
   MX (Mail Base)zSPF (Security)DKIMDMARCDNSSECzMTA-STSzDANE TLSBIMIz;^(?=.{1,253}$)(?!-)(?:[A-Za-z0-9-]{1,63}\.)+[A-Za-z]{2,63}$domainreturnc                 b     rt           t                    sdS                                                                   t	                     dk    st	                     dk     rdS g d}t           fd|D                       rdS t          t                                                   S )up   
    Valide strictement un nom de domaine.
    CRITIQUE : Empêche l'injection de commandes via subprocess.
    F      ;&|$`(){}[]<>!\"'
 c              3       K   | ]}|v V  	d S N ).0charr   s     7/var/www/html/MCyber-Diagnostic/services/dns_service.py	<genexpr>z"is_valid_domain.<locals>.<genexpr>:   '      
0
0d46>
0
0
0
0
0
0    )	
isinstancestrstriplowerlenanyboolDOMAIN_REGEXmatch)r   	forbiddens   ` r1   is_valid_domainr?   *   s    
  FC00 u\\^^!!##F 6{{SCKK!OOu xwwI

0
0
0
0i
0
0
000 u ""6**+++r4   c                    | sdS |                                                                  } t          j        dd|           } |                     d          d         } |                     d          r
| dd         } t          |           r| S dS )z8Nettoie et valide un domaine. Retourne None si invalide.Nz
^https?:// /r   zwww.r   )r7   r8   resubsplit
startswithr?   )r   s    r1   sanitize_domainrG   @   s     t\\^^!!##F VM2v..F \\#q!F    v 4r4   c                  @    t           j                            d          S )u.   Vérifie si 'dig' est disponible dans le PATH./usr/bin/dig)ospathexistsr.   r4   r1   dig_availablerM   Z   s    7>>.)))r4   @8.8.8.8   targetrecord_typeservertimeoutc                      rt           t                    sdS                                                                   t	                     dk    st	                     dk     rdS g d}t           fd|D                       rdS g d}|                                |vrd	d
| fS d| |dg}	 t          j        |dd|d          }|j	                                        }|j
                                        }	|j        dk    r|sd	d|j         d|	 fS |d	fS # t          $ r Y dS t          j        $ r Y dS t          $ r}
d	dt          |
           fcY d}
~
S d}
~
ww xY w)u<   
    Exécute une commande dig de manière sécurisée.
    )rA   zERROR: Cible invalide.      )rA   z!ERROR: Cible invalide (longueur).r   c              3       K   | ]}|v V  	d S r-   r.   )r/   r0   rP   s     r1   r2   zrun_dig.<locals>.<genexpr>n   r3   r4   )rA   u0   ERROR: Caractères non autorisés dans la cible.)	MXTXTDNSKEYTLSAAAAAANSSOACNAMErA   u,   ERROR: Type d'enregistrement non autorisé: rI   z+shortTF)capture_outputtextrS   shellr   zDig failed (code z): )rA   z4ERROR: L'outil 'dig' est introuvable sur le serveur.)rA   u+   ERROR: Timeout lors de l'exécution de dig.zERROR: Exception dig: N)r5   r6   r7   r8   r9   r:   upper
subprocessrunstdoutstderr
returncodeFileNotFoundErrorTimeoutExpired	Exception)rP   rQ   rR   rS   r>   allowed_typescommandresultrg   rh   es   `          r1   run_digrq   ^   s   
  ,FC00 ,++\\^^!!##F 6{{SCKK!OO66 xwwI

0
0
0
0i
0
0
000 FEE WVVM-//O+OOOO{FFHEG5
 
 
 $$&&$$&&!!&!I6+<IIIIIIrz J J JIII$ A A A@@@ 5 5 54CFF4444444445s1   3A&D D 
E#+E#<	E#EE#E#c                     t          | |          \  }}|r	d|v rd|dfS t          |od|v          }|rdnd}|||r|ndfS )u)   Vérifie si un enregistrement DNS existe.introuvableFN/ANXDOMAINu   Enregistrement trouvé.u   Enregistrement non trouvé.)rq   r;   )r   rQ   outputerrorrL   details         r1   check_record_existsry      sr    FK00MFE #%''eU""&5Zv566F*0S&&6SF6V66666r4   contentc                 p   | r| dk    r| S |dv r|                                  }|r|d                                         n|                                 }|                                }t          |          dk    r3|d         }t          |          dk    r|dd          d	|d
d          dS dS |dk    rt	          j        d|           }|rh|                    d                                                              dd          }t          |          dk    r|dd          d	|d
d          dS |S | S | S )u3   Masque les clés cryptographiques pour l'affichage.rt   )rZ   r[   r         Nr   z...iu
    [MASQUÉ]u   [Clé masquée]r   z
p=([^;"]+)   r'   rA      u    [MASQUÉE])
splitlinesr7   rE   r9   rC   searchgroupreplace)rz   rQ   lines
first_linepartskey_partmkeys           r1   mask_record_contentr      sV    g&&(((""$$).CU1X^^%%%GMMOO
  ""u::??RyH8}}r!!"3B3-FFHSTTNFFFF  fImW-- 	''!**""$$,,S"55C3xx"}}crc(==s344y====JNr4   c                    t          | d          \  }}d}g }d}|rd|vrd |                                D             }|D ]N}|                                }|r6|d                             d          }	|	rd|	v r|                    |	           Ot          |          dk    rd	}d
t          |           d}nt          |          dk    rd}d}nd}|rd                    |          nd}
|dk    |||
|dS )u/   Vérifie les enregistrements MX. MAX: 5 points.rX   r   u    Aucun enregistrement MX trouvé.ru   c                 ^    g | ]*}|                                 |                                 +S r.   )r7   r/   ls     r1   
<listcomp>z#check_mx_record.<locals>.<listcomp>   s-    EEEq17799EEEEr4   r}   .r|   r	   u    Plusieurs serveurs MX trouvés (z). Redondance OK.r   rV   u.   Un seul serveur MX trouvé. Redondance faible.zFormat MX non reconnu.r)   rt   )statusrx   scorerz   mx_hosts)rq   r   rE   rstripappendr9   join)r   rv   rw   r   r   rx   r   liner   hostnamerz   s              r1   check_mx_recordr      sB   FD))MFEEH/F .*F**EEF$5$5$7$7EEE 	. 	.DJJLLE . 9++C00 .xOOH---x==AEXHXXXFF]]aEEFF-F%-8dii!!!5G !)  r4   c                 >   t          | d          \  }}}d}d}|rwd |                                D             }|rT|d         }t          j        d|          }|r0|                    d          }|dk    rd}d	}n|d
k    rd}d}nd}d}n
d}d}nd}nd}|dk    |||dS )u.   Vérifie l'enregistrement SPF. MAX: 25 points.rY   rt   r   c                     g | ]@}d |                                 v |                                                    dd          AS )zv=spf1r'   rA   )r8   r7   r   r   s     r1   r   z$check_spf_record.<locals>.<listcomp>   sG    cccXYZY`Y`YbYbMbMb""3++MbMbMbr4   z([-\~\?])allr   -r
   u/   SPF strict (-all) trouvé. Protection maximale.~r   u/   SPF soft-fail (~all) trouvé. Bonne protection.   u)   SPF avec ?all trouvé. Protection faible.r	   u(   SPF trouvé mais sans mécanisme de fin.u*   Aucun enregistrement SPF (v=spf1) trouvé.u!   Aucun enregistrement TXT trouvé.r   rx   r   rz   )ry   r   rC   r   r   )	r   rL   rx   rz   
spf_recordr   r   r   kinds	            r1   check_spf_recordr      s    1&%@@FFGJE 5ccW5G5G5I5Iccc 	BqJ	/:66A Dwwqzz3;;ENFFS[[ENFFEHFFCAFF4ai6EjYYYr4   defaultselectorc                    |r|                                 nd}t          j        d|          sdddddS | d|  }t          |d	          \  }}d}d
| d}d}|rd|vr|                    dd                              dd                                           }d|                                v rd| d}d}t          |d          }n7d|                                v rd| d}d}t          |d          }nd| d}d}|dk    |||dS )u/   Vérifie l'enregistrement DKIM. MAX: 10 points.r   z^[a-zA-Z0-9_-]+$Fu   Sélecteur DKIM invalide.r   rt   r   z._domainkey.rY   u   Aucun DKIM trouvé pour r   ru   r)   r+   r'   rA   zv=dkim1u!   DKIM trouvé pour le sélecteur 'z'.r   r   zp=u   Clé DKIM trouvée pour 'z' (tag v= manquant).rO   u   TXT trouvé pour z mais format DKIM non reconnu.r|   )r7   rC   r=   rq   r   r8   r   )	r   r   dkim_domainrv   rw   r   rx   content_displayraws	            r1   check_dkim_recordr     sm   #+:x~~H 8'22 
1	
 
 	
 33633KK//MFEE6666FO *F**nnT3''//R88>>@@		##EEEEFE1#v>>OOSYY[[  OOOOFE1#v>>OOTTTTFEqjFU___r4   c                 "   d|  }t          |d          \  }}d}d}d}|rd|vr|                    dd                              d	d
                                          }d|                                v r|}t	          j        d|t          j                  }|rc|                    d                                                                          }	|	dk    rd}d}n&|	dk    rd}d}n|	dk    rd}d}nd}d|	 d}nd}d}nd}|dk    |||dS )u0   Vérifie l'enregistrement DMARC. MAX: 25 points.z_dmarc.rY   rt   r   u#   Aucun enregistrement DMARC trouvé.ru   r)   r+   r'   rA   zv=dmarc1zp\s*=\s*([a-zA-Z]+))flagsr   rejectr
   u*   DMARC reject trouvé. Protection maximale.
quarantiner   u,   DMARC quarantine trouvé. Protection active.noner	   u6   DMARC none (monitoring). Non protecteur mais présent.r|   z!DMARC avec politique inconnue: p=r   u,   DMARC trouvé mais politique (p=) manquante.u%   TXT trouvé mais pas de tag v=DMARC1.r   )rq   r   r7   r8   rC   r   
IGNORECASEr   )
r   dmarc_domainrv   rw   dmarc_recordr   rx   r   m_policypolicys
             r1   check_dmarc_recordr   +  s\   %V%%LL%00MFELE2F =*F**nnT3''//R88>>@@ $$L y!7BMRRRH H!**002288::X%%EIFF|++EKFFv%%EUFFEJJJJFFG<Fai6El[[[r4   c                     t          | d          \  }}t          |od|v          }|rdnd}|rdnd}t          |d          }||||dS )u    Vérifie DNSSEC. MAX: 10 points.rZ   ru   r   r   u    DNSSEC activé (DNSKEY trouvé).u   DNSSEC non activé.r   )rq   r;   r   )r   rv   rw   rL   r   rx   rz   s          r1   check_dnssecr   U  sl    FH--MFE&5Zv566FBBaE39T//?TF!&(33G7SSSr4   c                 n    t          d|  d          \  }}}|rd|v rdnd}|dk    rdnd}|dk    |||dS )	u!   Vérifie MTA-STS. MAX: 10 points.z	_mta-sts.rY   zv=STSv1r   r   u   MTA-STS (v=STSv1) détecté.u   MTA-STS non détecté.r   ry   )r   rL   rx   rz   r   s        r1   check_mta_stsr   _  sc    12Ff2F2FNNFFG8Y'11BBqE/4qyy++>VFai6EgVVVr4   r   c                    g }d|  }t          |d          \  }}|r1d|vr-|                                r|                    d|  d           |dd         D ]}|rt          |t                    s|                                                                                    d          }|rt          |          d	k     rid
| }t          |d          \  }}|r1d|vr-|                                r|                    d| d           t          |          }	|	rdnd}
|	rdd	                    |           dnd}|rd	                    |          nd}|	||
|dS )u"   Vérifie DANE TLS. MAX: 10 points.z
_443._tcp.r[   ru   zHTTPS (r   Nr	   r   rV   z	_25._tcp.zSMTP (r   r   u   DANE TLSA détecté (z, z).u   DANE TLSA non détecté.r)   rt   r   )
rq   r7   r   r5   r6   r8   r   r9   r;   r   )r   r   tlsa_recordshttps_targetoutput_https_hostsmtp_targetoutput_smtprL   r   rx   rz   s                r1   check_dane_tlsr   g  s   L )((LlF33OL! 1
,66<;M;M;O;O6/f///000 ! 2 2 	:dC00 	 zz||!!##**3// 	s4yy1}}($(( f55Q 	2:[88[=N=N=P=P8 0 0 0 0111,FBBaEDJj@TYY|%<%<@@@@PjF)5@dii%%%5G7SSSr4   c                 r    d|  }t          |d          \  }}}d}|r	d|v rd}d}n|rd}nd}|dk    |||d	S )
u   Vérifie BIMI. MAX: 5 points.zdefault._bimi.rY   r   zv=BIMI1r	   u   BIMI (v=BIMI1) trouvé.u$   TXT trouvé mais pas de tag v=BIMI1.u   BIMI non trouvé.r   r   )r   bimi_domainrL   rx   rz   r   s         r1   check_bimi_recordr     sr    +6++K1+uEEFFGE %)w&&*	 %7$ai6EgVVVr4   dkim_selectorc           
         t          |           }|s	ddddddiS t                      s	ddddddiS t          |          }|                    dg           }|t	          |          t          ||          t          |          t          |          t          |          t          ||          t          |          d	}d|d
         v r	|d
         d= |S )uu   
    Analyse complète de la sécurité DNS d'un domaine.
    Retourne un dictionnaire avec tous les résultats.
    FATAL_ERRORFzNom de domaine invalide.r   rt   r   u1   L'outil 'dig' n'est pas installé sur le serveur.r   r   r   )rG   rM   r   getr   r   r   r   r   r   r   )r   r   clean_domain	mx_resultr   resultss         r1   check_all_dns_securityr     s    #6**L 
4 	 
 	
 ?? 
M 	 
 	
  --I}}Z,,H $*<88!,>>#L11|,, .."<::!,//	 	G W-...$%j1Nr4   c                  4    t                                           S )u-   Retourne la répartition des scores maximums.)PLAN_SCOREScopyr.   r4   r1   get_max_score_breakdownr     s    r4   r   c                    d}|                                  D ]'\  }}|t          v r||                    dd          z  }(t          dt	          |t
                              }|dk    rd}n|dk    rd}nd}|t
          |dS )	zCalcule le score total sur 100.r   r   F   green#   orangered)r   	max_scorecolor)itemsr   r   maxminMAX_SCORE_TOTAL)r   current_scoreprotocoldatafinal_scorer   s         r1   calculate_total_scorer     s    M!--// 2 2${""TXXgq111Ma]O<<==K b	r		 $  r4   )rN   rO   )r   )#__doc__re   rC   shutilrJ   typingr   r   r   r   r   r   r   compiler<   r6   r;   r?   rG   rM   intrq   ry   r   r   r   r   r   r   r   r   r   r   r   r   r.   r4   r1   <module>r      s   
     				  				 5 5 5 5 5 5 5 5 5 5 5 5 5 5  	 	  rz ,C ,D , , , ,,C HSM    4*t * * * */5 /5C /5c /53 /5c /5Z_`ceh`hZi /5 /5 /5 /5b
7 
7# 
7%c3:O 
7 
7 
7 
7  3 3    @#C #D # # # #JZS ZT Z Z Z ZB$` $`c $`S $` $` $` $` $`L(\s (\t (\ (\ (\ (\TT T T T T TW# W$ W W W WT3 T$s) T T T T TBWc Wd W W W W(/ /3 /s /4PSUYPY? / / / /bc3h    4T	? tCsCx<P7Q      r4   