11use trust_dns_client:: client:: { Client , SyncClient } ;
2- use trust_dns_client:: udp :: UdpClientConnection ;
2+ use trust_dns_client:: tcp :: TcpClientConnection ;
33use std:: str:: FromStr ;
44use std:: net:: IpAddr ;
55use trust_dns_client:: op:: DnsResponse ;
@@ -9,34 +9,109 @@ use rayon::prelude::*;
99use std:: fs:: read_to_string;
1010use std:: env;
1111use std:: process;
12+ use std:: net:: SocketAddr ;
13+ use weighted_rs:: { RoundrobinWeight , Weight } ;
14+ use std:: time:: Duration ;
15+ use std:: thread;
1216
13- fn get_ptr ( conn : UdpClientConnection , addr : IpAddr ) {
17+ struct PtrResult {
18+ query_addr : IpAddr ,
19+ query : Name ,
20+ result : Option < Name > ,
21+ error : Option < String > ,
22+ }
23+
24+ #[ derive( Copy , Clone ) ]
25+ struct IpToResolve {
26+ address : IpAddr ,
27+ server : SocketAddr ,
28+ }
29+
30+ fn get_ptr ( to_resolve : IpToResolve ) -> PtrResult {
31+ let conn = match TcpClientConnection :: with_timeout ( to_resolve. server , Duration :: new ( 5 , 0 ) ) {
32+ Ok ( conn) => conn,
33+ Err ( err) => {
34+ eprintln ! ( "Something went wrong with the UDP client connection: {}" , err) ;
35+ process:: exit ( 1 ) ;
36+ }
37+ } ;
1438 let client = SyncClient :: new ( conn) ;
1539 // Specify the name, note the final '.' which specifies it's an FQDN
16- let name = Name :: from_str ( & reverse ( addr) ) . unwrap ( ) ;
40+ let name = match Name :: from_str ( & reverse ( to_resolve. address ) ) {
41+ Ok ( name) => name,
42+ Err ( err) => {
43+ eprintln ! (
44+ "Something went wrong while building the name ({}): {}" ,
45+ reverse( to_resolve. address) ,
46+ err
47+ ) ;
48+ process:: exit ( 1 ) ;
49+ }
50+ } ;
51+
52+ let response: DnsResponse = match client. query ( & name, DNSClass :: IN , RecordType :: PTR ) {
53+ Ok ( res) => res,
54+ Err ( err) => {
55+ let two_hundred_millis = Duration :: from_millis ( 400 ) ;
56+ thread:: sleep ( two_hundred_millis) ;
57+ eprintln ! ( "Query error for ({}) from ({}): {}" , name, to_resolve. server, err) ;
58+ return PtrResult {
59+ query_addr : to_resolve. address ,
60+ query : name,
61+ result : None ,
62+ error : Some ( err. to_string ( ) ) ,
63+ } ;
64+ }
65+ } ;
1766
18- let response: DnsResponse = client. query ( & name, DNSClass :: IN , RecordType :: PTR ) . unwrap ( ) ;
1967 let answers: & [ Record ] = response. answers ( ) ;
2068
2169 if answers. len ( ) == 0 {
22- println ! ( "{}" , addr) ;
23- return ;
70+ return PtrResult {
71+ query_addr : to_resolve. address ,
72+ query : name,
73+ result : None ,
74+ error : None ,
75+ } ;
2476 }
2577
2678 if let Some ( RData :: PTR ( ref res) ) = answers[ 0 ] . data ( ) {
27- println ! ( "{} # {}" , addr, res) ;
79+ return PtrResult {
80+ query_addr : to_resolve. address ,
81+ query : name,
82+ result : Some ( res. clone ( ) ) ,
83+ error : None ,
84+ } ;
2885 } else {
29- assert ! ( false , "unexpected result" )
86+ assert ! ( false , "unexpected result" ) ;
87+ process:: exit ( 1 ) ;
3088 }
3189}
3290
33- fn resolve_file ( filename : & str , dns_server : & str ) {
91+ fn resolve_file ( filename : & str , dns_servers : Vec < & str > ) {
92+ let mut rr: RoundrobinWeight < SocketAddr > = RoundrobinWeight :: new ( ) ;
93+ for dns_server in dns_servers {
94+ let address = match dns_server. parse ( ) {
95+ Ok ( addr) => addr,
96+ Err ( err) => {
97+ eprintln ! ( "Something went wrong while parsing the DNS server address: {}" , err) ;
98+ process:: exit ( 1 ) ;
99+ }
100+ } ;
101+
102+ rr. add ( address, 1 ) ;
103+ }
104+
34105 let mut ips = vec ! [ ] ;
35106 match read_to_string ( filename) {
36107 Ok ( file) => {
37108 for line in file. lines ( ) {
38109 match IpAddr :: from_str ( line) {
39- Ok ( addr) => ips. push ( addr) ,
110+ Ok ( addr) =>
111+ ips. push ( IpToResolve {
112+ address : addr,
113+ server : rr. next ( ) . unwrap ( ) ,
114+ } ) ,
40115 Err ( err) => {
41116 eprintln ! ( "Something went wrong while parsing the IP ({}): {}" , line, err) ;
42117 process:: exit ( 1 ) ;
@@ -49,20 +124,21 @@ fn resolve_file(filename: &str, dns_server: &str) {
49124 process:: exit ( 1 ) ;
50125 }
51126 }
52- rayon:: ThreadPoolBuilder :: new ( ) . num_threads ( 50 ) . build_global ( ) . unwrap ( ) ;
53- let address = dns_server. parse ( ) . unwrap ( ) ;
54- let conn = match UdpClientConnection :: new ( address) {
55- Ok ( conn) => conn,
127+ match rayon:: ThreadPoolBuilder :: new ( ) . num_threads ( 30 ) . build_global ( ) {
128+ Ok ( r) => r,
56129 Err ( err) => {
57- eprintln ! ( "Something went wrong with the UDP client connection : {}" , err) ;
130+ eprintln ! ( "Something went wrong while building the thread pool : {}" , err) ;
58131 process:: exit ( 1 ) ;
59132 }
60- } ;
133+ }
61134
62135 ips. into_par_iter ( )
63136 . enumerate ( )
64- . for_each ( |( _i, addr) | {
65- get_ptr ( conn, addr) ;
137+ . for_each ( |( _i, to_resolve) | {
138+ match get_ptr ( to_resolve) . result {
139+ Some ( res) => println ! ( "{} # {}" , to_resolve. address, res) ,
140+ None => println ! ( "{}" , to_resolve. address) ,
141+ } ;
66142 } ) ;
67143}
68144
@@ -72,7 +148,7 @@ fn main() {
72148 eprintln ! ( "Use: dns-ptr-resolver ./ips.txt" ) ;
73149 process:: exit ( 1 ) ;
74150 }
75- resolve_file ( & args[ 1 ] , "1.1.1.1:53" )
151+ resolve_file ( & args[ 1 ] , vec ! [ "1.1.1.1:53" , "1.0.0.1:53" , "8.8.8.8:53" , "8.8.4.4:53" ] )
76152}
77153
78154#[ cfg( test) ]
@@ -86,6 +162,6 @@ mod test {
86162
87163 #[ test]
88164 fn test_resolve_file ( ) {
89- resolve_file ( "./example/ips-to-resolve.txt" , "1.1.1.1:53" ) ;
165+ resolve_file ( "./example/ips-to-resolve.txt" , vec ! [ "1.1.1.1:53" ] ) ;
90166 }
91167}
0 commit comments