feat: profanity check service names; completely tested get_service

This commit is contained in:
Giuliano Bellini s294739
2024-02-09 00:33:47 +01:00
parent 2008135b92
commit 9f3b445fef
5 changed files with 519 additions and 11 deletions

44
Cargo.lock generated
View File

@@ -723,12 +723,24 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "downcast-rs"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "encoding_rs"
version = "0.8.33"
@@ -843,6 +855,12 @@ dependencies = [
"simd-adler32",
]
[[package]]
name = "finl_unicode"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6"
[[package]]
name = "flate2"
version = "1.0.28"
@@ -1661,6 +1679,15 @@ dependencies = [
"serde",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.10"
@@ -3087,6 +3114,22 @@ dependencies = [
"untrusted",
]
[[package]]
name = "rustrict"
version = "0.7.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cec1a563a7b388fb66b4947102848ce38e4f5adb70a544fdf0ebff0b890b1c88"
dependencies = [
"arrayvec",
"bitflags 1.3.2",
"doc-comment",
"finl_unicode",
"itertools",
"lazy_static",
"rustc-hash",
"unicode-normalization",
]
[[package]]
name = "rustybuzz"
version = "0.7.0"
@@ -3394,6 +3437,7 @@ dependencies = [
"rfd",
"rodio",
"rstest",
"rustrict",
"serde",
"serde_test",
"serial_test",

View File

@@ -73,6 +73,8 @@ serial_test = { version = "3.0.0", default_features = false }
[build-dependencies]
phf_codegen = "0.11.2"
phf_shared = "0.11.2"
rustrict = { version = "0.7.21", default-features = false, features = ["censor"] }
once_cell = "1.19.0"
[target."cfg(windows)".build-dependencies]
winres = "0.1.12"

106
build.rs
View File

@@ -6,6 +6,9 @@
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::Path;
use once_cell::sync::Lazy;
use rustrict::{Censor, Trie, Type};
include!("./src/networking/types/service_query.rs");
include!("./src/networking/types/protocol.rs");
@@ -68,6 +71,14 @@ fn get_valid_service_fmt_const(s: &str) -> String {
{
panic!("Invalid service name found: {invalid}")
}
inappropriate
if Censor::from_str(inappropriate)
.with_trie(&SAFE_WORDS_FOR_SERVICE_NAME)
.analyze()
.is(Type::INAPPROPRIATE) =>
{
panic!("Inappropriate service name found: {inappropriate}")
}
name => format!("Service::Name(\"{name}\")"),
}
}
@@ -84,3 +95,98 @@ fn get_valid_service_query(s: &str) -> ServiceQuery {
assert!(parts.next().is_none());
ServiceQuery(port, protocol)
}
pub static SAFE_WORDS_FOR_SERVICE_NAME: Lazy<Trie> = Lazy::new(|| {
let mut safe_words = Trie::default();
for word in [
"npp",
"emfis-cntl",
"ardus-cntl",
"pmip6-cntl",
"mpp",
"ipp",
"vpp",
"epp",
"kink",
"kvm-via-ip",
"dpp",
"slinkysearch",
"alta-ana-lm",
"vpps-qua",
"vpps-via",
"ibm-pps",
"ppsms",
"ppsuitemsg",
"icpps",
"rap-listen",
"cadabra-lm",
"pay-per-view",
"sixtrak",
"cvmon",
"houdini-lm",
"dic-aida",
"p2pq",
"bigbrother",
"bintec-admin",
"zymed-zpp",
"cvmmon",
"btpp2sectrans",
"conclave-cpp",
"btpp2audctr1",
"tclprodebugger",
"bintec-capi",
"bintec-tapi",
"dicom-iscl",
"dicom-tls",
"nmsigport",
"ppp",
"tl1-telnet",
"opcon-xps",
"netwatcher-mon",
"netwatcher-db",
"xnm-ssl",
"edm-mgr-cntrl",
"isoft-p2p",
"must-p2p",
"p2pgroup",
"quasar-server",
"int-rcv-cntrl",
"faxstfx-port",
"sunlps-http",
"fagordnc",
"p2pcommunity",
"minger",
"assuria-slm",
"wcpp",
"plcy-net-svcs",
"assyst-dr",
"mobile-p2p",
"assuria-ins",
"taep-as-svc",
"nlg-data",
"dj-ice",
"x500ms",
"X11:7",
"p2p-sip",
"p4p-portal",
"bmc-perf-agent",
"ntz-p2p-storage",
"citrixupp",
"freezexservice",
"p2pevolvenet",
"papachi-p2p-srv",
"espeasy-p2p",
"pim-port",
"vp2p",
"dicom",
"icpp",
"sauterdongle",
"vocaltec-hos",
"BackOrifice",
"dhanalakshmi",
"3gpp-w1ap",
] {
safe_words.set(word, Type::SAFE);
}
safe_words
});

View File

@@ -682,7 +682,7 @@ fn get_bars_length(
MIN_BAR_LENGTH
};
}
if outgoing_bar_len > 0.0 && outgoing_bar_len < 3.0 {
if outgoing_bar_len > 0.0 && outgoing_bar_len < MIN_BAR_LENGTH {
outgoing_bar_len = if incoming_bar_len > 0.0 {
MIN_BAR_LENGTH / 2.0
} else {

View File

@@ -156,7 +156,7 @@ fn analyze_transport_header(
}
pub fn get_service(key: &AddressPortPair, traffic_direction: TrafficDirection) -> Service {
if key.port1.is_none() || key.port2.is_none() {
if key.port1.is_none() || key.port2.is_none() || key.protocol == Protocol::ICMP {
return Service::NotApplicable;
}
@@ -175,30 +175,29 @@ pub fn get_service(key: &AddressPortPair, traffic_direction: TrafficDirection) -
let port1 = key.port1.unwrap();
let port2 = key.port2.unwrap();
let unknown = Service::Unknown;
let service1 = SERVICES
.get(&ServiceQuery(port1, key.protocol))
.cloned()
.unwrap_or_default();
.unwrap_or(&unknown);
let service2 = SERVICES
.get(&ServiceQuery(port2, key.protocol))
.cloned()
.unwrap_or_default();
.unwrap_or(&unknown);
let score1 = compute_service_score(
&service1,
service1,
port1,
traffic_direction.ne(&TrafficDirection::Outgoing),
);
let score2 = compute_service_score(
&service2,
service2,
port2,
traffic_direction.eq(&TrafficDirection::Outgoing),
);
if score1 > score2 {
service1
service1.clone()
} else {
service2
service2.clone()
}
}
@@ -598,8 +597,10 @@ mod tests {
use pcap::Address;
use crate::networking::manage_packets::{
get_traffic_direction, get_traffic_type, is_local_connection, mac_from_dec_to_hex,
get_service, get_traffic_direction, get_traffic_type, is_local_connection,
mac_from_dec_to_hex,
};
use crate::networking::types::address_port_pair::AddressPortPair;
use crate::networking::types::service_query::ServiceQuery;
use crate::networking::types::traffic_direction::TrafficDirection;
use crate::networking::types::traffic_type::TrafficType;
@@ -1072,6 +1073,243 @@ fn is_local_connection_ipv6_link_local_test() {
assert_eq!(result3, false);
}
#[test]
fn test_get_service_simple_only_one_valid() {
let unknown_port = Some(65000);
for p in [Protocol::TCP, Protocol::UDP] {
assert!(SERVICES
.get(&ServiceQuery(unknown_port.unwrap(), p))
.is_none());
for d in [TrafficDirection::Incoming, TrafficDirection::Outgoing] {
let key = AddressPortPair::new(
String::new(),
unknown_port,
String::new(),
unknown_port,
p,
);
assert_eq!(get_service(&key, d), Service::Unknown);
for (p1, p2) in [
(unknown_port, Some(22)),
(Some(22), unknown_port),
(Some(22), Some(22)),
] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Name("ssh"));
}
for (p1, p2) in [
(unknown_port, Some(443)),
(Some(443), unknown_port),
(Some(443), Some(443)),
] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Name("https"));
}
for (p1, p2) in [
(unknown_port, Some(80)),
(Some(80), unknown_port),
(Some(80), Some(80)),
] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Name("http"));
}
for (p1, p2) in [
(unknown_port, Some(1900)),
(Some(1900), unknown_port),
(Some(1900), Some(1900)),
] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Name("upnp"));
}
}
}
}
#[test]
fn test_get_service_well_known_ports_always_win() {
let valid_but_not_well_known = Some(1030);
for p in [Protocol::TCP, Protocol::UDP] {
assert_eq!(
SERVICES
.get(&ServiceQuery(valid_but_not_well_known.unwrap(), p))
.unwrap(),
&Service::Name("iad1")
);
for d in [TrafficDirection::Incoming, TrafficDirection::Outgoing] {
let key = AddressPortPair::new(
String::new(),
valid_but_not_well_known,
String::new(),
valid_but_not_well_known,
p,
);
assert_eq!(get_service(&key, d), Service::Name("iad1"));
for (p1, p2) in [
(valid_but_not_well_known, Some(67)),
(Some(67), valid_but_not_well_known),
(Some(67), Some(67)),
] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Name("dhcps"));
}
for (p1, p2) in [
(valid_but_not_well_known, Some(179)),
(Some(179), valid_but_not_well_known),
(Some(179), Some(179)),
] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Name("bgp"));
}
for (p1, p2) in [
(valid_but_not_well_known, Some(53)),
(Some(53), valid_but_not_well_known),
(Some(53), Some(53)),
] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Name("domain"));
}
for (p1, p2) in [
(valid_but_not_well_known, Some(1022)),
(Some(1022), valid_but_not_well_known),
(Some(1022), Some(1022)),
] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Name("exp2"));
}
}
}
}
#[test]
fn test_get_service_direction_bonus_matters() {
let smtp = Some(25);
let tacacs = Some(49);
let netmagic = Some(1196);
let tgp = Some(1223);
for p in [Protocol::TCP, Protocol::UDP] {
for d in [TrafficDirection::Incoming, TrafficDirection::Outgoing] {
for (p1, p2) in [(smtp, tacacs), (tacacs, smtp)] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(
get_service(&key, d),
Service::Name(match (p1, d) {
(source, TrafficDirection::Incoming) if source == tacacs => "tacacs",
(source, TrafficDirection::Outgoing) if source == tacacs => "smtp",
(source, TrafficDirection::Incoming) if source == smtp => "smtp",
(source, TrafficDirection::Outgoing) if source == smtp => "tacacs",
_ => panic!(),
})
);
}
for (p1, p2) in [(netmagic, tgp), (tgp, netmagic)] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(
get_service(&key, d),
Service::Name(match (p1, d) {
(source, TrafficDirection::Incoming) if source == netmagic =>
"netmagic",
(source, TrafficDirection::Outgoing) if source == netmagic => "tgp",
(source, TrafficDirection::Incoming) if source == tgp => "tgp",
(source, TrafficDirection::Outgoing) if source == tgp => "netmagic",
_ => panic!(),
})
);
}
}
}
}
#[test]
fn test_get_service_different_tcp_udp() {
for p in [Protocol::TCP, Protocol::UDP] {
for d in [TrafficDirection::Incoming, TrafficDirection::Outgoing] {
let key =
AddressPortPair::new(String::new(), Some(5353), String::new(), Some(5353), p);
assert_eq!(
get_service(&key, d),
Service::Name(match p {
Protocol::TCP => "mdns",
Protocol::UDP => "zeroconf",
Protocol::ICMP => panic!(),
})
);
let key = AddressPortPair::new(String::new(), Some(15), String::new(), Some(15), p);
assert_eq!(
get_service(&key, d),
match p {
Protocol::TCP => Service::Name("netstat"),
Protocol::UDP => Service::Unknown,
Protocol::ICMP => panic!(),
}
);
let key =
AddressPortPair::new(String::new(), Some(64738), String::new(), Some(64738), p);
assert_eq!(
get_service(&key, d),
match p {
Protocol::TCP => Service::Unknown,
Protocol::UDP => Service::Name("murmur"),
Protocol::ICMP => panic!(),
}
);
for (p1, p2) in [(Some(5353), Some(53)), (Some(53), Some(5353))] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Name("domain"));
}
}
}
}
#[test]
fn test_get_service_not_applicable() {
for p in Protocol::ALL {
for d in [TrafficDirection::Incoming, TrafficDirection::Outgoing] {
for (p1, p2) in [(None, Some(443)), (None, None), (Some(443), None)] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::NotApplicable);
}
}
}
}
#[test]
fn test_get_service_unknown() {
let unknown_port_1 = Some(39332);
let unknown_port_2 = Some(23679);
for p in [Protocol::TCP, Protocol::UDP] {
assert!(SERVICES
.get(&ServiceQuery(unknown_port_1.unwrap(), p))
.is_none());
assert!(SERVICES
.get(&ServiceQuery(unknown_port_2.unwrap(), p))
.is_none());
for d in [TrafficDirection::Incoming, TrafficDirection::Outgoing] {
for (p1, p2) in [
(unknown_port_1, unknown_port_2),
(unknown_port_2, unknown_port_1),
(unknown_port_1, unknown_port_1),
(unknown_port_2, unknown_port_2),
] {
let key = AddressPortPair::new(String::new(), p1, String::new(), p2, p);
assert_eq!(get_service(&key, d), Service::Unknown);
}
}
}
}
#[test]
fn test_all_services_map_key_and_values_are_valid() {
assert_eq!(SERVICES.len(), 12066);
@@ -1299,4 +1537,122 @@ fn test_service_names_of_old_application_protocols() {
&Service::Name("zeroconf")
);
}
#[test]
fn test_other_service_names() {
for p in [Protocol::TCP, Protocol::UDP] {
assert!(SERVICES.get(&ServiceQuery(4, p)).is_none());
assert!(SERVICES.get(&ServiceQuery(6, p)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(7, p)).unwrap(),
&Service::Name("echo")
);
assert!(SERVICES.get(&ServiceQuery(5811, p)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(6004, p)).unwrap(),
&Service::Name("X11:4")
);
assert_eq!(
SERVICES.get(&ServiceQuery(7777, p)).unwrap(),
&Service::Name("cbt")
);
assert!(SERVICES.get(&ServiceQuery(65000, p)).is_none());
}
assert_eq!(
SERVICES.get(&ServiceQuery(15, Protocol::TCP)).unwrap(),
&Service::Name("netstat")
);
assert!(SERVICES.get(&ServiceQuery(15, Protocol::UDP)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(26, Protocol::TCP)).unwrap(),
&Service::Name("rsftp")
);
assert!(SERVICES.get(&ServiceQuery(26, Protocol::UDP)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(87, Protocol::TCP)).unwrap(),
&Service::Name("priv-term-l")
);
assert!(SERVICES.get(&ServiceQuery(87, Protocol::UDP)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(106, Protocol::TCP)).unwrap(),
&Service::Name("pop3pw")
);
assert_eq!(
SERVICES.get(&ServiceQuery(106, Protocol::UDP)).unwrap(),
&Service::Name("3com-tsmux")
);
assert!(SERVICES.get(&ServiceQuery(1028, Protocol::TCP)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(1028, Protocol::UDP)).unwrap(),
&Service::Name("ms-lsa")
);
assert_eq!(
SERVICES.get(&ServiceQuery(1029, Protocol::TCP)).unwrap(),
&Service::Name("ms-lsa")
);
assert_eq!(
SERVICES.get(&ServiceQuery(1029, Protocol::UDP)).unwrap(),
&Service::Name("solid-mux")
);
assert_eq!(
SERVICES.get(&ServiceQuery(5820, Protocol::TCP)).unwrap(),
&Service::Name("autopassdaemon")
);
assert!(SERVICES.get(&ServiceQuery(5820, Protocol::UDP)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(5900, Protocol::TCP)).unwrap(),
&Service::Name("vnc")
);
assert_eq!(
SERVICES.get(&ServiceQuery(5900, Protocol::UDP)).unwrap(),
&Service::Name("rfb")
);
assert_eq!(
SERVICES.get(&ServiceQuery(5938, Protocol::TCP)).unwrap(),
&Service::Name("teamviewer")
);
assert!(SERVICES.get(&ServiceQuery(5938, Protocol::UDP)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(8888, Protocol::TCP)).unwrap(),
&Service::Name("sun-answerbook")
);
assert_eq!(
SERVICES.get(&ServiceQuery(8888, Protocol::UDP)).unwrap(),
&Service::Name("ddi-udp-1")
);
assert_eq!(
SERVICES.get(&ServiceQuery(23294, Protocol::TCP)).unwrap(),
&Service::Name("5afe-dir")
);
assert!(SERVICES.get(&ServiceQuery(23294, Protocol::UDP)).is_none());
assert!(SERVICES.get(&ServiceQuery(48899, Protocol::TCP)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(48899, Protocol::UDP)).unwrap(),
&Service::Name("tc_ads_discovery")
);
assert_eq!(
SERVICES.get(&ServiceQuery(62078, Protocol::TCP)).unwrap(),
&Service::Name("iphone-sync")
);
assert!(SERVICES.get(&ServiceQuery(62078, Protocol::UDP)).is_none());
assert!(SERVICES.get(&ServiceQuery(64738, Protocol::TCP)).is_none());
assert_eq!(
SERVICES.get(&ServiceQuery(64738, Protocol::UDP)).unwrap(),
&Service::Name("murmur")
);
}
}