1use clap::Parser;
2
3use crate::helpers::{Helpers, Res};
4
5#[derive(Parser, Debug, Clone)]
9#[command(name = "rusty_socks", version, about, long_about = None)]
10pub struct Config {
11 #[arg(long, env = "RS_LISTEN_INTERFACE")]
13 pub listen_interface: Option<String>,
14
15 #[arg(long, env = "RS_ENDPOINT_INTERFACE")]
17 pub endpoint_interface: Option<String>,
18
19 #[arg(long, env = "RS_PORT", default_value_t = 1080)]
21 pub port: u16,
22
23 #[arg(long, env = "RS_BUFFER_SIZE", default_value_t = 2048)]
25 pub buffer_size: usize,
26
27 #[arg(long, env = "RS_READ_TIMEOUT", default_value_t = 60_000)]
30 pub read_timeout: u64,
31
32 #[arg(long, env = "RS_ACCEPT_CIDR", default_value = "0.0.0.0/0")]
34 pub accept_cidr: String,
35}
36
37impl Config {
38 pub fn listen_ip(&self) -> Res<String> {
40 Self::interface_ip(self.listen_interface.as_deref())
41 }
42
43 pub fn endpoint_ip(&self) -> Res<String> {
45 Self::interface_ip(self.endpoint_interface.as_deref())
46 }
47
48 fn interface_ip(interface: Option<&str>) -> Res<String> {
49 match interface {
50 Some(name) => Ok(Helpers::get_interface_ip(name)?.to_string()),
51 None => Ok("0.0.0.0".to_owned()),
52 }
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59 use clap::Parser;
60 use pretty_assertions::assert_eq;
61
62 #[test]
63 fn cli_flags_override_defaults() {
64 let config = Config::parse_from(["rusty_socks", "--port", "9050", "--read-timeout", "0", "--accept-cidr", "10.0.0.0/8"]);
65
66 assert_eq!(config.port, 9050);
67 assert_eq!(config.read_timeout, 0);
68 assert_eq!(config.accept_cidr, "10.0.0.0/8");
69 }
70
71 #[test]
72 fn unspecified_interface_resolves_to_wildcard() {
73 let config = Config::parse_from(["rusty_socks", "--port", "1"]);
74
75 assert_eq!(config.listen_ip().unwrap(), "0.0.0.0");
76 assert_eq!(config.endpoint_ip().unwrap(), "0.0.0.0");
77 }
78}