diff --git a/src/network/address.rs b/src/network/address.rs index 0d9e18d6..c813e885 100644 --- a/src/network/address.rs +++ b/src/network/address.rs @@ -18,7 +18,9 @@ //! network addresses in Bitcoin messages. //! +use std::io; use std::fmt; +use std::net::{SocketAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; use network::serialize::{SimpleEncoder, SimpleDecoder}; use network::encodable::{ConsensusDecodable, ConsensusEncodable}; @@ -33,6 +35,38 @@ pub struct Address { pub port: u16 } +const ONION : [u16; 3] = [0xFD87, 0xD87E, 0xEB43]; + +impl Address { + /// Create an address message for a socket + pub fn new (socket :&SocketAddr, services: u64) -> Address { + let (address, port) = match socket { + &SocketAddr::V4(ref addr) => (addr.ip().to_ipv6_mapped().segments(), addr.port()), + &SocketAddr::V6(ref addr) => (addr.ip().segments(), addr.port()) + }; + Address { address: address, port: port, services: services } + } + + /// extract socket address from an address message + /// This will return io::Error ErrorKind::AddrNotAvailable if the message contains a Tor address. + pub fn socket_addr (&self) -> Result { + let addr = &self.address; + if addr[0..3] == ONION { + return Err(io::Error::from(io::ErrorKind::AddrNotAvailable)); + } + let ipv6 = Ipv6Addr::new( + addr[0],addr[1],addr[2],addr[3], + addr[4],addr[5],addr[6],addr[7] + ); + if let Some(ipv4) = ipv6.to_ipv4() { + Ok(SocketAddr::V4(SocketAddrV4::new(ipv4, self.port))) + } + else { + Ok(SocketAddr::V6(SocketAddrV6::new(ipv6, self.port, 0, 0))) + } + } +} + fn addr_to_be(addr: [u16; 8]) -> [u16; 8] { [addr[0].to_be(), addr[1].to_be(), addr[2].to_be(), addr[3].to_be(), addr[4].to_be(), addr[5].to_be(), addr[6].to_be(), addr[7].to_be()] @@ -88,7 +122,9 @@ impl Eq for Address {} #[cfg(test)] mod test { + use std::str::FromStr; use super::Address; + use std::net::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; use network::serialize::{deserialize, serialize}; @@ -110,6 +146,11 @@ mod test { 0, 1, 0x20, 0x8d]); assert!(addr.is_ok()); let full = addr.unwrap(); + assert!(match full.socket_addr().unwrap() { + SocketAddr::V4(_) => true, + _ => false + } + ); assert_eq!(full.services, 1); assert_eq!(full.address, [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001]); assert_eq!(full.port, 8333); @@ -118,5 +159,25 @@ mod test { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1]); assert!(addr.is_err()); } + + #[test] + fn test_socket_addr () { + let s4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(111,222,123,4)), 5555); + let a4 = Address::new(&s4, 9); + assert_eq!(a4.socket_addr().unwrap(), s4); + let s6 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, + 0x5555, 0x6666, 0x7777, 0x8888)), 9999); + let a6 = Address::new(&s6, 9); + assert_eq!(a6.socket_addr().unwrap(), s6); + } + + #[test] + fn onion_test () { + let onionaddr = SocketAddr::new( + IpAddr::V6( + Ipv6Addr::from_str("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").unwrap()), 1111); + let addr = Address::new(&onionaddr, 0); + assert!(addr.socket_addr().is_err()); + } }