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}