@@ -14,6 +14,7 @@ use std::time::Duration;
14
14
use tokio:: sync:: Semaphore ;
15
15
use tokio:: time:: timeout;
16
16
use colored:: * ;
17
+ use scraper:: { Html , Selector } ;
17
18
18
19
#[ tokio:: main]
19
20
async fn main ( ) {
@@ -75,6 +76,7 @@ async fn main() {
75
76
let ip_range = matches. value_of ( "iprange" ) ;
76
77
let ua_file = matches. value_of ( "useragents" ) ;
77
78
let timeout_secs: u64 = matches. value_of ( "timeout" ) . unwrap ( ) . parse ( ) . unwrap ( ) ;
79
+ let timeout_duration = Duration :: from_secs ( timeout_secs) ;
78
80
let aggressive = matches. is_present ( "aggressive" ) ;
79
81
80
82
let available_threads = num_cpus:: get ( ) ;
@@ -84,9 +86,8 @@ async fn main() {
84
86
. map ( |s| s. parse :: < usize > ( ) . unwrap_or ( available_threads) )
85
87
. unwrap_or ( available_threads) ;
86
88
87
-
88
89
println ! (
89
- "Use of : {} threads" ,
90
+ "Utilisation de : {} threads" ,
90
91
format!( "{}" , max_threads) . blue( )
91
92
) ;
92
93
@@ -101,21 +102,19 @@ async fn main() {
101
102
}
102
103
}
103
104
} else {
104
- eprintln ! ( "You must specify either an IP addresses file or a range of IP addresses ." ) ;
105
+ eprintln ! ( "Vous devez spécifier soit un fichier d'adresses IP, soit une plage d'adresses IP." ) ;
105
106
return ;
106
107
} ;
107
108
108
109
if ips. is_empty ( ) {
109
- eprintln ! ( "No IP address found ." ) ;
110
+ eprintln ! ( "Aucune adresse IP trouvée ." ) ;
110
111
return ;
111
112
}
112
113
113
114
let pb = ProgressBar :: new ( ips. len ( ) as u64 ) ;
114
115
pb. set_style (
115
116
ProgressStyle :: default_bar ( )
116
- . template ( "{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})" )
117
- . expect ( "Progress bar template error" )
118
- . progress_chars ( "#>-" ) ,
117
+ . template ( "{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})" ) ,
119
118
) ;
120
119
121
120
let user_agents = if let Some ( ua_path) = ua_file {
@@ -129,6 +128,15 @@ async fn main() {
129
128
vec ! [ "Mozilla/5.0 (compatible; CloudFade/1.0; +https://example.com)" . to_string( ) ]
130
129
} ;
131
130
131
+ // Extraction du motif unique du domaine cible
132
+ let target_pattern = match get_target_pattern ( domain, timeout_duration) . await {
133
+ Some ( pattern) => pattern,
134
+ None => {
135
+ eprintln ! ( "Impossible d'extraire un motif unique du domaine cible." ) ;
136
+ return ;
137
+ }
138
+ } ;
139
+
132
140
let semaphore = Arc :: new ( Semaphore :: new ( max_threads) ) ;
133
141
134
142
let mut tasks = FuturesUnordered :: new ( ) ;
@@ -138,15 +146,23 @@ async fn main() {
138
146
let domain = domain. to_string ( ) ;
139
147
let user_agents = user_agents. clone ( ) ;
140
148
let aggressive = aggressive;
141
- let timeout_duration = Duration :: from_secs ( timeout_secs ) ;
149
+ let timeout_duration = timeout_duration ;
142
150
let semaphore = semaphore. clone ( ) ;
143
151
let pb = pb. clone ( ) ;
152
+ let target_pattern = target_pattern. clone ( ) ;
144
153
145
154
let permit = semaphore. acquire_owned ( ) . await . unwrap ( ) ;
146
155
147
156
tasks. push ( tokio:: spawn ( async move {
148
- let result =
149
- test_ip ( ip, domain, user_agents, aggressive, timeout_duration) . await ;
157
+ let result = test_ip (
158
+ ip,
159
+ domain,
160
+ user_agents,
161
+ aggressive,
162
+ timeout_duration,
163
+ target_pattern,
164
+ )
165
+ . await ;
150
166
drop ( permit) ;
151
167
pb. inc ( 1 ) ;
152
168
result
@@ -161,15 +177,15 @@ async fn main() {
161
177
}
162
178
}
163
179
164
- pb. finish_with_message ( "Scan completed " ) ;
180
+ pb. finish_with_message ( "Scan terminé " ) ;
165
181
166
182
if possible_ips. is_empty ( ) {
167
183
println ! (
168
184
"{}" ,
169
- format!( "No IPs found linked to {}" , domain) . red( )
185
+ format!( "Aucune IP trouvée liée à {}" , domain) . red( )
170
186
) ;
171
187
} else {
172
- println ! ( "{}" , "Potential IP addresses found :" . green( ) ) ;
188
+ println ! ( "{}" , "Adresses IP potentielles trouvées :" . green( ) ) ;
173
189
for ip in possible_ips {
174
190
println ! ( "{}" , ip. green( ) ) ;
175
191
}
@@ -182,11 +198,12 @@ async fn test_ip(
182
198
user_agents : Vec < String > ,
183
199
aggressive : bool ,
184
200
timeout_duration : Duration ,
201
+ target_pattern : String ,
185
202
) -> Option < String > {
186
203
let socket_addr: SocketAddr = match format ! ( "{}:80" , ip) . parse ( ) {
187
204
Ok ( addr) => addr,
188
205
Err ( _) => {
189
- eprintln ! ( "Invalid IP address : {}" , ip) ;
206
+ eprintln ! ( "Adresse IP invalide : {}" , ip) ;
190
207
return None ;
191
208
}
192
209
} ;
@@ -219,46 +236,80 @@ async fn test_ip(
219
236
if let Ok ( Ok ( resp) ) = response {
220
237
let status = resp. status ( ) . as_u16 ( ) ;
221
238
if status == 200 || status == 301 || status == 302 {
222
- return Some ( ip) ;
239
+ if let Ok ( text) = resp. text ( ) . await {
240
+ if text. contains ( & target_pattern) {
241
+ return Some ( ip) ;
242
+ }
243
+ }
223
244
}
224
245
}
225
246
}
226
247
}
227
248
None
228
249
}
229
250
251
+ async fn get_target_pattern ( domain : & str , timeout_duration : Duration ) -> Option < String > {
252
+ let client = reqwest:: Client :: builder ( )
253
+ . danger_accept_invalid_certs ( true )
254
+ . build ( )
255
+ . unwrap ( ) ;
256
+
257
+ let url = format ! ( "http://{}/" , domain) ;
258
+ let request = client. get ( & url) ;
259
+
260
+ let response = timeout ( timeout_duration, request. send ( ) ) . await ;
261
+ if let Ok ( Ok ( resp) ) = response {
262
+ if let Ok ( text) = resp. text ( ) . await {
263
+ if let Some ( title) = extract_title ( & text) {
264
+ return Some ( title) ;
265
+ }
266
+ }
267
+ }
268
+ None
269
+ }
270
+
271
+ fn extract_title ( html : & str ) -> Option < String > {
272
+ let document = Html :: parse_document ( html) ;
273
+ let selector = Selector :: parse ( "title" ) . unwrap ( ) ;
274
+
275
+ document. select ( & selector) . next ( ) . map ( |element| element. inner_html ( ) )
276
+ }
277
+
230
278
fn read_lines ( filename : & str ) -> Vec < String > {
231
- let file = File :: open ( filename) . expect ( "Unable to open file " ) ;
279
+ let file = File :: open ( filename) . expect ( "Impossible d'ouvrir le fichier " ) ;
232
280
let reader = BufReader :: new ( file) ;
233
281
reader. lines ( ) . filter_map ( Result :: ok) . collect ( )
234
282
}
235
283
236
284
fn parse_ip_range ( ip_range : & str ) -> Result < Vec < String > , String > {
237
285
let parts: Vec < & str > = ip_range. split ( '-' ) . collect ( ) ;
238
286
if parts. len ( ) != 2 {
239
- return Err ( "IP range format is invalid. Use 'start-end' format ." . to_string ( ) ) ;
287
+ return Err ( "Le format de la plage IP est invalide. Utilisez le format 'début-fin' ." . to_string ( ) ) ;
240
288
}
241
289
242
- let start_ip = Ipv4Addr :: from_str ( parts[ 0 ] ) . map_err ( |_| "Start IP address invalid ." . to_string ( ) ) ?;
243
- let end_ip = Ipv4Addr :: from_str ( parts[ 1 ] ) . map_err ( |_| "End IP address invalid ." . to_string ( ) ) ?;
290
+ let start_ip = Ipv4Addr :: from_str ( parts[ 0 ] ) . map_err ( |_| "Adresse IP de début invalide ." . to_string ( ) ) ?;
291
+ let end_ip = Ipv4Addr :: from_str ( parts[ 1 ] ) . map_err ( |_| "Adresse IP de fin invalide ." . to_string ( ) ) ?;
244
292
245
293
let start: u32 = start_ip. into ( ) ;
246
294
let end: u32 = end_ip. into ( ) ;
247
295
248
296
if start > end {
249
- return Err ( "The starting IP address is greater than the ending IP address ." . to_string ( ) ) ;
297
+ return Err ( "L'adresse IP de début est supérieure à l'adresse IP de fin ." . to_string ( ) ) ;
250
298
}
251
299
252
300
let max_ips = 1_000_000 ;
253
301
let total_ips = end - start + 1 ;
254
302
255
303
if total_ips > max_ips {
256
- return Err ( format ! ( "The IP range is too large ({} addresses). Please specify a smaller range." , total_ips) ) ;
304
+ return Err ( format ! (
305
+ "La plage d'IP est trop grande ({} adresses). Veuillez spécifier une plage plus petite." ,
306
+ total_ips
307
+ ) ) ;
257
308
}
258
309
259
310
let ips: Vec < String > = ( start..=end)
260
311
. map ( |ip_num| Ipv4Addr :: from ( ip_num) . to_string ( ) )
261
312
. collect ( ) ;
262
313
263
314
Ok ( ips)
264
- }
315
+ }
0 commit comments