From c5a3b82ff24b0b3cf17249c2a424e106ef9e31ed Mon Sep 17 00:00:00 2001 From: Chloe <110362826+dayeon5470@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:25:12 +0900 Subject: [PATCH] Add block list event to all protocols (#77) --- CHANGELOG.md | 14 +++ Cargo.toml | 2 +- src/graphql/data_source.rs | 2 +- src/graphql/event.rs | 210 ++++++++++++++++++++++++++++------ src/graphql/event/dcerpc.rs | 111 ++++++++++++++++++ src/graphql/event/ftp.rs | 139 ++++++++++++++++++++++ src/graphql/event/http.rs | 170 +++++++++++++++++++++++++++ src/graphql/event/kerberos.rs | 131 +++++++++++++++++++++ src/graphql/event/ldap.rs | 118 +++++++++++++++++++ src/graphql/event/mqtt.rs | 119 +++++++++++++++++++ src/graphql/event/nfs.rs | 103 +++++++++++++++++ src/graphql/event/ntlm.rs | 123 ++++++++++++++++++++ src/graphql/event/rdp.rs | 94 +++++++++++++++ src/graphql/event/smb.rs | 139 ++++++++++++++++++++++ src/graphql/event/smtp.rs | 119 +++++++++++++++++++ src/graphql/event/ssh.rs | 143 +++++++++++++++++++++++ src/graphql/event/tls.rs | 167 +++++++++++++++++++++++++++ src/graphql/node/control.rs | 2 +- src/graphql/tidb.rs | 2 +- src/lib.rs | 4 +- 20 files changed, 1872 insertions(+), 40 deletions(-) create mode 100644 src/graphql/event/dcerpc.rs create mode 100644 src/graphql/event/kerberos.rs create mode 100644 src/graphql/event/mqtt.rs create mode 100644 src/graphql/event/nfs.rs create mode 100644 src/graphql/event/ntlm.rs create mode 100644 src/graphql/event/smb.rs create mode 100644 src/graphql/event/smtp.rs create mode 100644 src/graphql/event/ssh.rs create mode 100644 src/graphql/event/tls.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 22ccf022..b8bb02d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,20 @@ Versioning](https://semver.org/spec/v2.0.0.html). ### Added - Added `processList` graphql query to get the host's list of processes. +- Add block list event. + - DceRpc: `BlockListDceRpc` + - Ftp: `BlockListFtp` + - Http: `BlockListHttp` + - Kerberos: `BlockListKerberos` + - Ldap: `BlockListLdap` + - Mqtt: `BlockListMqtt` + - Nfs: `BlockListNfs` + - Ntlm: `BlockListNtlm` + - Rdp: `BlockListRdp` + - Smb: `BlockListSmb` + - Smtp: `BlockListSmtp` + - Ssh: `BlockListSsh` + - tls: `BlockListTls` ### Changed diff --git a/Cargo.toml b/Cargo.toml index 7f362545..080cc915 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ oinq = { git = "https://github.com/petabi/oinq.git", tag = "0.9.1" } reqwest = { version = "0.11", default-features = false, features = [ "rustls-tls-native-roots", ] } -review-database = { git = "https://github.com/petabi/review-database.git", tag = "0.18.0" } +review-database = { git = "https://github.com/petabi/review-database.git", tag = "0.20.0" } roxy = { git = "https://github.com/aicers/roxy.git", tag = "0.2.1" } rustls = "0.21" rustls-native-certs = "0.6" diff --git a/src/graphql/data_source.rs b/src/graphql/data_source.rs index 0c37691c..4d0b11ce 100644 --- a/src/graphql/data_source.rs +++ b/src/graphql/data_source.rs @@ -79,7 +79,7 @@ impl TryFrom for database::DataSource { server_name, address, data_type, - source: input.source.unwrap_or(String::new()), + source: input.source.unwrap_or_default(), kind: input.kind, description: input.description, }) diff --git a/src/graphql/event.rs b/src/graphql/event.rs index c013f996..c78df7e1 100644 --- a/src/graphql/event.rs +++ b/src/graphql/event.rs @@ -1,18 +1,30 @@ mod conn; +mod dcerpc; mod dns; mod ftp; mod group; mod http; +mod kerberos; mod ldap; +mod mqtt; +mod nfs; +mod ntlm; mod rdp; +mod smb; +mod smtp; +mod ssh; +mod tls; pub(super) use self::group::EventGroupQuery; use self::{ conn::BlockListConn, conn::ExternalDdos, conn::MultiHostPortScan, conn::PortScan, - dns::BlockListDns, dns::CryptocurrencyMiningPool, dns::DnsCovertChannel, ftp::FtpBruteForce, - ftp::FtpPlainText, http::DomainGenerationAlgorithm, http::HttpThreat, http::NonBrowser, - http::RepeatedHttpSessions, http::TorConnection, ldap::LdapBruteForce, ldap::LdapPlainText, - rdp::RdpBruteForce, + dcerpc::BlockListDceRpc, dns::BlockListDns, dns::CryptocurrencyMiningPool, + dns::DnsCovertChannel, ftp::BlockListFtp, ftp::FtpBruteForce, ftp::FtpPlainText, + http::BlockListHttp, http::DomainGenerationAlgorithm, http::HttpThreat, http::NonBrowser, + http::RepeatedHttpSessions, http::TorConnection, kerberos::BlockListKerberos, + ldap::BlockListLdap, ldap::LdapBruteForce, ldap::LdapPlainText, mqtt::BlockListMqtt, + nfs::BlockListNfs, ntlm::BlockListNtlm, rdp::BlockListRdp, rdp::RdpBruteForce, + smb::BlockListSmb, smtp::BlockListSmtp, ssh::BlockListSsh, tls::BlockListTls, }; use super::{ customer::{Customer, HostNetworkGroupInput}, @@ -120,41 +132,54 @@ async fn fetch_events( let mut cryptocurrency_time = start_time; let mut block_list_conn_time = start_time; let mut block_list_dns_time = start_time; + let mut block_list_dcerpc_time = start_time; + let mut block_list_ftp_time = start_time; + let mut block_list_http_time = start_time; + let mut block_list_kerberos_time = start_time; + let mut block_list_ldap_time = start_time; + let mut block_list_mqtt_time = start_time; + let mut block_list_nfs_time = start_time; + let mut block_list_ntlm_time = start_time; + let mut block_list_rdp_time = start_time; + let mut block_list_smb_time = start_time; + let mut block_list_smtp_time = start_time; + let mut block_list_ssh_time = start_time; + let mut block_list_tls_time = start_time; loop { itv.tick().await; // Select the minimum time for DB search - let start = dns_covert_time.min( - http_threat_time.min( - rdp_brute_time.min( - repeat_http_time.min( - tor_time.min( - dga_time.min( - ftp_brute_time.min( - ftp_plain_time.min( - port_scan_time.min( - multi_host_time.min( - ldap_brute_time.min( - ldap_plain_time.min( - non_browser_time.min( - external_ddos_time - .min(cryptocurrency_time) - .min(block_list_conn_time) - .min(block_list_dns_time), - ), - ), - ), - ), - ), - ), - ), - ), - ), - ), - ), - ), - ); + let start = dns_covert_time + .min(http_threat_time) + .min(rdp_brute_time) + .min(repeat_http_time) + .min(tor_time) + .min(dga_time) + .min(ftp_brute_time) + .min(ftp_plain_time) + .min(port_scan_time) + .min(multi_host_time) + .min(ldap_brute_time) + .min(ldap_plain_time) + .min(non_browser_time) + .min(external_ddos_time) + .min(cryptocurrency_time) + .min(block_list_conn_time) + .min(block_list_dns_time) + .min(block_list_dcerpc_time) + .min(block_list_ftp_time) + .min(block_list_http_time) + .min(block_list_kerberos_time) + .min(block_list_ldap_time) + .min(block_list_mqtt_time) + .min(block_list_nfs_time) + .min(block_list_ntlm_time) + .min(block_list_rdp_time) + .min(block_list_smb_time) + .min(block_list_smtp_time) + .min(block_list_ssh_time) + .min(block_list_tls_time); // Fetch event iterator based on time let start = i128::from(start) << 64; @@ -273,6 +298,84 @@ async fn fetch_events( block_list_dns_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; } } + EventKind::BlockListDceRpc => { + if event_time >= block_list_dcerpc_time { + tx.unbounded_send(value.into())?; + block_list_dcerpc_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListFtp => { + if event_time >= block_list_ftp_time { + tx.unbounded_send(value.into())?; + block_list_ftp_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListHttp => { + if event_time >= block_list_http_time { + tx.unbounded_send(value.into())?; + block_list_http_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListKerberos => { + if event_time >= block_list_kerberos_time { + tx.unbounded_send(value.into())?; + block_list_kerberos_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListLdap => { + if event_time >= block_list_ldap_time { + tx.unbounded_send(value.into())?; + block_list_ldap_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListMqtt => { + if event_time >= block_list_mqtt_time { + tx.unbounded_send(value.into())?; + block_list_mqtt_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListNfs => { + if event_time >= block_list_nfs_time { + tx.unbounded_send(value.into())?; + block_list_nfs_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListNtlm => { + if event_time >= block_list_ntlm_time { + tx.unbounded_send(value.into())?; + block_list_ntlm_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListRdp => { + if event_time >= block_list_rdp_time { + tx.unbounded_send(value.into())?; + block_list_rdp_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListSmb => { + if event_time >= block_list_smb_time { + tx.unbounded_send(value.into())?; + block_list_smb_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListSmtp => { + if event_time >= block_list_smtp_time { + tx.unbounded_send(value.into())?; + block_list_smtp_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListSsh => { + if event_time >= block_list_ssh_time { + tx.unbounded_send(value.into())?; + block_list_ssh_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } + EventKind::BlockListTls => { + if event_time >= block_list_tls_time { + tx.unbounded_send(value.into())?; + block_list_tls_time = event_time + ADD_TIME_FOR_NEXT_COMPARE; + } + } EventKind::Log => continue, } } @@ -371,6 +474,32 @@ enum Event { BlockListConn(BlockListConn), BlockListDns(BlockListDns), + + BlockListDceRpc(BlockListDceRpc), + + BlockListFtp(BlockListFtp), + + BlockListHttp(BlockListHttp), + + BlockListKerberos(BlockListKerberos), + + BlockListLdap(BlockListLdap), + + BlockListMqtt(BlockListMqtt), + + BlockListNfs(BlockListNfs), + + BlockListNtlm(BlockListNtlm), + + BlockListRdp(BlockListRdp), + + BlockListSmb(BlockListSmb), + + BlockListSmtp(BlockListSmtp), + + BlockListSsh(BlockListSsh), + + BlockListTls(BlockListTls), } impl From for Event { @@ -400,6 +529,19 @@ impl From for Event { database::Event::BlockList(record_type) => match record_type { RecordType::Conn(event) => Event::BlockListConn(event.into()), RecordType::Dns(event) => Event::BlockListDns(event.into()), + RecordType::DceRpc(event) => Event::BlockListDceRpc(event.into()), + RecordType::Ftp(event) => Event::BlockListFtp(event.into()), + RecordType::Http(event) => Event::BlockListHttp(event.into()), + RecordType::Kerberos(event) => Event::BlockListKerberos(event.into()), + RecordType::Ldap(event) => Event::BlockListLdap(event.into()), + RecordType::Mqtt(event) => Event::BlockListMqtt(event.into()), + RecordType::Nfs(event) => Event::BlockListNfs(event.into()), + RecordType::Ntlm(event) => Event::BlockListNtlm(event.into()), + RecordType::Rdp(event) => Event::BlockListRdp(event.into()), + RecordType::Smb(event) => Event::BlockListSmb(event.into()), + RecordType::Smtp(event) => Event::BlockListSmtp(event.into()), + RecordType::Ssh(event) => Event::BlockListSsh(event.into()), + RecordType::Tls(event) => Event::BlockListTls(event.into()), }, } } diff --git a/src/graphql/event/dcerpc.rs b/src/graphql/event/dcerpc.rs new file mode 100644 index 00000000..2cd9d5d4 --- /dev/null +++ b/src/graphql/event/dcerpc.rs @@ -0,0 +1,111 @@ +use super::{country_code, find_ip_customer, find_ip_network, TriageScore}; +use crate::graphql::{customer::Customer, network::Network}; +use async_graphql::{Context, Object, Result}; +use chrono::{DateTime, Utc}; +use review_database as database; + +pub(super) struct BlockListDceRpc { + inner: database::BlockListDceRpc, +} + +#[Object] +impl BlockListDceRpc { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn rtt(&self) -> i64 { + self.inner.rtt + } + + async fn named_pipe(&self) -> &str { + &self.inner.named_pipe + } + + async fn endpoint(&self) -> &str { + &self.inner.endpoint + } + + async fn operation(&self) -> &str { + &self.inner.endpoint + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListDceRpc { + fn from(inner: database::BlockListDceRpc) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/ftp.rs b/src/graphql/event/ftp.rs index 91481b58..ebb64020 100644 --- a/src/graphql/event/ftp.rs +++ b/src/graphql/event/ftp.rs @@ -233,3 +233,142 @@ impl From for FtpPlainText { Self { inner } } } + +#[allow(clippy::module_name_repetitions)] +pub(super) struct BlockListFtp { + inner: database::BlockListFtp, +} + +#[Object] +impl BlockListFtp { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn user(&self) -> &str { + &self.inner.user + } + + async fn password(&self) -> &str { + &self.inner.password + } + + async fn command(&self) -> &str { + &self.inner.command + } + + async fn reply_code(&self) -> &str { + &self.inner.reply_code + } + + async fn reply_msg(&self) -> &str { + &self.inner.reply_msg + } + + async fn data_passive(&self) -> bool { + self.inner.data_passive + } + + async fn data_orig_addr(&self) -> String { + self.inner.data_orig_addr.to_string() + } + + async fn data_resp_addr(&self) -> String { + self.inner.data_resp_addr.to_string() + } + + async fn data_resp_port(&self) -> u16 { + self.inner.data_resp_port + } + + async fn file(&self) -> &str { + &self.inner.file + } + + async fn file_size(&self) -> u64 { + self.inner.file_size + } + + async fn file_id(&self) -> &str { + &self.inner.file_id + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListFtp { + fn from(inner: database::BlockListFtp) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/http.rs b/src/graphql/event/http.rs index 5f8de6fd..a0fe8bc2 100644 --- a/src/graphql/event/http.rs +++ b/src/graphql/event/http.rs @@ -734,3 +734,173 @@ impl From for NonBrowser { Self { inner } } } + +pub(super) struct BlockListHttp { + inner: database::BlockListHttp, +} + +#[Object] +impl BlockListHttp { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn method(&self) -> &str { + &self.inner.method + } + + async fn host(&self) -> &str { + &self.inner.host + } + + async fn uri(&self) -> &str { + &self.inner.uri + } + + async fn referer(&self) -> &str { + &self.inner.referrer + } + + async fn version(&self) -> &str { + &self.inner.version + } + + async fn user_agent(&self) -> &str { + &self.inner.user_agent + } + + async fn request_len(&self) -> usize { + self.inner.request_len + } + + async fn response_len(&self) -> usize { + self.inner.response_len + } + + async fn status_code(&self) -> u16 { + self.inner.status_code + } + + async fn status_msg(&self) -> &str { + &self.inner.status_msg + } + + async fn username(&self) -> &str { + &self.inner.username + } + + async fn password(&self) -> &str { + &self.inner.password + } + + async fn cookie(&self) -> &str { + &self.inner.cookie + } + + async fn content_encoding(&self) -> &str { + &self.inner.content_encoding + } + + async fn content_type(&self) -> &str { + &self.inner.content_type + } + + async fn cache_control(&self) -> &str { + &self.inner.cache_control + } + + async fn orig_filenames(&self) -> Vec { + self.inner.orig_filenames.clone() + } + + async fn orig_mime_types(&self) -> Vec { + self.inner.orig_mime_types.clone() + } + + async fn resp_filenames(&self) -> Vec { + self.inner.resp_filenames.clone() + } + + async fn resp_mime_types(&self) -> Vec { + self.inner.resp_mime_types.clone() + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListHttp { + fn from(inner: database::BlockListHttp) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/kerberos.rs b/src/graphql/event/kerberos.rs new file mode 100644 index 00000000..3459d343 --- /dev/null +++ b/src/graphql/event/kerberos.rs @@ -0,0 +1,131 @@ +use super::{country_code, find_ip_customer, find_ip_network, TriageScore}; +use crate::graphql::{customer::Customer, network::Network}; +use async_graphql::{Context, Object, Result}; +use chrono::{DateTime, Utc}; +use review_database as database; + +pub(super) struct BlockListKerberos { + inner: database::BlockListKerberos, +} + +#[Object] +impl BlockListKerberos { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn client_time(&self) -> i64 { + self.inner.client_time + } + + async fn server_time(&self) -> i64 { + self.inner.server_time + } + + async fn error_code(&self) -> u32 { + self.inner.error_code + } + + async fn client_realm(&self) -> &str { + &self.inner.client_realm + } + + async fn cname_type(&self) -> u8 { + self.inner.cname_type + } + + async fn client_name(&self) -> Vec { + self.inner.client_name.clone() + } + + async fn realm(&self) -> &str { + &self.inner.realm + } + + async fn sname_type(&self) -> u8 { + self.inner.sname_type + } + + async fn service_name(&self) -> Vec { + self.inner.service_name.clone() + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListKerberos { + fn from(inner: database::BlockListKerberos) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/ldap.rs b/src/graphql/event/ldap.rs index 1ab92663..31de5424 100644 --- a/src/graphql/event/ldap.rs +++ b/src/graphql/event/ldap.rs @@ -213,3 +213,121 @@ impl From for LdapPlainText { Self { inner } } } + +pub(super) struct BlockListLdap { + inner: database::BlockListLdap, +} + +#[Object] +impl BlockListLdap { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn message_id(&self) -> u32 { + self.inner.message_id + } + + async fn version(&self) -> u8 { + self.inner.version + } + + async fn opcode(&self) -> Vec { + self.inner.opcode.clone() + } + + async fn result(&self) -> Vec { + self.inner.result.clone() + } + + async fn diagnostic_message(&self) -> Vec { + self.inner.diagnostic_message.clone() + } + + async fn object(&self) -> Vec { + self.inner.object.clone() + } + + async fn argument(&self) -> Vec { + self.inner.argument.clone() + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListLdap { + fn from(inner: database::BlockListLdap) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/mqtt.rs b/src/graphql/event/mqtt.rs new file mode 100644 index 00000000..196593cd --- /dev/null +++ b/src/graphql/event/mqtt.rs @@ -0,0 +1,119 @@ +use super::{country_code, find_ip_customer, find_ip_network, TriageScore}; +use crate::graphql::{customer::Customer, network::Network}; +use async_graphql::{Context, Object, Result}; +use chrono::{DateTime, Utc}; +use review_database as database; + +pub(super) struct BlockListMqtt { + inner: database::BlockListMqtt, +} + +#[Object] +impl BlockListMqtt { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn protocol(&self) -> &str { + &self.inner.protocol + } + + async fn version(&self) -> u8 { + self.inner.version + } + + async fn client_id(&self) -> &str { + &self.inner.client_id + } + + async fn connack_reason(&self) -> u8 { + self.inner.connack_reason + } + + async fn subscribe(&self) -> Vec { + self.inner.subscribe.clone() + } + + async fn suback_reason(&self) -> Vec { + self.inner.suback_reason.clone() + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListMqtt { + fn from(inner: database::BlockListMqtt) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/nfs.rs b/src/graphql/event/nfs.rs new file mode 100644 index 00000000..c1cde4b5 --- /dev/null +++ b/src/graphql/event/nfs.rs @@ -0,0 +1,103 @@ +use super::{country_code, find_ip_customer, find_ip_network, TriageScore}; +use crate::graphql::{customer::Customer, network::Network}; +use async_graphql::{Context, Object, Result}; +use chrono::{DateTime, Utc}; +use review_database as database; + +pub(super) struct BlockListNfs { + inner: database::BlockListNfs, +} + +#[Object] +impl BlockListNfs { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn read_files(&self) -> Vec { + self.inner.read_files.clone() + } + + async fn write_files(&self) -> Vec { + self.inner.write_files.clone() + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListNfs { + fn from(inner: database::BlockListNfs) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/ntlm.rs b/src/graphql/event/ntlm.rs new file mode 100644 index 00000000..8e3b1c3d --- /dev/null +++ b/src/graphql/event/ntlm.rs @@ -0,0 +1,123 @@ +use super::{country_code, find_ip_customer, find_ip_network, TriageScore}; +use crate::graphql::{customer::Customer, network::Network}; +use async_graphql::{Context, Object, Result}; +use chrono::{DateTime, Utc}; +use review_database as database; + +pub(super) struct BlockListNtlm { + inner: database::BlockListNtlm, +} + +#[Object] +impl BlockListNtlm { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn username(&self) -> &str { + &self.inner.username + } + + async fn hostname(&self) -> &str { + &self.inner.hostname + } + + async fn domainname(&self) -> &str { + &self.inner.domainname + } + + async fn server_nb_computer_name(&self) -> &str { + &self.inner.server_nb_computer_name + } + + async fn server_dns_computer_name(&self) -> &str { + &self.inner.server_dns_computer_name + } + + async fn server_tree_name(&self) -> &str { + &self.inner.server_tree_name + } + + async fn success(&self) -> &str { + &self.inner.success + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListNtlm { + fn from(inner: database::BlockListNtlm) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/rdp.rs b/src/graphql/event/rdp.rs index d836899f..9f7201dc 100644 --- a/src/graphql/event/rdp.rs +++ b/src/graphql/event/rdp.rs @@ -92,3 +92,97 @@ impl From for RdpBruteForce { Self { inner } } } + +pub(super) struct BlockListRdp { + inner: database::BlockListRdp, +} + +#[Object] +impl BlockListRdp { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + // The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn cookie(&self) -> String { + self.inner.cookie.to_string() + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListRdp { + fn from(inner: database::BlockListRdp) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/smb.rs b/src/graphql/event/smb.rs new file mode 100644 index 00000000..90175abc --- /dev/null +++ b/src/graphql/event/smb.rs @@ -0,0 +1,139 @@ +use super::{country_code, find_ip_customer, find_ip_network, TriageScore}; +use crate::graphql::{customer::Customer, network::Network}; +use async_graphql::{Context, Object, Result}; +use chrono::{DateTime, Utc}; +use review_database as database; + +pub(super) struct BlockListSmb { + inner: database::BlockListSmb, +} + +#[Object] +impl BlockListSmb { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn command(&self) -> u8 { + self.inner.command + } + + async fn path(&self) -> &str { + &self.inner.path + } + + async fn service(&self) -> &str { + &self.inner.service + } + + async fn file_name(&self) -> &str { + &self.inner.file_name + } + + async fn file_size(&self) -> u64 { + self.inner.file_size + } + + async fn resource_type(&self) -> u16 { + self.inner.resource_type + } + + async fn fid(&self) -> u16 { + self.inner.fid + } + + async fn create_time(&self) -> i64 { + self.inner.create_time + } + + async fn access_time(&self) -> i64 { + self.inner.access_time + } + + async fn write_time(&self) -> i64 { + self.inner.write_time + } + + async fn change_time(&self) -> i64 { + self.inner.change_time + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListSmb { + fn from(inner: database::BlockListSmb) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/smtp.rs b/src/graphql/event/smtp.rs new file mode 100644 index 00000000..f5c7bb11 --- /dev/null +++ b/src/graphql/event/smtp.rs @@ -0,0 +1,119 @@ +use super::{country_code, find_ip_customer, find_ip_network, TriageScore}; +use crate::graphql::{customer::Customer, network::Network}; +use async_graphql::{Context, Object, Result}; +use chrono::{DateTime, Utc}; +use review_database as database; + +pub(super) struct BlockListSmtp { + inner: database::BlockListSmtp, +} + +#[Object] +impl BlockListSmtp { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn mailfrom(&self) -> &str { + &self.inner.mailfrom + } + + async fn date(&self) -> &str { + &self.inner.date + } + + async fn from(&self) -> &str { + &self.inner.from + } + + async fn to(&self) -> &str { + &self.inner.to + } + + async fn subject(&self) -> &str { + &self.inner.subject + } + + async fn agent(&self) -> &str { + &self.inner.agent + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListSmtp { + fn from(inner: database::BlockListSmtp) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/ssh.rs b/src/graphql/event/ssh.rs new file mode 100644 index 00000000..760866eb --- /dev/null +++ b/src/graphql/event/ssh.rs @@ -0,0 +1,143 @@ +use super::{country_code, find_ip_customer, find_ip_network, TriageScore}; +use crate::graphql::{customer::Customer, network::Network}; +use async_graphql::{Context, Object, Result}; +use chrono::{DateTime, Utc}; +use review_database as database; + +pub(super) struct BlockListSsh { + inner: database::BlockListSsh, +} + +#[Object] +impl BlockListSsh { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn version(&self) -> i64 { + self.inner.version + } + + async fn auth_success(&self) -> &str { + &self.inner.auth_success + } + + async fn auth_attempts(&self) -> i64 { + self.inner.auth_attempts + } + + async fn direction(&self) -> &str { + &self.inner.direction + } + + async fn client(&self) -> &str { + &self.inner.client + } + + async fn server(&self) -> &str { + &self.inner.server + } + + async fn cipher_alg(&self) -> &str { + &self.inner.cipher_alg + } + + async fn mac_alg(&self) -> &str { + &self.inner.mac_alg + } + + async fn compression_alg(&self) -> &str { + &self.inner.compression_alg + } + + async fn kex_alg(&self) -> &str { + &self.inner.kex_alg + } + + async fn host_key_alg(&self) -> &str { + &self.inner.host_key_alg + } + + async fn host_key(&self) -> &str { + &self.inner.host_key + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListSsh { + fn from(inner: database::BlockListSsh) -> Self { + Self { inner } + } +} diff --git a/src/graphql/event/tls.rs b/src/graphql/event/tls.rs new file mode 100644 index 00000000..d4c2547e --- /dev/null +++ b/src/graphql/event/tls.rs @@ -0,0 +1,167 @@ +use super::{country_code, find_ip_customer, find_ip_network, TriageScore}; +use crate::graphql::{customer::Customer, network::Network}; +use async_graphql::{Context, Object, Result}; +use chrono::{DateTime, Utc}; +use review_database as database; + +pub(super) struct BlockListTls { + inner: database::BlockListTls, +} + +#[Object] +impl BlockListTls { + async fn time(&self) -> DateTime { + self.inner.time + } + + async fn source(&self) -> &str { + &self.inner.source + } + + async fn src_addr(&self) -> String { + self.inner.src_addr.to_string() + } + + /// The two-letter country code of the source IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn src_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.src_addr) + } + + async fn src_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.src_addr) + } + + async fn src_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.src_addr) + } + + async fn src_port(&self) -> u16 { + self.inner.src_port + } + + async fn dst_addr(&self) -> String { + self.inner.dst_addr.to_string() + } + + /// The two-letter country code of the destination IP address. `"XX"` if the + /// location of the address is not known, and `"ZZ"` if the location + /// database is unavailable. + async fn dst_country(&self, ctx: &Context<'_>) -> String { + country_code(ctx, self.inner.dst_addr) + } + + async fn dst_customer(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.customer_map(); + find_ip_customer(&map, self.inner.dst_addr) + } + + async fn dst_network(&self, ctx: &Context<'_>) -> Result> { + let store = crate::graphql::get_store(ctx).await?; + let map = store.network_map(); + find_ip_network(&map, self.inner.dst_addr) + } + + async fn dst_port(&self) -> u16 { + self.inner.dst_port + } + + async fn proto(&self) -> u8 { + self.inner.proto + } + + async fn last_time(&self) -> i64 { + self.inner.last_time + } + + async fn server_name(&self) -> &str { + &self.inner.server_name + } + + async fn alpn_protocol(&self) -> &str { + &self.inner.alpn_protocol + } + + async fn ja3(&self) -> &str { + &self.inner.ja3 + } + + async fn version(&self) -> &str { + &self.inner.version + } + + async fn cipher(&self) -> u16 { + self.inner.cipher + } + + async fn ja3s(&self) -> &str { + &self.inner.ja3s + } + + async fn serial(&self) -> &str { + &self.inner.serial + } + + async fn subject_country(&self) -> &str { + &self.inner.subject_country + } + + async fn subject_org_name(&self) -> &str { + &self.inner.subject_org_name + } + + async fn subject_common_name(&self) -> &str { + &self.inner.subject_common_name + } + + async fn validity_not_before(&self) -> i64 { + self.inner.validity_not_before + } + + async fn validity_not_after(&self) -> i64 { + self.inner.validity_not_after + } + + async fn subject_alt_name(&self) -> &str { + &self.inner.subject_alt_name + } + + async fn issuer_country(&self) -> &str { + &self.inner.issuer_country + } + + async fn issuer_org_name(&self) -> &str { + &self.inner.issuer_org_name + } + + async fn issuer_org_unit_name(&self) -> &str { + &self.inner.issuer_org_unit_name + } + + async fn issuer_common_name(&self) -> &str { + &self.inner.issuer_common_name + } + + async fn last_alert(&self) -> u8 { + self.inner.last_alert + } + + async fn triage_scores(&self) -> Option> { + self.inner + .triage_scores + .as_ref() + .map(|scores| scores.iter().map(Into::into).collect::>()) + } +} + +impl From for BlockListTls { + fn from(inner: database::BlockListTls) -> Self { + Self { inner } + } +} diff --git a/src/graphql/node/control.rs b/src/graphql/node/control.rs index 2454ea36..aee36eb7 100644 --- a/src/graphql/node/control.rs +++ b/src/graphql/node/control.rs @@ -36,7 +36,7 @@ impl NodeControlMutation { }; response.map_or_else( |e| Err(format!("unable to reboot the system: {e}").into()), - |_| Ok(hostname), + |()| Ok(hostname), ) } } diff --git a/src/graphql/tidb.rs b/src/graphql/tidb.rs index 65b55ebd..6cfe4d5f 100644 --- a/src/graphql/tidb.rs +++ b/src/graphql/tidb.rs @@ -72,7 +72,7 @@ impl TidbMutation { let mut removed = Vec::with_capacity(names.len()); for name in names { match database::Tidb::remove(&store, &name) { - Ok(_) => removed.push(name), + Ok(()) => removed.push(name), Err(e) => return Err(format!("{e:?}").into()), }; } diff --git a/src/lib.rs b/src/lib.rs index 8fab129b..cd19b5c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,14 +121,14 @@ where let cert_reload = config.cert_reload_handle.notified(); tokio::select! { - _ = wait_shutdown => { + () = wait_shutdown => { info!("Shutting down Web server"); notify_shutdown.notify_one(); shutdown_completed.notified().await; web_srv_shutdown_handle.notify_one(); return Ok(()); }, - _ = cert_reload => { + () = cert_reload => { info!("Restarting Web server to reload certificates"); notify_shutdown.notify_one(); shutdown_completed.notified().await;