1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Rust Bitcoin Library
// Written in 2014 by
//     Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! Bitcoin network addresses
//!
//! This module defines the structures and functions needed to encode
//! network addresses in Bitcoin messages.
//!

use std::io;
use std::fmt;
use std::net::{SocketAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6};

use consensus::encode::{self, Encoder, Decoder};
use consensus::encode::{Decodable, Encodable};

/// A message which can be sent on the Bitcoin network
pub struct Address {
    /// Services provided by the peer whose address this is
    pub services: u64,
    /// Network byte-order ipv6 address, or ipv4-mapped ipv6 address
    pub address: [u16; 8],
    /// Network port
    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<SocketAddr, io::Error> {
        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()]
}

impl<S: Encoder> Encodable<S> for Address {
    #[inline]
    fn consensus_encode(&self, s: &mut S) -> Result<(), encode::Error> {
        self.services.consensus_encode(s)?;
        addr_to_be(self.address).consensus_encode(s)?;
        self.port.to_be().consensus_encode(s)
    }
}

impl<D: Decoder> Decodable<D> for Address {
    #[inline]
    fn consensus_decode(d: &mut D) -> Result<Address, encode::Error> {
        Ok(Address {
            services: Decodable::consensus_decode(d)?,
            address: addr_to_be(Decodable::consensus_decode(d)?),
            port: u16::from_be(Decodable::consensus_decode(d)?)
        })
    }
}

impl fmt::Debug for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // TODO: render services and hex-ize address
        write!(f, "Address {{services: {:?}, address: {:?}, port: {:?}}}",
               self.services, &self.address[..], self.port)
    }
}

impl Clone for Address {
    fn clone(&self) -> Address {
        Address {
            services: self.services,
            address: self.address,
            port: self.port,
        }
    }
}

impl PartialEq for Address {
    fn eq(&self, other: &Address) -> bool {
        self.services == other.services &&
        &self.address[..] == &other.address[..] &&
        self.port == other.port
    }
}

impl Eq for Address {}

#[cfg(test)]
mod test {
    use std::str::FromStr;
    use super::Address;
    use std::net::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr};

    use consensus::encode::{deserialize, serialize};

    #[test]
    fn serialize_address_test() {
        assert_eq!(serialize(&Address {
            services: 1,
            address: [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001],
            port: 8333
        }),
        vec![1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
             0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1, 0x20, 0x8d]);
    }

    #[test]
    fn deserialize_address_test() {
        let mut addr: Result<Address, _> = deserialize(&[1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                                                       0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0,
                                                       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);

        addr = deserialize(&[1u8, 0, 0, 0, 0, 0, 0, 0, 0,
                             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());
    }
}