@@ -2,7 +2,108 @@ use regex::Regex;
22use std:: fs;
33use std:: path:: Path ;
44use anyhow:: Result ;
5- use crate :: types:: { ServicePattern , NmapService , NmapProbe , NmapMatch } ;
5+ use std:: collections:: HashMap ;
6+ use crate :: types:: { ServicePattern , NmapService , NmapProbe , NmapMatch , Protocol , MacPrefix , RpcInfo } ;
7+
8+ lazy_static:: lazy_static! {
9+ static ref PROTOCOLS : HashMap <String , Protocol > = {
10+ let mut map = HashMap :: new( ) ;
11+ if let Ok ( protocols) = load_protocols( "src/assets/nmap-protocols" ) {
12+ for protocol in protocols {
13+ map. insert( protocol. name. clone( ) , protocol) ;
14+ }
15+ }
16+ map
17+ } ;
18+
19+ static ref MAC_PREFIXES : HashMap <String , String > = {
20+ let mut map = HashMap :: new( ) ;
21+ if let Ok ( prefixes) = load_mac_prefixes( "src/assets/nmap-mac-prefixes" ) {
22+ for prefix in prefixes {
23+ map. insert( prefix. prefix, prefix. vendor) ;
24+ }
25+ }
26+ map
27+ } ;
28+
29+ static ref RPC_INFO : HashMap <( String , String ) , RpcInfo > = {
30+ let mut map = HashMap :: new( ) ;
31+ if let Ok ( info) = load_rpc_info( "src/assets/nmap-rpc" ) {
32+ for rpc in info {
33+ map. insert( ( rpc. program. clone( ) , rpc. version. clone( ) ) , rpc) ;
34+ }
35+ }
36+ map
37+ } ;
38+
39+ static ref NMAP_SERVICES : HashMap <u16 , Vec <NmapService >> = {
40+ let mut map = HashMap :: new( ) ;
41+ if let Ok ( services) = load_nmap_services( "src/assets/nmap-services" ) {
42+ for service in services {
43+ map. entry( service. port) . or_insert_with( Vec :: new) . push( service) ;
44+ }
45+ }
46+ map
47+ } ;
48+
49+ static ref SERVICE_PATTERNS : Vec <ServicePattern > = {
50+ let mut patterns = Vec :: with_capacity( 1000 ) ;
51+
52+ patterns. extend( get_ssh_patterns( ) ) ;
53+ patterns. extend( get_http_patterns( ) ) ;
54+ patterns. extend( get_ftp_patterns( ) ) ;
55+ patterns. extend( get_mysql_patterns( ) ) ;
56+ patterns. extend( get_redis_patterns( ) ) ;
57+
58+ if let Ok ( probes) = load_nmap_probes( "src/assets/nmap-service-probes" ) {
59+ for probe in probes {
60+ for nmap_match in probe. matches {
61+ if nmap_match. pattern. contains( "**" ) || nmap_match. pattern. contains( "\\ " ) || nmap_match. pattern. contains( "^" ) {
62+ continue ;
63+ }
64+
65+ if let Ok ( regex) = Regex :: new( & nmap_match. pattern) {
66+ let pattern = ServicePattern {
67+ name: nmap_match. service. clone( ) ,
68+ regex,
69+ probe: probe. probe_string. clone( ) ,
70+ version_regex: nmap_match. version_info. as_ref( ) . and_then( |v| Regex :: new( v) . ok( ) ) ,
71+ product_regex: nmap_match. product_info. as_ref( ) . and_then( |p| Regex :: new( p) . ok( ) ) ,
72+ os_regex: nmap_match. os_info. as_ref( ) . and_then( |o| Regex :: new( o) . ok( ) ) ,
73+ extra_info_regex: nmap_match. extra_info. as_ref( ) . and_then( |i| Regex :: new( i) . ok( ) ) ,
74+ cpe_regex: nmap_match. cpe. as_ref( ) . and_then( |c| Regex :: new( c) . ok( ) ) ,
75+ vulnerability_patterns: vec![ ] ,
76+ total_wait_ms: probe. total_wait_ms,
77+ tcp_wrapped_ms: probe. tcp_wrapped_ms,
78+ } ;
79+ patterns. push( pattern) ;
80+ }
81+ }
82+ }
83+ }
84+ patterns
85+ } ;
86+ }
87+
88+ pub fn get_all_patterns ( ) -> Vec < ServicePattern > {
89+ SERVICE_PATTERNS . clone ( )
90+ }
91+
92+ pub fn get_protocol ( name : & str ) -> Option < & Protocol > {
93+ PROTOCOLS . get ( name)
94+ }
95+
96+ pub fn get_mac_vendor ( prefix : & str ) -> Option < & String > {
97+ MAC_PREFIXES . get ( prefix)
98+ }
99+
100+ pub fn get_rpc_info < ' a > ( program : & ' a str , version : & ' a str ) -> Option < & ' static RpcInfo > {
101+ RPC_INFO . get ( & ( program. to_string ( ) , version. to_string ( ) ) )
102+ }
103+
104+ pub fn get_services_by_port ( port : u16 ) -> Option < & ' static Vec < NmapService > > {
105+ NMAP_SERVICES . get ( & port)
106+ }
6107
7108pub fn get_ssh_patterns ( ) -> Vec < ServicePattern > {
8109 vec ! [
@@ -230,41 +331,106 @@ pub fn load_nmap_probes(file_path: &str) -> Result<Vec<NmapProbe>> {
230331 Ok ( probes)
231332}
232333
233- pub fn get_all_patterns ( ) -> Vec < ServicePattern > {
234- let mut patterns = Vec :: new ( ) ;
235-
236- patterns. extend ( get_ssh_patterns ( ) ) ;
237- patterns. extend ( get_http_patterns ( ) ) ;
238- patterns. extend ( get_ftp_patterns ( ) ) ;
239- patterns. extend ( get_mysql_patterns ( ) ) ;
240- patterns. extend ( get_redis_patterns ( ) ) ;
241-
242- if let Ok ( probes) = load_nmap_probes ( "src/assets/nmap-service-probes" ) {
243- for probe in probes {
244- for nmap_match in probe. matches {
245- if nmap_match. pattern . contains ( "**" ) || nmap_match. pattern . contains ( "\\ " ) || nmap_match. pattern . contains ( "^" ) {
246- continue ;
247- }
334+ pub fn load_protocols ( file_path : & str ) -> Result < Vec < Protocol > > {
335+ let path = Path :: new ( file_path) ;
336+ if !path. exists ( ) {
337+ return Ok ( Vec :: new ( ) ) ;
338+ }
248339
249- if let Ok ( regex) = Regex :: new ( & nmap_match. pattern ) {
250- let pattern = ServicePattern {
251- name : nmap_match. service . clone ( ) ,
252- regex,
253- probe : probe. probe_string . clone ( ) ,
254- version_regex : nmap_match. version_info . as_ref ( ) . and_then ( |v| Regex :: new ( v) . ok ( ) ) ,
255- product_regex : nmap_match. product_info . as_ref ( ) . and_then ( |p| Regex :: new ( p) . ok ( ) ) ,
256- os_regex : nmap_match. os_info . as_ref ( ) . and_then ( |o| Regex :: new ( o) . ok ( ) ) ,
257- extra_info_regex : nmap_match. extra_info . as_ref ( ) . and_then ( |i| Regex :: new ( i) . ok ( ) ) ,
258- cpe_regex : nmap_match. cpe . as_ref ( ) . and_then ( |c| Regex :: new ( c) . ok ( ) ) ,
259- vulnerability_patterns : vec ! [ ] ,
260- total_wait_ms : probe. total_wait_ms ,
261- tcp_wrapped_ms : probe. tcp_wrapped_ms ,
262- } ;
263- patterns. push ( pattern) ;
264- }
340+ let content = fs:: read_to_string ( path) ?;
341+ let mut protocols = Vec :: new ( ) ;
342+
343+ for line in content. lines ( ) {
344+ if line. starts_with ( '#' ) || line. trim ( ) . is_empty ( ) {
345+ continue ;
346+ }
347+
348+ let parts: Vec < & str > = line. split_whitespace ( ) . collect ( ) ;
349+ if parts. len ( ) >= 2 {
350+ let name = parts[ 0 ] . to_string ( ) ;
351+ if let Ok ( number) = parts[ 1 ] . parse :: < u8 > ( ) {
352+ let aliases = if parts. len ( ) > 2 {
353+ parts[ 2 ..] . iter ( ) . map ( |& s| s. to_string ( ) ) . collect ( )
354+ } else {
355+ Vec :: new ( )
356+ } ;
357+
358+ protocols. push ( Protocol {
359+ name,
360+ number,
361+ aliases,
362+ } ) ;
265363 }
266364 }
267365 }
268-
269- patterns
366+
367+ Ok ( protocols)
368+ }
369+
370+ pub fn load_mac_prefixes ( file_path : & str ) -> Result < Vec < MacPrefix > > {
371+ let path = Path :: new ( file_path) ;
372+ if !path. exists ( ) {
373+ return Ok ( Vec :: new ( ) ) ;
374+ }
375+
376+ let content = fs:: read_to_string ( path) ?;
377+ let mut prefixes = Vec :: new ( ) ;
378+
379+ for line in content. lines ( ) {
380+ if line. starts_with ( '#' ) || line. trim ( ) . is_empty ( ) {
381+ continue ;
382+ }
383+
384+ let parts: Vec < & str > = line. split_whitespace ( ) . collect ( ) ;
385+ if parts. len ( ) >= 2 {
386+ let prefix = parts[ 0 ] . to_string ( ) ;
387+ let vendor = parts[ 1 ..] . join ( " " ) ;
388+
389+ prefixes. push ( MacPrefix {
390+ prefix,
391+ vendor,
392+ } ) ;
393+ }
394+ }
395+
396+ Ok ( prefixes)
397+ }
398+
399+ pub fn load_rpc_info ( file_path : & str ) -> Result < Vec < RpcInfo > > {
400+ let path = Path :: new ( file_path) ;
401+ if !path. exists ( ) {
402+ return Ok ( Vec :: new ( ) ) ;
403+ }
404+
405+ let content = fs:: read_to_string ( path) ?;
406+ let mut rpc_info = Vec :: new ( ) ;
407+
408+ for line in content. lines ( ) {
409+ if line. starts_with ( '#' ) || line. trim ( ) . is_empty ( ) {
410+ continue ;
411+ }
412+
413+ let parts: Vec < & str > = line. split_whitespace ( ) . collect ( ) ;
414+ if parts. len ( ) >= 3 {
415+ let program = parts[ 0 ] . to_string ( ) ;
416+ let version = parts[ 1 ] . to_string ( ) ;
417+ let protocol = parts[ 2 ] . to_string ( ) ;
418+ let port = parts. get ( 3 ) . and_then ( |p| p. parse :: < u16 > ( ) . ok ( ) ) ;
419+ let description = if parts. len ( ) > 4 {
420+ Some ( parts[ 4 ..] . join ( " " ) )
421+ } else {
422+ None
423+ } ;
424+
425+ rpc_info. push ( RpcInfo {
426+ program,
427+ version,
428+ protocol,
429+ port,
430+ description,
431+ } ) ;
432+ }
433+ }
434+
435+ Ok ( rpc_info)
270436}
0 commit comments