@@ -8,6 +8,7 @@ use reqwest::header::HeaderMap;
88use std:: collections:: HashMap ;
99use std:: fs:: File ;
1010use std:: io:: { BufRead , BufReader } ;
11+ use std:: io:: Read ;
1112use std:: net:: { Ipv4Addr , SocketAddr } ;
1213use std:: process:: Command ;
1314use std:: str:: FromStr ;
@@ -18,6 +19,8 @@ use tokio::sync::Semaphore;
1819use tokio:: time:: timeout;
1920use colored:: * ;
2021use scraper:: { Html , Selector } ;
22+ use rquest:: tls:: Impersonate ;
23+ use flate2:: read:: GzDecoder ;
2124
2225#[ tokio:: main]
2326async fn main ( ) {
@@ -325,6 +328,7 @@ async fn test_ip(
325328 None
326329}
327330
331+
328332async fn is_domain_valid ( domain : & str , timeout_duration : Duration ) -> bool {
329333 let client = reqwest:: Client :: builder ( )
330334 . danger_accept_invalid_certs ( true )
@@ -338,17 +342,58 @@ async fn is_domain_valid(domain: &str, timeout_duration: Duration) -> bool {
338342 if let Ok ( Ok ( resp) ) = response {
339343 let status = resp. status ( ) ;
340344 if status == 200 {
341- true
345+ return true ;
346+ } else if status == 403 {
347+ return retry_with_rquest ( domain) . await ;
342348 } else {
343349 eprintln ! ( "Domain {} returned status code {}" , domain, status) ;
344- false
350+ return false ;
345351 }
346352 } else {
347353 eprintln ! ( "Domain {} is unresponsive" , domain) ;
348- false
354+ return false ;
349355 }
350356}
351357
358+
359+ async fn retry_with_rquest ( domain : & str ) -> bool {
360+ let client2 = match rquest:: Client :: builder ( )
361+ . impersonate ( Impersonate :: Chrome129 )
362+ . build ( )
363+ {
364+ Ok ( client) => client,
365+ Err ( e) => {
366+ eprintln ! ( "Erreur lors de la création du client: {}" , e) ;
367+ return false ;
368+ }
369+ } ;
370+
371+ let url = format ! ( "https://{}" , domain) ;
372+
373+ let request_builder = client2. get ( & url) ;
374+ let request = match request_builder. build ( ) {
375+ Ok ( req) => req,
376+ Err ( e) => {
377+ eprintln ! ( "Erreur lors de la construction de la requête: {}" , e) ;
378+ return false ;
379+ }
380+ } ;
381+
382+ let resp = match client2. execute ( request) . await {
383+ Ok ( response) => response,
384+ Err ( e) => {
385+ eprintln ! ( "Erreur lors de l'exécution de la requête: {}" , e) ;
386+ return false ;
387+ }
388+ } ;
389+
390+ let status = resp. status ( ) ;
391+
392+ status. is_success ( )
393+ }
394+
395+
396+
352397async fn get_target_pattern ( domain : & str , timeout_duration : Duration ) -> Option < String > {
353398 let client = reqwest:: Client :: builder ( )
354399 . danger_accept_invalid_certs ( true )
@@ -359,22 +404,68 @@ async fn get_target_pattern(domain: &str, timeout_duration: Duration) -> Option<
359404 let request = client. get ( & url) ;
360405
361406 let response = timeout ( timeout_duration, request. send ( ) ) . await ;
407+
362408 if let Ok ( Ok ( resp) ) = response {
363- if resp. status ( ) != 200 {
364- eprintln ! ( "Domain {} returned status code {}" , domain, resp. status( ) ) ;
365- return None ;
409+ if resp. status ( ) == 200 {
410+ if let Ok ( text) = resp. text ( ) . await {
411+ if let Some ( title) = extract_title ( & text) {
412+ return Some ( title) ;
413+ }
414+ }
415+ } else if resp. status ( ) == 403 {
416+ return match fetch_title_with_rquest ( domain) . await {
417+ Ok ( title) => Some ( title) ,
418+ Err ( e) => {
419+ eprintln ! ( "Failed to fetch title via rquest: {}" , e) ;
420+ None
421+ }
422+ } ;
366423 }
367- if let Ok ( text) = resp. text ( ) . await {
368- if let Some ( title) = extract_title ( & text) {
369- return Some ( title) ;
424+ }
425+
426+ eprintln ! ( "Domain {} is unresponsive or returned an error." , domain) ;
427+ None
428+ }
429+
430+ async fn fetch_title_with_rquest ( domain : & str ) -> Result < String , Box < dyn std:: error:: Error > > {
431+ let client = rquest:: Client :: builder ( )
432+ . impersonate ( Impersonate :: Chrome129 )
433+ . build ( ) ?;
434+
435+ let url = format ! ( "https://{}/" , domain) ;
436+ let resp = client. get ( & url) . send ( ) . await ?;
437+
438+ let status = resp. status ( ) ;
439+ if status == 200 {
440+ let body = if let Some ( encoding) = resp. headers ( ) . get ( "Content-Encoding" ) {
441+ if encoding == "gzip" {
442+ let body = resp. bytes ( ) . await ?;
443+ let mut decoder = GzDecoder :: new ( & body[ ..] ) ;
444+ let mut decompressed_body = String :: new ( ) ;
445+ decoder. read_to_string ( & mut decompressed_body) ?;
446+ decompressed_body
447+ } else {
448+ resp. text ( ) . await ?
370449 }
450+ } else {
451+ resp. text ( ) . await ?
452+ } ;
453+
454+ let document = Html :: parse_document ( & body) ;
455+ let selector = Selector :: parse ( "title" ) . unwrap ( ) ;
456+
457+ if let Some ( title_element) = document. select ( & selector) . next ( ) {
458+ let title = title_element. inner_html ( ) ;
459+ return Ok ( title) ;
460+ } else {
461+ return Err ( "No <title> found." . into ( ) ) ;
371462 }
372463 } else {
373- eprintln ! ( "Domain {} is unresponsive " , domain ) ;
464+ return Err ( format ! ( "Request failed with status: {} " , status ) . into ( ) ) ;
374465 }
375- None
376466}
377467
468+
378469fn extract_title ( html : & str ) -> Option < String > {
379470 let document = Html :: parse_document ( html) ;
380471 let selector = Selector :: parse ( "title" ) . unwrap ( ) ;
@@ -399,12 +490,10 @@ fn read_lines(filename: &str) -> Vec<String> {
399490fn parse_ip_range ( ip_range : & str ) -> Result < Vec < String > , String > {
400491 let parts: Vec < & str > = ip_range. split ( '-' ) . collect ( ) ;
401492 if parts. len ( ) == 1 {
402- // Traiter comme une seule adresse IP
403493 let ip = parts[ 0 ] ;
404494 let ip_addr = Ipv4Addr :: from_str ( ip) . map_err ( |_| "Adresse IP invalide." . to_string ( ) ) ?;
405495 Ok ( vec ! [ ip_addr. to_string( ) ] )
406496 } else if parts. len ( ) == 2 {
407- // Traiter comme une plage d'adresses IP
408497 let start_ip =
409498 Ipv4Addr :: from_str ( parts[ 0 ] ) . map_err ( |_| "Adresse IP de début invalide." . to_string ( ) ) ?;
410499 let end_ip =
0 commit comments