Skip to content

Commit 158c2d0

Browse files
author
Roman Proskuryakov
authored
Merge pull request #312 from tox-rs/onion_client
Onion client
2 parents ef72894 + b239572 commit 158c2d0

File tree

7 files changed

+3076
-0
lines changed

7 files changed

+3076
-0
lines changed

examples/onion_client.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
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+
}

src/toxcore/onion/client/errors.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
error_kind! {
2+
#[doc = "Error that can happen when handling `OnionAnnounceResponse` packet."]
3+
#[derive(Debug)]
4+
HandleAnnounceResponseError,
5+
#[doc = "The specific kind of error that can occur."]
6+
#[derive(Clone, Debug, Eq, PartialEq, failure::Fail)]
7+
HandleAnnounceResponseErrorKind {
8+
#[doc = "Invalid request ID when handling OnionAnnounceResponse."]
9+
#[fail(display = "Invalid request ID when handling OnionAnnounceResponse")]
10+
InvalidRequestId,
11+
#[doc = "Invalid announce status in OnionAnnounceResponse."]
12+
#[fail(display = "Invalid announce status in OnionAnnounceResponse")]
13+
InvalidAnnounceStatus,
14+
#[doc = "No friend with PK specified in OnionAnnounceResponse."]
15+
#[fail(display = "No friend with PK specified in OnionAnnounceResponse")]
16+
NoFriendWithPk,
17+
#[doc = "Invalid payload."]
18+
#[fail(display = "Invalid payload")]
19+
InvalidPayload,
20+
#[doc = "Send packet(s) error."]
21+
#[fail(display = "Send packet(s) error")]
22+
SendTo,
23+
}
24+
}
25+
26+
error_kind! {
27+
#[doc = "Error that can happen when handling `DhtPkAnnounce` packet."]
28+
#[derive(Debug)]
29+
HandleDhtPkAnnounceError,
30+
#[doc = "The specific kind of error that can occur."]
31+
#[derive(Clone, Debug, Eq, PartialEq, failure::Fail)]
32+
HandleDhtPkAnnounceErrorKind {
33+
#[doc = "No friend with PK specified in OnionAnnounceResponse."]
34+
#[fail(display = "No friend with PK specified in OnionAnnounceResponse")]
35+
NoFriendWithPk,
36+
#[doc = "Invalid no_reply."]
37+
#[fail(display = "Invalid no_reply")]
38+
InvalidNoReply,
39+
#[doc = "Failed to ping node."]
40+
#[fail(display = "Failed to ping node")]
41+
PingNode,
42+
#[doc = "Failed to add TCP relay."]
43+
#[fail(display = "Failed to add TCP relay")]
44+
AddRelay,
45+
#[doc = "Send packet(s) error."]
46+
#[fail(display = "Send packet(s) error")]
47+
SendTo,
48+
}
49+
}
50+
51+
error_kind! {
52+
#[doc = "Error that can happen when handling `OnionDataResponse` packet."]
53+
#[derive(Debug)]
54+
HandleDataResponseError,
55+
#[doc = "The specific kind of error that can occur."]
56+
#[derive(Clone, Debug, Eq, PartialEq, failure::Fail)]
57+
HandleDataResponseErrorKind {
58+
#[doc = "Invalid payload."]
59+
#[fail(display = "Invalid payload")]
60+
InvalidPayload,
61+
#[doc = "Invalid inner payload."]
62+
#[fail(display = "Invalid inner payload")]
63+
InvalidInnerPayload,
64+
#[doc = "Failed to handle DHT `PublicKey` announce."]
65+
#[fail(display = "Failed to handle DHT PublicKey announce")]
66+
DhtPkAnnounce,
67+
}
68+
}
69+
70+
error_kind! {
71+
#[doc = "Error that can happen when calling `run_*`."]
72+
#[derive(Debug)]
73+
RunError,
74+
#[doc = "The specific kind of error that can occur."]
75+
#[derive(Clone, Debug, Eq, PartialEq, failure::Fail)]
76+
RunErrorKind {
77+
#[doc = "Timer error."]
78+
#[fail(display = "Timer error")]
79+
Wakeup,
80+
#[doc = "Send packet(s) error."]
81+
#[fail(display = "Send packet(s) error")]
82+
SendTo,
83+
}
84+
}

0 commit comments

Comments
 (0)