sbd_server/config.rs
1#[cfg(feature = "unstable")]
2const DEF_IP_DENY_DIR: &str = ".";
3#[cfg(feature = "unstable")]
4const DEF_IP_DENY_S: i32 = 600;
5const DEF_LIMIT_CLIENTS: i32 = 32768;
6const DEF_LIMIT_IP_KBPS: i32 = 1000;
7const DEF_LIMIT_IP_BYTE_BURST: i32 = 16 * 16 * 1024;
8const DEF_LIMIT_IDLE_MILLIS: i32 = 10_000;
9
10/// Configure and execute an SBD server.
11#[derive(clap::Parser, Debug, Clone)]
12#[command(version, styles=get_styles())]
13pub struct Config {
14 /// TLS certificate path (pem).
15 /// If specified, `--priv-key-pem-file` must also be specified.
16 /// It is recommended to run acme service on port 80 and only
17 /// bind SBD to port 443.
18 #[arg(long)]
19 pub cert_pem_file: Option<std::path::PathBuf>,
20
21 /// TLS private key path (pem).
22 /// If specified, `--cert-pem-file` must also be specified.
23 /// It is recommended to run acme service on port 80 and only
24 /// bind SBD to port 443.
25 #[arg(long)]
26 pub priv_key_pem_file: Option<std::path::PathBuf>,
27
28 /// Bind to this interface and port. If multiple bindings specify port
29 /// zero, the server will attempt to bind the same port to each interface.
30 /// If it cannot, it will allow all the ports to be different.
31 /// Can be specified more than once.
32 /// E.g. `--bind 127.0.0.1:0 --bind [::1]:0 --bind 192.168.0.10:443`.
33 #[arg(long)]
34 pub bind: Vec<String>,
35
36 #[cfg(feature = "unstable")]
37 /// Watch this directory, and reload TLS certificates 10s after any
38 /// files change within it. Must be an exact match to the parent directory
39 /// of both `--cert-pem-file` and `--priv-key-pem-file`.
40 #[arg(long)]
41 pub watch_reload_tls_dir: Option<std::path::PathBuf>,
42
43 /// Use this http header to determine IP address instead of the raw
44 /// TCP connection details.
45 #[arg(long)]
46 pub trusted_ip_header: Option<String>,
47
48 #[cfg(feature = "unstable")]
49 /// The directory in which to store the blocked ip addresses.
50 /// Note v4 addresses will be mapped to v6 addresses per
51 /// <https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2>.
52 #[arg(long, default_value = DEF_IP_DENY_DIR)]
53 pub ip_deny_dir: std::path::PathBuf,
54
55 #[cfg(feature = "unstable")]
56 /// How long to block ip addresses in seconds. Set to zero to block
57 /// forever (or until the file is manually deleted).
58 #[arg(long, default_value_t = DEF_IP_DENY_S)]
59 pub ip_deny_s: i32,
60
61 #[cfg(feature = "unstable")]
62 /// Bind to this backchannel interface and port.
63 /// Can be specified more than once.
64 /// Note, this should be a local only or virtual private interface.
65 #[arg(long)]
66 pub back_bind: Vec<String>,
67
68 #[cfg(feature = "unstable")]
69 /// Allow incoming backchannel connections only
70 /// from the following explicit addresses. Note, this is expecting direct
71 /// connections, not through a proxy, so only the raw TCP address will
72 /// be validated. (This ignores the --trusted-ip-header parameter).
73 /// Can be specified more than once.
74 /// E.g. `--back-allow-ip 192.168.0.2 --back-allow-ip 192.168.0.3`.
75 #[arg(long)]
76 pub back_allow_ip: Vec<String>,
77
78 #[cfg(feature = "unstable")]
79 /// Try to establish outgoing backchannel connections
80 /// to the following ip+port addresses.
81 /// Can be specified more than once.
82 /// E.g. `--back-open 192.168.0.3:1443`
83 #[arg(long)]
84 pub back_open: Vec<String>,
85
86 #[cfg(feature = "unstable")]
87 /// Bind to this interface and port to provide prometheus metrics.
88 /// Note, this should be a local only or virtual private interface.
89 #[arg(long)]
90 pub bind_prometheus: Option<String>,
91
92 /// Limit client connections.
93 #[arg(long, default_value_t = DEF_LIMIT_CLIENTS)]
94 pub limit_clients: i32,
95
96 /// If set, rate-limiting will be disabled on the server,
97 /// and clients will be informed they have an 8gbps rate limit.
98 #[arg(long)]
99 pub disable_rate_limiting: bool,
100
101 /// Rate limit connections to this kilobits per second.
102 /// The default value of 1000 obviously limits connections to 1 mbps.
103 /// If the default of 32768 connections were all sending this amount
104 /// at the same time, the server would need a ~33 gbps connection.
105 /// The rate limit passed to clients will be divided by the number
106 /// of open connections for a given ip address.
107 #[arg(long, default_value_t = DEF_LIMIT_IP_KBPS)]
108 pub limit_ip_kbps: i32,
109
110 /// Allow IPs to burst by this byte count.
111 /// If the max message size is 16K, this value must be at least 16K.
112 /// The default value provides 16 * 16K to allow for multiple connections
113 /// from a single ip address sending full messages at the same time.
114 #[arg(long, default_value_t = DEF_LIMIT_IP_BYTE_BURST)]
115 pub limit_ip_byte_burst: i32,
116
117 /// How long in milliseconds connections can remain idle before being
118 /// closed. Clients must send either a message or a keepalive before
119 /// this time expires to keep the connection alive.
120 #[arg(long, default_value_t = DEF_LIMIT_IDLE_MILLIS)]
121 pub limit_idle_millis: i32,
122}
123
124impl Default for Config {
125 /// Construct a new config with some defaults set.
126 fn default() -> Self {
127 Self {
128 cert_pem_file: None,
129 priv_key_pem_file: None,
130 bind: Vec::new(),
131 #[cfg(feature = "unstable")]
132 watch_reload_tls_dir: None,
133 trusted_ip_header: None,
134 #[cfg(feature = "unstable")]
135 ip_deny_dir: std::path::PathBuf::from(DEF_IP_DENY_DIR),
136 #[cfg(feature = "unstable")]
137 ip_deny_s: DEF_IP_DENY_S,
138 #[cfg(feature = "unstable")]
139 back_bind: Vec::new(),
140 #[cfg(feature = "unstable")]
141 back_allow_ip: Vec::new(),
142 #[cfg(feature = "unstable")]
143 back_open: Vec::new(),
144 #[cfg(feature = "unstable")]
145 bind_prometheus: None,
146 limit_clients: DEF_LIMIT_CLIENTS,
147 disable_rate_limiting: false,
148 limit_ip_kbps: DEF_LIMIT_IP_KBPS,
149 limit_ip_byte_burst: DEF_LIMIT_IP_BYTE_BURST,
150 limit_idle_millis: DEF_LIMIT_IDLE_MILLIS,
151 }
152 }
153}
154
155impl Config {
156 pub(crate) fn idle_dur(&self) -> std::time::Duration {
157 std::time::Duration::from_millis(self.limit_idle_millis as u64)
158 }
159
160 /// convert kbps into the nanosecond weight of each byte
161 /// (easier to rate limit with this value)
162 pub(crate) fn limit_ip_byte_nanos(&self) -> i32 {
163 8_000_000 / self.limit_ip_kbps
164 }
165}
166
167fn get_styles() -> clap::builder::Styles {
168 clap::builder::Styles::styled()
169 .usage(
170 anstyle::Style::new()
171 .bold()
172 .fg_color(Some(anstyle::Color::Ansi(
173 anstyle::AnsiColor::Yellow,
174 ))),
175 )
176 .header(
177 anstyle::Style::new()
178 .bold()
179 .fg_color(Some(anstyle::Color::Ansi(
180 anstyle::AnsiColor::Yellow,
181 ))),
182 )
183 .literal(
184 anstyle::Style::new().fg_color(Some(anstyle::Color::Ansi(
185 anstyle::AnsiColor::Green,
186 ))),
187 )
188 .invalid(
189 anstyle::Style::new()
190 .bold()
191 .fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Red))),
192 )
193 .error(
194 anstyle::Style::new()
195 .bold()
196 .fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Red))),
197 )
198 .valid(
199 anstyle::Style::new()
200 .bold()
201 .fg_color(Some(anstyle::Color::Ansi(
202 anstyle::AnsiColor::Green,
203 ))),
204 )
205 .placeholder(
206 anstyle::Style::new().fg_color(Some(anstyle::Color::Ansi(
207 anstyle::AnsiColor::White,
208 ))),
209 )
210}