@@ -363,7 +363,12 @@ async fn main() -> Result<()> {
363363 }
364364 }
365365
366- setup_logging ( args. run_args . verbose ) ;
366+ // Server mode defaults to INFO level logging for visibility
367+ let verbosity = args
368+ . run_args
369+ . verbose
370+ . max ( if args. run_args . server { 1 } else { 0 } ) ;
371+ setup_logging ( verbosity) ;
367372
368373 // Log the version at startup for easier diagnostics
369374 debug ! ( "httpjail version: {}" , env!( "VERSION_WITH_GIT_HASH" ) ) ;
@@ -487,32 +492,70 @@ async fn main() -> Result<()> {
487492 }
488493
489494 // Parse bind configuration from env vars
490- // Supports both "port" and "ip:port" formats
495+ // Returns Some(addr) for "port" or "ip:port" formats (including explicit :0)
496+ // Returns None for "ip" only or missing config
491497 fn parse_bind_config ( env_var : & str ) -> Option < std:: net:: SocketAddr > {
492498 if let Ok ( val) = std:: env:: var ( env_var) {
493- // First try parsing as "ip:port"
499+ // First try parsing as "ip:port" (respects explicit :0)
494500 if let Ok ( addr) = val. parse :: < std:: net:: SocketAddr > ( ) {
495501 return Some ( addr) ;
496502 }
497- // Try parsing as just a port number, defaulting to localhost
503+ // Try parsing as just a port number - bind to all interfaces (0.0.0.0)
498504 if let Ok ( port) = val. parse :: < u16 > ( ) {
499- return Some ( std:: net:: SocketAddr :: from ( ( [ 127 , 0 , 0 , 1 ] , port) ) ) ;
505+ return Some ( std:: net:: SocketAddr :: from ( ( [ 0 , 0 , 0 , 0 ] , port) ) ) ;
500506 }
501507 }
502508 None
503509 }
504510
511+ // Parse IP-only from env var (for default port handling)
512+ fn parse_ip_from_env ( env_var : & str ) -> Option < std:: net:: IpAddr > {
513+ std:: env:: var ( env_var) . ok ( ) ?. parse ( ) . ok ( )
514+ }
515+
516+ // Resolve bind address with optional default port for IP-only configs
517+ fn resolve_bind_with_default (
518+ parsed : Option < std:: net:: SocketAddr > ,
519+ env_var : & str ,
520+ default_ip : std:: net:: IpAddr ,
521+ default_port : u16 ,
522+ ) -> Option < std:: net:: SocketAddr > {
523+ match parsed {
524+ Some ( addr) => Some ( addr) , // Respect explicit config including :0
525+ None => {
526+ // Check if user provided just IP without port
527+ if let Some ( ip) = parse_ip_from_env ( env_var) {
528+ Some ( std:: net:: SocketAddr :: new ( ip, default_port) )
529+ } else {
530+ Some ( std:: net:: SocketAddr :: new ( default_ip, default_port) )
531+ }
532+ }
533+ }
534+ }
535+
505536 // Determine bind addresses
506537 let http_bind = parse_bind_config ( "HTTPJAIL_HTTP_BIND" ) ;
507538 let https_bind = parse_bind_config ( "HTTPJAIL_HTTPS_BIND" ) ;
508539
509540 // For strong jail mode (not weak, not server), we need to bind to a specific IP
510541 // so the proxy is accessible from the veth interface. For weak mode or server mode,
511- // use the configured address or None (will auto-select) .
542+ // use the configured address or defaults .
512543 // TODO: This has security implications - see GitHub issue #31
513- let ( http_bind, https_bind) = if args. run_args . weak || args. run_args . server {
514- // In weak/server mode, respect HTTPJAIL_HTTP_BIND and HTTPJAIL_HTTPS_BIND environment variables
515- ( http_bind, https_bind)
544+ let ( http_bind, https_bind) = if args. run_args . server {
545+ // Server mode: default to localhost:8080/8443, respect explicit ports including :0
546+ let localhost = std:: net:: IpAddr :: from ( [ 127 , 0 , 0 , 1 ] ) ;
547+ let http = resolve_bind_with_default ( http_bind, "HTTPJAIL_HTTP_BIND" , localhost, 8080 ) ;
548+ let https = resolve_bind_with_default ( https_bind, "HTTPJAIL_HTTPS_BIND" , localhost, 8443 ) ;
549+ ( http, https)
550+ } else if args. run_args . weak {
551+ // Weak mode: If IP-only provided, use port 0 (OS auto-select), else None
552+ let http = http_bind. or_else ( || {
553+ parse_ip_from_env ( "HTTPJAIL_HTTP_BIND" ) . map ( |ip| std:: net:: SocketAddr :: new ( ip, 0 ) )
554+ } ) ;
555+ let https = https_bind. or_else ( || {
556+ parse_ip_from_env ( "HTTPJAIL_HTTPS_BIND" ) . map ( |ip| std:: net:: SocketAddr :: new ( ip, 0 ) )
557+ } ) ;
558+ ( http, https)
516559 } else {
517560 #[ cfg( target_os = "linux" ) ]
518561 {
@@ -542,15 +585,16 @@ async fn main() -> Result<()> {
542585 let ( actual_http_port, actual_https_port) = proxy. start ( ) . await ?;
543586
544587 if args. run_args . server {
545- let http_bind_str = http_bind
546- . map ( |addr| addr. ip ( ) . to_string ( ) )
547- . unwrap_or_else ( || "localhost" . to_string ( ) ) ;
548- let https_bind_str = https_bind
549- . map ( |addr| addr. ip ( ) . to_string ( ) )
550- . unwrap_or_else ( || "localhost" . to_string ( ) ) ;
588+ let bind_str = |addr : Option < std:: net:: SocketAddr > | {
589+ addr. map ( |a| a. ip ( ) . to_string ( ) )
590+ . unwrap_or_else ( || "localhost" . to_string ( ) )
591+ } ;
551592 info ! (
552593 "Proxy server running on http://{}:{} and https://{}:{}" ,
553- http_bind_str, actual_http_port, https_bind_str, actual_https_port
594+ bind_str( http_bind) ,
595+ actual_http_port,
596+ bind_str( https_bind) ,
597+ actual_https_port
554598 ) ;
555599 std:: future:: pending :: < ( ) > ( ) . await ;
556600 unreachable ! ( ) ;
0 commit comments