Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] P2P: initial I2P support #2932

Closed
wants to merge 54 commits into from
Closed
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
1e872e0
I2P config and peer address wrapper
ignopeverell Apr 10, 2019
2dd7ea1
Many reference fixes now that PeerAddr isn't Copy
ignopeverell Apr 10, 2019
a9738c5
Move i2p config to p2p, set capabilities
ignopeverell Apr 11, 2019
0081cf6
I2P connection init and addr/key handling
ignopeverell Apr 14, 2019
3696b16
Starting listener impl and The Great Wrapping
ignopeverell Apr 14, 2019
22b2432
Listener impl more or less done, but untested
ignopeverell Apr 20, 2019
f1f3849
rustfm
ignopeverell Apr 20, 2019
396efc1
i2p client connection impl; fix existing p2p tests
ignopeverell May 1, 2019
7d01407
rustfmt
ignopeverell May 1, 2019
f6f0484
P2P: remove panic!, add PeerAddrType enum
chisa0a May 1, 2019
0e16fd1
P2P: rustfmt + add I2P as fullnode capability
chisa0a May 1, 2019
a2d823f
P2P: gracefully shutdown I2P listener
chisa0a May 14, 2019
d2682cd
P2P: rust-fmt
chisa0a May 14, 2019
f420a9a
P2P: add serde decorator for PeerAddr enum
chisa0a May 20, 2019
77735f9
P2P: add serde decorators for I2pMode enum
chisa0a May 27, 2019
828b8fd
P2P: rust-fmt
chisa0a May 27, 2019
a1313b5
Config: adds i2p_mode section + I2P peer examples
chisa0a Jun 1, 2019
63a2507
I2P: create keyfile directory if needed
chisa0a Jun 1, 2019
7264f0a
I2P: start i2pd by default
chisa0a Jun 1, 2019
f6cbcfd
P2P: various fixups for 2.x.x
chisa0a Jun 28, 2019
be57444
Remove extra clones
hashmap Jul 8, 2019
98d5ffb
address review comments
hashmap Jul 8, 2019
b053e43
Represent Stream as a trait
hashmap Jul 10, 2019
f627e8e
Merge pull request #5 from cyclefortytwo/stream-trait
hashmap Jul 12, 2019
0fd584c
I2P config and peer address wrapper
ignopeverell Apr 10, 2019
76dc942
Many reference fixes now that PeerAddr isn't Copy
ignopeverell Apr 10, 2019
457dfec
Move i2p config to p2p, set capabilities
ignopeverell Apr 11, 2019
7e8684c
I2P connection init and addr/key handling
ignopeverell Apr 14, 2019
3712c6d
Starting listener impl and The Great Wrapping
ignopeverell Apr 14, 2019
9139e25
Listener impl more or less done, but untested
ignopeverell Apr 20, 2019
31b49b0
rustfm
ignopeverell Apr 20, 2019
bc6b906
i2p client connection impl; fix existing p2p tests
ignopeverell May 1, 2019
914ad0e
rustfmt
ignopeverell May 1, 2019
f555e30
P2P: remove panic!, add PeerAddrType enum
chisa0a May 1, 2019
cfceb2b
P2P: rustfmt + add I2P as fullnode capability
chisa0a May 1, 2019
a693faa
P2P: gracefully shutdown I2P listener
chisa0a May 14, 2019
f3dfff9
P2P: add serde decorator for PeerAddr enum
chisa0a May 20, 2019
a1de0ff
P2P: add serde decorators for I2pMode enum
chisa0a May 27, 2019
3012c2a
P2P: rust-fmt
chisa0a May 27, 2019
23fc301
Config: adds i2p_mode section + I2P peer examples
chisa0a Jun 1, 2019
fb4cd81
I2P: create keyfile directory if needed
chisa0a Jun 1, 2019
8fd318f
I2P: start i2pd by default
chisa0a Jun 1, 2019
8490ace
P2P: various fixups for 2.x.x
chisa0a Jun 28, 2019
b9564a7
Remove extra clones
hashmap Jul 8, 2019
49cecb7
address review comments
hashmap Jul 8, 2019
c1e5fbd
Represent Stream as a trait
hashmap Jul 10, 2019
3b1ce97
P2P: add set_read/write_timeout to Stream trait
chisa0a Jul 13, 2019
6c53ba1
P2P: add i2p_thread for error handling on shutdown
chisa0a Jul 13, 2019
14b7b46
P2P: minor style + doc updates for PeerAddr
chisa0a Jul 13, 2019
8e2f1a4
P2P: fixes for rebase onto ea1d14dd
chisa0a Aug 9, 2019
d65f77f
I2P: change i2p-rs to mimblewimble org repo
chisa0a Aug 9, 2019
7cabd44
Merge to fix forced push
hashmap Aug 22, 2019
5bdae1e
Make i2p config param optional
hashmap Aug 22, 2019
8628f80
Merge remote-tracking branch 'origin/master' into i2p-2.x.x
hashmap Aug 22, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions api/src/handlers/peers_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,15 @@ impl Handler for PeerHandler {
if let Ok(ip_addr) = command.parse() {
peer_addr = PeerAddr::from_ip(ip_addr);
} else if let Ok(addr) = command.parse() {
peer_addr = PeerAddr(addr);
peer_addr = PeerAddr::Socket(addr);
} else {
return response(
StatusCode::BAD_REQUEST,
format!("peer address unrecognized: {}", req.uri().path()),
);
}

match w_fut!(&self.peers).get_peer(peer_addr) {
match w_fut!(&self.peers).get_peer(&peer_addr) {
Ok(peer) => json_response(&peer),
Err(_) => response(StatusCode::NOT_FOUND, "peer not found"),
}
Expand All @@ -90,7 +90,7 @@ impl Handler for PeerHandler {
if let Ok(ip_addr) = a.parse() {
PeerAddr::from_ip(ip_addr)
} else if let Ok(addr) = a.parse() {
PeerAddr(addr)
PeerAddr::Socket(addr)
} else {
return response(
StatusCode::BAD_REQUEST,
Expand All @@ -101,8 +101,8 @@ impl Handler for PeerHandler {
};

match command {
"ban" => w_fut!(&self.peers).ban_peer(addr, ReasonForBan::ManualBan),
"unban" => w_fut!(&self.peers).unban_peer(addr),
"ban" => w_fut!(&self.peers).ban_peer(&addr, ReasonForBan::ManualBan),
"unban" => w_fut!(&self.peers).unban_peer(&addr),
_ => return response(StatusCode::BAD_REQUEST, "invalid command"),
};

Expand Down
2 changes: 1 addition & 1 deletion chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ serde = "1"
serde_derive = "1"
chrono = "0.4.4"
lru-cache = "0.1"
lazy_static = "1"
lazy_static = "1.3.0"
regex = "1"

grin_core = { path = "../core", version = "2.0.1-beta.1" }
Expand Down
33 changes: 31 additions & 2 deletions config/src/comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,40 @@ fn comments() -> HashMap<String, String> {
.to_string(),
);

retval.insert(
"i2p_mode".to_string(),
"
#Configuration for I2P support (\"Disabled\" by default)
#I2P can be enabled by the following:
#[server.p2p_config.i2p_mode]
#mode = \"Enabled\"

#[server.p2p_config.i2p_mode.i2p_config]
#autostart = true/false - start I2P automatically
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More admin-friendly config:

# Start I2P automatically
# autostart = true
# Exclusively connect through I2P, or also use TCP/IP
# exclusive = true

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed this before the most recent push of updates. Can add with next round of changes.

#exclusive = true/false - exclusively connect through I2P, or also use TCP
#addr = \"127.0.0.1:7656\" - address of local I2P server
"
.to_string(),
);

retval.insert(
"[server.p2p_config.capabilities]".to_string(),
"#If the seeding type is List, the list of peers to connect to can
#be specified as follows:
#seeds = [\"192.168.0.1:3414\",\"192.168.0.2:3414\"]
#be specified as follows (same for other peer types):
#For TCP addresses:
#[[server.p2p_config.seeds]]
#peer_type = \"Socket\"
#peer_addr = \"192.168.0.1:3414\"

#For I2P addresses:
#[[server.p2p_config.seeds]]
#peer_type = \"I2p\"

#[server.p2p_config.seeds.peer_addr]
#port = 3414

#[server.p2p_config.seeds.peer_addr.dest]
#inner = \"4jcuryak7cabdqrv72ytqonf4xnk3jcryfkzqz43wo67dqwlh2xa.b32.i2p\"

#hardcoded peer lists for allow/deny
#will *only* connect to peers in allow list
Expand Down
2 changes: 2 additions & 0 deletions p2p/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ edition = "2018"
bitflags = "1"
bytes = "0.4"
enum_primitive = "0.1"
i2p = { version = "0.1.0", git = "https://github.com/ignopeverell/i2p-rs"}
hashmap marked this conversation as resolved.
Show resolved Hide resolved
net2 = "0.2"
num = "0.1"
rand = "0.6"
Expand All @@ -29,3 +30,4 @@ grin_chain = { path = "../chain", version = "2.0.1-beta.1" }

[dev-dependencies]
grin_pool = { path = "../pool", version = "2.0.1-beta.1" }
toml = "0.4"
8 changes: 4 additions & 4 deletions p2p/src/conn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

use std::fs::File;
use std::io::{self, Read, Write};
use std::net::{Shutdown, TcpStream};
use std::net::Shutdown;
use std::sync::{mpsc, Arc};
use std::{
cmp,
Expand All @@ -35,7 +35,7 @@ use crate::msg::{
read_body, read_discard, read_header, read_item, write_to_buf, MsgHeader, MsgHeaderWrapper,
Type,
};
use crate::types::Error;
use crate::types::{Error, Stream};
use crate::util::read_write::{read_exact, write_all};
use crate::util::{RateCounter, RwLock};

Expand Down Expand Up @@ -262,7 +262,7 @@ impl Tracker {
/// the current thread, instead just returns a future and the Connection
/// itself.
pub fn listen<H>(
stream: TcpStream,
stream: Stream,
version: ProtocolVersion,
tracker: Arc<Tracker>,
handler: H,
Expand Down Expand Up @@ -290,7 +290,7 @@ where
}

fn poll<H>(
conn: TcpStream,
conn: Stream,
version: ProtocolVersion,
handler: H,
send_rx: mpsc::Receiver<Vec<u8>>,
Expand Down
46 changes: 27 additions & 19 deletions p2p/src/handshake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ use crate::core::pow::Difficulty;
use crate::core::ser::ProtocolVersion;
use crate::msg::{read_message, write_message, Hand, Shake, Type, USER_AGENT};
use crate::peer::Peer;
use crate::types::{Capabilities, Direction, Error, P2PConfig, PeerAddr, PeerInfo, PeerLiveInfo};
use crate::types::{
Capabilities, Direction, Error, P2PConfig, PeerAddr, PeerInfo, PeerLiveInfo, Stream,
};
use crate::util::RwLock;
use rand::{thread_rng, Rng};
use std::collections::VecDeque;
use std::net::{SocketAddr, TcpStream};
use std::net::SocketAddr;
use std::sync::Arc;

/// Local generated nonce for peer connecting.
Expand Down Expand Up @@ -64,14 +66,11 @@ impl Handshake {
capabilities: Capabilities,
total_difficulty: Difficulty,
self_addr: PeerAddr,
conn: &mut TcpStream,
conn: &mut Stream,
) -> Result<PeerInfo, Error> {
// prepare the first part of the handshake
let nonce = self.next_nonce();
let peer_addr = match conn.peer_addr() {
Ok(pa) => PeerAddr(pa),
Err(e) => return Err(Error::Connection(e)),
};
let peer_addr = conn.peer_addr()?;

// Using our default version here.
let version = ProtocolVersion::default();
Expand All @@ -83,7 +82,7 @@ impl Handshake {
genesis: self.genesis,
total_difficulty,
sender_addr: self_addr,
receiver_addr: peer_addr,
receiver_addr: peer_addr.clone(),
user_agent: USER_AGENT.to_string(),
};

Expand All @@ -102,15 +101,15 @@ impl Handshake {
let peer_info = PeerInfo {
capabilities: shake.capabilities,
user_agent: shake.user_agent,
addr: peer_addr,
addr: peer_addr.clone(),
version: shake.version,
live_info: Arc::new(RwLock::new(PeerLiveInfo::new(shake.total_difficulty))),
direction: Direction::Outbound,
};

// If denied then we want to close the connection
// (without providing our peer with any details why).
if Peer::is_denied(&self.config, peer_info.addr) {
if Peer::is_denied(&self.config, &peer_info.addr.clone()) {
return Err(Error::ConnectionClose);
}

Expand All @@ -129,7 +128,7 @@ impl Handshake {
&self,
capab: Capabilities,
total_difficulty: Difficulty,
conn: &mut TcpStream,
conn: &mut Stream,
) -> Result<PeerInfo, Error> {
// Note: We read the Hand message *before* we know which protocol version
// is supported by our peer (it is in the Hand message).
Expand All @@ -145,7 +144,7 @@ impl Handshake {
} else {
// check the nonce to see if we are trying to connect to ourselves
let nonces = self.nonces.read();
let addr = resolve_peer_addr(hand.sender_addr, &conn);
let addr = resolve_peer_addr(hand.sender_addr.clone(), &conn);
if nonces.contains(&hand.nonce) {
// save ip addresses of ourselves
let mut addrs = self.addrs.write();
Expand All @@ -171,7 +170,7 @@ impl Handshake {
// so check if we are configured to explicitly allow or deny it.
// If denied then we want to close the connection
// (without providing our peer with any details why).
if Peer::is_denied(&self.config, peer_info.addr) {
if Peer::is_denied(&self.config, &peer_info.addr.clone()) {
hashmap marked this conversation as resolved.
Show resolved Hide resolved
return Err(Error::ConnectionClose);
}

Expand Down Expand Up @@ -205,11 +204,20 @@ impl Handshake {
}

/// Resolve the correct peer_addr based on the connection and the advertised port.
fn resolve_peer_addr(advertised: PeerAddr, conn: &TcpStream) -> PeerAddr {
let port = advertised.0.port();
if let Ok(addr) = conn.peer_addr() {
PeerAddr(SocketAddr::new(addr.ip(), port))
} else {
advertised
fn resolve_peer_addr(advertised: PeerAddr, conn: &Stream) -> PeerAddr {
match advertised.clone() {
PeerAddr::Socket(addr) => {
let port = addr.port();
if let Ok(addr) = conn.peer_addr() {
if let Ok(ip) = addr.unwrap_ip() {
PeerAddr::Socket(SocketAddr::new(ip.ip(), port))
} else {
advertised
}
} else {
advertised
}
}
PeerAddr::I2p(_) => advertised,
}
}
4 changes: 2 additions & 2 deletions p2p/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ pub use crate::peers::Peers;
pub use crate::serv::{DummyAdapter, Server};
pub use crate::store::{PeerData, State};
pub use crate::types::{
Capabilities, ChainAdapter, Direction, Error, P2PConfig, PeerAddr, PeerInfo, ReasonForBan,
Seeding, TxHashSetRead, MAX_BLOCK_HEADERS, MAX_LOCATORS, MAX_PEER_ADDRS,
Capabilities, ChainAdapter, Direction, Error, I2pMode, P2PConfig, PeerAddr, PeerInfo,
ReasonForBan, Seeding, TxHashSetRead, MAX_BLOCK_HEADERS, MAX_LOCATORS, MAX_PEER_ADDRS,
};
36 changes: 26 additions & 10 deletions p2p/src/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::util::{Mutex, RwLock};
use std::fmt;
use std::fs::File;
use std::io::Read;
use std::net::{Shutdown, TcpStream};
use std::net::Shutdown;
use std::path::PathBuf;
use std::sync::Arc;

Expand All @@ -33,7 +33,7 @@ use crate::msg::{
use crate::protocol::Protocol;
use crate::types::{
Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, PeerInfo, ReasonForBan,
TxHashSetRead,
Stream, TxHashSetRead,
};
use chrono::prelude::{DateTime, Utc};

Expand Down Expand Up @@ -70,7 +70,7 @@ impl fmt::Debug for Peer {

impl Peer {
// Only accept and connect can be externally used to build a peer
fn new(info: PeerInfo, conn: TcpStream, adapter: Arc<dyn NetAdapter>) -> std::io::Result<Peer> {
fn new(info: PeerInfo, conn: Stream, adapter: Arc<dyn NetAdapter>) -> std::io::Result<Peer> {
let state = Arc::new(RwLock::new(State::Connected));
let tracking_adapter = TrackingAdapter::new(adapter);
let handler = Protocol::new(Arc::new(tracking_adapter.clone()), info.clone());
Expand All @@ -89,7 +89,7 @@ impl Peer {
}

pub fn accept(
mut conn: TcpStream,
mut conn: Stream,
capab: Capabilities,
total_difficulty: Difficulty,
hs: &Handshake,
Expand All @@ -114,7 +114,7 @@ impl Peer {
}

pub fn connect(
mut conn: TcpStream,
mut conn: Stream,
capab: Capabilities,
total_difficulty: Difficulty,
self_addr: PeerAddr,
Expand All @@ -139,9 +139,25 @@ impl Peer {
}
}

pub fn is_denied(config: &P2PConfig, peer_addr: PeerAddr) -> bool {
/// Main peer loop listening for messages and forwarding to the rest of the
/// system.
pub fn start(&mut self, conn: Stream) -> Result<(), Error> {
let adapter = Arc::new(self.tracking_adapter.clone());
let handler = Protocol::new(adapter, self.info.clone());
let (sendh, stoph) = conn::listen(
conn,
self.info.version.clone(),
self.tracker.clone(),
handler,
)?;
self.send_handle = Mutex::new(sendh);
self.stop_handle = Mutex::new(stoph);
Ok(())
}

pub fn is_denied(config: &P2PConfig, peer_addr: &PeerAddr) -> bool {
if let Some(ref denied) = config.peers_deny {
if denied.contains(&peer_addr) {
if denied.contains(peer_addr) {
debug!(
"checking peer allowed/denied: {:?} explicitly denied",
peer_addr
Expand All @@ -150,7 +166,7 @@ impl Peer {
}
}
if let Some(ref allowed) = config.peers_allow {
if allowed.contains(&peer_addr) {
if allowed.contains(peer_addr) {
debug!(
"checking peer allowed/denied: {:?} explicitly allowed",
peer_addr
Expand Down Expand Up @@ -603,11 +619,11 @@ impl NetAdapter for TrackingAdapter {
self.adapter.peer_addrs_received(addrs)
}

fn peer_difficulty(&self, addr: PeerAddr, diff: Difficulty, height: u64) {
fn peer_difficulty(&self, addr: &PeerAddr, diff: Difficulty, height: u64) {
self.adapter.peer_difficulty(addr, diff, height)
}

fn is_banned(&self, addr: PeerAddr) -> bool {
fn is_banned(&self, addr: &PeerAddr) -> bool {
self.adapter.is_banned(addr)
}
}
Loading