use crc32fast;
use gcdx::gcdx;
use pnet::packet::Packet;
use pnet::packet::icmp::IcmpCode;
use pnet::packet::icmp::IcmpPacket;
use pnet::packet::ipv4;
use pnet::packet::ipv4::Ipv4Packet;
use pnet::packet::tcp::TcpOptionNumbers;
use pnet::packet::tcp::TcpPacket;
use pnet::packet::udp::UdpPacket;
use tracing::warn;
use crate::error::PistolError;
use crate::os::rr::IERR;
use crate::os::rr::SEQRR;
use crate::os::rr::TXRR;
use crate::os::rr::U1RR;
use crate::utils::PistolHex;
const CWR_MASK: u8 = 0b10000000;
const ECE_MASK: u8 = 0b01000000;
const URG_MASK: u8 = 0b00100000;
const ACK_MASK: u8 = 0b00010000;
const PSH_MASK: u8 = 0b00001000;
const RST_MASK: u8 = 0b00000100;
const SYN_MASK: u8 = 0b00000010;
const FIN_MASK: u8 = 0b00000001;
const PROGRAM_ESTIMATION_ERROR_ISR: f64 = 0.0;
const PROGRAM_ESTIMATION_ERROR_SP: f64 = 0.0;
fn build_ipv4_packet<'a>(
ipv4_buff: &'a [u8],
probe_name: &str,
) -> Result<Ipv4Packet<'a>, PistolError> {
if ipv4_buff.len() > 0 {
match Ipv4Packet::new(ipv4_buff) {
Some(p) => return Ok(p),
None => (),
}
}
Err(PistolError::BuildIpv4PacketFailed {
probe_name: probe_name.to_string(),
})
}
fn build_tcp_packet<'a>(
tcp_buff: &'a [u8],
probe_name: &str,
) -> Result<TcpPacket<'a>, PistolError> {
if tcp_buff.len() > 0 {
match TcpPacket::new(tcp_buff) {
Some(p) => return Ok(p),
None => (),
}
}
Err(PistolError::BuildTcpPacketFailed {
probe_name: probe_name.to_string(),
})
}
fn build_icmp_packet<'a>(
icmp_buff: &'a [u8],
probe_name: &str,
) -> Result<IcmpPacket<'a>, PistolError> {
if icmp_buff.len() > 0 {
match IcmpPacket::new(icmp_buff) {
Some(p) => return Ok(p),
None => (),
}
}
Err(PistolError::BuildIcmpPacketFailed {
probe_name: probe_name.to_string(),
})
}
fn build_udp_packet<'a>(
udp_buff: &'a [u8],
probe_name: &str,
) -> Result<UdpPacket<'a>, PistolError> {
if udp_buff.len() > 0 {
match UdpPacket::new(udp_buff) {
Some(p) => return Ok(p),
None => (),
}
}
Err(PistolError::BuildUdpPacketFailed {
probe_name: probe_name.to_string(),
})
}
fn get_tcp_seq(ipv4_buff: &[u8], probe_name: &str) -> Result<u32, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_buff, probe_name)?;
let tcp_packet = build_tcp_packet(ipv4_packet.payload(), probe_name)?;
Ok(tcp_packet.get_sequence())
}
fn get_diff_u32(input: &[u32]) -> Vec<u32> {
if input.len() >= 2 {
let input_slice = input[0..(input.len() - 1)].to_vec();
let mut diff = Vec::new();
for (i, x) in input_slice.iter().enumerate() {
let y = input[i + 1];
let x = *x;
let k = if x <= y { y - x } else { !(x - y) };
diff.push(k);
}
diff
} else {
Vec::new()
}
}
fn get_diff_u16(input: &[u16]) -> Vec<u16> {
if input.len() >= 2 {
let input_slice = input[0..(input.len() - 1)].to_vec();
let mut diff = Vec::new();
for (i, x) in input_slice.iter().enumerate() {
let y = input[i + 1];
let x = *x;
let k = if x <= y { y - x } else { !(x - y) };
diff.push(k);
}
diff
} else {
Vec::new()
}
}
pub fn tcp_gcd(seqrr: &SEQRR) -> Result<(u32, Vec<u32>), PistolError> {
let s1 = get_tcp_seq(&seqrr.seq1.response, "seq1");
let s2 = get_tcp_seq(&seqrr.seq2.response, "seq2");
let s3 = get_tcp_seq(&seqrr.seq3.response, "seq3");
let s4 = get_tcp_seq(&seqrr.seq4.response, "seq4");
let s5 = get_tcp_seq(&seqrr.seq5.response, "seq5");
let s6 = get_tcp_seq(&seqrr.seq6.response, "seq6");
let mut tmp_vec = Vec::new();
tmp_vec.push(s1);
tmp_vec.push(s2);
tmp_vec.push(s3);
tmp_vec.push(s4);
tmp_vec.push(s5);
tmp_vec.push(s6);
let mut seq_vec: Vec<u32> = Vec::new();
for s in tmp_vec {
match s {
Ok(s) => seq_vec.push(s),
Err(e) => warn!("{}", e),
}
}
let diff = get_diff_u32(&seq_vec);
if diff.len() > 1 {
let gcd = match gcdx(&diff) {
Some(g) => g,
None => return Err(PistolError::CalcDiffFailed),
};
Ok((gcd, diff))
} else if diff.len() == 1 {
let gcd = diff[0];
Ok((gcd, diff))
} else {
Err(PistolError::CalcDiffFailed)
}
}
pub fn tcp_isr(diff: Vec<u32>, elapsed: f64) -> Result<(u32, Vec<f64>), PistolError> {
if diff.len() > 0 {
let mut seq_rates: Vec<f64> = Vec::new();
let mut sum = 0.0;
for d in &diff {
let f = (*d as f64) / elapsed;
seq_rates.push(f);
sum += f;
}
let avg = sum / diff.len() as f64;
let isr = if avg < 1.0 {
0
} else {
((8.0 - PROGRAM_ESTIMATION_ERROR_ISR) * avg.log2()).round() as u32
};
Ok((isr, seq_rates))
} else {
Err(PistolError::CalcISRFailed)
}
}
fn vec_std(values: &[f64]) -> f64 {
let mut sum = 0.0;
for v in values {
sum += *v;
}
let mean = sum / values.len() as f64;
let mut ret = 0.0;
for v in values {
ret += (v - mean).powi(2);
}
ret.sqrt()
}
pub fn tcp_sp(seq_rates: Vec<f64>, gcd: u32) -> Result<u32, PistolError> {
if seq_rates.len() >= 4 {
let mut seq_rates_clone = seq_rates.clone();
if gcd > 9 {
for i in 0..seq_rates.len() {
seq_rates_clone[i] /= gcd as f64;
}
}
let sd = vec_std(&seq_rates);
let sp = if sd <= 1.0 {
0
} else {
((8.0 - PROGRAM_ESTIMATION_ERROR_SP) * sd.log2()).round() as u32
};
Ok(sp)
} else {
Ok(0) }
}
fn get_ip_id(ipv4_buff: &[u8], probe_name: &str) -> Result<u16, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_buff, probe_name)?;
Ok(ipv4_packet.get_identification())
}
pub fn tcp_ti_ci_ii(
seqrr: &SEQRR,
t2t7rr: &TXRR,
ierr: &IERR,
) -> Result<(String, String, String), PistolError> {
let z_judgement = |x: &[u16]| -> bool {
let mut conditon = true; for v in x {
if *v != 0 {
conditon = false;
}
}
conditon
};
let rd_judgement = |diff: &[u16]| -> bool {
let mut condition = true; for d in diff {
if *d < 20000 {
condition = false;
}
}
condition
};
let hex_judgement = |ip_id_vec: &[u16]| -> Result<bool, PistolError> {
let v3 = get_diff_u16(ip_id_vec);
let mut sum = 0;
for v in v3 {
sum += v;
}
if sum == 0 { Ok(true) } else { Ok(false) }
};
let ri_judgement = |diff: &[u16]| -> bool {
let mut condition_1 = true; let mut condition_2 = true; for d in diff {
if *d < 1000 {
condition_1 = false;
}
if *d % 256 == 0 {
condition_2 = false;
}
}
if condition_1 && condition_2 {
true
} else {
false
}
};
let bi_judgement = |diff: &[u16]| -> bool {
let mut condition_1 = true; let mut condition_2 = true; for d in diff {
if *d % 256 != 0 {
condition_1 = false;
}
if *d > 5120 {
condition_2 = false;
}
}
if condition_1 && condition_2 {
true
} else {
false
}
};
let i_judgement = |diff: &[u16]| -> bool {
let mut condition = true; for d in diff {
if *d >= 10 {
condition = false;
}
}
condition
};
let seq1_ip_id = get_ip_id(&seqrr.seq1.response, "seq1");
let seq2_ip_id = get_ip_id(&seqrr.seq2.response, "seq2");
let seq3_ip_id = get_ip_id(&seqrr.seq3.response, "seq3");
let seq4_ip_id = get_ip_id(&seqrr.seq4.response, "seq4");
let seq5_ip_id = get_ip_id(&seqrr.seq5.response, "seq5");
let seq6_ip_id = get_ip_id(&seqrr.seq6.response, "seq6");
let mut tmp_vec = Vec::new();
tmp_vec.push(seq1_ip_id);
tmp_vec.push(seq2_ip_id);
tmp_vec.push(seq3_ip_id);
tmp_vec.push(seq4_ip_id);
tmp_vec.push(seq5_ip_id);
tmp_vec.push(seq6_ip_id);
let mut seq_ip_id_vec = Vec::new();
for s in tmp_vec {
match s {
Ok(s) => seq_ip_id_vec.push(s),
Err(e) => warn!("{}", e),
}
}
let seq_diff = get_diff_u16(&seq_ip_id_vec);
let ti = if seq_ip_id_vec.len() >= 3 {
if z_judgement(&seq_ip_id_vec) {
String::from("Z")
} else if ri_judgement(&seq_diff) {
String::from("RD")
} else if hex_judgement(&seq_ip_id_vec)? {
format!("{:X}", seq_ip_id_vec[0])
} else if ri_judgement(&seq_diff) {
String::from("RI")
} else if bi_judgement(&seq_diff) {
String::from("BI")
} else if i_judgement(&seq_diff) {
String::from("I")
} else {
String::new()
}
} else {
String::new()
};
let t5_ip_id = get_ip_id(&t2t7rr.t5.response, "t5");
let t6_ip_id = get_ip_id(&t2t7rr.t6.response, "t6");
let t7_ip_id = get_ip_id(&t2t7rr.t7.response, "t7");
let mut tmp_vec = Vec::new();
tmp_vec.push(t5_ip_id);
tmp_vec.push(t6_ip_id);
tmp_vec.push(t7_ip_id);
let mut t_ip_id_vec = Vec::new();
for t in tmp_vec {
match t {
Ok(t) => t_ip_id_vec.push(t),
Err(e) => warn!("{}", e),
}
}
let t_diff = get_diff_u16(&t_ip_id_vec);
let ci = if t_ip_id_vec.len() >= 2 {
if z_judgement(&t_ip_id_vec) {
String::from("Z")
} else if rd_judgement(&t_diff) {
String::from("RD")
} else if hex_judgement(&t_ip_id_vec)? {
format!("{:X}", t_ip_id_vec[0])
} else if ri_judgement(&t_diff) {
String::from("RI")
} else if bi_judgement(&t_diff) {
String::from("BI")
} else if i_judgement(&t_diff) {
String::from("I")
} else {
String::new()
}
} else {
String::new()
};
let ie1_ip_id = get_ip_id(&ierr.ie1.response, "ie1");
let ie2_ip_id = get_ip_id(&ierr.ie2.response, "ie2");
let mut tmp_vec = Vec::new();
tmp_vec.push(ie1_ip_id);
tmp_vec.push(ie2_ip_id);
let mut ie_ip_id_vec = Vec::new();
for i in tmp_vec {
match i {
Ok(i) => ie_ip_id_vec.push(i),
Err(e) => warn!("{}", e),
}
}
let ie_diff = get_diff_u16(&ie_ip_id_vec);
let ii = if ie_ip_id_vec.len() >= 2 {
if z_judgement(&ie_ip_id_vec) {
String::from("Z")
} else if hex_judgement(&ie_ip_id_vec)? {
format!("{:X}", ie_ip_id_vec[0])
} else if ri_judgement(&ie_diff) {
String::from("RI")
} else if bi_judgement(&ie_diff) {
String::from("BI")
} else if i_judgement(&ie_diff) {
String::from("I")
} else {
String::new()
}
} else {
String::new()
};
Ok((ti, ci, ii))
}
pub fn tcp_ss(seqrr: &SEQRR, ierr: &IERR, ti: &str, ii: &str) -> Result<String, PistolError> {
let judge_value = |x: &str| -> bool {
if x == "RI" || x == "BI" || x == "I" {
true
} else {
false
}
};
let c1 = judge_value(ii);
let c2 = judge_value(ti);
if c1 && c2 {
let seq1_ip_id = get_ip_id(&seqrr.seq1.response, "seq1");
let seq2_ip_id = get_ip_id(&seqrr.seq2.response, "seq2");
let seq3_ip_id = get_ip_id(&seqrr.seq3.response, "seq3");
let seq4_ip_id = get_ip_id(&seqrr.seq4.response, "seq4");
let seq5_ip_id = get_ip_id(&seqrr.seq5.response, "seq5");
let seq6_ip_id = get_ip_id(&seqrr.seq6.response, "seq6");
let mut tmp_vec = Vec::new();
tmp_vec.push(seq1_ip_id);
tmp_vec.push(seq2_ip_id);
tmp_vec.push(seq3_ip_id);
tmp_vec.push(seq4_ip_id);
tmp_vec.push(seq5_ip_id);
tmp_vec.push(seq6_ip_id);
let mut ip_id_vec = Vec::new();
for i in tmp_vec {
match i {
Ok(i) => ip_id_vec.push(Some(i)),
Err(e) => {
warn!("{}", e);
ip_id_vec.push(None) }
}
}
let first_ip_id = |ip_id_vec: &[Option<u16>]| -> Option<(u16, usize)> {
for (i, ip_id) in ip_id_vec.iter().enumerate() {
match ip_id {
Some(ip_id) => return Some((*ip_id, i)),
None => (),
}
}
None
};
let last_ip_id = |ip_id_vec: &[Option<u16>]| -> Option<(u16, usize)> {
for (i, ip_id) in ip_id_vec.iter().rev().enumerate() {
match ip_id {
Some(ip_id) => return Some((*ip_id, ip_id_vec.len() - i)),
None => (),
}
}
None
};
let (seq_first_ip_id, first) = match first_ip_id(&ip_id_vec) {
Some((s, f)) => (s, f),
None => return Err(PistolError::CalcSSFailed),
};
let (seq_last_ip_id, last) = match last_ip_id(&ip_id_vec) {
Some((s, f)) => (s, f),
None => return Err(PistolError::CalcSSFailed),
};
if last <= first {
return Ok(String::new());
}
let difference = if seq_last_ip_id > seq_first_ip_id {
seq_last_ip_id - seq_first_ip_id
} else {
!(seq_first_ip_id - seq_last_ip_id)
};
let avg = difference as f64 / (last - first) as f64;
let ie1_ip_id = get_ip_id(&ierr.ie1.response, "ie1");
let ss = match ie1_ip_id {
Ok(ie1_ip_id) => {
let temp_value = seq_last_ip_id as f64 + (3.0 * avg);
let ss = if (ie1_ip_id as f64) < temp_value {
String::from("S")
} else {
String::from("O")
};
ss
}
Err(e) => {
warn!("{}", e);
String::new()
}
};
Ok(ss)
} else {
Ok(String::new())
}
}
fn get_tsval(ipv4_response: &[u8], probe_name: &str) -> Result<u32, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let tcp_packet = build_tcp_packet(ipv4_packet.payload(), probe_name)?;
let options_vec = tcp_packet.get_options();
for option in options_vec {
match option.number {
TcpOptionNumbers::TIMESTAMPS => {
if option.data.len() >= 4 {
let tsval_vec = option.data[0..4].to_vec();
let tsval = PistolHex::be_vec_to_u32(&tsval_vec)?;
return Ok(tsval);
}
}
_ => (),
}
}
Err(PistolError::TsValIsNull)
}
pub fn tcp_ts(seqrr: &SEQRR) -> Result<String, PistolError> {
let tsval_1 = get_tsval(&seqrr.seq1.response, "seq1");
let tsval_2 = get_tsval(&seqrr.seq2.response, "seq2");
let tsval_3 = get_tsval(&seqrr.seq3.response, "seq3");
let tsval_4 = get_tsval(&seqrr.seq4.response, "seq4");
let tsval_5 = get_tsval(&seqrr.seq5.response, "seq5");
let tsval_6 = get_tsval(&seqrr.seq6.response, "seq6");
let mut tmp_vec = Vec::new();
tmp_vec.push(tsval_1);
tmp_vec.push(tsval_2);
tmp_vec.push(tsval_3);
tmp_vec.push(tsval_4);
tmp_vec.push(tsval_5);
tmp_vec.push(tsval_6);
let mut tsval_vec = Vec::new();
for t in tmp_vec {
match t {
Ok(t) => tsval_vec.push(t),
Err(e) => warn!("{}", e),
}
}
let mut one_tsval_zero = false;
for tsval in &tsval_vec {
if *tsval == 0 {
one_tsval_zero = true;
}
}
let ts = if tsval_vec.len() == 0 {
String::from("U")
} else if one_tsval_zero {
String::from("0")
} else {
let diff = get_diff_u32(&tsval_vec);
let ts = if diff.len() > 0 {
let mut sum = 0.0;
for d in &diff {
sum += *d as f64 / 0.1;
}
let avg = sum / diff.len() as f64;
let ts = if avg > 0.0 && avg <= 5.66 {
String::from("1")
} else if avg > 70.0 && avg <= 150.0 {
String::from("7")
} else if avg > 150.0 && avg <= 350.0 {
String::from("8")
} else {
let a = avg.log2().round() as u64;
let hex_str = format!("{:X}", a);
hex_str
};
ts
} else {
String::new()
};
ts
};
Ok(ts)
}
pub fn tcp_o(ipv4_response: &[u8], probe_name: &str) -> Result<String, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let tcp_packet = build_tcp_packet(ipv4_packet.payload(), probe_name)?;
let options_vec = tcp_packet.get_options();
let mut o_ret = String::new();
for option in options_vec {
match option.number {
TcpOptionNumbers::MSS => {
let data = if option.data.len() > 4 {
&option.data[0..4]
} else {
&option.data
};
let mss = PistolHex::be_vec_to_u32(data)?;
let o_str = format!("M{:X}", mss);
o_ret += &o_str;
}
TcpOptionNumbers::SACK_PERMITTED => {
o_ret += "S";
}
TcpOptionNumbers::EOL => {
o_ret += "L";
}
TcpOptionNumbers::NOP => {
o_ret += "N";
}
TcpOptionNumbers::WSCALE => {
let data = if option.data.len() > 4 {
&option.data[0..4]
} else {
&option.data
};
let wscale = PistolHex::be_vec_to_u32(data)?;
let o_str = format!("W{:X}", wscale);
o_ret += &o_str;
}
TcpOptionNumbers::TIMESTAMPS => {
o_ret += "T";
let t0 = if option.data.len() > 0 {
if option.data.len() >= 4 {
option.data[0..4].to_vec()
} else {
option.data[0..option.data.len() - 1].to_vec()
}
} else {
vec![0; 4]
};
let t1 = if option.data.len() > 4 {
if option.data.len() >= 8 {
option.data[4..8].to_vec()
} else {
option.data[4..option.data.len() - 1].to_vec()
}
} else {
vec![0; 4]
};
let t0_u32 = PistolHex::be_vec_to_u32(&t0)?;
let t1_u32 = PistolHex::be_vec_to_u32(&t1)?;
if t0_u32 == 0 {
o_ret += "0";
} else {
o_ret += "1";
}
if t1_u32 == 0 {
o_ret += "0";
} else {
o_ret += "1";
}
}
_ => (),
}
}
return Ok(o_ret);
}
pub fn tcp_ox(
seqrr: &SEQRR,
) -> Result<(String, String, String, String, String, String), PistolError> {
let o1 = tcp_o(&seqrr.seq1.response, "seq1")?;
let o2 = tcp_o(&seqrr.seq2.response, "seq2")?;
let o3 = tcp_o(&seqrr.seq3.response, "seq3")?;
let o4 = tcp_o(&seqrr.seq4.response, "seq4")?;
let o5 = tcp_o(&seqrr.seq5.response, "seq5")?;
let o6 = tcp_o(&seqrr.seq6.response, "seq6")?;
Ok((o1, o2, o3, o4, o5, o6))
}
pub fn tcp_w(ipv4_response: &[u8], probe_name: &str) -> Result<u16, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let tcp_packet = build_tcp_packet(ipv4_packet.payload(), probe_name)?;
let window = tcp_packet.get_window();
Ok(window)
}
pub fn tcp_wx(seqrr: &SEQRR) -> Result<(u16, u16, u16, u16, u16, u16), PistolError> {
let w1 = tcp_w(&seqrr.seq1.response, "seq1")?;
let w2 = tcp_w(&seqrr.seq2.response, "seq2")?;
let w3 = tcp_w(&seqrr.seq3.response, "seq3")?;
let w4 = tcp_w(&seqrr.seq4.response, "seq4")?;
let w5 = tcp_w(&seqrr.seq5.response, "seq5")?;
let w6 = tcp_w(&seqrr.seq6.response, "seq6")?;
Ok((w1, w2, w3, w4, w5, w6))
}
pub fn tcp_udp_icmp_r(ipv4_response: &[u8]) -> Result<String, PistolError> {
match ipv4_response.len() {
0 => Ok(String::from("N")),
_ => Ok(String::from("Y")),
}
}
pub fn tcp_udp_df(ipv4_response: &[u8], probe_name: &str) -> Result<String, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let ipv4_flags = ipv4_packet.get_flags();
let df_mask: u8 = 0b0010;
let ret = if (ipv4_flags & df_mask) != 0 {
String::from("Y")
} else {
String::from("N")
};
Ok(ret)
}
fn udp_hops(u1rr: &U1RR, probe_name: &str) -> Result<Option<u8>, PistolError> {
let request = build_ipv4_packet(&u1rr.u1.request, probe_name)?; match build_ipv4_packet(&u1rr.u1.response, probe_name) {
Ok(ipv4_packet) => {
let icmp_packet = build_icmp_packet(ipv4_packet.payload(), probe_name)?;
let r_ipv4_buff = icmp_packet.payload()[4..].to_vec();
let r_ipv4_packet = build_ipv4_packet(&r_ipv4_buff, probe_name)?;
let ttl_1 = request.get_ttl();
let ttl_2 = r_ipv4_packet.get_ttl();
let hops = ttl_1 - ttl_2;
Ok(Some(hops))
}
Err(e) => {
warn!("udp hops calc failed: {}", e);
Ok(None)
}
}
}
pub fn tcp_udp_icmp_t(
ipv4_response: &[u8],
u1rr: &U1RR,
probe_name: &str,
) -> Result<Option<u16>, PistolError> {
let hops = udp_hops(u1rr, probe_name)?;
match hops {
Some(hops) => {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let ipv4_ttl = ipv4_packet.get_ttl();
Ok(Some(hops as u16 + ipv4_ttl as u16))
}
None => Ok(None), }
}
pub fn tcp_udp_icmp_tg(ipv4_response: &[u8], probe_name: &str) -> Result<u16, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let ipv4_ttl = ipv4_packet.get_ttl() as u16;
let er_lim = 5;
let regual_ttl_vec = vec![32, 64, 128, 255];
let mut guess_value = 0;
for r in regual_ttl_vec {
if ipv4_ttl > r {
if ipv4_ttl - r <= er_lim {
guess_value = r;
}
} else {
if r - ipv4_ttl <= er_lim {
guess_value = r;
}
}
}
if guess_value != 0 {
Ok(guess_value)
} else {
Ok(ipv4_ttl)
}
}
pub fn tcp_cc(ipv4_response: &[u8], probe_name: &str) -> Result<String, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let tcp_packet = build_tcp_packet(ipv4_packet.payload(), probe_name)?;
let tcp_flag = tcp_packet.get_flags();
let ret = if (tcp_flag & ECE_MASK != 0) && (tcp_flag & CWR_MASK == 0) {
String::from("Y")
} else if (tcp_flag & CWR_MASK == 0) && (tcp_flag & ECE_MASK == 0) {
String::from("N")
} else if (tcp_flag & CWR_MASK != 0) && (tcp_flag & ECE_MASK != 0) {
String::from("S")
} else {
String::from("O")
};
Ok(ret)
}
pub fn tcp_q(ipv4_response: &[u8], probe_name: &str) -> Result<String, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let tcp_packet = build_tcp_packet(ipv4_packet.payload(), probe_name)?;
let mut ret = String::new();
let tcp_reserved = tcp_packet.get_reserved();
if tcp_reserved != 0 {
ret += "R"
}
if tcp_packet.get_urgent_ptr() != 0 {
ret += "U"
}
Ok(ret)
}
pub fn tcp_s(
ipv4_request: &[u8],
ipv4_response: &[u8],
probe_name: &str,
) -> Result<String, PistolError> {
let ipv4_packet_request = build_ipv4_packet(ipv4_request, probe_name)?; let tcp_packet_request = build_tcp_packet(ipv4_packet_request.payload(), probe_name)?;
let ipv4_packet_response = build_ipv4_packet(ipv4_response, probe_name)?;
let tcp_packet_response = build_tcp_packet(ipv4_packet_response.payload(), probe_name)?;
let ack_request = tcp_packet_request.get_acknowledgement();
let seq_response = tcp_packet_response.get_sequence();
let ret = if seq_response == 0 {
String::from("Z")
} else if seq_response == ack_request {
String::from("A")
} else if seq_response == (ack_request + 1) {
String::from("A+")
} else {
String::from("O")
};
Ok(ret)
}
pub fn tcp_a(
ipv4_request: &[u8],
ipv4_response: &[u8],
probe_name: &str,
) -> Result<String, PistolError> {
let ipv4_packet_request = build_ipv4_packet(ipv4_request, probe_name)?; let tcp_packet_request = build_tcp_packet(ipv4_packet_request.payload(), probe_name)?;
let ipv4_packet_response = build_ipv4_packet(ipv4_response, probe_name)?;
let tcp_packet_response = build_tcp_packet(ipv4_packet_response.payload(), probe_name)?;
let seq_request = tcp_packet_request.get_sequence();
let ack_response = tcp_packet_response.get_acknowledgement();
let ret = if ack_response == 0 {
String::from("Z")
} else if ack_response == seq_request {
String::from("S")
} else if ack_response == (seq_request + 1) {
String::from("S+")
} else {
String::from("O")
};
Ok(ret)
}
pub fn tcp_f(ipv4_response: &[u8], probe_name: &str) -> Result<String, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let tcp_packet = build_tcp_packet(ipv4_packet.payload(), probe_name)?;
let tcp_flag = tcp_packet.get_flags();
let mut ret = String::new();
if tcp_flag & ECE_MASK != 0 {
ret += "E";
}
if tcp_flag & URG_MASK != 0 {
ret += "U";
}
if tcp_flag & ACK_MASK != 0 {
ret += "A";
}
if tcp_flag & PSH_MASK != 0 {
ret += "P";
}
if tcp_flag & RST_MASK != 0 {
ret += "R";
}
if tcp_flag & SYN_MASK != 0 {
ret += "S";
}
if tcp_flag & FIN_MASK != 0 {
ret += "F";
}
Ok(ret)
}
pub fn tcp_rd(ipv4_response: &[u8], probe_name: &str) -> Result<u32, PistolError> {
let ipv4_packet = build_ipv4_packet(ipv4_response, probe_name)?;
let tcp_packet = build_tcp_packet(ipv4_packet.payload(), probe_name)?;
let tcp_payload = tcp_packet.payload();
Ok(crc32fast::hash(tcp_payload))
}
pub fn udp_ipl(u1: &U1RR) -> Result<usize, PistolError> {
let response = &u1.u1.response;
Ok(response.len())
}
pub fn udp_un(u1: &U1RR, probe_name: &str) -> Result<u32, PistolError> {
let response = &u1.u1.response;
let ipv4_packet = build_ipv4_packet(response, probe_name)?;
let icmp_packet = ipv4_packet.payload().to_vec();
if icmp_packet.len() > 4 {
let rest_of_header = if icmp_packet.len() >= 8 {
icmp_packet[4..8].to_vec()
} else {
icmp_packet[4..icmp_packet.len() - 1].to_vec()
};
let un = PistolHex::be_vec_to_u32(&rest_of_header)?;
Ok(un)
} else {
Err(PistolError::CalcUNFailed)
}
}
pub fn udp_ripl(u1: &U1RR, probe_name: &str) -> Result<String, PistolError> {
let response = &u1.u1.response;
let ipv4_packet = build_ipv4_packet(response, probe_name)?;
let icmp_packet = build_icmp_packet(ipv4_packet.payload(), probe_name)?;
let ripl = icmp_packet.payload().len() - 4;
let ret = if ripl == 328 {
String::from("G")
} else {
format!("{:X}", ripl)
};
Ok(ret)
}
pub fn udp_rid(u1: &U1RR, probe_name: &str) -> Result<String, PistolError> {
let response = &u1.u1.response;
let ipv4_packet = build_ipv4_packet(response, probe_name)?;
let icmp_packet = build_icmp_packet(ipv4_packet.payload(), probe_name)?;
let r_ipv4_packet = build_ipv4_packet(&icmp_packet.payload()[4..], probe_name)?;
let rid = r_ipv4_packet.get_identification();
let ret = if rid == 0x1042 {
String::from("G")
} else {
format!("{:X}", rid)
};
Ok(ret)
}
pub fn udp_ripck(u1: &U1RR, probe_name: &str) -> Result<String, PistolError> {
let response = &u1.u1.response;
let ipv4_packet = build_ipv4_packet(response, probe_name)?;
let o_checksum = ipv4_packet.get_checksum();
let t_checksum = ipv4::checksum(&ipv4_packet.to_immutable());
let ret = if o_checksum == t_checksum {
String::from("G")
} else if o_checksum == 0 {
String::from("Z")
} else {
String::from("I")
};
Ok(ret)
}
pub fn udp_ruck(u1: &U1RR, probe_name: &str) -> Result<String, PistolError> {
let request = &u1.u1.request;
let response = &u1.u1.response;
let ipv4_packet_request = build_ipv4_packet(request, probe_name)?; let udp_packet_request = build_udp_packet(ipv4_packet_request.payload(), probe_name)?; let checksum_request = udp_packet_request.get_checksum();
let ipv4_packet_response = build_ipv4_packet(response, probe_name)?;
let icmp_packet_response = build_icmp_packet(ipv4_packet_response.payload(), probe_name)?;
let r_ipv4_packet_response =
build_ipv4_packet(&icmp_packet_response.payload()[4..], probe_name)?;
let udp_packet_response = build_udp_packet(r_ipv4_packet_response.payload(), probe_name)?;
let checksum_response = udp_packet_response.get_checksum();
let ret = if checksum_response == checksum_request {
String::from("G")
} else {
format!("{:X}", checksum_response)
};
Ok(ret)
}
pub fn udp_rud(u1: &U1RR, probe_name: &str) -> Result<String, PistolError> {
let response = &u1.u1.response;
let ipv4_packet_response = build_ipv4_packet(response, probe_name)?;
let icmp_packet_response = build_icmp_packet(ipv4_packet_response.payload(), probe_name)?;
let r_ipv4_packet_response =
build_ipv4_packet(&icmp_packet_response.payload()[4..], probe_name)?;
let r_udp_packet_response = build_udp_packet(&r_ipv4_packet_response.payload(), probe_name)?;
let payload_c_judge = |payload: &[u8]| -> bool {
for p in payload {
if *p != 0x43 {
return false;
}
}
true
};
let c = payload_c_judge(r_udp_packet_response.payload());
let ret = if c || r_udp_packet_response.payload().len() == 0 {
String::from("G")
} else {
String::from("I")
};
Ok(ret)
}
pub fn icmp_dfi(ie: &IERR, probe_name: &str) -> Result<String, PistolError> {
let df_mask: u8 = 0b0010;
let request_1 = &ie.ie1.request;
let request_2 = &ie.ie2.request;
let response_1 = &ie.ie1.response;
let response_2 = &ie.ie2.response;
let ipv4_packet_1 = build_ipv4_packet(request_1, probe_name)?;
let flag_1 = ipv4_packet_1.get_flags();
let df_1_set = if flag_1 & df_mask != 0 { true } else { false };
let ipv4_packet_2 = build_ipv4_packet(request_2, probe_name)?;
let flag_2 = ipv4_packet_2.get_flags();
let df_2_set = if flag_2 & df_mask != 0 { true } else { false };
let ipv4_packet_3 = build_ipv4_packet(response_1, probe_name)?;
let flag_3 = ipv4_packet_3.get_flags();
let df_3_set = if flag_3 & df_mask != 0 { true } else { false };
let ipv4_packet_4 = build_ipv4_packet(response_2, probe_name)?;
let flag_4 = ipv4_packet_4.get_flags();
let df_4_set = if flag_4 & df_mask != 0 { true } else { false };
let ret = if !df_3_set && !df_4_set {
String::from("N")
} else if (df_1_set == df_3_set) && (df_2_set == df_4_set) {
String::from("S")
} else if df_3_set && df_4_set {
String::from("Y")
} else {
String::from("O")
};
Ok(ret)
}
pub fn icmp_cd(ie: &IERR, probe_name: &str) -> Result<String, PistolError> {
let request_1 = &ie.ie1.request;
let request_2 = &ie.ie2.request;
let response_1 = &ie.ie1.response;
let response_2 = &ie.ie2.response;
if response_1.len() > 0 && response_2.len() > 0 {
let ipv4_packet_1 = build_ipv4_packet(&request_1, probe_name)?;
let icmp_packet_1 = build_icmp_packet(ipv4_packet_1.payload(), probe_name)?;
let ipv4_packet_2 = build_ipv4_packet(&request_2, probe_name)?;
let icmp_packet_2 = build_icmp_packet(ipv4_packet_2.payload(), probe_name)?;
let code_1 = icmp_packet_1.get_icmp_code();
let code_2 = icmp_packet_2.get_icmp_code();
let ipv4_packet_3 = build_ipv4_packet(&response_1, probe_name)?;
let icmp_packet_3 = build_icmp_packet(ipv4_packet_3.payload(), probe_name)?;
let ipv4_packet_4 = build_ipv4_packet(&response_2, probe_name)?;
let icmp_packet_4 = build_icmp_packet(ipv4_packet_4.payload(), probe_name)?;
let code_3 = icmp_packet_3.get_icmp_code();
let code_4 = icmp_packet_4.get_icmp_code();
let ret = if (code_3 == IcmpCode(0)) && (code_4 == IcmpCode(0)) {
String::from("Z")
} else if (code_1 == code_3) && (code_2 == code_4) {
String::from("S")
} else if code_3 == code_4 {
format!("{:X}", code_3.0)
} else {
String::from("O")
};
Ok(ret)
} else {
Ok(String::new())
}
}