From c9503273a7a0879dc8847c6a961904f7bb6d01e3 Mon Sep 17 00:00:00 2001 From: Sven Geuer <68420948@users.noreply.github.com> Date: Sat, 16 Dec 2023 23:37:36 +0100 Subject: [PATCH] Allow for binding to a link-local IPv6 address Requires to also give the interface like ipv6%interface --- cmdline.c | 23 +++++++++++++++++++++-- cmdline.h | 2 ++ proxytunnel.c | 10 ++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/cmdline.c b/cmdline.c index e1103a2..a8a0adf 100644 --- a/cmdline.c +++ b/cmdline.c @@ -150,6 +150,8 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->ntlm_given = 0; args_info->inetd_given = 0; args_info->standalone_given = 0; + args_info->standalone_addr_given = 0; + args_info->standalone_iface_given = 0; args_info->header_given = 0; args_info->domain_given = 0; args_info->encrypt_given = 0; @@ -184,6 +186,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->inetd_flag = 0; \ args_info->standalone_arg = NULL; \ args_info->standalone_addr = NULL; \ + args_info->standalone_iface = NULL; \ args_info->standalone_port = 0; \ args_info->encrypt_flag = 0; \ args_info->encryptproxy_flag = 0; \ @@ -665,7 +668,8 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar if ( args_info->standalone_given ) { char standalone_arg_fmt[32]; size_t standalone_arg_len; - char * aaddr; + char *aaddr; + char *aiface; int aport; standalone_arg_len = strlen( args_info->standalone_arg ); @@ -673,6 +677,10 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar message( "Out of memory\n" ); exit(1); } + if ( (aiface = 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 ); @@ -681,6 +689,17 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar 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 ) { + /* try bracket-enclosed IPv6 literal, interface and port */ + snprintf( standalone_arg_fmt, sizeof(standalone_arg_fmt), "[%%%zu[0-9A-Fa-f:]%%%%%%%zu[^]]]:%%5u", standalone_arg_len - 1, standalone_arg_len - 1 ); + if ( sscanf( args_info->standalone_arg, standalone_arg_fmt, aaddr, aiface, &aport ) == 3 ) + r = 3; + } + if ( r == 3 ) { + args_info->standalone_iface = aiface; + args_info->standalone_iface_given = 1; + r--; + } if ( r == 2 ) { args_info->standalone_addr = aaddr; args_info->standalone_port = aport; @@ -689,7 +708,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar } 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 ); + message( "parse_cmdline: specified standalone argument (%s) does not fit one of the expected patterns: port, ipv4:port, [ipv6]:port, [ipv6%%interface]:port\n", args_info->standalone_arg ); missing_required_options++; } } diff --git a/cmdline.h b/cmdline.h index a5a2e48..b0cddd2 100644 --- a/cmdline.h +++ b/cmdline.h @@ -45,6 +45,7 @@ struct gengetopt_args_info { int inetd_flag; /* Turn on inetd (default=off). */ char *standalone_arg; /* Turn on standalone (-a) on [addr:]port */ char *standalone_addr; + char *standalone_iface; int standalone_port; int encrypt_flag; /* Turn on SSL encryption (default=off). */ int encryptproxy_flag; /* Turn on client to proxy SSL encryption (def=off).*/ @@ -80,6 +81,7 @@ struct gengetopt_args_info { int inetd_given; /* Whether inetd was given. */ int standalone_given; /* Whether standalone was given */ int standalone_addr_given; /* Whether standalone address was given */ + int standalone_iface_given; /* Whether standalone interface 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/proxytunnel.c b/proxytunnel.c index 2e5e8ce..7d08b2a 100644 --- a/proxytunnel.c +++ b/proxytunnel.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -189,6 +190,15 @@ void do_daemon() sa_serv.sin6_addr = in6addr_any; sa_serv.sin6_port = htons( args_info.standalone_port ); + /* In case a standalone interface was specified ... */ + if ( args_info.standalone_iface_given ) { + /* ... try to get and set the interface's index */ + if ( !(sa_serv.sin6_scope_id = if_nametoindex(args_info.standalone_iface)) ) { + my_perror("Setting server socket interface failed, possibly mis-spelled"); + exit(1); + } + } + /* In case a standalone address was specified ... */ if ( args_info.standalone_addr_given ) { /* ... try to set it as an IPv6 address ... */