summaryrefslogtreecommitdiffstats
path: root/src/bin/server
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/bin/server/args.rs85
-rw-r--r--src/bin/server/main.rs21
-rw-r--r--src/bin/server/tls.rs34
3 files changed, 99 insertions, 41 deletions
diff --git a/src/bin/server/args.rs b/src/bin/server/args.rs
index fc844ea..1babd1d 100644
--- a/src/bin/server/args.rs
+++ b/src/bin/server/args.rs
@@ -2,6 +2,7 @@ pub struct Args {
2 pub ip: String, 2 pub ip: String,
3 pub port: u16, 3 pub port: u16,
4 pub unsafe_mode: bool, 4 pub unsafe_mode: bool,
5 pub init: bool,
5} 6}
6 7
7pub fn parse_args() -> Args { 8pub fn parse_args() -> Args {
@@ -9,42 +10,80 @@ pub fn parse_args() -> Args {
9 let mut ip = "127.0.0.1".to_string(); 10 let mut ip = "127.0.0.1".to_string();
10 let mut port = 11525; 11 let mut port = 11525;
11 let mut unsafe_mode = false; 12 let mut unsafe_mode = false;
13 let mut init = false;
12 let mut i = 1; 14 let mut i = 1;
15
13 while i < args.len() { 16 while i < args.len() {
14 if args[i] == "-p" { 17 match args[i].as_str() {
15 if i + 1 < args.len() { 18 "-p" => {
16 port = args[i + 1].parse::<u16>().unwrap_or_else(|_| { 19 if i + 1 < args.len() {
17 eprintln!("Invalid port number: {}", args[i + 1]); 20 port = args[i + 1].parse::<u16>().unwrap_or_else(|_| {
21 eprintln!("Invalid port number: {}", args[i + 1]);
22 std::process::exit(1);
23 });
24 i += 2;
25 } else {
26 eprintln!("-p requires a port number");
18 std::process::exit(1); 27 std::process::exit(1);
19 }); 28 }
20 i += 2;
21 } else {
22 eprintln!("-p requires a port number");
23 std::process::exit(1);
24 } 29 }
25 } else if args[i] == "-i" { 30 "-i" => {
26 if i + 1 < args.len() { 31 if i + 1 < args.len() {
27 ip = args[i + 1].clone(); 32 ip = args[i + 1].clone();
28 if ip != "127.0.0.1" && ip != "0.0.0.0" { 33 if ip != "127.0.0.1" && ip != "0.0.0.0" {
29 eprintln!("Invalid IP address: {}. Must be 127.0.0.1 or 0.0.0.0", ip); 34 eprintln!(
35 "Invalid IP address: {}. Must be 127.0.0.1 or 0.0.0.0",
36 ip
37 );
38 std::process::exit(1);
39 }
40 i += 2;
41 } else {
42 eprintln!("-i requires an IP address");
30 std::process::exit(1); 43 std::process::exit(1);
31 } 44 }
32 i += 2; 45 }
33 } else { 46 "--unsafe" => {
34 eprintln!("-i requires an IP address"); 47 unsafe_mode = true;
48 i += 1;
49 }
50 "--init" => {
51 init = true;
52 i += 1;
53 }
54 "-h" | "--help" => {
55 print_usage();
56 std::process::exit(0);
57 }
58 other => {
59 eprintln!("Unknown argument: {other}");
60 print_usage();
35 std::process::exit(1); 61 std::process::exit(1);
36 } 62 }
37 } else if args[i] == "--unsafe" {
38 unsafe_mode = true;
39 i += 1;
40 } else {
41 eprintln!("Unknown argument: {}", args[i]);
42 std::process::exit(1);
43 } 63 }
44 } 64 }
65
45 Args { 66 Args {
46 ip, 67 ip,
47 port, 68 port,
48 unsafe_mode, 69 unsafe_mode,
70 init,
49 } 71 }
50} 72}
73
74fn print_usage() {
75 println!(
76 "Usage: server [OPTIONS]\n\
77 \n\
78 Options:\n\
79 \x20 -i <ip> Bind address (127.0.0.1 or 0.0.0.0)\n\
80 \x20 -p <port> Bind port (default 11525)\n\
81 \x20 --init Generate identity.p12, key.pem and cert.pem, then exit\n\
82 \x20 --unsafe Run in unsafe mode (warning only)\n\
83 \x20 -h, --help Show this help\n\
84 \n\
85 First run:\n\
86 \x20 cargo run --bin server -- --init\n\
87 \x20 cargo run --bin server"
88 );
89}
diff --git a/src/bin/server/main.rs b/src/bin/server/main.rs
index 8dba415..2770387 100644
--- a/src/bin/server/main.rs
+++ b/src/bin/server/main.rs
@@ -8,6 +8,25 @@ use std::thread;
8 8
9fn main() { 9fn main() {
10 let args = args::parse_args(); 10 let args = args::parse_args();
11
12 if args.init {
13 match zagan_bet::server::setup::init_identity(std::path::Path::new("."), "localhost") {
14 Ok(report) => {
15 println!("TLS identity created:");
16 println!(" {} (PKCS#12, empty password)", report.identity.display());
17 println!(" {} (private key)", report.key.display());
18 println!(" {} (certificate)", report.cert.display());
19 println!("\nStart the server with:\n cargo run --bin server");
20 println!("Clients will trust this certificate on first contact.");
21 }
22 Err(error) => {
23 eprintln!("TLS setup failed:\n{error}");
24 std::process::exit(1);
25 }
26 }
27 return;
28 }
29
11 let listener = match TcpListener::bind(format!("{}:{}", args.ip, args.port)) { 30 let listener = match TcpListener::bind(format!("{}:{}", args.ip, args.port)) {
12 Ok(l) => l, 31 Ok(l) => l,
13 Err(e) => { 32 Err(e) => {
@@ -16,7 +35,7 @@ fn main() {
16 } 35 }
17 }; 36 };
18 37
19 let tls = match tls::TlsServer::new("identity.p12", "key.pem", args.unsafe_mode) { 38 let tls = match tls::TlsServer::new("identity.p12") {
20 Ok(t) => Arc::new(t), 39 Ok(t) => Arc::new(t),
21 Err(e) => { 40 Err(e) => {
22 eprintln!("Failed to initialize TLS: {}", e); 41 eprintln!("Failed to initialize TLS: {}", e);
diff --git a/src/bin/server/tls.rs b/src/bin/server/tls.rs
index 62a25db..292ebf7 100644
--- a/src/bin/server/tls.rs
+++ b/src/bin/server/tls.rs
@@ -9,25 +9,25 @@ pub struct TlsServer {
9} 9}
10 10
11impl TlsServer { 11impl TlsServer {
12 pub fn new( 12 pub fn new(cert_path: &str) -> Result<Self, Box<dyn std::error::Error>> {
13 cert_path: &str, 13 let cert_data = match std::fs::read(cert_path) {
14 _key_path: &str, 14 Ok(data) => data,
15 unsafe_mode: bool, 15 Err(error) => {
16 ) -> Result<Self, Box<dyn std::error::Error>> {
17 let cert_data = if unsafe_mode {
18 if std::path::Path::new(cert_path).exists() {
19 std::fs::read(cert_path)?
20 } else {
21 return Err(format!( 16 return Err(format!(
22 "Certificate file '{}' not found. In --unsafe mode, you must provide a valid PKCS12 certificate file.\n\ 17 "Could not read TLS identity '{}': {}\n\
23 You can generate one with:\n\ 18 \n\
24 openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes\n\ 19 First-time setup:\n\
25 openssl pkcs12 -export -out identity.p12 -inkey key.pem -in cert.pem", 20 \x20 cargo run --bin server -- --init\n\
26 cert_path 21 \n\
27 ).into()); 22 Or generate it manually:\n\
23 \x20 openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \\\n\
24 \x20 -days 3650 -nodes -subj \"/CN=localhost\"\n\
25 \x20 openssl pkcs12 -export -out identity.p12 -inkey key.pem -in cert.pem \\\n\
26 \x20 -passout pass:",
27 cert_path, error
28 )
29 .into());
28 } 30 }
29 } else {
30 std::fs::read(cert_path)?
31 }; 31 };
32 32
33 let identity = native_tls::Identity::from_pkcs12(&cert_data, "")?; 33 let identity = native_tls::Identity::from_pkcs12(&cert_data, "")?;