@@ -17,6 +17,7 @@ use string::{String, ToString};
1717use sys:: syscall:: EINVAL ;
1818use time:: { self , Duration } ;
1919use vec:: { IntoIter , Vec } ;
20+ use convert:: { TryFrom , TryInto } ;
2021
2122use self :: dns:: { Dns , DnsQuery } ;
2223
@@ -29,7 +30,13 @@ mod dns;
2930mod tcp;
3031mod udp;
3132
32- pub struct LookupHost ( IntoIter < SocketAddr > ) ;
33+ pub struct LookupHost ( IntoIter < SocketAddr > , u16 ) ;
34+
35+ impl LookupHost {
36+ pub fn port ( & self ) -> u16 {
37+ self . 1
38+ }
39+ }
3340
3441impl Iterator for LookupHost {
3542 type Item = SocketAddr ;
@@ -38,65 +45,94 @@ impl Iterator for LookupHost {
3845 }
3946}
4047
41- pub fn lookup_host ( host : & str ) -> Result < LookupHost > {
42- let mut ip_string = String :: new ( ) ;
43- File :: open ( "/etc/net/ip" ) ?. read_to_string ( & mut ip_string) ?;
44- let ip: Vec < u8 > = ip_string. trim ( ) . split ( '.' ) . map ( |part| part. parse :: < u8 > ( )
45- . unwrap_or ( 0 ) ) . collect ( ) ;
46-
47- let mut dns_string = String :: new ( ) ;
48- File :: open ( "/etc/net/dns" ) ?. read_to_string ( & mut dns_string) ?;
49- let dns: Vec < u8 > = dns_string. trim ( ) . split ( '.' ) . map ( |part| part. parse :: < u8 > ( )
50- . unwrap_or ( 0 ) ) . collect ( ) ;
51-
52- if ip. len ( ) == 4 && dns. len ( ) == 4 {
53- let time = time:: SystemTime :: now ( ) . duration_since ( time:: UNIX_EPOCH ) . unwrap ( ) ;
54- let tid = ( time. subsec_nanos ( ) >> 16 ) as u16 ;
55-
56- let packet = Dns {
57- transaction_id : tid,
58- flags : 0x0100 ,
59- queries : vec ! [ DnsQuery {
60- name: host. to_string( ) ,
61- q_type: 0x0001 ,
62- q_class: 0x0001 ,
63- } ] ,
64- answers : vec ! [ ]
65- } ;
66-
67- let packet_data = packet. compile ( ) ;
68-
69- let my_ip = Ipv4Addr :: new ( ip[ 0 ] , ip[ 1 ] , ip[ 2 ] , ip[ 3 ] ) ;
70- let dns_ip = Ipv4Addr :: new ( dns[ 0 ] , dns[ 1 ] , dns[ 2 ] , dns[ 3 ] ) ;
71- let socket = UdpSocket :: bind ( & SocketAddr :: V4 ( SocketAddrV4 :: new ( my_ip, 0 ) ) ) ?;
72- socket. set_read_timeout ( Some ( Duration :: new ( 5 , 0 ) ) ) ?;
73- socket. set_write_timeout ( Some ( Duration :: new ( 5 , 0 ) ) ) ?;
74- socket. connect ( & SocketAddr :: V4 ( SocketAddrV4 :: new ( dns_ip, 53 ) ) ) ?;
75- socket. send ( & packet_data) ?;
76-
77- let mut buf = [ 0 ; 65536 ] ;
78- let count = socket. recv ( & mut buf) ?;
79-
80- match Dns :: parse ( & buf[ .. count] ) {
81- Ok ( response) => {
82- let mut addrs = vec ! [ ] ;
83- for answer in response. answers . iter ( ) {
84- if answer. a_type == 0x0001 && answer. a_class == 0x0001
85- && answer. data . len ( ) == 4
86- {
87- let answer_ip = Ipv4Addr :: new ( answer. data [ 0 ] ,
88- answer. data [ 1 ] ,
89- answer. data [ 2 ] ,
90- answer. data [ 3 ] ) ;
91- addrs. push ( SocketAddr :: V4 ( SocketAddrV4 :: new ( answer_ip, 0 ) ) ) ;
92- }
48+ impl < ' a > TryFrom < & ' a str > for LookupHost {
49+ type Error = io:: Error ;
50+
51+ fn try_from ( s : & str ) -> io:: Result < LookupHost > {
52+ macro_rules! try_opt {
53+ ( $e: expr, $msg: expr) => (
54+ match $e {
55+ Some ( r) => r,
56+ None => return Err ( io:: Error :: new( io:: ErrorKind :: InvalidInput ,
57+ $msg) ) ,
9358 }
94- Ok ( LookupHost ( addrs. into_iter ( ) ) )
95- } ,
96- Err ( _err) => Err ( Error :: from_raw_os_error ( EINVAL ) )
59+ )
60+ }
61+
62+ // split the string by ':' and convert the second part to u16
63+ let mut parts_iter = s. rsplitn ( 2 , ':' ) ;
64+ let port_str = try_opt ! ( parts_iter. next( ) , "invalid socket address" ) ;
65+ let host = try_opt ! ( parts_iter. next( ) , "invalid socket address" ) ;
66+ let port: u16 = try_opt ! ( port_str. parse( ) . ok( ) , "invalid port value" ) ;
67+
68+ ( host, port) . try_into ( )
69+ }
70+ }
71+
72+ impl < ' a > TryFrom < ( & ' a str , u16 ) > for LookupHost {
73+ type Error = io:: Error ;
74+
75+ fn try_from ( ( host, port) : ( & ' a str , u16 ) ) -> io:: Result < LookupHost > {
76+ let host = host. host_port ( ) ?. 0 ;
77+ let mut ip_string = String :: new ( ) ;
78+ File :: open ( "/etc/net/ip" ) ?. read_to_string ( & mut ip_string) ?;
79+ let ip: Vec < u8 > = ip_string. trim ( ) . split ( '.' ) . map ( |part| part. parse :: < u8 > ( )
80+ . unwrap_or ( 0 ) ) . collect ( ) ;
81+
82+ let mut dns_string = String :: new ( ) ;
83+ File :: open ( "/etc/net/dns" ) ?. read_to_string ( & mut dns_string) ?;
84+ let dns: Vec < u8 > = dns_string. trim ( ) . split ( '.' ) . map ( |part| part. parse :: < u8 > ( )
85+ . unwrap_or ( 0 ) ) . collect ( ) ;
86+
87+ if ip. len ( ) == 4 && dns. len ( ) == 4 {
88+ let time = time:: SystemTime :: now ( ) . duration_since ( time:: UNIX_EPOCH ) . unwrap ( ) ;
89+ let tid = ( time. subsec_nanos ( ) >> 16 ) as u16 ;
90+
91+ let packet = Dns {
92+ transaction_id : tid,
93+ flags : 0x0100 ,
94+ queries : vec ! [ DnsQuery {
95+ name: host. to_string( ) ,
96+ q_type: 0x0001 ,
97+ q_class: 0x0001 ,
98+ } ] ,
99+ answers : vec ! [ ]
100+ } ;
101+
102+ let packet_data = packet. compile ( ) ;
103+
104+ let my_ip = Ipv4Addr :: new ( ip[ 0 ] , ip[ 1 ] , ip[ 2 ] , ip[ 3 ] ) ;
105+ let dns_ip = Ipv4Addr :: new ( dns[ 0 ] , dns[ 1 ] , dns[ 2 ] , dns[ 3 ] ) ;
106+ let socket = UdpSocket :: bind ( & SocketAddr :: V4 ( SocketAddrV4 :: new ( my_ip, 0 ) ) ) ?;
107+ socket. set_read_timeout ( Some ( Duration :: new ( 5 , 0 ) ) ) ?;
108+ socket. set_write_timeout ( Some ( Duration :: new ( 5 , 0 ) ) ) ?;
109+ socket. connect ( & SocketAddr :: V4 ( SocketAddrV4 :: new ( dns_ip, 53 ) ) ) ?;
110+ socket. send ( & packet_data) ?;
111+
112+ let mut buf = [ 0 ; 65536 ] ;
113+ let count = socket. recv ( & mut buf) ?;
114+
115+ match Dns :: parse ( & buf[ .. count] ) {
116+ Ok ( response) => {
117+ let mut addrs = vec ! [ ] ;
118+ for answer in response. answers . iter ( ) {
119+ if answer. a_type == 0x0001 && answer. a_class == 0x0001
120+ && answer. data . len ( ) == 4
121+ {
122+ let answer_ip = Ipv4Addr :: new ( answer. data [ 0 ] ,
123+ answer. data [ 1 ] ,
124+ answer. data [ 2 ] ,
125+ answer. data [ 3 ] ) ;
126+ addrs. push ( SocketAddr :: V4 ( SocketAddrV4 :: new ( answer_ip, 0 ) ) ) ;
127+ }
128+ }
129+ Ok ( LookupHost ( addrs. into_iter ( ) ) )
130+ } ,
131+ Err ( _err) => Err ( Error :: from_raw_os_error ( EINVAL ) )
132+ }
133+ } else {
134+ Err ( Error :: from_raw_os_error ( EINVAL ) )
97135 }
98- } else {
99- Err ( Error :: from_raw_os_error ( EINVAL ) )
100136 }
101137}
102138
0 commit comments