|
| 1 | +#[macro_use] |
| 2 | +extern crate log; |
| 3 | + |
| 4 | +use std::net::{SocketAddr, IpAddr}; |
| 5 | + |
| 6 | +use failure::Error; |
| 7 | +use futures::*; |
| 8 | +use futures::sync::mpsc; |
| 9 | +use hex::FromHex; |
| 10 | +use tokio::net::{UdpSocket, UdpFramed}; |
| 11 | + |
| 12 | +use tox::toxcore::dht::codec::*; |
| 13 | +use tox::toxcore::dht::packed_node::*; |
| 14 | +use tox::toxcore::dht::packet::*; |
| 15 | +use tox::toxcore::dht::server::Server; |
| 16 | +use tox::toxcore::crypto_core::*; |
| 17 | +use tox::toxcore::onion::client::*; |
| 18 | +use tox::toxcore::tcp::client::Connections; |
| 19 | +use tox::toxcore::stats::Stats; |
| 20 | + |
| 21 | +const BOOTSTRAP_NODES: [(&str, &str); 9] = [ |
| 22 | + // Impyy |
| 23 | + ("1D5A5F2F5D6233058BF0259B09622FB40B482E4FA0931EB8FD3AB8E7BF7DAF6F", "198.98.51.198:33445"), |
| 24 | + // nurupo |
| 25 | + ("F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67", "67.215.253.85:33445"), |
| 26 | + // Manolis |
| 27 | + ("461FA3776EF0FA655F1A05477DF1B3B614F7D6B124F7DB1DD4FE3C08B03B640F", "130.133.110.14:33445"), |
| 28 | + // Busindre |
| 29 | + ("A179B09749AC826FF01F37A9613F6B57118AE014D4196A0E1105A98F93A54702", "205.185.116.116:33445"), |
| 30 | + // ray65536 |
| 31 | + ("8E7D0B859922EF569298B4D261A8CCB5FEA14FB91ED412A7603A585A25698832", "85.172.30.117:33445"), |
| 32 | + // fluke571 |
| 33 | + ("3CEE1F054081E7A011234883BC4FC39F661A55B73637A5AC293DDF1251D9432B", "194.249.212.109:33445"), |
| 34 | + // MAH69K |
| 35 | + ("DA4E4ED4B697F2E9B000EEFE3A34B554ACD3F45F5C96EAEA2516DD7FF9AF7B43", "185.25.116.107:33445"), |
| 36 | + // clearmartin |
| 37 | + ("CD133B521159541FB1D326DE9850F5E56A6C724B5B8E5EB5CD8D950408E95707", "46.101.197.175:443"), |
| 38 | + // tastytea |
| 39 | + ("2B2137E094F743AC8BD44652C55F41DFACC502F125E99E4FE24D40537489E32F", "5.189.176.217:5190"), |
| 40 | +]; |
| 41 | + |
| 42 | +const SELF_SK: &str = "1A5EC1D6C3F1FA720A313C01F432B6AE0D4649A5121964C9992DDF32871E8DFD"; |
| 43 | + |
| 44 | +const FRIEND_PK: &str = "3E6A06DA48D1AB98549AD76890770B704AE9116D8654FBCD35C9BF2DB9233E21"; |
| 45 | + |
| 46 | +/// Bind a UDP listener to the socket address. |
| 47 | +fn bind_socket(addr: SocketAddr) -> UdpSocket { |
| 48 | + let socket = UdpSocket::bind(&addr).expect("Failed to bind UDP socket"); |
| 49 | + socket.set_broadcast(true).expect("set_broadcast call failed"); |
| 50 | + if addr.is_ipv6() { |
| 51 | + socket.set_multicast_loop_v6(true).expect("set_multicast_loop_v6 call failed"); |
| 52 | + } |
| 53 | + socket |
| 54 | +} |
| 55 | + |
| 56 | +fn main() { |
| 57 | + env_logger::init(); |
| 58 | + |
| 59 | + let (dht_pk, dht_sk) = gen_keypair(); |
| 60 | + |
| 61 | + let real_sk_bytes: [u8; 32] = FromHex::from_hex(SELF_SK).unwrap(); |
| 62 | + let real_sk = SecretKey::from_slice(&real_sk_bytes).unwrap(); |
| 63 | + let real_pk = real_sk.public_key(); |
| 64 | + |
| 65 | + // Create a channel for server to communicate with network |
| 66 | + let (tx, rx) = mpsc::channel(32); |
| 67 | + |
| 68 | + let local_addr: SocketAddr = "0.0.0.0:33445".parse().unwrap(); // 0.0.0.0 for IPv4 |
| 69 | + // let local_addr: SocketAddr = "[::]:33445".parse().unwrap(); // [::] for IPv6 |
| 70 | + |
| 71 | + let socket = bind_socket(local_addr); |
| 72 | + |
| 73 | + let (dht_pk_tx, dht_pk_rx) = mpsc::unbounded(); |
| 74 | + |
| 75 | + let (tcp_incoming_tx, _tcp_incoming_rx) = mpsc::unbounded(); |
| 76 | + |
| 77 | + let dht_server = Server::new(tx.clone(), dht_pk, dht_sk.clone()); |
| 78 | + let tcp_connections = Connections::new(dht_pk, dht_sk, tcp_incoming_tx); |
| 79 | + let onion_client = OnionClient::new(dht_server, tcp_connections, dht_pk_tx, real_sk, real_pk); |
| 80 | + |
| 81 | + for &(pk, saddr) in &BOOTSTRAP_NODES { |
| 82 | + // get PK bytes of the bootstrap node |
| 83 | + let bootstrap_pk_bytes: [u8; 32] = FromHex::from_hex(pk).unwrap(); |
| 84 | + // create PK from bytes |
| 85 | + let bootstrap_pk = PublicKey::from_slice(&bootstrap_pk_bytes).unwrap(); |
| 86 | + |
| 87 | + let node = PackedNode::new(saddr.parse().unwrap(), &bootstrap_pk); |
| 88 | + |
| 89 | + onion_client.add_path_node(node); |
| 90 | + } |
| 91 | + |
| 92 | + let friend_pk_bytes: [u8; 32] = FromHex::from_hex(FRIEND_PK).unwrap(); |
| 93 | + let friend_pk = PublicKey::from_slice(&friend_pk_bytes).unwrap(); |
| 94 | + |
| 95 | + onion_client.add_friend(friend_pk); |
| 96 | + |
| 97 | + let stats = Stats::new(); |
| 98 | + let codec = DhtCodec::new(stats); |
| 99 | + let (sink, stream) = UdpFramed::new(socket, codec).split(); |
| 100 | + |
| 101 | + let onion_client_c = onion_client.clone(); |
| 102 | + |
| 103 | + let network_reader = stream.then(future::ok).filter(|event| |
| 104 | + match event { |
| 105 | + Ok(_) => true, |
| 106 | + Err(ref e) => { |
| 107 | + error!("packet receive error = {:?}", e); |
| 108 | + // ignore packet decode errors |
| 109 | + *e.kind() == DecodeErrorKind::Io |
| 110 | + } |
| 111 | + } |
| 112 | + ).and_then(|event| event).for_each(move |(packet, addr)| { |
| 113 | + trace!("Received packet {:?}", packet); |
| 114 | + match packet { |
| 115 | + Packet::OnionAnnounceResponse(packet) => { |
| 116 | + Box::new(onion_client_c.handle_announce_response(&packet, addr).map_err(Error::from)) |
| 117 | + as Box<dyn Future<Item = _, Error = _> + Send> |
| 118 | + }, |
| 119 | + Packet::OnionDataResponse(packet) => { |
| 120 | + Box::new(onion_client_c.handle_data_response(&packet).map_err(Error::from)) |
| 121 | + }, |
| 122 | + _ => Box::new(future::ok(())), |
| 123 | + }.or_else(|err| { |
| 124 | + error!("Failed to handle packet: {:?}", err); |
| 125 | + future::ok(()) |
| 126 | + }) |
| 127 | + }).map_err(Error::from); |
| 128 | + |
| 129 | + let network_writer = rx |
| 130 | + .map_err(|()| unreachable!("rx can't fail")) |
| 131 | + // filter out IPv6 packets if node is running in IPv4 mode |
| 132 | + .filter(move |&(ref _packet, addr)| !(local_addr.is_ipv4() && addr.is_ipv6())) |
| 133 | + .fold(sink, move |sink, (packet, mut addr)| { |
| 134 | + if local_addr.is_ipv6() { |
| 135 | + if let IpAddr::V4(ip) = addr.ip() { |
| 136 | + addr = SocketAddr::new(IpAddr::V6(ip.to_ipv6_mapped()), addr.port()); |
| 137 | + } |
| 138 | + } |
| 139 | + trace!("Sending packet {:?} to {:?}", packet, addr); |
| 140 | + sink.send((packet, addr)).map_err(Error::from) |
| 141 | + }) |
| 142 | + // drop sink when rx stream is exhausted |
| 143 | + .map(|_sink| ()); |
| 144 | + |
| 145 | + let dht_pk_future = dht_pk_rx |
| 146 | + .map_err(|()| unreachable!("rx can't fail")) |
| 147 | + .for_each(|(real_pk, dht_pk)| { |
| 148 | + println!("Found DHT PK for {} - {}", hex::encode(real_pk.as_ref()), hex::encode(dht_pk)); |
| 149 | + future::ok(()) |
| 150 | + }); |
| 151 | + |
| 152 | + let future = network_reader |
| 153 | + .select(network_writer) |
| 154 | + .map(|_| ()) |
| 155 | + .map_err(|(e, _)| e) |
| 156 | + .select(onion_client.run().map_err(Error::from)) |
| 157 | + .map(|_| ()) |
| 158 | + .map_err(|(e, _)| e) |
| 159 | + .select(dht_pk_future) |
| 160 | + .map(|_| ()) |
| 161 | + .map_err(|(e, _)| error!("Processing ended with error: {:?}", e)); |
| 162 | + |
| 163 | + info!("Running onion client on {}", local_addr); |
| 164 | + |
| 165 | + tokio::run(future); |
| 166 | +} |
0 commit comments