use chrono::DateTime;
use chrono::Local;
use chrono::Utc;
use pnet::datalink::MacAddr;
use rand::Rng;
use std::collections::HashMap;
use std::fmt;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::sync::mpsc::channel;
use std::thread::sleep;
use std::time::Duration;
use std::time::Instant;
use tracing::debug;
use tracing::warn;
use crate::IpCheckMethods;
use crate::error::PistolError;
use crate::layer::Layer3Match;
use crate::layer::Layer4MatchIcmp;
use crate::layer::Layer4MatchTcpUdp;
use crate::layer::LayerMatch;
use crate::layer::layer3_ipv4_send;
use crate::os::OsInfo;
use crate::os::dbparser::NmapOSDB;
use crate::os::operator::icmp_cd;
use crate::os::operator::icmp_dfi;
use crate::os::operator::tcp_a;
use crate::os::operator::tcp_cc;
use crate::os::operator::tcp_f;
use crate::os::operator::tcp_gcd;
use crate::os::operator::tcp_isr;
use crate::os::operator::tcp_o;
use crate::os::operator::tcp_ox;
use crate::os::operator::tcp_q;
use crate::os::operator::tcp_rd;
use crate::os::operator::tcp_s;
use crate::os::operator::tcp_sp;
use crate::os::operator::tcp_ss;
use crate::os::operator::tcp_ti_ci_ii;
use crate::os::operator::tcp_ts;
use crate::os::operator::tcp_udp_df;
use crate::os::operator::tcp_udp_icmp_r;
use crate::os::operator::tcp_udp_icmp_t;
use crate::os::operator::tcp_udp_icmp_tg;
use crate::os::operator::tcp_w;
use crate::os::operator::tcp_wx;
use crate::os::operator::udp_ipl;
use crate::os::operator::udp_rid;
use crate::os::operator::udp_ripck;
use crate::os::operator::udp_ripl;
use crate::os::operator::udp_ruck;
use crate::os::operator::udp_rud;
use crate::os::operator::udp_un;
use crate::os::packet;
use crate::os::rr::AllPacketRR;
use crate::os::rr::ECNRR;
use crate::os::rr::IERR;
use crate::os::rr::RequestResponse;
use crate::os::rr::SEQRR;
use crate::os::rr::TXRR;
use crate::os::rr::U1RR;
use crate::route::RouteVia;
use crate::trace::icmp_trace;
use crate::utils::get_threads_pool;
use crate::utils::random_port;
use crate::utils::random_port_range;
const MAX_RETRY: usize = 5;
#[derive(Debug, Clone)]
pub struct Fingerprint {
pub scan: String,
pub seqx: SEQX,
pub opsx: OPSX,
pub winx: WINX,
pub ecnx: ECNX,
pub t1x: TXX,
pub t2x: TXX,
pub t3x: TXX,
pub t4x: TXX,
pub t5x: TXX,
pub t6x: TXX,
pub t7x: TXX,
pub u1x: U1X,
pub iex: IEX,
}
impl Fingerprint {
pub fn empty() -> Fingerprint {
Fingerprint {
scan: String::new(),
seqx: SEQX::empty(),
opsx: OPSX::empty(),
winx: WINX::empty(),
ecnx: ECNX::empty(),
t1x: TXX::empty(),
t2x: TXX::empty(),
t3x: TXX::empty(),
t4x: TXX::empty(),
t5x: TXX::empty(),
t6x: TXX::empty(),
t7x: TXX::empty(),
u1x: U1X::empty(),
iex: IEX::empty(),
}
}
}
impl fmt::Display for Fingerprint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut output = format!("{}", self.scan);
let seqx_str = format!("\n{}", self.seqx);
let opsx_str = format!("\n{}", self.opsx);
let winx_str = format!("\n{}", self.winx);
let ecnx_str = format!("\n{}", self.ecnx);
let t1x_str = format!("\n{}", self.t1x);
let t2x_str = format!("\n{}", self.t2x);
let t3x_str = format!("\n{}", self.t3x);
let t4x_str = format!("\n{}", self.t4x);
let t5x_str = format!("\n{}", self.t5x);
let t6x_str = format!("\n{}", self.t6x);
let t7x_str = format!("\n{}", self.t7x);
let u1x_str = format!("\n{}", self.u1x);
let iex_str = format!("\n{}", self.iex);
output += &seqx_str;
output += &opsx_str;
output += &winx_str;
output += &ecnx_str;
output += &t1x_str;
output += &t2x_str;
output += &t3x_str;
output += &t4x_str;
output += &t5x_str;
output += &t6x_str;
output += &t7x_str;
output += &u1x_str;
output += &iex_str;
write!(f, "{}", output)
}
}
impl Fingerprint {
pub fn nmap_format(&self) -> String {
let interval = 72;
let mut ret = String::new();
let mut i = 0;
let fingerprint = format!("{}", self);
for ch in fingerprint.chars() {
if i % interval == 0 {
ret += "\nOS:"
}
if ch != '\n' {
ret += &format!("{}", ch);
i += 1;
}
}
ret.trim().to_string()
}
}
pub fn get_scan_line(
dst_mac: MacAddr,
dst_open_tcp_port: u16,
dst_closed_tcp_port: u16,
dst_closed_udp_port: u16,
dst_addr: IpAddr,
hops: u8,
good_results: bool,
) -> String {
let v = format!("pistol_{}", env!("CARGO_PKG_VERSION"));
let now: DateTime<Local> = Local::now();
let date = format!("{}", now.format("%-m/%-d"));
let (pv, ds, dc) = if dst_addr.is_loopback() {
("Y", 0, "L")
} else if !dst_addr.is_global_x() {
("Y", 1, "D")
} else {
("N", hops, "I")
};
let g = if good_results { "Y" } else { "N" };
let m = if ds == 1 {
let mut dst_mac_vec: [u8; 6] = dst_mac.octets();
let mut dst_mac_str = String::new();
for m in &mut dst_mac_vec[0..3] {
dst_mac_str = format!("{}{:X}", dst_mac_str, m);
}
dst_mac_str
} else {
"".to_string()
};
let now: DateTime<Utc> = Utc::now();
let tm = format!("{:X}", now.timestamp());
let p = "RUST";
let info_str = match dst_addr {
IpAddr::V4(_) => {
let info_str = if m.len() > 0 {
format!(
"SCAN(V={v}%D={date}%OT={dst_open_tcp_port}%CT={dst_closed_tcp_port}%CU={dst_closed_udp_port}PV={pv}%DS={ds}%DC={dc}%G={g}%M={m}%TM={tm}%P={p})",
)
} else {
format!(
"SCAN(V={v}%D={date}%OT={dst_open_tcp_port}%CT={dst_closed_tcp_port}%CU={dst_closed_udp_port}PV={pv}%DS={ds}%DC={dc}%G={g}%TM={tm}%P={p})",
)
};
info_str
}
IpAddr::V6(_) => {
let info_str = if m.len() > 0 {
format!(
"SCAN(V={v}%E=6%D={date}%OT={dst_open_tcp_port}%CT={dst_closed_tcp_port}%CU={dst_closed_udp_port}PV={pv}%DS={ds}%DC={dc}%G={g}%M={m}%TM={tm}%P={p})",
)
} else {
format!(
"SCAN(V={v}%E=6%D={date}%OT={dst_open_tcp_port}%CT={dst_closed_tcp_port}%CU={dst_closed_udp_port}PV={pv}%DS={ds}%DC={dc}%G={g}%TM={tm}%P={p})",
)
};
info_str
}
};
info_str
}
fn send_seq_probes(
dst_ipv4: Ipv4Addr,
dst_open_port: u16,
src_ipv4: Ipv4Addr,
timeout: Option<Duration>,
) -> Result<SEQRR, PistolError> {
let pool = get_threads_pool(6);
let (tx, rx) = channel();
let src_port_start = random_port_range(1000, 6540);
let mut src_ports = Vec::new();
for i in 0..6 {
src_ports.push(src_port_start * 10 + i);
}
let buff_1 = packet::seq_packet_1_layer3(dst_ipv4, dst_open_port, src_ipv4, src_ports[0])?;
let buff_2 = packet::seq_packet_2_layer3(dst_ipv4, dst_open_port, src_ipv4, src_ports[1])?;
let buff_3 = packet::seq_packet_3_layer3(dst_ipv4, dst_open_port, src_ipv4, src_ports[2])?;
let buff_4 = packet::seq_packet_4_layer3(dst_ipv4, dst_open_port, src_ipv4, src_ports[3])?;
let buff_5 = packet::seq_packet_5_layer3(dst_ipv4, dst_open_port, src_ipv4, src_ports[4])?;
let buff_6 = packet::seq_packet_6_layer3(dst_ipv4, dst_open_port, src_ipv4, src_ports[5])?;
let buffs = vec![buff_1, buff_2, buff_3, buff_4, buff_5, buff_6];
let start = Instant::now();
for (i, buff) in buffs.into_iter().enumerate() {
let src_port = src_ports[i];
let name_string = format!("os scan seq {} layer3", i + 1);
let name = Box::leak(name_string.into_boxed_str());
let layer3 = Layer3Match {
name,
layer2: None,
src_addr: Some(dst_ipv4.into()),
dst_addr: Some(src_ipv4.into()),
};
let name_string = format!("os scan seq {} tcp_udp", i + 1);
let name = Box::leak(name_string.into_boxed_str());
let layer4_tcp_udp = Layer4MatchTcpUdp {
name,
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_port),
};
let layer_match = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp);
let tx = tx.clone();
pool.execute(move || {
for retry_time in 0..MAX_RETRY {
let ret = layer3_ipv4_send(
dst_ipv4,
src_ipv4,
&buff,
vec![layer_match.clone()],
timeout,
true,
);
match ret {
Ok((response, rtt)) => {
if response.len() > 0 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt))));
break;
} else if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt))));
}
}
Err(e) => {
if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Err(e)));
}
}
}
}
});
sleep(Duration::from_millis(100));
}
let mut seq_hm = HashMap::new();
let iter = rx.into_iter().take(6);
for (i, request, ret) in iter {
let (response, _rtt) = ret?;
if response.len() == 0 {
warn!("SQX-{} response is null", i);
}
let rr = RequestResponse { request, response };
seq_hm.insert(i, rr);
}
let elapsed = start.elapsed().as_secs_f64();
let seq1 = seq_hm
.get(&0)
.map_or(RequestResponse::empty(), |x| x.clone());
let seq2 = seq_hm
.get(&1)
.map_or(RequestResponse::empty(), |x| x.clone());
let seq3 = seq_hm
.get(&2)
.map_or(RequestResponse::empty(), |x| x.clone());
let seq4 = seq_hm
.get(&3)
.map_or(RequestResponse::empty(), |x| x.clone());
let seq5 = seq_hm
.get(&4)
.map_or(RequestResponse::empty(), |x| x.clone());
let seq6 = seq_hm
.get(&5)
.map_or(RequestResponse::empty(), |x| x.clone());
let seqrr = SEQRR {
seq1,
seq2,
seq3,
seq4,
seq5,
seq6,
elapsed,
};
Ok(seqrr)
}
fn send_ie_probes(
dst_ipv4: Ipv4Addr,
src_ipv4: Ipv4Addr,
timeout: Option<Duration>,
) -> Result<IERR, PistolError> {
let (tx, rx) = channel();
let mut rng = rand::rng();
let id_1 = rng.random();
let id_2 = id_1 + 1;
let buff_1 = packet::ie_packet_1_layer3(dst_ipv4, src_ipv4, id_1)?;
let buff_2 = packet::ie_packet_2_layer3(dst_ipv4, src_ipv4, id_2)?;
let buffs = vec![buff_1, buff_2];
let layer3 = Layer3Match {
name: "os scan ie layer3",
layer2: None,
src_addr: Some(dst_ipv4.into()),
dst_addr: Some(src_ipv4.into()),
};
let layer4_icmp = Layer4MatchIcmp {
name: "os scan ie icmp",
layer3: Some(layer3),
icmp_type: None,
icmp_code: None,
payload: None,
};
let layer_match = LayerMatch::Layer4MatchIcmp(layer4_icmp);
for (i, buff) in buffs.into_iter().enumerate() {
let tx = tx.clone();
for retry_time in 0..MAX_RETRY {
let ret = layer3_ipv4_send(
dst_ipv4,
src_ipv4,
&buff,
vec![layer_match.clone()],
timeout,
true,
);
match ret {
Ok((response, rtt)) => {
if response.len() > 0 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt))));
break;
} else if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt))));
}
}
Err(e) => {
if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Err(e)));
}
}
}
}
}
let mut ies = HashMap::new();
let iter = rx.into_iter().take(2);
for (i, request, ret) in iter {
let (response, _rtt) = ret?;
let rr = RequestResponse { request, response };
ies.insert(i, rr);
}
let ie1 = ies.get(&0).map_or(RequestResponse::empty(), |x| x.clone());
let ie2 = ies.get(&1).map_or(RequestResponse::empty(), |x| x.clone());
let ie = IERR { ie1, ie2 };
Ok(ie)
}
fn send_ecn_probe(
dst_ipv4: Ipv4Addr,
dst_open_port: u16,
src_ipv4: Ipv4Addr,
timeout: Option<Duration>,
) -> Result<ECNRR, PistolError> {
let src_port = random_port();
let layer3 = Layer3Match {
name: "os scan ecn layer3",
layer2: None,
src_addr: Some(dst_ipv4.into()),
dst_addr: Some(src_ipv4.into()),
};
let layer4_tcp_udp = Layer4MatchTcpUdp {
name: "os scan ecn tcp_udp",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_port),
};
let layer_match = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp);
let buff = packet::ecn_packet_layer3(dst_ipv4, dst_open_port, src_ipv4, src_port)?;
for _ in 0..MAX_RETRY {
let (response, _rtt) = layer3_ipv4_send(
dst_ipv4,
src_ipv4,
&buff,
vec![layer_match.clone()],
timeout,
true,
)?;
if response.len() > 0 {
let rr = RequestResponse {
request: buff,
response,
};
let ecn = ECNRR { ecn: rr };
return Ok(ecn);
}
}
let rr = RequestResponse {
request: buff,
response: vec![],
};
let ecn = ECNRR { ecn: rr };
return Ok(ecn);
}
fn send_tx_probes(
dst_ipv4: Ipv4Addr,
dst_open_port: u16,
dst_closed_port: u16,
src_ipv4: Ipv4Addr,
timeout: Option<Duration>,
) -> Result<TXRR, PistolError> {
let pool = get_threads_pool(6);
let (tx, rx) = channel();
let src_port_start = random_port_range(1000, 6540);
let mut src_ports = Vec::new();
for i in 0..6 {
src_ports.push(src_port_start * 10 + i);
}
let layer3 = Layer3Match {
name: "os scan tx layer3",
layer2: None,
src_addr: Some(dst_ipv4.into()),
dst_addr: Some(src_ipv4.into()),
};
let layer4_tcp_udp_1 = Layer4MatchTcpUdp {
name: "os scan ecn tcp_udp 1",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_ports[0]),
};
let layer4_tcp_udp_2 = Layer4MatchTcpUdp {
name: "os scan ecn tcp_udp 2",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_ports[1]),
};
let layer4_tcp_udp_3 = Layer4MatchTcpUdp {
name: "os scan ecn tcp_udp 3",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_ports[2]),
};
let layer4_tcp_udp_4 = Layer4MatchTcpUdp {
name: "os scan ecn tcp_udp 4",
layer3: Some(layer3),
src_port: Some(dst_closed_port),
dst_port: Some(src_ports[3]),
};
let layer4_tcp_udp_5 = Layer4MatchTcpUdp {
name: "os scan ecn tcp_udp 5",
layer3: Some(layer3),
src_port: Some(dst_closed_port),
dst_port: Some(src_ports[4]),
};
let layer4_tcp_udp_6 = Layer4MatchTcpUdp {
name: "os scan ecn tcp_udp 6",
layer3: Some(layer3),
src_port: Some(dst_closed_port),
dst_port: Some(src_ports[5]),
};
let layer_match_1 = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp_1);
let layer_match_2 = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp_2);
let layer_match_3 = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp_3);
let layer_match_4 = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp_4);
let layer_match_5 = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp_5);
let layer_match_6 = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp_6);
let ms = vec![
layer_match_1,
layer_match_2,
layer_match_3,
layer_match_4,
layer_match_5,
layer_match_6,
];
let buff_2 = packet::t2_packet_layer3(dst_ipv4, dst_open_port, src_ipv4, src_ports[0])?;
let buff_3 = packet::t3_packet_layer3(dst_ipv4, dst_open_port, src_ipv4, src_ports[1])?;
let buff_4 = packet::t4_packet_layer3(dst_ipv4, dst_open_port, src_ipv4, src_ports[2])?;
let buff_5 = packet::t5_packet_layer3(dst_ipv4, dst_closed_port, src_ipv4, src_ports[3])?;
let buff_6 = packet::t6_packet_layer3(dst_ipv4, dst_closed_port, src_ipv4, src_ports[4])?;
let buff_7 = packet::t7_packet_layer3(dst_ipv4, dst_closed_port, src_ipv4, src_ports[5])?;
let buffs = vec![buff_2, buff_3, buff_4, buff_5, buff_6, buff_7];
for (i, buff) in buffs.into_iter().enumerate() {
let tx = tx.clone();
let m = ms[i].clone();
pool.execute(move || {
for retry_time in 0..MAX_RETRY {
let ret =
layer3_ipv4_send(dst_ipv4, src_ipv4, &buff, vec![m.clone()], timeout, true);
match ret {
Ok((response, rtt)) => {
if response.len() > 0 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt))));
break;
} else if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt))));
}
}
Err(e) => {
if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Err(e)));
}
}
}
}
});
}
let mut tx_hm = HashMap::new();
let iter = rx.into_iter().take(6);
for (i, request, ret) in iter {
let (response, _rtt) = ret?;
let rr = RequestResponse { request, response };
tx_hm.insert(i, rr);
}
let t2 = tx_hm
.get(&0)
.map_or(RequestResponse::empty(), |x| x.clone());
let t3 = tx_hm
.get(&1)
.map_or(RequestResponse::empty(), |x| x.clone());
let t4 = tx_hm
.get(&2)
.map_or(RequestResponse::empty(), |x| x.clone());
let t5 = tx_hm
.get(&3)
.map_or(RequestResponse::empty(), |x| x.clone());
let t6 = tx_hm
.get(&4)
.map_or(RequestResponse::empty(), |x| x.clone());
let t7 = tx_hm
.get(&5)
.map_or(RequestResponse::empty(), |x| x.clone());
let txrr = TXRR {
t2,
t3,
t4,
t5,
t6,
t7,
};
Ok(txrr)
}
fn send_u1_probe(
dst_ipv4: Ipv4Addr,
dst_closed_port: u16, src_ipv4: Ipv4Addr,
timeout: Option<Duration>,
) -> Result<U1RR, PistolError> {
let src_port = random_port();
let layer3 = Layer3Match {
name: "os scan u1 layer3",
layer2: None,
src_addr: Some(dst_ipv4.into()),
dst_addr: Some(src_ipv4.into()),
};
let layer4_icmp = Layer4MatchIcmp {
name: "os scan u1 icmp",
layer3: Some(layer3),
icmp_type: None,
icmp_code: None,
payload: None,
};
let layer_match = LayerMatch::Layer4MatchIcmp(layer4_icmp);
let buff = packet::udp_packet_layer3(dst_ipv4, dst_closed_port, src_ipv4, src_port)?;
for _ in 0..MAX_RETRY {
let (response, _rtt) = layer3_ipv4_send(
dst_ipv4,
src_ipv4,
&buff,
vec![layer_match.clone()],
timeout,
true,
)?;
if response.len() > 0 {
let rr = RequestResponse {
request: buff,
response,
};
let u1 = U1RR { u1: rr };
return Ok(u1);
}
}
let rr = RequestResponse {
request: buff,
response: vec![],
};
let u1 = U1RR { u1: rr };
return Ok(u1);
}
fn send_all_probes(
dst_ipv4: Ipv4Addr,
dst_open_tcp_port: u16,
dst_closed_tcp_port: u16,
dst_closed_udp_port: u16,
src_ipv4: Ipv4Addr,
timeout: Option<Duration>,
) -> Result<AllPacketRR, PistolError> {
debug!("sending SEQ probe");
let seq = send_seq_probes(dst_ipv4, dst_open_tcp_port, src_ipv4, timeout)?;
debug!("sending IE probe");
let ie = send_ie_probes(dst_ipv4, src_ipv4, timeout)?;
debug!("sending ECN probe");
let ecn = send_ecn_probe(dst_ipv4, dst_open_tcp_port, src_ipv4, timeout)?;
debug!("sending TX probe");
let tx = send_tx_probes(
dst_ipv4,
dst_open_tcp_port,
dst_closed_tcp_port,
src_ipv4,
timeout,
)?;
debug!("sending U1 probe");
let u1 = send_u1_probe(dst_ipv4, dst_closed_udp_port, src_ipv4, timeout)?;
let ap = AllPacketRR {
seq,
ie,
ecn,
tx,
u1,
};
Ok(ap)
}
#[derive(Debug, Clone)]
pub struct SEQX {
pub sp: u32,
pub gcd: u32,
pub isr: u32,
pub ti: String,
pub ci: String,
pub ii: String,
pub ss: String,
pub ts: String,
pub r: String,
}
impl SEQX {
pub fn empty() -> SEQX {
SEQX {
sp: 0,
gcd: 0,
isr: 0,
ti: String::new(),
ci: String::new(),
ii: String::new(),
ss: String::new(),
ts: String::new(),
r: String::new(),
}
}
}
impl fmt::Display for SEQX {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.r.as_str() {
"Y" => {
let mut output =
format!("SEQ(SP={:X}%GCD={:X}%ISR={:X}", self.sp, self.gcd, self.isr);
if self.ti.len() > 0 {
let ti_str = format!("%TI={}", self.ti);
output += &ti_str;
}
if self.ci.len() > 0 {
let ci_str = format!("%CI={}", self.ci);
output += &ci_str;
}
if self.ii.len() > 0 {
let ii_str = format!("%II={}", self.ii);
output += &ii_str;
}
if self.ss.len() > 0 {
let ss_str = format!("%SS={}", self.ss);
output += &ss_str;
}
if self.ts.len() > 0 {
let ts_str = format!("%TS={}", self.ts);
output += &ts_str;
}
output += ")";
write!(f, "{}", output)
}
_ => {
let output = format!("SEQ(R={})", self.r);
write!(f, "{}", output)
}
}
}
}
pub fn seq_fingerprint(ap: &AllPacketRR) -> Result<SEQX, PistolError> {
let rynum = |rvec: Vec<String>| -> usize {
let mut num = 0;
for r in rvec {
if r == "Y" {
num += 1;
}
}
num
};
let r1 = tcp_udp_icmp_r(&ap.seq.seq1.response)?;
let r2 = tcp_udp_icmp_r(&ap.seq.seq2.response)?;
let r3 = tcp_udp_icmp_r(&ap.seq.seq3.response)?;
let r4 = tcp_udp_icmp_r(&ap.seq.seq4.response)?;
let r5 = tcp_udp_icmp_r(&ap.seq.seq5.response)?;
let r6 = tcp_udp_icmp_r(&ap.seq.seq6.response)?;
let rvec = vec![r1, r2, r3, r4, r5, r6];
let num = rynum(rvec);
let (r, sp, gcd, isr, ti, ci, ii, ss, ts) = if num >= 4 {
let (gcd, diff) = tcp_gcd(&ap.seq)?; let elapsed = ap.seq.elapsed / 6.0;
let (isr, seq_rates) = tcp_isr(diff, elapsed as f64)?;
let sp = tcp_sp(seq_rates, gcd)?;
let (ti, ci, ii) = tcp_ti_ci_ii(&ap.seq, &ap.tx, &ap.ie)?;
let ss = tcp_ss(&ap.seq, &ap.ie, &ti, &ii)?;
let ts = tcp_ts(&ap.seq)?;
let r = String::from("Y");
(r, sp, gcd, isr, ti, ci, ii, ss, ts)
} else {
let r = String::from("N");
let gcd = 0;
let isr = 0;
let sp = 0;
let ti = String::new();
let ci = String::new();
let ii = String::new();
let ss = String::new();
let ts = String::new();
(r, sp, gcd, isr, ti, ci, ii, ss, ts)
};
Ok(SEQX {
sp,
gcd,
isr,
ti,
ci,
ii,
ss,
ts,
r,
})
}
#[derive(Debug, Clone)]
pub struct OPSX {
pub o1: String,
pub o2: String,
pub o3: String,
pub o4: String,
pub o5: String,
pub o6: String,
pub r: String,
}
impl OPSX {
pub fn empty() -> OPSX {
OPSX {
o1: String::new(),
o2: String::new(),
o3: String::new(),
o4: String::new(),
o5: String::new(),
o6: String::new(),
r: String::new(),
}
}
}
impl fmt::Display for OPSX {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.r.as_str() {
"Y" => {
let mut first_elem = true;
let mut output = String::from("OPS(");
if self.o1.len() > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("O1={}", self.o1)
} else {
format!("%O1={}", self.o1)
};
output += &ox_str;
}
if self.o2.len() > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("O2={}", self.o2)
} else {
format!("%O2={}", self.o2)
};
output += &ox_str;
}
if self.o3.len() > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("O3={}", self.o3)
} else {
format!("%O3={}", self.o3)
};
output += &ox_str;
}
if self.o4.len() > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("O4={}", self.o4)
} else {
format!("%O4={}", self.o4)
};
output += &ox_str;
}
if self.o5.len() > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("O5={}", self.o5)
} else {
format!("%O5={}", self.o5)
};
output += &ox_str;
}
if self.o6.len() > 0 {
let ox_str = if first_elem {
format!("O6={}", self.o6)
} else {
format!("%O6={}", self.o6)
};
output += &ox_str;
}
output += ")";
write!(f, "{}", output)
}
_ => {
let output = format!("OPS(R={})", self.r);
write!(f, "{}", output)
}
}
}
}
pub fn ops_fingerprint(ap: &AllPacketRR) -> Result<OPSX, PistolError> {
let rops = |rvec: Vec<String>| -> bool {
let mut flag = true;
for r in rvec {
if r == "N" {
flag = false;
}
}
flag
};
let r1 = tcp_udp_icmp_r(&ap.seq.seq1.response)?;
let r2 = tcp_udp_icmp_r(&ap.seq.seq2.response)?;
let r3 = tcp_udp_icmp_r(&ap.seq.seq3.response)?;
let r4 = tcp_udp_icmp_r(&ap.seq.seq4.response)?;
let r5 = tcp_udp_icmp_r(&ap.seq.seq5.response)?;
let r6 = tcp_udp_icmp_r(&ap.seq.seq6.response)?;
let rvec = vec![r1, r2, r3, r4, r5, r6];
let flag = rops(rvec);
let r = if flag {
String::from("Y")
} else {
String::from("N")
};
let (o1, o2, o3, o4, o5, o6) = tcp_ox(&ap.seq)?;
Ok(OPSX {
o1,
o2,
o3,
o4,
o5,
o6,
r,
})
}
#[derive(Debug, Clone)]
pub struct WINX {
pub w1: u16,
pub w2: u16,
pub w3: u16,
pub w4: u16,
pub w5: u16,
pub w6: u16,
pub r: String,
}
impl WINX {
pub fn empty() -> WINX {
WINX {
w1: 0,
w2: 0,
w3: 0,
w4: 0,
w5: 0,
w6: 0,
r: String::new(),
}
}
}
impl fmt::Display for WINX {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.r.as_str() {
"Y" => {
let mut first_elem = true;
let mut output = String::from("WIN(");
if self.w1 > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("W1={:X}", self.w1)
} else {
format!("%W1={:X}", self.w1)
};
output += &ox_str;
}
if self.w2 > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("W2={:X}", self.w2)
} else {
format!("%W2={:X}", self.w2)
};
output += &ox_str;
}
if self.w3 > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("W3={:X}", self.w3)
} else {
format!("%W3={:X}", self.w3)
};
output += &ox_str;
}
if self.w4 > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("W4={:X}", self.w4)
} else {
format!("%W4={:X}", self.w4)
};
output += &ox_str;
}
if self.w5 > 0 {
let ox_str = if first_elem {
first_elem = false;
format!("W5={:X}", self.w5)
} else {
format!("%W5={:X}", self.w5)
};
output += &ox_str;
}
if self.w6 > 0 {
let ox_str = if first_elem {
format!("W6={:X}", self.w6)
} else {
format!("%W6={:X}", self.w6)
};
output += &ox_str;
}
output += ")";
write!(f, "{}", output)
}
_ => {
let output = format!("WIN(R={})", self.r);
write!(f, "{}", output)
}
}
}
}
pub fn win_fingerprint(ap: &AllPacketRR) -> Result<WINX, PistolError> {
let rwin = |rvec: Vec<String>| -> bool {
let mut flag = true;
for r in rvec {
if r == "N" {
flag = false;
}
}
flag
};
let r1 = tcp_udp_icmp_r(&ap.seq.seq1.response)?;
let r2 = tcp_udp_icmp_r(&ap.seq.seq2.response)?;
let r3 = tcp_udp_icmp_r(&ap.seq.seq3.response)?;
let r4 = tcp_udp_icmp_r(&ap.seq.seq4.response)?;
let r5 = tcp_udp_icmp_r(&ap.seq.seq5.response)?;
let r6 = tcp_udp_icmp_r(&ap.seq.seq6.response)?;
let rvec = vec![r1, r2, r3, r4, r5, r6];
let flag = rwin(rvec);
let r = if flag {
String::from("Y")
} else {
String::from("N")
};
let (w1, w2, w3, w4, w5, w6) = tcp_wx(&ap.seq)?;
Ok(WINX {
w1,
w2,
w3,
w4,
w5,
w6,
r,
})
}
#[derive(Debug, Clone)]
pub struct ECNX {
pub r: String,
pub df: String,
pub t: Option<u16>, pub tg: u16,
pub w: u16,
pub o: String,
pub cc: String,
pub q: String,
}
impl ECNX {
pub fn empty() -> ECNX {
ECNX {
r: String::new(),
df: String::new(),
t: None,
tg: 0,
w: 0,
o: String::new(),
cc: String::new(),
q: String::new(),
}
}
}
impl fmt::Display for ECNX {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.r.as_str() {
"Y" => {
let mut first_elem = true;
let mut output = String::from("ECN(");
if self.r.len() > 0 {
let r_str = if first_elem {
first_elem = false;
format!("R={}", self.r)
} else {
format!("%R={}", self.r)
};
output += &r_str;
}
if self.df.len() > 0 {
let df_str = if first_elem {
first_elem = false;
format!("DF={}", self.df)
} else {
format!("%DF={}", self.df)
};
output += &df_str;
}
if let Some(t) = self.t {
let t_str = if first_elem {
first_elem = false;
format!("T={:X}", t)
} else {
format!("%T={:X}", t)
};
output += &t_str;
} else if self.tg > 0 {
let tg_str = if first_elem {
first_elem = false;
format!("TG={:X}", self.tg)
} else {
format!("%TG={:X}", self.tg)
};
output += &tg_str;
}
if self.w > 0 {
let w_str = if first_elem {
first_elem = false;
format!("W={:X}", self.w)
} else {
format!("%W={:X}", self.w)
};
output += &w_str;
}
if self.o.len() > 0 {
let o_str = if first_elem {
first_elem = false;
format!("O={}", self.o)
} else {
format!("%O={}", self.o)
};
output += &o_str;
}
if self.cc.len() > 0 {
let cc_str = if first_elem {
first_elem = false;
format!("CC={}", self.cc)
} else {
format!("%CC={}", self.cc)
};
output += &cc_str;
}
let q_str = if first_elem {
format!("Q={}", self.q)
} else {
format!("%Q={}", self.q)
};
output += &q_str;
output += ")";
write!(f, "{}", output)
}
_ => {
let output = format!("ECN(R={})", self.r);
write!(f, "{}", output)
}
}
}
}
pub fn ecn_fingerprint(ap: &AllPacketRR) -> Result<ECNX, PistolError> {
let r = tcp_udp_icmp_r(&ap.ecn.ecn.response)?;
let (df, t, tg, w, o, cc, q) = match r.as_str() {
"Y" => {
let df = tcp_udp_df(&ap.ecn.ecn.response, "ecn")?;
let t = tcp_udp_icmp_t(&ap.ecn.ecn.response, &ap.u1, "ecn")?;
let tg = tcp_udp_icmp_tg(&ap.ecn.ecn.response, "ecn")?;
let w = tcp_w(&ap.ecn.ecn.response, "ecn")?;
let o = tcp_o(&ap.ecn.ecn.response, "ecn")?;
let cc = tcp_cc(&ap.ecn.ecn.response, "ecn")?;
let q = tcp_q(&ap.ecn.ecn.response, "ecn")?;
(df, t, tg, w, o, cc, q)
}
_ => {
let df = String::new();
let t = Some(0);
let tg = 0;
let w = 0;
let o = String::new();
let cc = String::new();
let q = String::new();
(df, t, tg, w, o, cc, q)
}
};
Ok(ECNX {
r,
df,
t,
tg,
w,
o,
cc,
q,
})
}
#[derive(Debug, Clone)]
pub struct TXX {
pub name: String,
pub r: String,
pub df: String,
pub t: Option<u16>,
pub tg: u16,
pub w: u16,
pub s: String,
pub a: String,
pub f: String,
pub o: String,
pub rd: u32, pub q: String,
}
impl TXX {
pub fn empty() -> TXX {
TXX {
name: String::new(),
r: String::new(),
df: String::new(),
t: None,
tg: 0,
w: 0,
s: String::new(),
a: String::new(),
f: String::new(),
o: String::new(),
rd: 0,
q: String::new(),
}
}
}
impl fmt::Display for TXX {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.r.as_str() {
"Y" => {
let mut first_elem = true;
let mut output = format!("{}(", self.name);
if self.r.len() > 0 {
let r_str = if first_elem {
first_elem = false;
format!("R={}", self.r)
} else {
format!("%R={}", self.r)
};
output += &r_str;
}
if self.df.len() > 0 {
let df_str = if first_elem {
first_elem = false;
format!("DF={}", self.df)
} else {
format!("%DF={}", self.df)
};
output += &df_str;
}
if let Some(t) = self.t {
let t_str = if first_elem {
first_elem = false;
format!("T={:X}", t)
} else {
format!("%T={:X}", t)
};
output += &t_str;
} else if self.tg > 0 {
let tg_str = if first_elem {
first_elem = false;
format!("TG={:X}", self.tg)
} else {
format!("%TG={:X}", self.tg)
};
output += &tg_str;
}
if self.name != "T1" {
let w_str = if first_elem {
first_elem = false;
format!("W={:X}", self.w)
} else {
format!("%W={:X}", self.w)
};
output += &w_str;
}
if self.s.len() > 0 {
let s_str = if first_elem {
first_elem = false;
format!("S={}", self.s)
} else {
format!("%S={}", self.s)
};
output += &s_str;
}
if self.a.len() > 0 {
let a_str = if first_elem {
first_elem = false;
format!("A={}", self.a)
} else {
format!("%A={}", self.a)
};
output += &a_str;
}
if self.f.len() > 0 {
let f_str = if first_elem {
first_elem = false;
format!("F={}", self.f)
} else {
format!("%F={}", self.f)
};
output += &f_str;
}
if self.name != "T1" {
let o_str = if first_elem {
first_elem = false;
format!("O={}", self.o)
} else {
format!("%O={}", self.o)
};
output += &o_str;
}
let rd_str = if first_elem {
first_elem = false;
format!("RD={:X}", self.rd)
} else {
format!("%RD={:X}", self.rd)
};
output += &rd_str;
let q_str = if first_elem {
format!("Q={}", self.q)
} else {
format!("%Q={}", self.q)
};
output += &q_str;
output += ")";
write!(f, "{}", output)
}
_ => {
let output = format!("{}(R={})", self.name, self.r);
write!(f, "{}", output)
}
}
}
}
fn tx_fingerprint_func(tx: &RequestResponse, u1rr: &U1RR, name: &str) -> Result<TXX, PistolError> {
let r = tcp_udp_icmp_r(&tx.response)?;
let (df, t, tg, w, s, a, f, o, rd, q) = match r.as_str() {
"Y" => {
let df = tcp_udp_df(&tx.response, &name.to_lowercase())?;
let t = tcp_udp_icmp_t(&tx.response, u1rr, &name.to_lowercase())?;
let tg = tcp_udp_icmp_tg(&tx.response, &name.to_lowercase())?;
let w = tcp_w(&tx.response, &name.to_lowercase())?;
let s = tcp_s(&tx.request, &tx.response, &name.to_lowercase())?;
let a = tcp_a(&tx.request, &tx.response, &name.to_lowercase())?;
let f = tcp_f(&tx.response, &name.to_lowercase())?;
let o = tcp_o(&tx.response, &name.to_lowercase())?;
let rd = tcp_rd(&tx.response, &name.to_lowercase())?;
let q = tcp_q(&tx.response, &name.to_lowercase())?;
(df, t, tg, w, s, a, f, o, rd, q)
}
_ => {
let df = String::new();
let t = Some(0);
let tg = 0;
let w = 0;
let s = String::new();
let a = String::new();
let f = String::new();
let o = String::new();
let rd = 0;
let q = String::new();
(df, t, tg, w, s, a, f, o, rd, q)
}
};
Ok(TXX {
name: name.to_string(),
r,
df,
t,
tg,
w,
s,
a,
f,
o,
rd,
q,
})
}
pub fn tx_fingerprint(
ap: &AllPacketRR,
) -> Result<(TXX, TXX, TXX, TXX, TXX, TXX, TXX), PistolError> {
let t1 = tx_fingerprint_func(&ap.seq.seq1, &ap.u1, "T1")?;
let t2 = tx_fingerprint_func(&ap.tx.t2, &ap.u1, "T2")?;
let t3 = tx_fingerprint_func(&ap.tx.t3, &ap.u1, "T3")?;
let t4 = tx_fingerprint_func(&ap.tx.t4, &ap.u1, "T4")?;
let t5 = tx_fingerprint_func(&ap.tx.t5, &ap.u1, "T5")?;
let t6 = tx_fingerprint_func(&ap.tx.t6, &ap.u1, "T6")?;
let t7 = tx_fingerprint_func(&ap.tx.t7, &ap.u1, "T7")?;
Ok((t1, t2, t3, t4, t5, t6, t7))
}
#[derive(Debug, Clone)]
pub struct U1X {
pub r: String,
pub df: String,
pub t: Option<u16>,
pub tg: u16,
pub ipl: usize,
pub un: u32,
pub ripl: String,
pub rid: String,
pub ripck: String,
pub ruck: String,
pub rud: String,
}
impl U1X {
pub fn empty() -> U1X {
U1X {
r: String::new(),
df: String::new(),
t: None,
tg: 0,
ipl: 0,
un: 0,
ripl: String::new(),
rid: String::new(),
ripck: String::new(),
ruck: String::new(),
rud: String::new(),
}
}
}
impl fmt::Display for U1X {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut first_elem = true;
let mut output = String::from("U1(");
if self.r.len() > 0 {
let r_str = if first_elem {
first_elem = false;
format!("R={}", self.r)
} else {
format!("%R={}", self.r)
};
output += &r_str;
}
if self.df.len() > 0 {
let df_str = if first_elem {
first_elem = false;
format!("DF={}", self.df)
} else {
format!("%DF={}", self.df)
};
output += &df_str;
}
if let Some(t) = self.t {
let t_str = if first_elem {
first_elem = false;
format!("T={:X}", t)
} else {
format!("%T={:X}", t)
};
output += &t_str;
} else if self.tg > 0 {
let tg_str = if first_elem {
first_elem = false;
format!("TG={}", self.tg)
} else {
format!("%TG={}", self.tg)
};
output += &tg_str;
}
if self.ipl > 0 {
let ipl_str = if first_elem {
first_elem = false;
format!("IPL={:X}", self.ipl)
} else {
format!("%IPL={:X}", self.ipl)
};
output += &ipl_str;
}
let un_str = if first_elem {
first_elem = false;
format!("UN={:X}", self.un)
} else {
format!("%UN={:X}", self.un)
};
output += &un_str;
if self.ripl.len() > 0 {
let ripl_str = if first_elem {
first_elem = false;
format!("RIPL={}", self.ripl)
} else {
format!("%RIPL={}", self.ripl)
};
output += &ripl_str;
}
if self.rid.len() > 0 {
let rid_str = if first_elem {
first_elem = false;
format!("RID={}", self.rid)
} else {
format!("%RID={}", self.rid)
};
output += &rid_str;
}
if self.ripck.len() > 0 {
let ripck_str = if first_elem {
first_elem = false;
format!("RIPCK={}", self.ripck)
} else {
format!("%RIPCK={}", self.ripck)
};
output += &ripck_str;
}
if self.ruck.len() > 0 {
let ruck_str = if first_elem {
first_elem = false;
format!("RUCK={}", self.ruck)
} else {
format!("%RUCK={}", self.ruck)
};
output += &ruck_str;
}
if self.rud.len() > 0 {
let rud_str = if first_elem {
format!("RUD={}", self.rud)
} else {
format!("%RUD={}", self.rud)
};
output += &rud_str;
}
output += ")";
write!(f, "{}", output)
}
}
pub fn u1_fingerprint(ap: &AllPacketRR) -> Result<U1X, PistolError> {
let r = tcp_udp_icmp_r(&ap.u1.u1.response)?;
let (df, t, tg, ipl, un, ripl, rid, ripck, ruck, rud) = match r.as_str() {
"Y" => {
let df = tcp_udp_df(&ap.u1.u1.response, "u1")?;
let t = tcp_udp_icmp_t(&ap.u1.u1.response, &ap.u1, "u1")?;
let tg = tcp_udp_icmp_tg(&ap.u1.u1.response, "u1")?;
let ipl = udp_ipl(&ap.u1)?;
let un = udp_un(&ap.u1, "u1")?;
let ripl = udp_ripl(&ap.u1, "u1")?;
let rid = udp_rid(&ap.u1, "u1")?;
let ripck = udp_ripck(&ap.u1, "u1")?;
let ruck = udp_ruck(&ap.u1, "u1")?;
let rud = udp_rud(&ap.u1, "u1")?;
(df, t, tg, ipl, un, ripl, rid, ripck, ruck, rud)
}
_ => {
let df = String::new();
let t = Some(0);
let tg = 0;
let ipl = 0;
let un = 0;
let ripl = String::new();
let rid = String::new();
let ripck = String::new();
let ruck = String::new();
let rud = String::new();
(df, t, tg, ipl, un, ripl, rid, ripck, ruck, rud)
}
};
Ok(U1X {
r,
df,
t,
tg,
ipl,
un,
ripl,
rid,
ripck,
ruck,
rud,
})
}
#[derive(Debug, Clone)]
pub struct IEX {
pub r: String,
pub dfi: String,
pub t: Option<u16>,
pub tg: u16,
pub cd: String,
}
impl IEX {
pub fn empty() -> IEX {
IEX {
r: String::new(),
dfi: String::new(),
t: None,
tg: 0,
cd: String::new(),
}
}
}
impl fmt::Display for IEX {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut first_elem = true;
let mut output = String::from("IE(");
if self.r.len() > 0 {
let r_str = if first_elem {
first_elem = false;
format!("R={}", self.r)
} else {
format!("%R={}", self.r)
};
output += &r_str;
}
if self.dfi.len() > 0 {
let dfi_str = if first_elem {
first_elem = false;
format!("DFI={}", self.dfi)
} else {
format!("%DFI={}", self.dfi)
};
output += &dfi_str;
}
if let Some(t) = self.t {
let t_str = if first_elem {
first_elem = false;
format!("T={:X}", t)
} else {
format!("%T={:X}", t)
};
output += &t_str;
} else if self.tg > 0 {
let tg_str = if first_elem {
first_elem = false;
format!("TG={}", self.tg)
} else {
format!("%TG={}", self.tg)
};
output += &tg_str;
}
if self.cd.len() > 0 {
let cd_str = if first_elem {
format!("CD={}", self.cd)
} else {
format!("%CD={}", self.cd)
};
output += &cd_str;
}
output += ")";
write!(f, "{}", output)
}
}
pub fn ie_fingerprint(ap: &AllPacketRR) -> Result<IEX, PistolError> {
let r1 = tcp_udp_icmp_r(&ap.ie.ie1.response)?;
let r2 = tcp_udp_icmp_r(&ap.ie.ie2.response)?;
let (r, dfi, t, tg, cd) = if r1 == "Y" && r2 == "Y" {
let r = String::from("Y");
let dfi = icmp_dfi(&ap.ie, "ie")?;
let t = tcp_udp_icmp_t(&ap.ie.ie1.response, &ap.u1, "ie")?;
let tg = tcp_udp_icmp_tg(&ap.ie.ie1.response, "ie")?;
let cd = icmp_cd(&ap.ie, "ie")?;
(r, dfi, t, tg, cd)
} else {
let r = String::from("N");
let dfi = String::new();
let t = Some(0);
let tg = 0;
let cd = String::new();
(r, dfi, t, tg, cd)
};
Ok(IEX { r, dfi, t, tg, cd })
}
fn sort_pick(arr: &[OsInfo], top_k: usize) -> Vec<OsInfo> {
let mut ret = Vec::new();
let mut arr = arr.to_vec();
fn pick(arr: &[OsInfo]) -> (OsInfo, Vec<OsInfo>) {
let mut max_score = 0;
let mut max_score_loc = 0;
let mut arr = arr.to_vec();
let mut i = 0;
for a in &arr {
if a.score > max_score {
max_score = a.score;
max_score_loc = i;
}
i += 1;
}
let ret = arr.remove(max_score_loc);
(ret, arr)
}
let mut count = top_k;
let mut last_score = 0;
while count > 0 {
let (max, new_arr) = pick(&arr);
if max.score != last_score {
count -= 1;
last_score = max.score;
}
arr = new_arr;
ret.push(max)
}
ret
}
pub fn os_probe_thread(
dst_ipv4: Ipv4Addr,
dst_open_tcp_port: u16,
dst_closed_tcp_port: u16,
dst_closed_udp_port: u16,
src_ipv4: Ipv4Addr,
nmap_os_db: Vec<NmapOSDB>,
top_k: usize,
timeout: Option<Duration>,
) -> Result<(Fingerprint, Vec<OsInfo>), PistolError> {
let (dst_mac, _interface) =
RouteVia::get_dst_mac_and_src_if(dst_ipv4.into(), src_ipv4.into(), timeout)?;
debug!("send all probes now");
let ap = send_all_probes(
dst_ipv4,
dst_open_tcp_port,
dst_closed_tcp_port,
dst_closed_udp_port,
src_ipv4,
timeout,
)?;
debug!("send all probes done");
let good_results = true;
debug!("send trace packet");
let hops = icmp_trace(dst_ipv4.into(), src_ipv4.into(), timeout)?;
let scan = get_scan_line(
dst_mac,
dst_open_tcp_port,
dst_closed_tcp_port,
dst_closed_udp_port,
dst_ipv4.into(),
hops,
good_results,
);
let seqx = seq_fingerprint(&ap);
match seqx {
Ok(seqx) => {
debug!("SEQX fingerprint parse done");
let opsx = ops_fingerprint(&ap)?;
debug!("OPSX parse done");
let winx = win_fingerprint(&ap)?;
debug!("WINX parse done");
let ecnx = ecn_fingerprint(&ap)?;
debug!("ECNX parse done");
let (t1x, t2x, t3x, t4x, t5x, t6x, t7x) = tx_fingerprint(&ap)?;
debug!("TX parse done");
let u1x = u1_fingerprint(&ap)?;
debug!("U1X parse done");
let iex = ie_fingerprint(&ap)?;
debug!("IEX parse done");
debug!("generate the fingerprint");
let target_fingerprint = Fingerprint {
scan,
seqx,
opsx,
winx,
ecnx,
t1x,
t2x,
t3x,
t4x,
t5x,
t6x,
t7x,
u1x,
iex,
};
let mut sort_vec = Vec::new();
for db in &nmap_os_db {
let (score, total) = db.check(&target_fingerprint);
let osinfo = OsInfo {
name: db.name.clone(),
class: db.class.clone(),
score,
total,
db: db.clone(),
cpe: db.cpe.clone(),
};
sort_vec.push(osinfo);
}
let detect_rets = sort_pick(&sort_vec, top_k);
if detect_rets.len() > 0 {
debug!("ipv4 fingerprint:\n{}", target_fingerprint);
Ok((target_fingerprint, detect_rets))
} else {
Err(PistolError::OSDetectResultsNullError)
}
}
Err(e) => Err(e),
}
}
#[cfg(test)]
mod tests {
use pnet::packet::ipv4::Ipv4Packet;
use super::*;
use crate::PistolLogger;
use crate::PistolRunner;
use tracing::error;
use tracing::info;
#[test]
fn test_send_probes() {
let _pr = PistolRunner::init(
PistolLogger::Debug,
Some(String::from("debug2.pcapng")),
None, )
.unwrap();
let build_ipv4_packet = |buff: &[u8], debug_info: &str| {
if let Some(_ipv4_packet) = Ipv4Packet::new(buff) {
info!("{} build ipv4 success", debug_info);
} else {
error!("{} build ipv4 failed", debug_info);
}
};
let dst_ipv4 = Ipv4Addr::new(192, 168, 1, 4);
let dst_open_tcp_port = 3389;
let src_ipv4 = Ipv4Addr::new(192, 168, 5, 3);
let timeout = Some(Duration::from_secs_f64(1.0));
let dst_closed_tcp_port = 7890;
let dst_closed_udp_port = 8901;
debug!("send all probes now");
let seq = send_seq_probes(dst_ipv4, dst_open_tcp_port, src_ipv4, timeout).unwrap();
build_ipv4_packet(&seq.seq1.response, "seq1");
build_ipv4_packet(&seq.seq2.response, "seq2");
build_ipv4_packet(&seq.seq3.response, "seq3");
build_ipv4_packet(&seq.seq4.response, "seq4");
build_ipv4_packet(&seq.seq5.response, "seq5");
let ie = send_ie_probes(dst_ipv4, src_ipv4, timeout).unwrap();
build_ipv4_packet(&ie.ie1.response, "ie1");
build_ipv4_packet(&ie.ie2.response, "ie2");
let ecn = send_ecn_probe(dst_ipv4, dst_open_tcp_port, src_ipv4, timeout).unwrap();
build_ipv4_packet(&ecn.ecn.response, "ecn");
let tx = send_tx_probes(
dst_ipv4,
dst_open_tcp_port,
dst_closed_tcp_port,
src_ipv4,
timeout,
)
.unwrap();
build_ipv4_packet(&tx.t2.response, "t2");
build_ipv4_packet(&tx.t3.response, "t3");
build_ipv4_packet(&tx.t4.response, "t4");
build_ipv4_packet(&tx.t5.response, "t5");
build_ipv4_packet(&tx.t6.response, "t6");
build_ipv4_packet(&tx.t7.response, "t7");
let u1 = send_u1_probe(dst_ipv4, dst_closed_udp_port, src_ipv4, timeout).unwrap();
build_ipv4_packet(&u1.u1.response, "u1");
debug!("send all probes done");
}
}