1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Lading blackholes
//!
//! For targets that need to push bytes themselves lading has b'blackhole'
//! support. These are listening servers that catch payloads from the target, do
//! as little as possible with them and respond as minimally as possible in
//! order to avoid overhead.
use serde::Deserialize;
use crate::signals::Shutdown;
pub mod http;
pub mod splunk_hec;
pub mod sqs;
pub mod tcp;
pub mod udp;
pub mod unix_datagram;
pub mod unix_stream;
#[derive(Debug)]
/// Errors produced by [`Server`].
pub enum Error {
/// See [`crate::blackhole::tcp::Error`] for details.
Tcp(tcp::Error),
/// See [`crate::blackhole::http::Error`] for details.
Http(http::Error),
/// See [`crate::blackhole::splunk_hec::Error`] for details.
SplunkHec(splunk_hec::Error),
/// See [`crate::blackhole::udp::Error`] for details.
Udp(udp::Error),
/// See [`crate::blackhole::unix_stream::Error`] for details.
UnixStream(unix_stream::Error),
/// See [`crate::blackhole::unix_datagram::Error`] for details.
UnixDatagram(unix_datagram::Error),
/// See [`crate::blackhole::sqs::Error`] for details.
Sqs(sqs::Error),
}
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
/// Configuration for [`Server`]
pub struct Config {
/// Common blackhole configs
#[serde(flatten)]
pub general: General,
/// The blackhole config
#[serde(flatten)]
pub inner: Inner,
}
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
/// Configurations common to all [`Server`] variants
pub struct General {
/// The ID assigned to this blackhole
pub id: Option<String>,
}
#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
/// Configuration for [`Server`]
pub enum Inner {
/// See [`crate::blackhole::tcp::Config`] for details.
Tcp(tcp::Config),
/// See [`crate::blackhole::http::Config`] for details.
Http(http::Config),
/// See [`crate::blackhole::splunk_hec::Config`] for details.
SplunkHec(splunk_hec::Config),
/// See [`crate::blackhole::udp::Config`] for details.
Udp(udp::Config),
/// See [`crate::blackhole::unix_stream::Config`] for details.
UnixStream(unix_stream::Config),
/// See [`crate::blackhole::unix_datagram::Config`] for details.
UnixDatagram(unix_datagram::Config),
/// See [`crate::blackhole::sqs::Config`] for details.
Sqs(sqs::Config),
}
#[derive(Debug)]
/// The blackhole server.
///
/// All blackholes supported by lading are a variant of this enum. Please see
/// variant documentation for details.
pub enum Server {
/// See [`crate::blackhole::tcp::Tcp`] for details.
Tcp(tcp::Tcp),
/// See [`crate::blackhole::http::Http`] for details.
Http(http::Http),
/// See [`crate::blackhole::splunk_hec::SplunkHec`] for details.
SplunkHec(splunk_hec::SplunkHec),
/// See [`crate::blackhole::udp::Udp`] for details.
Udp(udp::Udp),
/// See [`crate::blackhole::unix_stream::UnixStream`] for details.
UnixStream(unix_stream::UnixStream),
/// See [`crate::blackhole::unix_datagram::UnixDatagram`] for details.
UnixDatagram(unix_datagram::UnixDatagram),
/// See [`crate::blackhole::sqs::Sqs`] for details.
Sqs(sqs::Sqs),
}
impl Server {
/// Create a new [`Server`]
///
/// This function creates a new [`Server`] instance, deferring to the
/// underlying sub-server.
///
/// # Errors
///
/// Function will return an error if the underlying sub-server creation
/// signals error.
pub fn new(config: Config, shutdown: Shutdown) -> Result<Self, Error> {
let server = match config.inner {
Inner::Tcp(conf) => Self::Tcp(tcp::Tcp::new(config.general, &conf, shutdown)),
Inner::Http(conf) => {
Self::Http(http::Http::new(config.general, &conf, shutdown).map_err(Error::Http)?)
}
Inner::Udp(conf) => Self::Udp(udp::Udp::new(config.general, &conf, shutdown)),
Inner::UnixStream(conf) => {
Self::UnixStream(unix_stream::UnixStream::new(config.general, conf, shutdown))
}
Inner::UnixDatagram(conf) => Self::UnixDatagram(unix_datagram::UnixDatagram::new(
config.general,
conf,
shutdown,
)),
Inner::Sqs(conf) => Self::Sqs(sqs::Sqs::new(config.general, &conf, shutdown)),
Inner::SplunkHec(conf) => {
Self::SplunkHec(splunk_hec::SplunkHec::new(config.general, &conf, shutdown))
}
};
Ok(server)
}
/// Runs this [`Server`] to completion
///
/// This function runs the user supplied process to its completion, or until
/// a shutdown signal is received.
///
/// # Errors
///
/// Function will return an error if the underlying sub-server signals
/// error.
pub async fn run(self) -> Result<(), Error> {
match self {
Server::Tcp(inner) => inner.run().await.map_err(Error::Tcp),
Server::Http(inner) => inner.run().await.map_err(Error::Http),
Server::Udp(inner) => Box::pin(inner.run()).await.map_err(Error::Udp),
Server::UnixStream(inner) => inner.run().await.map_err(Error::UnixStream),
Server::UnixDatagram(inner) => Box::pin(inner.run()).await.map_err(Error::UnixDatagram),
Server::Sqs(inner) => inner.run().await.map_err(Error::Sqs),
Server::SplunkHec(inner) => inner.run().await.map_err(Error::SplunkHec),
}
}
}