use pnet::datalink::MacAddr;
use pnet::packet::icmpv6::Icmpv6Type;
use std::collections::HashMap;
use std::fmt;
use std::iter::zip;
use std::net::Ipv6Addr;
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::error::PistolError;
use crate::layer::Layer3Match;
use crate::layer::Layer4MatchIcmpv6;
use crate::layer::Layer4MatchTcpUdp;
use crate::layer::LayerMatch;
use crate::layer::layer3_ipv6_send;
use crate::os::Linear;
use crate::os::OsInfo6;
use crate::os::operator6::apply_scale;
use crate::os::operator6::vectorize;
use crate::os::osscan::get_scan_line;
use crate::os::packet6;
use crate::os::rr::AllPacketRR6;
use crate::os::rr::IERR6;
use crate::os::rr::NXRR6;
use crate::os::rr::RequestResponse;
use crate::os::rr::SEQRR6;
use crate::os::rr::TECNRR6;
use crate::os::rr::TXRR6;
use crate::os::rr::U1RR6;
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;
fn p_reduce(p: &str) -> String {
let mut new_p = String::new();
let mut count = 0;
let p_chars: Vec<char> = p.chars().collect();
let mut i = 0;
loop {
if i + 1 > p_chars.len() {
break;
}
let ch_i = p_chars[i];
let ch_i_next = if i + 1 >= p_chars.len() {
0 as char
} else {
p_chars[i + 1]
};
let ch_i_p_2 = if i + 2 >= p_chars.len() {
0 as char
} else {
p_chars[i + 2]
};
let ch_i_next_p_2 = if i + 3 >= p_chars.len() {
0 as char
} else {
p_chars[i + 3]
};
if ch_i == ch_i_p_2 && ch_i_next == ch_i_next_p_2 {
count += 1;
i += 2;
} else {
if count != 0 {
i += 2;
} else {
i += 1;
}
if count == 0 {
new_p += &format!("{}", ch_i);
} else {
new_p += &format!("{}{}{{{}}}", ch_i, ch_i_next, count + 1);
}
count = 0;
}
}
new_p.trim().to_string()
}
fn p_as_nmap_format(input: &[u8]) -> String {
let mut p = String::new();
let ip_start = 16;
let ip_end = ip_start + 32 * 2;
for (i, b) in input.iter().enumerate() {
if i >= ip_start && i < ip_end {
p += "X";
} else {
p += &format!("{:x}", b);
}
}
let new_p = p_reduce(&p);
new_p
}
#[derive(Debug, Clone)]
pub struct SEQX6 {
pub name: String,
pub rr: RequestResponse,
pub st: Duration,
pub rt: Duration,
}
impl SEQX6 {
pub fn empty() -> SEQX6 {
SEQX6 {
name: String::new(),
rr: RequestResponse::empty(),
st: Duration::new(0, 0),
rt: Duration::new(0, 0),
}
}
}
impl fmt::Display for SEQX6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output = if self.rr.response.len() > 0 {
let output = format!(
"{}(P={}%ST={:.6}%RT={:.6})",
self.name,
p_as_nmap_format(&self.rr.response),
self.st.as_secs_f64(),
self.rt.as_secs_f64()
);
output
} else {
String::new()
};
write!(f, "{}", output)
}
}
#[derive(Debug, Clone)]
pub struct IEX6 {
pub name: String,
pub rr: RequestResponse,
pub st: Duration,
pub rt: Duration,
}
impl IEX6 {
pub fn empty() -> IEX6 {
IEX6 {
name: String::new(),
rr: RequestResponse::empty(),
st: Duration::new(0, 0),
rt: Duration::new(0, 0),
}
}
}
impl fmt::Display for IEX6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output = if self.rr.response.len() > 0 {
let output = format!(
"{}(P={}%ST={:.6}%RT={:.6})",
self.name,
p_as_nmap_format(&self.rr.response),
self.st.as_secs_f64(),
self.rt.as_secs_f64()
);
output
} else {
String::new()
};
write!(f, "{}", output)
}
}
#[derive(Debug, Clone)]
pub struct NX6 {
pub name: String,
pub rr: RequestResponse,
pub st: Duration,
pub rt: Duration,
}
impl NX6 {
pub fn empty() -> NX6 {
NX6 {
name: String::new(),
rr: RequestResponse::empty(),
st: Duration::new(0, 0),
rt: Duration::new(0, 0),
}
}
}
impl fmt::Display for NX6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output = if self.rr.response.len() > 0 {
let output = format!(
"{}(P={}%ST={:.6}%RT={:.6})",
self.name,
p_as_nmap_format(&self.rr.response),
self.st.as_secs_f64(),
self.rt.as_secs_f64()
);
output
} else {
String::new()
};
write!(f, "{}", output)
}
}
#[derive(Debug, Clone)]
pub struct U1X6 {
pub rr: RequestResponse,
pub st: Duration,
pub rt: Duration,
}
impl U1X6 {
pub fn empty() -> U1X6 {
U1X6 {
rr: RequestResponse::empty(),
st: Duration::new(0, 0),
rt: Duration::new(0, 0),
}
}
}
impl fmt::Display for U1X6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output = if self.rr.response.len() > 0 {
let output = format!(
"U1(P={}%ST={:.6}%RT={:.6})",
p_as_nmap_format(&self.rr.response),
self.st.as_secs_f64(),
self.rt.as_secs_f64()
);
output
} else {
String::new()
};
write!(f, "{}", output)
}
}
#[derive(Debug, Clone)]
pub struct TECNX6 {
pub rr: RequestResponse,
pub st: Duration,
pub rt: Duration,
}
impl TECNX6 {
pub fn empty() -> TECNX6 {
TECNX6 {
rr: RequestResponse::empty(),
st: Duration::new(0, 0),
rt: Duration::new(0, 0),
}
}
}
impl fmt::Display for TECNX6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output = if self.rr.response.len() > 0 {
let output = format!(
"TECN(P={}%ST={:.6}%RT={:.6})",
p_as_nmap_format(&self.rr.response),
self.st.as_secs_f64(),
self.rt.as_secs_f64()
);
output
} else {
String::new()
};
write!(f, "{}", output)
}
}
#[derive(Debug, Clone)]
pub struct TX6 {
pub name: String,
pub rr: RequestResponse,
pub st: Duration,
pub rt: Duration,
}
impl TX6 {
pub fn empty() -> TX6 {
TX6 {
name: String::new(),
rr: RequestResponse::empty(),
st: Duration::new(0, 0),
rt: Duration::new(0, 0),
}
}
}
impl fmt::Display for TX6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output = if self.rr.response.len() > 0 {
let output = format!(
"{}(P={}%ST={:.6}%RT={:.6})",
self.name,
p_as_nmap_format(&self.rr.response),
self.st.as_secs_f64(),
self.rt.as_secs_f64()
);
output
} else {
String::new()
};
write!(f, "{}", output)
}
}
#[derive(Debug, Clone)]
pub struct Fingerprint6 {
pub scan: String,
pub s1x: SEQX6,
pub s2x: SEQX6,
pub s3x: SEQX6,
pub s4x: SEQX6,
pub s5x: SEQX6,
pub s6x: SEQX6,
pub ie1x: IEX6,
pub ie2x: IEX6,
pub ni: NX6,
pub ns: NX6,
pub u1x: U1X6,
pub tecnx: TECNX6,
pub t2x: TX6,
pub t3x: TX6,
pub t4x: TX6,
pub t5x: TX6,
pub t6x: TX6,
pub t7x: TX6,
pub extra: String,
pub novelty: f64,
pub status: bool,
}
impl Fingerprint6 {
pub fn empty() -> Fingerprint6 {
Fingerprint6 {
scan: String::new(),
s1x: SEQX6::empty(),
s2x: SEQX6::empty(),
s3x: SEQX6::empty(),
s4x: SEQX6::empty(),
s5x: SEQX6::empty(),
s6x: SEQX6::empty(),
ie1x: IEX6::empty(),
ie2x: IEX6::empty(),
ni: NX6::empty(),
ns: NX6::empty(),
u1x: U1X6::empty(),
tecnx: TECNX6::empty(),
t2x: TX6::empty(),
t3x: TX6::empty(),
t4x: TX6::empty(),
t5x: TX6::empty(),
t6x: TX6::empty(),
t7x: TX6::empty(),
extra: String::new(),
novelty: 0.0,
status: false,
}
}
}
impl Fingerprint6 {
pub fn nmap_format(&self) -> String {
let interval = 71; 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()
}
}
impl fmt::Display for Fingerprint6 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut output = String::new();
let scan_str = format!("{}", self.scan);
let s1x_str = format!("\n{}", self.s1x);
let s2x_str = format!("\n{}", self.s2x);
let s3x_str = format!("\n{}", self.s3x);
let s4x_str = format!("\n{}", self.s4x);
let s5x_str = format!("\n{}", self.s5x);
let s6x_str = format!("\n{}", self.s6x);
let ie1x_str = format!("\n{}", self.ie1x);
let ie2x_str = format!("\n{}", self.ie2x);
let nsx_str = format!("\n{}", self.ns);
let u1x_str = format!("\n{}", self.u1x);
let tecnx_str = format!("\n{}", self.tecnx);
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 extra_str = format!("\nEXTRA(FL={})", self.extra);
if scan_str.trim().len() > 0 {
output += &scan_str;
}
if s1x_str.trim().len() > 0 {
output += &s1x_str;
}
if s2x_str.trim().len() > 0 {
output += &s2x_str;
}
if s3x_str.trim().len() > 0 {
output += &s3x_str;
}
if s4x_str.trim().len() > 0 {
output += &s4x_str;
}
if s5x_str.trim().len() > 0 {
output += &s5x_str;
}
if s6x_str.trim().len() > 0 {
output += &s6x_str;
}
if ie1x_str.trim().len() > 0 {
output += &ie1x_str;
}
if ie2x_str.trim().len() > 0 {
output += &ie2x_str;
}
if nsx_str.trim().len() > 0 {
output += &nsx_str;
}
if u1x_str.trim().len() > 0 {
output += &u1x_str;
}
if tecnx_str.trim().len() > 0 {
output += &tecnx_str;
}
if t2x_str.trim().len() > 0 {
output += &t2x_str;
}
if t3x_str.trim().len() > 0 {
output += &t3x_str;
}
if t4x_str.trim().len() > 0 {
output += &t4x_str;
}
if t5x_str.trim().len() > 0 {
output += &t5x_str;
}
if t6x_str.trim().len() > 0 {
output += &t6x_str;
}
if t7x_str.trim().len() > 0 {
output += &t7x_str;
}
if extra_str.trim().len() > 0 {
output += &extra_str;
}
write!(f, "{}", output)
}
}
fn send_seq_probes(
dst_ipv6: Ipv6Addr,
dst_open_port: u16,
src_ipv6: Ipv6Addr,
timeout: Option<Duration>,
start_time: Instant,
) -> Result<SEQRR6, 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 = packet6::seq_packet_1_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[0])?;
let buff_2 = packet6::seq_packet_2_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[1])?;
let buff_3 = packet6::seq_packet_3_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[2])?;
let buff_4 = packet6::seq_packet_4_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[3])?;
let buff_5 = packet6::seq_packet_5_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[4])?;
let buff_6 = packet6::seq_packet_6_layer3(dst_ipv6, dst_open_port, src_ipv6, 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 scan6 seq {} layer3", i + 1);
let name = Box::leak(name_string.into_boxed_str());
let layer3 = Layer3Match {
name,
layer2: None,
src_addr: Some(dst_ipv6.into()),
dst_addr: Some(src_ipv6.into()),
};
let name_string = format!("os scan6 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 st = start_time.elapsed();
let ret = layer3_ipv6_send(
dst_ipv6,
src_ipv6,
&buff,
vec![layer_match.clone()],
timeout,
true,
);
let rt = start_time.elapsed();
match ret {
Ok((response, rtt)) => {
if response.len() > 0 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt)), st, rt));
break;
} else if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt)), st, rt));
}
}
Err(e) => {
if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Err(e), st, rt));
}
}
}
}
});
sleep(Duration::from_millis(100));
}
let mut seqs = HashMap::new();
let mut sts = HashMap::new();
let mut rts = HashMap::new();
let iter = rx.into_iter().take(6);
for (i, request, ret, st, rt) in iter {
let (response, _rtt) = ret?;
let rr = RequestResponse { request, response };
seqs.insert(i, rr);
sts.insert(i, st);
rts.insert(i, rt);
}
let elapsed = start.elapsed().as_secs_f64();
let seq1: RequestResponse = seqs.get(&0).map_or(RequestResponse::empty(), |x| x.clone());
let seq2 = seqs.get(&1).map_or(RequestResponse::empty(), |x| x.clone());
let seq3 = seqs.get(&2).map_or(RequestResponse::empty(), |x| x.clone());
let seq4 = seqs.get(&3).map_or(RequestResponse::empty(), |x| x.clone());
let seq5 = seqs.get(&4).map_or(RequestResponse::empty(), |x| x.clone());
let seq6 = seqs.get(&5).map_or(RequestResponse::empty(), |x| x.clone());
let st1 = sts.get(&0).map_or(Duration::new(0, 0), |x| *x);
let st2 = sts.get(&1).map_or(Duration::new(0, 0), |x| *x);
let st3 = sts.get(&2).map_or(Duration::new(0, 0), |x| *x);
let st4 = sts.get(&3).map_or(Duration::new(0, 0), |x| *x);
let st5 = sts.get(&4).map_or(Duration::new(0, 0), |x| *x);
let st6 = sts.get(&5).map_or(Duration::new(0, 0), |x| *x);
let rt1 = rts.get(&0).map_or(Duration::new(0, 0), |x| *x);
let rt2 = rts.get(&1).map_or(Duration::new(0, 0), |x| *x);
let rt3 = rts.get(&2).map_or(Duration::new(0, 0), |x| *x);
let rt4 = rts.get(&3).map_or(Duration::new(0, 0), |x| *x);
let rt5 = rts.get(&4).map_or(Duration::new(0, 0), |x| *x);
let rt6 = rts.get(&5).map_or(Duration::new(0, 0), |x| *x);
let seqrr = SEQRR6 {
seq1,
seq2,
seq3,
seq4,
seq5,
seq6,
elapsed,
st1,
rt1,
st2,
rt2,
st3,
rt3,
st4,
rt4,
st5,
rt5,
st6,
rt6,
};
Ok(seqrr)
}
fn send_ie_probes(
dst_ipv6: Ipv6Addr,
src_ipv6: Ipv6Addr,
timeout: Option<Duration>,
start_time: Instant,
) -> Result<IERR6, PistolError> {
let (tx, rx) = channel();
let buff_1 = packet6::ie_packet_1_layer3(dst_ipv6, src_ipv6)?;
let buff_2 = packet6::ie_packet_2_layer3(dst_ipv6, src_ipv6)?;
let buffs = vec![buff_1, buff_2];
let layer3 = Layer3Match {
name: "os scan6 ie layer3",
layer2: None,
src_addr: Some(dst_ipv6.into()),
dst_addr: Some(src_ipv6.into()),
};
let layer4_icmpv6_1 = Layer4MatchIcmpv6 {
name: "os scan6 ie icmpv6 type 1",
layer3: Some(layer3),
icmpv6_type: Some(Icmpv6Type(1)),
icmpv6_code: None,
payload: None,
};
let layer4_icmpv6_2 = Layer4MatchIcmpv6 {
name: "os scan6 ie icmpv6 type 2",
layer3: Some(layer3),
icmpv6_type: Some(Icmpv6Type(2)),
icmpv6_code: None,
payload: None,
};
let layer4_icmpv6_3 = Layer4MatchIcmpv6 {
name: "os scan6 ie icmpv6 type 3",
layer3: Some(layer3),
icmpv6_type: Some(Icmpv6Type(3)),
icmpv6_code: None,
payload: None,
};
let layer4_icmpv6_4 = Layer4MatchIcmpv6 {
name: "os scan6 ie icmpv6 type 4",
layer3: Some(layer3),
icmpv6_type: Some(Icmpv6Type(4)),
icmpv6_code: None,
payload: None,
};
let layer_match_1 = LayerMatch::Layer4MatchIcmpv6(layer4_icmpv6_1);
let layer_match_2 = LayerMatch::Layer4MatchIcmpv6(layer4_icmpv6_2);
let layer_match_3 = LayerMatch::Layer4MatchIcmpv6(layer4_icmpv6_3);
let layer_match_4 = LayerMatch::Layer4MatchIcmpv6(layer4_icmpv6_4);
for (i, buff) in buffs.into_iter().enumerate() {
let tx = tx.clone();
for retry_time in 0..MAX_RETRY {
let st = start_time.elapsed();
let ret = layer3_ipv6_send(
dst_ipv6,
src_ipv6,
&buff,
vec![
layer_match_1.clone(),
layer_match_2.clone(),
layer_match_3.clone(),
layer_match_4.clone(),
],
timeout,
true,
);
let rt = start_time.elapsed();
match ret {
Ok((response, rtt)) => {
if response.len() > 0 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt)), st, rt));
break;
} else if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt)), st, rt));
}
}
Err(e) => {
if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Err(e), st, rt));
}
}
}
}
}
let mut ies = HashMap::new();
let mut sts = HashMap::new();
let mut rts = HashMap::new();
let iter = rx.into_iter().take(2);
for (i, request, ret, st, rt) in iter {
let (response, _rtt) = ret?;
let rr = RequestResponse { request, response };
ies.insert(i, rr);
sts.insert(i, st);
rts.insert(i, rt);
}
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 st1 = sts.get(&0).map_or(Duration::new(0, 0), |x| *x);
let st2 = sts.get(&1).map_or(Duration::new(0, 0), |x| *x);
let rt1 = rts.get(&0).map_or(Duration::new(0, 0), |x| *x);
let rt2 = rts.get(&1).map_or(Duration::new(0, 0), |x| *x);
let ie = IERR6 {
ie1,
ie2,
st1,
rt1,
st2,
rt2,
};
Ok(ie)
}
fn send_nx_probes(
dst_ipv6: Ipv6Addr,
src_ipv6: Ipv6Addr,
src_mac: MacAddr,
timeout: Option<Duration>,
start_time: Instant,
) -> Result<NXRR6, PistolError> {
let (tx, rx) = channel();
let buff_1 = packet6::ni_packet_layer3(dst_ipv6, src_ipv6)?;
let buff_2 = packet6::ns_packet_layer3(dst_ipv6, src_ipv6, src_mac)?;
let buffs = vec![buff_1, buff_2];
let layer3 = Layer3Match {
name: "os scan6 nx layer3",
layer2: None,
src_addr: Some(dst_ipv6.into()),
dst_addr: Some(src_ipv6.into()),
};
let layer4_icmpv6 = Layer4MatchIcmpv6 {
name: "os scan6 nx icmpv6",
layer3: Some(layer3),
icmpv6_type: None,
icmpv6_code: None,
payload: None,
};
let layer_match = LayerMatch::Layer4MatchIcmpv6(layer4_icmpv6);
for (i, buff) in buffs.into_iter().enumerate() {
let tx = tx.clone();
for retry_time in 0..MAX_RETRY {
let st = start_time.elapsed();
let ret = layer3_ipv6_send(
dst_ipv6,
src_ipv6,
&buff,
vec![layer_match.clone()],
timeout,
true,
);
let rt = start_time.elapsed();
match ret {
Ok((response, rtt)) => {
if response.len() > 0 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt)), st, rt));
break;
} else if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt)), st, rt));
}
}
Err(e) => {
if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Err(e), st, rt));
}
}
}
}
}
let mut nxs = HashMap::new();
let mut sts = HashMap::new();
let mut rts = HashMap::new();
let iter = rx.into_iter().take(2);
for (i, request, ret, st, rt) in iter {
let (response, _rtt) = ret?;
let rr = RequestResponse { request, response };
nxs.insert(i, rr);
sts.insert(i, st);
rts.insert(i, rt);
}
let ni = nxs.get(&0).map_or(RequestResponse::empty(), |x| x.clone());
let ns = nxs.get(&1).map_or(RequestResponse::empty(), |x| x.clone());
let sti = sts.get(&0).map_or(Duration::new(0, 0), |x| *x);
let sts = sts.get(&1).map_or(Duration::new(0, 0), |x| *x);
let rti = rts.get(&0).map_or(Duration::new(0, 0), |x| *x);
let rts = rts.get(&1).map_or(Duration::new(0, 0), |x| *x);
let ns = NXRR6 {
ni,
ns,
sti,
rti,
sts,
rts,
};
Ok(ns)
}
fn send_u1_probe(
dst_ipv6: Ipv6Addr,
dst_closed_port: u16, src_ipv6: Ipv6Addr,
timeout: Option<Duration>,
start_time: Instant,
) -> Result<U1RR6, PistolError> {
let src_port = random_port();
let buff = packet6::udp_packet_layer3(dst_ipv6, dst_closed_port, src_ipv6, src_port)?;
let layer3 = Layer3Match {
name: "os scan6 u1 layer3",
layer2: None,
src_addr: Some(dst_ipv6.into()),
dst_addr: Some(src_ipv6.into()),
};
let layer4_icmpv6 = Layer4MatchIcmpv6 {
name: "os scan6 u1 icmpv6",
layer3: Some(layer3),
icmpv6_type: None,
icmpv6_code: None,
payload: None,
};
let layer_match = LayerMatch::Layer4MatchIcmpv6(layer4_icmpv6);
let mut st = start_time.elapsed();
let mut rt = start_time.elapsed();
for _retry_time in 0..MAX_RETRY {
st = start_time.elapsed();
let (response, _rtt) = layer3_ipv6_send(
dst_ipv6,
src_ipv6,
&buff,
vec![layer_match.clone()],
timeout,
true,
)?;
rt = start_time.elapsed();
if response.len() > 0 {
let rr = RequestResponse {
request: buff,
response,
};
let u1 = U1RR6 { u1: rr, st, rt };
return Ok(u1);
}
}
let rr = RequestResponse {
request: buff,
response: vec![],
};
let u1 = U1RR6 { u1: rr, st, rt };
return Ok(u1);
}
fn send_tecn_probe(
dst_ipv6: Ipv6Addr,
dst_open_port: u16,
src_ipv6: Ipv6Addr,
timeout: Option<Duration>,
start_time: Instant,
) -> Result<TECNRR6, PistolError> {
let src_port = random_port();
let layer3 = Layer3Match {
name: "os scan6 tecn layer3",
layer2: None,
src_addr: Some(dst_ipv6.into()),
dst_addr: Some(src_ipv6.into()),
};
let layer4_tcp_udp = Layer4MatchTcpUdp {
name: "os scan6 tecn 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 = packet6::tecn_packet_layer3(dst_ipv6, dst_open_port, src_ipv6, src_port)?;
let st = start_time.elapsed();
let (response, _rtt) =
layer3_ipv6_send(dst_ipv6, src_ipv6, &buff, vec![layer_match], timeout, true)?;
let rt = start_time.elapsed();
let rr = RequestResponse {
request: buff,
response,
};
let tecn = TECNRR6 { tecn: rr, st, rt };
Ok(tecn)
}
fn send_tx_probes(
dst_ipv6: Ipv6Addr,
src_ipv6: Ipv6Addr,
dst_open_port: u16,
dst_closed_port: u16,
timeout: Option<Duration>,
start_time: Instant,
) -> Result<TXRR6, 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 scan6 tx layer3",
layer2: None,
src_addr: Some(dst_ipv6.into()),
dst_addr: Some(src_ipv6.into()),
};
let layer4_tcp_udp_2 = Layer4MatchTcpUdp {
name: "os scan6 tx tcp_udp 2",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_ports[0]),
};
let layer4_tcp_udp_3 = Layer4MatchTcpUdp {
name: "os scan6 tx tcp_udp 3",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_ports[1]),
};
let layer4_tcp_udp_4 = Layer4MatchTcpUdp {
name: "os scan6 tx tcp_udp 4",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_ports[2]),
};
let layer4_tcp_udp_5 = Layer4MatchTcpUdp {
name: "os scan6 tx tcp_udp 5",
layer3: Some(layer3),
src_port: Some(dst_closed_port),
dst_port: Some(src_ports[3]),
};
let layer4_tcp_udp_6 = Layer4MatchTcpUdp {
name: "os scan6 tx tcp_udp 6",
layer3: Some(layer3),
src_port: Some(dst_closed_port),
dst_port: Some(src_ports[4]),
};
let layer4_tcp_udp_7 = Layer4MatchTcpUdp {
name: "os scan6 tx tcp_udp 7",
layer3: Some(layer3),
src_port: Some(dst_closed_port),
dst_port: Some(src_ports[5]),
};
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 layer_match_7 = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp_7);
let ms = vec![
layer_match_2,
layer_match_3,
layer_match_4,
layer_match_5,
layer_match_6,
layer_match_7,
];
let buff_2 = packet6::t2_packet_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[0])?;
let buff_3 = packet6::t3_packet_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[1])?;
let buff_4 = packet6::t4_packet_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[2])?;
let buff_5 = packet6::t5_packet_layer3(dst_ipv6, dst_closed_port, src_ipv6, src_ports[3])?;
let buff_6 = packet6::t6_packet_layer3(dst_ipv6, dst_closed_port, src_ipv6, src_ports[4])?;
let buff_7 = packet6::t7_packet_layer3(dst_ipv6, dst_closed_port, src_ipv6, 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 st = start_time.elapsed();
let ret =
layer3_ipv6_send(dst_ipv6, src_ipv6, &buff, vec![m.clone()], timeout, true);
let rt = start_time.elapsed();
match ret {
Ok((response, rtt)) => {
if response.len() > 0 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt)), st, rt));
break;
} else if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Ok((response, rtt)), st, rt));
}
}
Err(e) => {
if retry_time == MAX_RETRY - 1 {
let _ = tx.send((i, buff.to_vec(), Err(e), st, rt));
}
}
}
}
});
sleep(Duration::from_millis(100));
}
let mut txs = HashMap::new();
let mut sts = HashMap::new();
let mut rts = HashMap::new();
let iter = rx.into_iter().take(6);
for (i, request, ret, st, rt) in iter {
let (response, _rtt) = ret?;
let rr = RequestResponse { request, response };
txs.insert(i, rr);
sts.insert(i, st);
rts.insert(i, rt);
}
let t2 = txs.get(&0).map_or(RequestResponse::empty(), |x| x.clone());
let t3 = txs.get(&1).map_or(RequestResponse::empty(), |x| x.clone());
let t4 = txs.get(&2).map_or(RequestResponse::empty(), |x| x.clone());
let t5 = txs.get(&3).map_or(RequestResponse::empty(), |x| x.clone());
let t6 = txs.get(&4).map_or(RequestResponse::empty(), |x| x.clone());
let t7 = txs.get(&5).map_or(RequestResponse::empty(), |x| x.clone());
let st2 = sts.get(&0).map_or(Duration::new(0, 0), |x| *x);
let st3 = sts.get(&1).map_or(Duration::new(0, 0), |x| *x);
let st4 = sts.get(&2).map_or(Duration::new(0, 0), |x| *x);
let st5 = sts.get(&3).map_or(Duration::new(0, 0), |x| *x);
let st6 = sts.get(&4).map_or(Duration::new(0, 0), |x| *x);
let st7 = sts.get(&5).map_or(Duration::new(0, 0), |x| *x);
let rt2 = rts.get(&0).map_or(Duration::new(0, 0), |x| *x);
let rt3 = rts.get(&1).map_or(Duration::new(0, 0), |x| *x);
let rt4 = rts.get(&2).map_or(Duration::new(0, 0), |x| *x);
let rt5 = rts.get(&3).map_or(Duration::new(0, 0), |x| *x);
let rt6 = rts.get(&4).map_or(Duration::new(0, 0), |x| *x);
let rt7 = rts.get(&5).map_or(Duration::new(0, 0), |x| *x);
let txrr = TXRR6 {
t2,
t3,
t4,
t5,
t6,
t7,
st2,
rt2,
st3,
rt3,
st4,
rt4,
st5,
rt5,
st6,
rt6,
st7,
rt7,
};
Ok(txrr)
}
fn send_all_probes(
dst_ipv6: Ipv6Addr,
dst_open_tcp_port: u16,
dst_closed_tcp_port: u16,
dst_closed_udp_port: u16,
src_ipv6: Ipv6Addr,
src_mac: MacAddr,
timeout: Option<Duration>,
) -> Result<AllPacketRR6, PistolError> {
let start_time = Instant::now();
debug!("sending SEQ probe");
let seq = send_seq_probes(dst_ipv6, dst_open_tcp_port, src_ipv6, timeout, start_time)?;
debug!("sending IE probe");
let ie = send_ie_probes(dst_ipv6, src_ipv6, timeout, start_time)?;
debug!("sending NX probe");
let nx = send_nx_probes(dst_ipv6, src_ipv6, src_mac, timeout, start_time)?;
debug!("sending U1 probe");
let u1 = send_u1_probe(dst_ipv6, dst_closed_udp_port, src_ipv6, timeout, start_time)?;
debug!("sending TECN probe");
let tecn = send_tecn_probe(dst_ipv6, dst_open_tcp_port, src_ipv6, timeout, start_time)?;
debug!("sending TX probe");
let tx = send_tx_probes(
dst_ipv6,
src_ipv6,
dst_open_tcp_port,
dst_closed_tcp_port,
timeout,
start_time,
)?;
let ap = AllPacketRR6 {
seq,
ie,
nx,
u1,
tecn,
tx,
};
Ok(ap)
}
fn predict_value(features: &[f64], wvec: &[Vec<f64>]) -> Vec<f64> {
let vec_time = |x: &[f64], y: &[f64]| -> f64 {
assert_eq!(x.len(), y.len());
let mut sum = 0.0;
for (a, b) in zip(x, y) {
sum += a * b;
}
sum
};
let mut dec_value = [0f64; 92];
for (idx, w) in wvec.iter().enumerate() {
dec_value[idx] = vec_time(features, w);
}
let dec_value = dec_value.map(|x| 1.0 / (1.0 + (-x as f64).exp()));
dec_value.to_vec()
}
fn novelty_of(features: &[f64], mean: &[f64], variance: &[f64]) -> f64 {
assert_eq!(features.len(), 695);
assert_eq!(mean.len(), 695);
assert_eq!(variance.len(), 695);
let mut sum = 0.0;
for i in 0..695 {
let d = features[i] - mean[i];
let mut v = variance[i];
if v == 0.0 {
v = 0.01;
}
sum += (d * d) / v;
}
sum.sqrt()
}
fn isort(arr: &[OsInfo6]) -> Vec<OsInfo6> {
fn pick(arr: &[OsInfo6]) -> (OsInfo6, Vec<OsInfo6>) {
let mut max_score = 0.0;
let mut max_score_loc = 0;
let mut i = 0;
let mut arr = arr.to_vec();
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 ret = Vec::new();
let mut arr = arr.to_vec();
while arr.len() > 0 {
let (r, new_arr) = pick(&arr);
arr = new_arr;
ret.push(r);
}
ret
}
pub fn os_probe_thread6(
dst_ipv6: Ipv6Addr,
dst_open_tcp_port: u16,
dst_closed_tcp_port: u16,
dst_closed_udp_port: u16,
src_ipv6: Ipv6Addr,
top_k: usize,
linear: Linear,
timeout: Option<Duration>,
) -> Result<(Fingerprint6, Vec<OsInfo6>), PistolError> {
let (dst_mac, interface) =
RouteVia::get_dst_mac_and_src_if(dst_ipv6.into(), src_ipv6.into(), timeout)?;
let src_mac = match interface.mac {
Some(mac) => mac,
None => return Err(PistolError::CanNotFoundMacAddress),
};
debug!("send all probes now");
let ap = send_all_probes(
dst_ipv6,
dst_open_tcp_port,
dst_closed_tcp_port,
dst_closed_udp_port,
src_ipv6,
src_mac, timeout,
)?;
debug!("send all probes done");
let good_results = true;
let hops = icmp_trace(dst_ipv6.into(), src_ipv6.into(), timeout)?;
let scan = get_scan_line(
dst_mac,
dst_open_tcp_port,
dst_closed_tcp_port,
dst_closed_udp_port,
dst_ipv6.into(),
hops,
good_results,
);
let features = vectorize(&ap)?;
debug!("featured vectorize done");
let features = apply_scale(&features, &linear.scale);
debug!("apply scale done");
let predict = predict_value(&features, &linear.w);
debug!("predict done");
let mut detect_rets = Vec::new();
for (i, (name, &score)) in zip(&linear.infolist, &predict).into_iter().enumerate() {
let class = &linear.cpe[i].osclass;
if class.len() > 0 {
let class = class[0].join(" | ");
let cpe = linear.cpe[i].cpe.join(" ");
let dr = OsInfo6 {
name: name.to_string(),
class,
cpe,
score,
label: i,
};
detect_rets.push(dr);
}
}
debug!("detect rets len: {}", detect_rets.len());
let detect_rets = isort(&detect_rets);
let mut perfect_match = 1;
for i in 1..36 {
if detect_rets[i].score >= 0.9 * detect_rets[0].score {
perfect_match += 1;
}
}
debug!("prefect match: {}", perfect_match);
let label = detect_rets[0].label;
let novelty = novelty_of(&features, &linear.mean[label], &linear.variance[label]);
debug!("novelty: {}", novelty);
let s1x = SEQX6 {
name: String::from("S1"),
rr: ap.seq.seq1,
st: ap.seq.st1,
rt: ap.seq.rt1,
};
let s2x = SEQX6 {
name: String::from("S2"),
rr: ap.seq.seq2,
st: ap.seq.st2,
rt: ap.seq.rt2,
};
let s3x = SEQX6 {
name: String::from("S3"),
rr: ap.seq.seq3,
st: ap.seq.st3,
rt: ap.seq.rt3,
};
let s4x = SEQX6 {
name: String::from("S4"),
rr: ap.seq.seq4,
st: ap.seq.st4,
rt: ap.seq.rt4,
};
let s5x = SEQX6 {
name: String::from("S5"),
rr: ap.seq.seq5,
st: ap.seq.st5,
rt: ap.seq.rt5,
};
let s6x = SEQX6 {
name: String::from("S6"),
rr: ap.seq.seq6,
st: ap.seq.st6,
rt: ap.seq.rt6,
};
let ie1x = IEX6 {
name: String::from("IE1"),
rr: ap.ie.ie1,
st: ap.ie.st1,
rt: ap.ie.rt1,
};
let ie2x = IEX6 {
name: String::from("IE2"),
rr: ap.ie.ie2,
st: ap.ie.st2,
rt: ap.ie.rt2,
};
let ni = NX6 {
name: String::from("NI"),
rr: ap.nx.ni,
st: ap.nx.sti,
rt: ap.nx.rti,
};
let ns = NX6 {
name: String::from("NS"),
rr: ap.nx.ns,
st: ap.nx.sts,
rt: ap.nx.rts,
};
let u1x = U1X6 {
rr: ap.u1.u1,
st: ap.u1.st,
rt: ap.u1.rt,
};
let tecnx = TECNX6 {
rr: ap.tecn.tecn,
st: ap.tecn.st,
rt: ap.tecn.rt,
};
let t2x = TX6 {
name: String::from("T2"),
rr: ap.tx.t2,
st: ap.tx.st2,
rt: ap.tx.rt2,
};
let t3x = TX6 {
name: String::from("T3"),
rr: ap.tx.t3,
st: ap.tx.st3,
rt: ap.tx.rt3,
};
let t4x = TX6 {
name: String::from("T4"),
rr: ap.tx.t4,
st: ap.tx.st4,
rt: ap.tx.rt4,
};
let t5x = TX6 {
name: String::from("T5"),
rr: ap.tx.t5,
st: ap.tx.st5,
rt: ap.tx.rt5,
};
let t6x = TX6 {
name: String::from("T6"),
rr: ap.tx.t6,
st: ap.tx.st6,
rt: ap.tx.rt6,
};
let t7x = TX6 {
name: String::from("T7"),
rr: ap.tx.t7,
st: ap.tx.st7,
rt: ap.tx.rt7,
};
const FP_NOVELTY_THRESHOLD: f64 = 15.0;
let status = if perfect_match == 1 {
if novelty < FP_NOVELTY_THRESHOLD {
true
} else {
false
}
} else {
false
};
let target_fingerprint = Fingerprint6 {
scan,
s1x,
s2x,
s3x,
s4x,
s5x,
s6x,
ie1x,
ie2x,
ni,
ns,
u1x,
tecnx,
t2x,
t3x,
t4x,
t5x,
t6x,
t7x,
extra: String::from("12345"), novelty,
status,
};
let ret = if status {
let mut count = top_k;
let mut last_score = 0.0;
let mut ret = Vec::new();
let mut iter = detect_rets.into_iter();
while count > 0 {
let r = match iter.next() {
Some(r) => r,
None => break,
};
if last_score != r.score {
last_score = r.score;
count -= 1;
}
ret.push(r);
}
ret
} else {
warn!(
"os scan6 novelty {} > FP_NOVELTY_THRESHOLD {}, so there are no results returned",
novelty, FP_NOVELTY_THRESHOLD
);
let ret = vec![];
ret
};
debug!("ipv6 fingerprint:\n{}", target_fingerprint);
Ok((target_fingerprint, ret))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_something() {
let p = "000XXXXXX";
let ret = p_reduce(p);
println!("{}", ret);
let p = "0000XXXXXX";
let ret = p_reduce(p);
println!("{}", ret);
let p = "0000XXXXXXX";
let ret = p_reduce(p);
println!("{}", ret);
}
#[test]
fn test_send_tx() {
let dst_ipv6 = Ipv6Addr::new(0xfe80, 0, 0, 0, 0x0020c, 0x29ff, 0xfe2c, 0x09e4);
let src_ipv6 = Ipv6Addr::new(0xfe80, 0, 0, 0, 0x0020c, 0x29ff, 0xfe2c, 0x09e4);
let dst_open_port = 22;
let dst_closed_port = 9876;
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);
}
println!("src_ports: {:?}", src_ports);
let layer3 = Layer3Match {
name: "test layer3",
layer2: None,
src_addr: Some(dst_ipv6.into()),
dst_addr: Some(src_ipv6.into()),
};
let layer4_tcp_udp_2 = Layer4MatchTcpUdp {
name: "test tcp_udp 2",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_ports[0]),
};
let layer4_tcp_udp_3 = Layer4MatchTcpUdp {
name: "test tcp_udp 3",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_ports[1]),
};
let layer4_tcp_udp_4 = Layer4MatchTcpUdp {
name: "test tcp_udp 4",
layer3: Some(layer3),
src_port: Some(dst_open_port),
dst_port: Some(src_ports[2]),
};
let layer4_tcp_udp_5 = Layer4MatchTcpUdp {
name: "test tcp_udp 5",
layer3: Some(layer3),
src_port: Some(dst_closed_port),
dst_port: Some(src_ports[3]),
};
let layer4_tcp_udp_6 = Layer4MatchTcpUdp {
name: "test tcp_udp 6",
layer3: Some(layer3),
src_port: Some(dst_closed_port),
dst_port: Some(src_ports[4]),
};
let layer4_tcp_udp_7 = Layer4MatchTcpUdp {
name: "test tcp_udp 7",
layer3: Some(layer3),
src_port: Some(dst_closed_port),
dst_port: Some(src_ports[5]),
};
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 layer_match_7 = LayerMatch::Layer4MatchTcpUdp(layer4_tcp_udp_7);
let ms = vec![
layer_match_2,
layer_match_3,
layer_match_4,
layer_match_5,
layer_match_6,
layer_match_7,
];
let buff_2 =
packet6::t2_packet_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[0]).unwrap();
let buff_3 =
packet6::t3_packet_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[1]).unwrap();
let buff_4 =
packet6::t4_packet_layer3(dst_ipv6, dst_open_port, src_ipv6, src_ports[2]).unwrap();
let buff_5 =
packet6::t5_packet_layer3(dst_ipv6, dst_closed_port, src_ipv6, src_ports[3]).unwrap();
let buff_6 =
packet6::t6_packet_layer3(dst_ipv6, dst_closed_port, src_ipv6, src_ports[4]).unwrap();
let buff_7 =
packet6::t7_packet_layer3(dst_ipv6, dst_closed_port, src_ipv6, src_ports[5]).unwrap();
let buffs = vec![buff_2, buff_3, buff_4, buff_5, buff_6, buff_7];
let i = 0;
let m = ms[i].clone();
let buff = buffs[i].clone();
let timeout = Some(Duration::new(3, 0));
let (ret, _rtt) =
layer3_ipv6_send(dst_ipv6, src_ipv6, &buff, vec![m], timeout, true).unwrap();
println!("ret: {}", ret.len());
}
}