From 809d16919da2e1588577afc3c69edc42e2ad2624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Frosteg=C3=A5rd?= Date: Sat, 1 Aug 2020 00:08:18 +0200 Subject: [PATCH] aquatic_ws: convert ipv4-mapped ipv6 addresses to ipv4 (for state split) --- TODO.md | 8 +++----- aquatic_ws/src/lib/common.rs | 7 +++++-- aquatic_ws/src/lib/handler.rs | 12 +++++++----- aquatic_ws/src/lib/network/mod.rs | 12 ++++++++++-- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/TODO.md b/TODO.md index 387929c..3e6d063 100644 --- a/TODO.md +++ b/TODO.md @@ -2,9 +2,6 @@ ## General -* use ipv4-mapped address functions, but I should check that they really - work as they really work as they should. All announces over ipv4 should - go to ipv4 map, all over ipv6 to ipv6 map * init logging in cli helper crate? ## aquatic_http_load_test @@ -30,13 +27,14 @@ write actually block here? And what action should be taken then? ## aquatic_ws -* test transfer again with crossbeam-channel +* test transfer again with changes made: + * crossbeam-channel + * ipv6/ipv4 mapping * is 'key' sent in announce request? if so, maybe handle it like in aquatic_http (including ip uniqueness part of peer map key) * established connections do not get valid_until updated, I think? * tests * use enum as return type for handshake machine -* ipv4 and ipv6 state split: think about this more.. ## aquatic_udp * mio: set oneshot for epoll and kqueue? otherwise, stop reregistering? diff --git a/aquatic_ws/src/lib/common.rs b/aquatic_ws/src/lib/common.rs index f631f3e..949ceaf 100644 --- a/aquatic_ws/src/lib/common.rs +++ b/aquatic_ws/src/lib/common.rs @@ -1,4 +1,4 @@ -use std::net::SocketAddr; +use std::net::{SocketAddr, IpAddr}; use std::sync::Arc; use crossbeam_channel::{Sender, Receiver}; @@ -18,7 +18,10 @@ pub struct ConnectionMeta { /// Index of socket worker responsible for this connection. Required for /// sending back response through correct channel to correct worker. pub worker_index: usize, - pub peer_addr: SocketAddr, + /// Peer address as received from socket, meaning it wasn't converted to + /// an IPv4 address if it was a IPv4-mapped IPv6 address + pub naive_peer_addr: SocketAddr, + pub converted_peer_ip: IpAddr, pub poll_token: Token, } diff --git a/aquatic_ws/src/lib/handler.rs b/aquatic_ws/src/lib/handler.rs index ab15e87..0b6b68e 100644 --- a/aquatic_ws/src/lib/handler.rs +++ b/aquatic_ws/src/lib/handler.rs @@ -93,7 +93,7 @@ pub fn handle_announce_requests( let valid_until = ValidUntil::new(config.cleaning.max_peer_age); for (request_sender_meta, request) in requests { - let torrent_data: &mut TorrentData = if request_sender_meta.peer_addr.is_ipv4(){ + let torrent_data: &mut TorrentData = if request_sender_meta.converted_peer_ip.is_ipv4(){ torrent_maps.ipv4.entry(request.info_hash).or_default() } else { torrent_maps.ipv6.entry(request.info_hash).or_default() @@ -102,9 +102,11 @@ pub fn handle_announce_requests( // If there is already a peer with this peer_id, check that socket // addr is same as that of request sender. Otherwise, ignore request. // Since peers have access to each others peer_id's, they could send - // requests using them, causing all sorts of issues. + // requests using them, causing all sorts of issues. Checking naive + // (non-converted) socket addresses is enough, since state is split + // on converted peer ip. if let Some(previous_peer) = torrent_data.peers.get(&request.peer_id){ - if request_sender_meta.peer_addr != previous_peer.connection_meta.peer_addr { + if request_sender_meta.naive_peer_addr != previous_peer.connection_meta.naive_peer_addr { continue; } } @@ -177,7 +179,7 @@ pub fn handle_announce_requests( // possible to write a new version of that function which isn't // shared with aquatic_udp and goes about it differently // though. - if request_sender_meta.peer_addr == offer_receiver.connection_meta.peer_addr { + if request_sender_meta.naive_peer_addr == offer_receiver.connection_meta.naive_peer_addr { continue; } @@ -244,7 +246,7 @@ pub fn handle_scrape_requests( files: HashMap::with_capacity(num_to_take), }; - let torrent_map: &mut TorrentMap = if meta.peer_addr.is_ipv4(){ + let torrent_map: &mut TorrentMap = if meta.converted_peer_ip.is_ipv4(){ &mut torrent_maps.ipv4 } else { &mut torrent_maps.ipv6 diff --git a/aquatic_ws/src/lib/network/mod.rs b/aquatic_ws/src/lib/network/mod.rs index 4bc159b..7e2da6c 100644 --- a/aquatic_ws/src/lib/network/mod.rs +++ b/aquatic_ws/src/lib/network/mod.rs @@ -9,6 +9,8 @@ use mio::{Events, Poll, Interest, Token}; use mio::net::TcpListener; use tungstenite::protocol::WebSocketConfig; +use aquatic_common::convert_ipv4_mapped_ipv6; + use crate::common::*; use crate::config::Config; use crate::protocol::*; @@ -187,10 +189,16 @@ pub fn run_handshakes_and_read_messages( match established_ws.ws.read_message(){ Ok(ws_message) => { if let Some(in_message) = InMessage::from_ws_message(ws_message){ + let naive_peer_addr = established_ws.peer_addr; + let converted_peer_ip = convert_ipv4_mapped_ipv6( + naive_peer_addr.ip() + ); + let meta = ConnectionMeta { worker_index: socket_worker_index, poll_token, - peer_addr: established_ws.peer_addr + naive_peer_addr, + converted_peer_ip, }; debug!("read message"); @@ -249,7 +257,7 @@ pub fn send_out_messages( .and_then(Connection::get_established_ws); if let Some(established_ws) = opt_established_ws { - if established_ws.peer_addr != meta.peer_addr { + if established_ws.peer_addr != meta.naive_peer_addr { info!("socket worker error: peer socket addrs didn't match"); continue;