@@ -359,7 +359,12 @@ async fn main() -> Result<()> {
359359 }
360360 }
361361
362- setup_logging ( args. run_args . verbose ) ;
362+ // Server mode defaults to INFO level logging for visibility
363+ let verbosity = args
364+ . run_args
365+ . verbose
366+ . max ( if args. run_args . server { 1 } else { 0 } ) ;
367+ setup_logging ( verbosity) ;
363368
364369 // Log the version at startup for easier diagnostics
365370 debug ! ( "httpjail version: {}" , env!( "VERSION_WITH_GIT_HASH" ) ) ;
@@ -483,32 +488,70 @@ async fn main() -> Result<()> {
483488 }
484489
485490 // Parse bind configuration from env vars
486- // Supports both "port" and "ip:port" formats
491+ // Returns Some(addr) for "port" or "ip:port" formats (including explicit :0)
492+ // Returns None for "ip" only or missing config
487493 fn parse_bind_config ( env_var : & str ) -> Option < std:: net:: SocketAddr > {
488494 if let Ok ( val) = std:: env:: var ( env_var) {
489- // First try parsing as "ip:port"
495+ // First try parsing as "ip:port" (respects explicit :0)
490496 if let Ok ( addr) = val. parse :: < std:: net:: SocketAddr > ( ) {
491497 return Some ( addr) ;
492498 }
493- // Try parsing as just a port number, defaulting to localhost
499+ // Try parsing as just a port number - bind to all interfaces (0.0.0.0)
494500 if let Ok ( port) = val. parse :: < u16 > ( ) {
495- return Some ( std:: net:: SocketAddr :: from ( ( [ 127 , 0 , 0 , 1 ] , port) ) ) ;
501+ return Some ( std:: net:: SocketAddr :: from ( ( [ 0 , 0 , 0 , 0 ] , port) ) ) ;
496502 }
497503 }
498504 None
499505 }
500506
507+ // Parse IP-only from env var (for default port handling)
508+ fn parse_ip_from_env ( env_var : & str ) -> Option < std:: net:: IpAddr > {
509+ std:: env:: var ( env_var) . ok ( ) ?. parse ( ) . ok ( )
510+ }
511+
512+ // Resolve bind address with optional default port for IP-only configs
513+ fn resolve_bind_with_default (
514+ parsed : Option < std:: net:: SocketAddr > ,
515+ env_var : & str ,
516+ default_ip : std:: net:: IpAddr ,
517+ default_port : u16 ,
518+ ) -> Option < std:: net:: SocketAddr > {
519+ match parsed {
520+ Some ( addr) => Some ( addr) , // Respect explicit config including :0
521+ None => {
522+ // Check if user provided just IP without port
523+ if let Some ( ip) = parse_ip_from_env ( env_var) {
524+ Some ( std:: net:: SocketAddr :: new ( ip, default_port) )
525+ } else {
526+ Some ( std:: net:: SocketAddr :: new ( default_ip, default_port) )
527+ }
528+ }
529+ }
530+ }
531+
501532 // Determine bind addresses
502533 let http_bind = parse_bind_config ( "HTTPJAIL_HTTP_BIND" ) ;
503534 let https_bind = parse_bind_config ( "HTTPJAIL_HTTPS_BIND" ) ;
504535
505536 // For strong jail mode (not weak, not server), we need to bind to a specific IP
506537 // so the proxy is accessible from the veth interface. For weak mode or server mode,
507- // use the configured address or None (will auto-select) .
538+ // use the configured address or defaults .
508539 // TODO: This has security implications - see GitHub issue #31
509- let ( http_bind, https_bind) = if args. run_args . weak || args. run_args . server {
510- // In weak/server mode, respect HTTPJAIL_HTTP_BIND and HTTPJAIL_HTTPS_BIND environment variables
511- ( http_bind, https_bind)
540+ let ( http_bind, https_bind) = if args. run_args . server {
541+ // Server mode: default to localhost:8080/8443, respect explicit ports including :0
542+ let localhost = std:: net:: IpAddr :: from ( [ 127 , 0 , 0 , 1 ] ) ;
543+ let http = resolve_bind_with_default ( http_bind, "HTTPJAIL_HTTP_BIND" , localhost, 8080 ) ;
544+ let https = resolve_bind_with_default ( https_bind, "HTTPJAIL_HTTPS_BIND" , localhost, 8443 ) ;
545+ ( http, https)
546+ } else if args. run_args . weak {
547+ // Weak mode: If IP-only provided, use port 0 (OS auto-select), else None
548+ let http = http_bind. or_else ( || {
549+ parse_ip_from_env ( "HTTPJAIL_HTTP_BIND" ) . map ( |ip| std:: net:: SocketAddr :: new ( ip, 0 ) )
550+ } ) ;
551+ let https = https_bind. or_else ( || {
552+ parse_ip_from_env ( "HTTPJAIL_HTTPS_BIND" ) . map ( |ip| std:: net:: SocketAddr :: new ( ip, 0 ) )
553+ } ) ;
554+ ( http, https)
512555 } else {
513556 #[ cfg( target_os = "linux" ) ]
514557 {
@@ -538,15 +581,16 @@ async fn main() -> Result<()> {
538581 let ( actual_http_port, actual_https_port) = proxy. start ( ) . await ?;
539582
540583 if args. run_args . server {
541- let http_bind_str = http_bind
542- . map ( |addr| addr. ip ( ) . to_string ( ) )
543- . unwrap_or_else ( || "localhost" . to_string ( ) ) ;
544- let https_bind_str = https_bind
545- . map ( |addr| addr. ip ( ) . to_string ( ) )
546- . unwrap_or_else ( || "localhost" . to_string ( ) ) ;
584+ let bind_str = |addr : Option < std:: net:: SocketAddr > | {
585+ addr. map ( |a| a. ip ( ) . to_string ( ) )
586+ . unwrap_or_else ( || "localhost" . to_string ( ) )
587+ } ;
547588 info ! (
548589 "Proxy server running on http://{}:{} and https://{}:{}" ,
549- http_bind_str, actual_http_port, https_bind_str, actual_https_port
590+ bind_str( http_bind) ,
591+ actual_http_port,
592+ bind_str( https_bind) ,
593+ actual_https_port
550594 ) ;
551595 std:: future:: pending :: < ( ) > ( ) . await ;
552596 unreachable ! ( ) ;
0 commit comments