diff --git a/src/eth_util.rs b/src/eth_util.rs deleted file mode 100644 index 953b8a3..0000000 --- a/src/eth_util.rs +++ /dev/null @@ -1,250 +0,0 @@ -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; -use std::time::{Duration, Instant}; -use std::{env, process}; - -use pnet::datalink::{Channel, DataLinkReceiver, DataLinkSender, NetworkInterface}; -use pnet::packet::arp::{ArpHardwareTypes, ArpOperations, ArpPacket, MutableArpPacket}; -use pnet::packet::ethernet::{EtherTypes, EthernetPacket, MutableEthernetPacket}; -use pnet::packet::icmpv6::ndp::{ - MutableNdpOptionPacket, MutableNeighborSolicitPacket, NdpOptionPacket, NdpOptionTypes, - NeighborAdvertPacket, NeighborSolicitPacket, -}; -use pnet::packet::icmpv6::{self, Icmpv6Types, MutableIcmpv6Packet}; -use pnet::packet::ip::IpNextHeaderProtocols; -use pnet::packet::ipv6::{Ipv6Packet, MutableIpv6Packet}; -use pnet::util::MacAddr; - -const TIMEOUT: Duration = Duration::from_secs(10); - -// Constants used to help locate our nested packets -const PKT_ETH_SIZE: usize = EthernetPacket::minimum_packet_size(); -const PKT_ARP_SIZE: usize = ArpPacket::minimum_packet_size(); -const PKT_IP6_SIZE: usize = Ipv6Packet::minimum_packet_size(); -const PKT_NDP_SOL_SIZE: usize = NeighborSolicitPacket::minimum_packet_size(); -const PKT_NDP_ADV_SIZE: usize = NeighborAdvertPacket::minimum_packet_size(); -const PKT_OPT_SIZE: usize = NdpOptionPacket::minimum_packet_size(); -const PKT_MAC_SIZE: usize = 6; - -const PKT_ARP_OFFSET: usize = PKT_ETH_SIZE; -const PKT_IP6_OFFSET: usize = PKT_ETH_SIZE; -const PKT_NDP_OFFSET: usize = PKT_IP6_OFFSET + PKT_IP6_SIZE; - -const PKT_MIN_ARP_RESP_SIZE: usize = PKT_ETH_SIZE + PKT_ARP_SIZE; -const PKT_MIN_NDP_RESP_SIZE: usize = PKT_ETH_SIZE + PKT_IP6_SIZE + PKT_NDP_ADV_SIZE; - -/// Given an IPv4 or IPv6 address and an interface name -pub fn get_mac(ifname: &str, ip: IpAddr) -> Result { - let interfaces = pnet::datalink::interfaces(); - - let interface = interfaces - .into_iter() - .find(|iface| iface.name == ifname) - .ok_or_else(|| Error::Interface(ifname.into()))?; - - println!("Source MAC address: {}", interface.mac.unwrap()); - - match ip { - IpAddr::V4(ipv4) => get_mac_via_arp(&interface, ipv4), - IpAddr::V6(ipv6) => get_mac_via_ndp(&interface, ipv6), - } -} - -/// Use ARP to locate the MAC of an IPv4 address -fn get_mac_via_arp(interface: &NetworkInterface, target_ipv4: Ipv4Addr) -> Result { - let source_ipv4 = interface - .ips - .iter() - .find_map(|ip| match ip.ip() { - IpAddr::V4(addr) => Some(addr), - IpAddr::V6(_) => None, - }) - .unwrap(); - - let source_mac = interface.mac.unwrap(); - let mut pkt_buf = [0u8; PKT_ETH_SIZE + PKT_ARP_SIZE]; - - // Use scope blocks so we can reborrow our buffer - { - // Build our base ethernet frame - let mut pkt_eth = MutableEthernetPacket::new(&mut pkt_buf).unwrap(); - - pkt_eth.set_destination(MacAddr::broadcast()); - pkt_eth.set_source(interface.mac.unwrap()); - pkt_eth.set_ethertype(EtherTypes::Arp); - } - - { - // Build the ARP frame on top of the ethernet frame - let mut pkt_arp = MutableArpPacket::new(&mut pkt_buf[PKT_ARP_OFFSET..]).unwrap(); - - pkt_arp.set_hardware_type(ArpHardwareTypes::Ethernet); - pkt_arp.set_protocol_type(EtherTypes::Ipv4); - pkt_arp.set_hw_addr_len(6); - pkt_arp.set_proto_addr_len(4); - pkt_arp.set_operation(ArpOperations::Request); - pkt_arp.set_sender_hw_addr(interface.mac.unwrap()); - pkt_arp.set_sender_proto_addr(source_ipv4); - pkt_arp.set_target_hw_addr(MacAddr::zero()); - pkt_arp.set_target_proto_addr(target_ipv4); - } - - let (mut sender, mut receiver) = build_eth_channel(interface); - let start = Instant::now(); - - // Send to the broadcast address - sender.send_to(&pkt_buf, None).unwrap().unwrap(); - eprintln!("Sent ARP request"); - - // Zero buffer for sanity check - pkt_buf.fill(0); - - loop { - let buf = receiver.next().unwrap(); - - if buf.len() < PKT_MIN_ARP_RESP_SIZE { - timeout_check(start)?; - continue; - } - - let pkt_arp = ArpPacket::new(&buf[PKT_ARP_OFFSET..]).unwrap(); - - if pkt_arp.get_sender_proto_addr() == target_ipv4 - && pkt_arp.get_target_hw_addr() == source_mac - { - return Ok(pkt_arp.get_sender_hw_addr()); - } - - timeout_check(start)?; - } -} - -/// Use NDP to locate the MAC of an IPv6 address -fn get_mac_via_ndp(interface: &NetworkInterface, target_ipv6: Ipv6Addr) -> Result { - let source_ipv6 = interface - .ips - .iter() - .find_map(|ip| match ip.ip() { - IpAddr::V4(_) => None, - IpAddr::V6(addr) => Some(addr), - }) - .unwrap(); - - let source_mac = interface.mac.unwrap(); - let mut pkt_buf = - [0u8; PKT_ETH_SIZE + PKT_IP6_SIZE + PKT_NDP_SOL_SIZE + PKT_OPT_SIZE + PKT_MAC_SIZE]; - - // Use scope blocks so we can reborrow our buffer - { - // Build our base ethernet frame - let mut pkt_eth = MutableEthernetPacket::new(&mut pkt_buf).unwrap(); - - pkt_eth.set_destination(MacAddr::broadcast()); - pkt_eth.set_source(interface.mac.unwrap()); - pkt_eth.set_ethertype(EtherTypes::Ipv6); - } - - { - // Build the ipv6 packet - let mut pkt_ipv6 = MutableIpv6Packet::new(&mut pkt_buf[PKT_IP6_OFFSET..]).unwrap(); - - pkt_ipv6.set_version(0x06); - pkt_ipv6.set_payload_length( - (PKT_NDP_SOL_SIZE + PKT_OPT_SIZE + PKT_MAC_SIZE) - .try_into() - .unwrap(), - ); - pkt_ipv6.set_next_header(IpNextHeaderProtocols::Icmpv6); - pkt_ipv6.set_hop_limit(u8::MAX); - pkt_ipv6.set_source(source_ipv6); - pkt_ipv6.set_destination(target_ipv6); - } - - { - // Build the NDP packet - let mut pkt_ndp = - MutableNeighborSolicitPacket::new(&mut pkt_buf[PKT_NDP_OFFSET..]).unwrap(); - pkt_ndp.set_target_addr(target_ipv6); - pkt_ndp.set_icmpv6_type(Icmpv6Types::NeighborSolicit); - pkt_ndp.set_checksum(0x3131); - - let mut pkt_opt = MutableNdpOptionPacket::new(pkt_ndp.get_options_raw_mut()).unwrap(); - pkt_opt.set_option_type(NdpOptionTypes::SourceLLAddr); - pkt_opt.set_length(octets_len(PKT_MAC_SIZE)); - pkt_opt.set_data(&source_mac.octets()); - } - - { - // Set the checksum (part of the NDP packet) - let mut pkt_icmpv6 = MutableIcmpv6Packet::new(&mut pkt_buf[PKT_NDP_OFFSET..]).unwrap(); - pkt_icmpv6.set_checksum(icmpv6::checksum( - &pkt_icmpv6.to_immutable(), - &source_ipv6, - &target_ipv6, - )); - } - - let (mut sender, mut receiver) = build_eth_channel(interface); - let start = Instant::now(); - - // Send to the broadcast address - sender.send_to(&pkt_buf, None).unwrap().unwrap(); - eprintln!("Sent NDP request"); - - // Zero buffer for sanity check - pkt_buf.fill(0); - - loop { - let buf = receiver.next().unwrap(); - - if buf.len() < PKT_MIN_NDP_RESP_SIZE { - timeout_check(start)?; - continue; - } - - let pkt_eth = EthernetPacket::new(buf).unwrap(); - let pkt_ipv6 = Ipv6Packet::new(&buf[PKT_IP6_OFFSET..]).unwrap(); - let _pkt_ndp = NeighborAdvertPacket::new(&buf[PKT_NDP_OFFSET..]).unwrap(); - - if pkt_ipv6.get_source() == target_ipv6 && pkt_eth.get_destination() == source_mac { - return Ok(pkt_eth.get_source()); - } - - timeout_check(start)?; - } -} - -/// Construct a sender/receiver channel from an interface -fn build_eth_channel( - interface: &NetworkInterface, -) -> (Box, Box) { - let cfg = pnet::datalink::Config::default(); - match pnet::datalink::channel(interface, cfg) { - Ok(Channel::Ethernet(tx, rx)) => (tx, rx), - Ok(_) => panic!("Unknown channel type"), - Err(e) => panic!("Channel error: {e}"), - } -} - -/// Length in octets (8bytes) -fn octets_len(len: usize) -> u8 { - // 3 = log2(8) - (len.next_power_of_two() >> 3).try_into().unwrap() -} - -/// Bail if we exceed TIMEOUT -fn timeout_check(start: Instant) -> Result<(), Error> { - if Instant::now().duration_since(start) > TIMEOUT { - Err(Error::Timeout(TIMEOUT)) - } else { - Ok(()) - } -} - -/// Simple error types for this demo -#[derive(Debug)] -pub enum Error { - /// Something didn't happen on time - Timeout(Duration), - /// Interface of this name did not exist - Interface(String), -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 405ce4c..cff9de0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use tokio::{net::UdpSocket, sync::mpsc}; -use std::{io::{self, Read}, net::SocketAddr, sync::Arc, thread, time}; +use std::{io::{self, Error, Read}, net::SocketAddr, sync::Arc, thread, time}; use std::process::Command; use clap::{App, Arg}; use env_logger::Builder; @@ -12,19 +12,28 @@ use serde_derive::Deserialize; //mod server; mod tcp_client; mod tcp_server; -mod eth_util; -const HEADER: [u8;3] = [0x56, 0x66, 0x76]; -const TAIL: [u8;3] = [0x76, 0x66, 0x56]; - -#[derive(Serialize, Deserialize)] struct VpnPacket { //start: Vec - len: u64, data: Vec //end: Vec } +impl VpnPacket { + fn serialize(&self) -> Vec { + let len: [u8; 8] = (self.data.len() as u64).to_be_bytes(); + len.iter().cloned().chain(self.data.iter().cloned()).collect() + } + + fn deserialize_length(d: [u8; 8]) -> u64 { + u64::from_be_bytes(d) + } + + fn deserialize(d: Vec) -> Result { + Ok(VpnPacket{ data: d }) + } +} + #[tokio::main] async fn main() { diff --git a/src/tcp_client.rs b/src/tcp_client.rs index 65a7a99..9885f4a 100644 --- a/src/tcp_client.rs +++ b/src/tcp_client.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use std::process::Command; use tokio::io::AsyncReadExt; -use crate::{VpnPacket, HEADER, TAIL}; +use crate::VpnPacket; fn configure_routes() { let ip_output = Command::new("ip") @@ -101,21 +101,24 @@ pub async fn client_mode(remote_addr: String) { tokio::spawn(async move { let mut buf = vec![0; 4096]; loop { - if let Ok(n) = sock_reader.read(&mut buf).await { - info!("Catch from socket"); - match bincode::deserialize::(&buf[..n]) { - Ok(vpn_packet) => tx.send(vpn_packet.data).unwrap(), - Err(error) => error!("Deserialization error {:?}", error), - }; - //if vpn_packet.start != &HEADER || vpn_packet.end != &TAIL { error!("Bad packet"); continue; } + if let Ok(l) = sock_reader.read_u64().await { + buf = vec![0; l.try_into().unwrap()]; + if let Ok(n) = sock_reader.read(&mut buf).await { + info!("Catch from socket"); + match VpnPacket::deserialize((&buf[..n]).to_vec()) { + Ok(vpn_packet) => tx.send(vpn_packet.data).unwrap(), + Err(error) => error!("Deserialization error {:?}", error), + }; + //if vpn_packet.start != &HEADER || vpn_packet.end != &TAIL { error!("Bad packet"); continue; } + } } } }); loop { if let Ok(bytes) = mx.recv() { - let vpn_packet = VpnPacket{ len: bytes.len() as u64, data: bytes }; - let serialized_data = bincode::serialize::(&vpn_packet).unwrap(); + let vpn_packet = VpnPacket{ data: bytes }; + let serialized_data = vpn_packet.serialize(); //info!("Writing to sock: {:?}", serialized_data); sock_writer.write_all(&serialized_data).await.unwrap(); } diff --git a/src/tcp_server.rs b/src/tcp_server.rs index 65766dd..cfd8c4b 100644 --- a/src/tcp_server.rs +++ b/src/tcp_server.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use tokio::io::AsyncReadExt; use std::process::Command; -use crate::{VpnPacket, HEADER, TAIL}; +use crate::VpnPacket; pub async fn server_mode(bind_addr: String) { info!("Starting server..."); @@ -115,8 +115,8 @@ pub async fn server_mode(bind_addr: String) { tokio::spawn(async move { loop { if let Ok(bytes) = thread_mx.recv() { - let vpn_packet = VpnPacket{ len: bytes.len() as u64, data: bytes }; - let serialized_data = bincode::serialize::(&vpn_packet).unwrap(); + let vpn_packet = VpnPacket{ data: bytes }; + let serialized_data = vpn_packet.serialize(); sock_writer.write_all(&serialized_data).await.unwrap(); //info!("Wrote to sock: {:?}", serialized_data); } @@ -126,13 +126,16 @@ pub async fn server_mode(bind_addr: String) { tokio::spawn(async move { let mut buf = vec![0; 4096]; loop { - if let Ok(n) = sock_reader.read(&mut buf).await { - //info!("Catched from sock: {:?}", &buf[..n]); - match bincode::deserialize::(&buf[..n]) { - Ok(vpn_packet) => thread_tx.send(vpn_packet.data).unwrap(), - Err(error) => error!("Deserializing error {:?}", error), - }; - //if vpn_packet.start != &HEADER || vpn_packet.end != &TAIL { error!("Bad packet"); continue; } + if let Ok(l) = sock_reader.read_u64().await { + buf = vec![0; l.try_into().unwrap()]; + if let Ok(n) = sock_reader.read(&mut buf).await { + //info!("Catched from sock: {:?}", &buf[..n]); + match VpnPacket::deserialize((&buf[..n]).to_vec()) { + Ok(vpn_packet) => thread_tx.send(vpn_packet.data).unwrap(), + Err(error) => error!("Deserializing error {:?}", error), + }; + //if vpn_packet.start != &HEADER || vpn_packet.end != &TAIL { error!("Bad packet"); continue; } + } } } });