diff --git a/cmdline.c b/cmdline.c index a10a704..fd38953 100644 --- a/cmdline.c +++ b/cmdline.c @@ -50,7 +50,8 @@ void cmdline_parser_print_help (void) { "Standard options:\n" // FIXME: " -c, --config=FILE Read config options from file\n" " -i, --inetd Run from inetd (default: off)\n" -" -a, --standalone=INT Run as standalone daemon on specified port\n" +" -a, --standalone=STRING Run as standalone daemon on specified port or\n" +" address:port combination\n" // FIXME: " -f, --nobackground Don't fork to background in standalone mode\n" " -p, --proxy=STRING Local proxy host:port combination\n" " -r, --remproxy=STRING Remote proxy host:port combination (using 2 proxies)\n" @@ -145,9 +146,10 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->remproxy_given = 0; args_info->remproxyauth_given = 0; args_info->verbose_given = 0; + args_info->quiet_given = 0; args_info->ntlm_given = 0; args_info->inetd_given = 0; - args_info->quiet_given = 0; + args_info->standalone_given = 0; args_info->header_given = 0; args_info->domain_given = 0; args_info->encrypt_given = 0; @@ -177,10 +179,12 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->remproxyauth_arg = NULL; \ args_info->header_arg[0] = '\0'; \ args_info->verbose_flag = 0; \ + args_info->quiet_flag = 0; \ args_info->ntlm_flag = 0; \ args_info->inetd_flag = 0; \ - args_info->quiet_flag = 0; \ - args_info->standalone_arg = 0; \ + args_info->standalone_arg = NULL; \ + args_info->standalone_addr = NULL; \ + args_info->standalone_port = 0; \ args_info->encrypt_flag = 0; \ args_info->encryptproxy_flag = 0; \ args_info->encryptremproxy_flag = 0; \ @@ -321,16 +325,18 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar break; case 'a': /* Run as standalone daemon */ + if (args_info->standalone_given) { + fprintf (stderr, "%s: '--standalone' ('-a') option given more than once\n", PACKAGE); + clear_args (); + exit(1); + } if ( args_info->inetd_flag ) { fprintf( stderr, "%s: `--standalone' (`-a') conflicts with `--inetd' (`-i')\n", PACKAGE ); clear_args(); exit(1); } - if ( ( args_info->standalone_arg = atoi( optarg ) ) < 1 ) { - fprintf( stderr, "%s: Illegal port value for `--standalone' (`-a')\n", PACKAGE); - clear_args(); - exit(1); - } + args_info->standalone_given = 1; + args_info->standalone_arg = gengetopt_strdup (optarg); break; case 'V': /* Print version and exit. */ @@ -625,6 +631,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar exit(1); } + /* Parse -p/--proxy information */ if (args_info->proxy_given ) { char proxy_arg_fmt[32]; size_t proxy_arg_len; @@ -649,7 +656,40 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->proxyhost_given = 1; args_info->proxyport_given = 1; } else { - message( "parse_cmdline: specified proxy hostname/ip:port (%s) does not fit expected pattern\n", args_info->proxy_arg ); + message( "parse_cmdline: specified proxy (%s) does not fit the expected pattern hostname/ip:port\n", args_info->proxy_arg ); + missing_required_options++; + } + } + + /* Parse -a/--standalone information */ + if ( args_info->standalone_given ) { + char standalone_arg_fmt[32]; + size_t standalone_arg_len; + char * aaddr; + int aport; + + standalone_arg_len = strlen( args_info->standalone_arg ); + if ( (aaddr = malloc( standalone_arg_len + 1 )) == NULL ) { + message( "Out of memory\n" ); + exit(1); + } + /* try IPv4 literal and port */ + snprintf( standalone_arg_fmt, sizeof(standalone_arg_fmt), "%%%zu[0-9.]:%%5u", standalone_arg_len - 1 ); + r = sscanf( args_info->standalone_arg, standalone_arg_fmt, aaddr, &aport ); + if ( r != 2 ) { + /* try bracket-enclosed IPv6 literal and port */ + snprintf( standalone_arg_fmt, sizeof(standalone_arg_fmt), "[%%%zu[0-9A-Fa-f:]]:%%5u", standalone_arg_len - 1 ); + r = sscanf( args_info->standalone_arg, standalone_arg_fmt, aaddr, &aport ); + } + if ( r == 2 ) { + args_info->standalone_addr = aaddr; + args_info->standalone_port = aport; + args_info->standalone_addr_given = 1; + /* try port only */ + } else if ( sscanf( args_info->standalone_arg, "%5u", &aport ) ) { + args_info->standalone_port = aport; + } else { + message( "parse_cmdline: specified standalone argument (%s) does not fit the expected pattern [ip:]port\n", args_info->standalone_arg ); missing_required_options++; } } @@ -699,6 +739,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar missing_required_options++; } } + if ( missing_required_options ) exit(1); diff --git a/cmdline.h b/cmdline.h index 498a5e6..a5a2e48 100644 --- a/cmdline.h +++ b/cmdline.h @@ -40,10 +40,12 @@ struct gengetopt_args_info { char *remproxy_arg; /* Remote proxy to tunnel to. */ char *remproxyauth_arg; /* Remote proxy auth. */ int verbose_flag; /* Turn on verbosity (default=off). */ + int quiet_flag; /* Turn on quiet mode (default=off). */ int ntlm_flag; /* Turn on ntlm (default=off). */ int inetd_flag; /* Turn on inetd (default=off). */ - int quiet_flag; /* Turn on quiet mode (default=off). */ - int standalone_arg; /* Turn on stdalone (-a) on port */ + char *standalone_arg; /* Turn on standalone (-a) on [addr:]port */ + char *standalone_addr; + int standalone_port; int encrypt_flag; /* Turn on SSL encryption (default=off). */ int encryptproxy_flag; /* Turn on client to proxy SSL encryption (def=off).*/ int encryptremproxy_flag; /* Turn on local to remote proxy SSL encryption (def=off).*/ @@ -73,9 +75,11 @@ struct gengetopt_args_info { int remproxy_given; /* Whether remproxy was given. */ int remproxyauth_given; /* Whether remproxy was given. */ int verbose_given; /* Whether verbose was given. */ + int quiet_given; /* Whether quiet mode was given. */ int ntlm_given; /* Whether ntlm was given. */ int inetd_given; /* Whether inetd was given. */ - int quiet_given; /* Whether quiet mode was given. */ + int standalone_given; /* Whether standalone was given */ + int standalone_addr_given; /* Whether standalone address was given */ int header_given; /* Whether extra headers are given */ int encrypt_given; /* Whether encrypt was given */ int encryptproxy_given; /* Whether encrypt was given */ diff --git a/docs/proxytunnel.1.adoc b/docs/proxytunnel.1.adoc index 1967825..317f881 100644 --- a/docs/proxytunnel.1.adoc +++ b/docs/proxytunnel.1.adoc @@ -21,8 +21,10 @@ also be used for other proxy-traversing purposes like proxy bouncing. *-i*, *--inetd*:: Run from inetd (default: off). -*-a*, *--standalone*=_port_:: - Run as standalone daemon on specified _port_. +*-a*, *--standalone*=++[++_address_++:]++_port_:: + Run as standalone daemon on specified _address_ and _port_. _address_ may + be a IPv4 address or a bracket-enclosed IPv6 address. Listens on any + address if _address_ is not given. *-p*, *--proxy*=_host_++:++_port_:: Use _host_ and _port_ as the local proxy to connect to, if not specified diff --git a/proxytunnel.c b/proxytunnel.c index e96a717..2e5e8ce 100644 --- a/proxytunnel.c +++ b/proxytunnel.c @@ -187,7 +187,20 @@ void do_daemon() memset( &sa_serv, '\0', sizeof( sa_serv ) ); sa_serv.sin6_family = AF_INET6; sa_serv.sin6_addr = in6addr_any; - sa_serv.sin6_port = htons( args_info.standalone_arg ); + sa_serv.sin6_port = htons( args_info.standalone_port ); + + /* In case a standalone address was specified ... */ + if ( args_info.standalone_addr_given ) { + /* ... try to set it as an IPv6 address ... */ + if ( inet_pton(AF_INET6, args_info.standalone_addr, &sa_serv.sin6_addr) < 1 ) { + /* ... if this failed, try to set it as an IPv4-mapped address */ + snprintf(buf, sizeof(buf), "::FFFF:%s", args_info.standalone_addr); + if ( inet_pton(AF_INET6, buf, &sa_serv.sin6_addr) < 1 ) { + my_perror("Setting server socket IP address failed, possibly malformed"); + exit(1); + } + } + } if ( bind( listen_sd, (struct sockaddr *)&sa_serv, sizeof(sa_serv) ) < 0) { my_perror("Server socket bind failed");