further ipv6 support + addr generation from pubkey

This commit is contained in:
Maxime Van Hees
2023-05-23 09:18:32 +00:00
parent 4d0c7a2173
commit bd8de3bb2f
7 changed files with 239 additions and 90 deletions
Generated
+49 -1
View File
@@ -66,6 +66,30 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "blake2"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
dependencies = [
"digest 0.10.7",
]
[[package]]
name = "blake2b"
version = "0.99.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81ce94c69d161e5588f2ebd67fed9220ede4f7e6a174141a76299a538b2ee90d"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -147,6 +171,16 @@ dependencies = [
"windows-sys 0.45.0",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "curve25519-dalek"
version = "3.2.1"
@@ -154,7 +188,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
dependencies = [
"byteorder",
"digest",
"digest 0.9.0",
"rand_core 0.5.1",
"subtle",
"zeroize",
@@ -169,6 +203,17 @@ dependencies = [
"generic-array",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
name = "errno"
version = "0.3.0"
@@ -421,8 +466,11 @@ dependencies = [
name = "masterproef_v2"
version = "0.1.0"
dependencies = [
"blake2",
"blake2b",
"bytes",
"clap",
"digest 0.10.7",
"etherparse",
"futures",
"getrandom 0.2.9",
+3
View File
@@ -21,3 +21,6 @@ getrandom = "0.2.9"
rand_core = { version = "0.5.1", features = ["getrandom"] }
x25519-dalek = "1.2.0"
serde_json = "1.0.96"
blake2b = "0.99.0"
blake2 = "0.10.6"
digest = "0.10.7"
+9 -6
View File
@@ -24,8 +24,6 @@ const LINK_MTU: usize = 1420;
#[derive(Parser)]
struct Cli {
#[arg(short = 'a', long = "tun-addr")]
tun_addr: Ipv6Addr,
#[arg(short = 'p', long = "peers", num_args = 1..)]
static_peers: Vec<SocketAddr>,
}
@@ -34,8 +32,14 @@ struct Cli {
async fn main() -> Result<(), Box<dyn Error>> {
let cli = Cli::parse();
// Generate a new keypair for this node, panic if it fails
let node_keypair = x25519::get_keypair().unwrap();
// Generate the node's IPv6 address from its public key
let node_addr = x25519::generate_addr_from_pubkey(&node_keypair.1);
// Create TUN interface and add static route
let node_tun = match node_setup::setup_node(cli.tun_addr).await {
let node_tun = match node_setup::setup_node(node_addr).await {
Ok(tun) => {
println!("Node setup complete");
tun
@@ -45,8 +49,6 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
};
// Generate a new keypair for this node, panic if it fails
let node_keypair = x25519::get_keypair().unwrap();
println!("Node public key: {:?}", node_keypair.1);
@@ -56,7 +58,8 @@ async fn main() -> Result<(), Box<dyn Error>> {
// Creating a new Router instance
let router = match router::Router::new(
node_tun.clone(),
vec![StaticRoute::new(cli.tun_addr.into())],
node_addr,
vec![StaticRoute::new(node_addr.into())],
node_keypair
) {
Ok(router) => {
+72 -26
View File
@@ -1,16 +1,20 @@
use futures::stream::TryStreamExt;
use futures::TryStreamExt;
use rtnetlink::Handle;
use std::{error::Error, net::{Ipv4Addr, Ipv6Addr}, sync::Arc};
use x25519_dalek::PublicKey;
use std::{
net::{IpAddr, Ipv6Addr},
sync::Arc,
};
use tokio_tun::{Tun, TunBuilder};
pub const TUN_NAME: &str = "tun0";
pub const TUN_ROUTE_DEST: Ipv6Addr = Ipv6Addr::new(0xfd, 0x00, 0, 0, 0, 0, 0, 0);
pub const TUN_ROUTE_PREFIX: u8 = 16;
pub const TUN_ROUTE_DEST: Ipv6Addr = Ipv6Addr::new(0x200, 0, 0, 0, 0, 0, 0, 0);
pub const TUN_ROUTE_PREFIX: u8 = 7;
// Create a TUN interface
pub fn create_tun_interface() -> Result<Arc<Tun>, Box<dyn Error>> {
pub fn create_tun_interface() -> Result<Arc<Tun>, Box<dyn std::error::Error>> {
let tun = TunBuilder::new()
.name(TUN_NAME)
.name("tun0")
.tap(false)
.mtu(1420)
.packet_info(false)
@@ -20,43 +24,85 @@ pub fn create_tun_interface() -> Result<Arc<Tun>, Box<dyn Error>> {
Ok(Arc::new(tun))
}
// Add a route to the TUN interface
pub async fn add_route(handle: Handle) -> Result<(), Box<dyn Error>> {
let mut link_request = handle
.link()
.get()
.match_name(String::from(TUN_NAME))
.execute();
let link_idx = if let Some(link) = link_request.try_next().await? {
pub async fn retrieve_tun_link_index(handle: Handle) -> Result<u32, Box<dyn std::error::Error>> {
let mut link_req = handle.link().get().match_name(TUN_NAME.to_string()).execute();
let link_index = if let Some(link) = link_req.try_next().await? {
link.header.index
} else {
eprintln!("link not found");
panic!("link not found");
};
let route = handle.route();
route
.add()
.v4()
.destination_prefix(TUN_ROUTE_DEST, TUN_ROUTE_PREFIX)
.output_interface(link_idx)
Ok(link_index)
}
// Add address to TUN interface
pub async fn add_address(handle: Handle, addr: Ipv6Addr) -> Result<(), Box<dyn std::error::Error>> {
let link_index = retrieve_tun_link_index(handle.clone()).await?;
// add address to tun interface
handle
.address()
.add(
link_index,
IpAddr::V6(addr),
7,
)
.execute()
.await?;
Ok(())
}
pub async fn setup_node(tun_addr: Ipv6Addr) -> Result<Arc<Tun>, Box<dyn Error>> {
let tun = create_tun_interface(tun_addr)?;
println!("Interface '{}' ({}) created", TUN_NAME, tun_addr);
// Adding route to TUN interface
pub async fn add_route(handle: Handle) -> Result<(), Box<dyn std::error::Error>> {
let link_index = retrieve_tun_link_index(handle.clone()).await?;
// add route to tun interface
let route = handle.route();
route
.add()
.v6()
.destination_prefix(Ipv6Addr::new(0x200, 0, 0, 0, 0, 0, 0, 0), 7)
.output_interface(link_index)
.execute()
.await?;
Ok(())
}
pub async fn setup_node(addr: Ipv6Addr) -> Result<Arc<Tun>, Box<dyn std::error::Error>> {
let tun = match create_tun_interface() {
Ok(tun) => {
println!("TUN interface created");
tun
}
Err(e) => {
panic!("Error creating TUN interface: {}", e);
}
};
let (conn, handle, _) = rtnetlink::new_connection()?;
tokio::spawn(conn);
add_route(handle.clone()).await?;
match add_address(handle.clone(), addr).await {
Ok(_) => {
println!("Address added to TUN interface");
}
Err(e) => {
panic!("Error adding address to TUN interface: {}", e);
}
};
println!("Static route created");
match add_route(handle.clone()).await {
Ok(_) => {
println!("Route added to TUN interface");
}
Err(e) => {
panic!("Error adding route to TUN interface: {}", e);
}
};
Ok(tun)
}
+67 -47
View File
@@ -69,16 +69,22 @@ impl PeerManager {
);
let mut buf = [0u8; 17];
match self.router.node_tun_addr() {
IpAddr::V4(tun_addr) => {
buf[0] = 0;
buf[1..5].copy_from_slice(&tun_addr.octets()[..]);
}
IpAddr::V6(tun_addr) => {
buf[0] = 1;
buf[1..].copy_from_slice(&tun_addr.octets()[..]);
}
}
// old:
// match self.router.node_tun_addr() {
// IpAddr::V4(tun_addr) => {
// buf[0] = 0;
// buf[1..5].copy_from_slice(&tun_addr.octets()[..]);
// }
// IpAddr::V6(tun_addr) => {
// buf[0] = 1;
// buf[1..].copy_from_slice(&tun_addr.octets()[..]);
// }
// }
// new:
// only using IPv6
buf[0] = 1;
buf[1..].copy_from_slice(&self.router.node_tun_addr().octets()[..]);
peer_stream.write_all(&buf).await.unwrap();
let peer_stream_ip = peer_addr.ip();
@@ -125,17 +131,21 @@ impl PeerManager {
);
let mut buf = [0u8; 17];
match self.router.node_tun_addr() {
IpAddr::V4(tun_addr) => {
buf[0] = 0;
buf[1..5].copy_from_slice(&tun_addr.octets()[..]);
}
IpAddr::V6(tun_addr) => {
buf[0] = 1;
buf[1..].copy_from_slice(&tun_addr.octets()[..]);
}
}
// old:
// match self.router.node_tun_addr() {
// IpAddr::V4(tun_addr) => {
// buf[0] = 0;
// buf[1..5].copy_from_slice(&tun_addr.octets()[..]);
// }
// IpAddr::V6(tun_addr) => {
// buf[0] = 1;
// buf[1..].copy_from_slice(&tun_addr.octets()[..]);
// }
// }
// new:
// only using IPv6
buf[0] = 1;
buf[1..].copy_from_slice(&self.router.node_tun_addr().octets()[..]);
peer_stream.write_all(&buf).await.unwrap();
@@ -183,16 +193,22 @@ impl PeerManager {
);
let mut buf = [0u8; 17];
match self.router.node_tun_addr() {
IpAddr::V4(tun_addr) => {
buf[0] = 0;
buf[1..5].copy_from_slice(&tun_addr.octets()[..]);
}
IpAddr::V6(tun_addr) => {
buf[0] = 1;
buf[1..].copy_from_slice(&tun_addr.octets()[..]);
}
}
// old:
// match self.router.node_tun_addr() {
// IpAddr::V4(tun_addr) => {
// buf[0] = 0;
// buf[1..5].copy_from_slice(&tun_addr.octets()[..]);
// }
// IpAddr::V6(tun_addr) => {
// buf[0] = 1;
// buf[1..].copy_from_slice(&tun_addr.octets()[..]);
// }
// }
// new:
// only using IPv6
buf[0] = 1;
buf[1..].copy_from_slice(&self.router.node_tun_addr().octets()[..]);
peer_stream.write_all(&buf).await.unwrap();
let peer_stream_ip = peer.ip();
@@ -216,7 +232,7 @@ impl PeerManager {
Ok(listener) => loop {
match listener.accept().await {
Ok((stream, _)) => {
PeerManager::start_reverse_peer_exchange(stream, self.router.clone()).await;
self.start_reverse_peer_exchange(stream).await;
}
Err(e) => {
eprintln!("Error accepting connection: {}", e);
@@ -229,23 +245,27 @@ impl PeerManager {
}
}
async fn start_reverse_peer_exchange(mut stream: TcpStream, router: Router) {
async fn start_reverse_peer_exchange(&self, mut stream: TcpStream) {
// Steps:
// 1. Send own TUN address over the stream
// 2. Read other node's TUN address from the stream
let mut buf = [0u8; 17];
match router.node_tun_addr() {
IpAddr::V4(tun_addr) => {
buf[0] = 0;
buf[1..5].copy_from_slice(&tun_addr.octets()[..]);
}
IpAddr::V6(tun_addr) => {
buf[0] = 1;
buf[1..].copy_from_slice(&tun_addr.octets()[..]);
}
}
// old:
// match self.router.node_tun_addr() {
// IpAddr::V4(tun_addr) => {
// buf[0] = 0;
// buf[1..5].copy_from_slice(&tun_addr.octets()[..]);
// }
// IpAddr::V6(tun_addr) => {
// buf[0] = 1;
// buf[1..].copy_from_slice(&tun_addr.octets()[..]);
// }
// }
// new:
// only using IPv6
buf[0] = 1;
buf[1..].copy_from_slice(&self.router.node_tun_addr().octets()[..]);
stream.write_all(&buf).await.unwrap();
@@ -267,14 +287,14 @@ impl PeerManager {
let peer_stream_ip = stream.peer_addr().unwrap().ip();
let new_peer = Peer::new(
peer_stream_ip,
router.router_data_tx(),
router.router_control_tx(),
self.router.router_data_tx(),
self.router.router_control_tx(),
stream,
received_overlay_ip,
);
match new_peer {
Ok(new_peer) => {
router.add_peer_interface(new_peer);
self.router.add_peer_interface(new_peer);
}
Err(e) => {
eprintln!("Error creating peer: {}", e);
+11 -5
View File
@@ -9,7 +9,7 @@ use x25519_dalek::{StaticSecret, PublicKey};
use std::{
error::Error,
fmt::Debug,
net::IpAddr,
net::{IpAddr, Ipv6Addr},
sync::{Arc, RwLock},
};
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
@@ -44,6 +44,7 @@ pub struct Router {
impl Router {
pub fn new(
node_tun: Arc<Tun>,
node_tun_addr: Ipv6Addr,
static_routes: Vec<StaticRoute>,
node_keypair: (StaticSecret, PublicKey),
) -> Result<Self, Box<dyn Error>> {
@@ -55,6 +56,7 @@ impl Router {
let router = Router {
inner: Arc::new(RwLock::new(RouterInner::new(
node_tun,
node_tun_addr,
static_routes,
router_data_tx,
router_control_tx,
@@ -91,8 +93,9 @@ impl Router {
self.inner.read().unwrap().router_data_tx.clone()
}
pub fn node_tun_addr(&self) -> IpAddr {
IpAddr::V6(self.inner.read().unwrap().node_tun.address().unwrap())
pub fn node_tun_addr(&self) -> Ipv6Addr {
// IpAddr::V6(self.inner.read().unwrap().node_tun.address().unwrap())
self.inner.read().unwrap().node_tun_addr
}
pub fn node_tun(&self) -> Arc<Tun> {
@@ -485,7 +488,7 @@ impl Router {
// If destination IP of packet is same as TUN interface IP, send to TUN interface
// If destination IP of packet is not same as TUN interface IP, send to peer with matching overlay IP
let node_tun = self.node_tun();
let node_tun_addr = node_tun.address().unwrap();
let node_tun_addr = self.node_tun_addr();
loop {
while let Some(data_packet) = router_data_rx.recv().await {
match data_packet.dest_ip {
@@ -497,7 +500,7 @@ impl Router {
}
},
_ => {
let best_route = self.select_best_route(IpAddr::V4(data_packet.dest_ip));
let best_route = self.select_best_route(IpAddr::V6(data_packet.dest_ip));
match best_route {
Some (route_entry) => {
let peer = self.peer_by_ip(route_entry.next_hop).unwrap();
@@ -580,6 +583,7 @@ pub struct RouterInner {
router_control_tx: UnboundedSender<ControlStruct>,
router_data_tx: UnboundedSender<DataPacket>,
node_tun: Arc<Tun>,
node_tun_addr: Ipv6Addr,
selected_routing_table: RoutingTable,
fallback_routing_table: RoutingTable,
source_table: SourceTable,
@@ -591,6 +595,7 @@ pub struct RouterInner {
impl RouterInner {
pub fn new(
node_tun: Arc<Tun>,
node_tun_addr: Ipv6Addr,
static_routes: Vec<StaticRoute>,
router_data_tx: UnboundedSender<DataPacket>,
router_control_tx: UnboundedSender<ControlStruct>,
@@ -608,6 +613,7 @@ impl RouterInner {
router_seqno: 0,
static_routes: static_routes,
node_keypair: node_keypair,
node_tun_addr,
};
Ok(router_inner)
+28 -5
View File
@@ -1,13 +1,17 @@
use blake2::digest::{Update, VariableOutput};
use blake2::Blake2bVar;
use rand_core::OsRng;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;
use rand_core::OsRng;
use std::{
net::Ipv6Addr,
};
use x25519_dalek::{PublicKey, StaticSecret, SharedSecret};
// Read the secret key from a file if it exists, otherwise generate a new one and write it to a file
// Returns the secret key and the corresponding public key
pub fn get_keypair() -> Result<(StaticSecret, PublicKey), Box<dyn std::error::Error>>{
pub fn get_keypair() -> Result<(StaticSecret, PublicKey), Box<dyn std::error::Error>> {
let path = Path::new("keys.txt");
let (secret_key, public_key) = if path.exists() {
@@ -29,7 +33,8 @@ pub fn get_keypair() -> Result<(StaticSecret, PublicKey), Box<dyn std::error::Er
.open(&path)
.expect("Failed to open file");
file.write_all(secret_key.to_bytes().as_ref()).expect("Failed to write to file");
file.write_all(secret_key.to_bytes().as_ref())
.expect("Failed to write to file");
(secret_key, public_key)
};
@@ -39,4 +44,22 @@ pub fn get_keypair() -> Result<(StaticSecret, PublicKey), Box<dyn std::error::Er
pub fn shared_secret_from_keypair(secret: StaticSecret, pubkey: PublicKey) -> SharedSecret {
secret.diffie_hellman(&pubkey)
}
}
pub fn generate_addr_from_pubkey(pubkey: &PublicKey) -> Ipv6Addr {
let mut hasher = Blake2bVar::new(16).unwrap(); // output ipv6 is 16 bytes
hasher.update(pubkey.as_bytes());
let mut buf = [0u8; 16];
hasher.finalize_variable(&mut buf).unwrap();
let ipv6_bytes: [u8; 16] = [
0x20, 0x00, // This prefix ensures the address falls into the 200::/7 range
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10],
buf[11], buf[12], buf[13],
];
let addr = Ipv6Addr::from(ipv6_bytes);
println!("output buf : {:?}", addr);
addr
}