[client] add --server-resolve-ipv4 to only accept IPv4 addresses from DNS for the SPA server

This commit is contained in:
Michael Rash 2015-09-27 10:17:36 -04:00
parent a4309ad768
commit b03c007c44
8 changed files with 61 additions and 8 deletions

View File

@ -49,6 +49,7 @@ enum {
RC_FILE_PATH, RC_FILE_PATH,
RESOLVE_HTTP_ONLY, RESOLVE_HTTP_ONLY,
RESOLVE_URL, RESOLVE_URL,
SERVER_RESOLVE_IPV4,
USE_HMAC, USE_HMAC,
USE_WGET_USER_AGENT, USE_WGET_USER_AGENT,
SPA_ICMP_TYPE, SPA_ICMP_TYPE,
@ -139,6 +140,7 @@ static struct option cmd_opts[] =
{"resolve-ip-https", 0, NULL, 'R'}, /* synonym, default is HTTPS */ {"resolve-ip-https", 0, NULL, 'R'}, /* synonym, default is HTTPS */
{"resolve-http-only", 0, NULL, RESOLVE_HTTP_ONLY}, {"resolve-http-only", 0, NULL, RESOLVE_HTTP_ONLY},
{"resolve-url", 1, NULL, RESOLVE_URL}, {"resolve-url", 1, NULL, RESOLVE_URL},
{"server-resolve-ipv4", 0, NULL, SERVER_RESOLVE_IPV4},
{"show-last", 0, NULL, SHOW_LAST_ARGS}, {"show-last", 0, NULL, SHOW_LAST_ARGS},
{"source-ip", 0, NULL, 's'}, {"source-ip", 0, NULL, 's'},
{"source-port", 1, NULL, 'S'}, {"source-port", 1, NULL, 'S'},

View File

@ -124,6 +124,7 @@ enum
FWKNOP_CLI_ARG_NAT_ACCESS, FWKNOP_CLI_ARG_NAT_ACCESS,
FWKNOP_CLI_ARG_HTTP_USER_AGENT, FWKNOP_CLI_ARG_HTTP_USER_AGENT,
FWKNOP_CLI_ARG_RESOLVE_URL, FWKNOP_CLI_ARG_RESOLVE_URL,
FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4,
FWKNOP_CLI_ARG_NAT_LOCAL, FWKNOP_CLI_ARG_NAT_LOCAL,
FWKNOP_CLI_ARG_NAT_RAND_PORT, FWKNOP_CLI_ARG_NAT_RAND_PORT,
FWKNOP_CLI_ARG_NAT_PORT, FWKNOP_CLI_ARG_NAT_PORT,
@ -172,6 +173,7 @@ static fko_var_t fko_var_array[FWKNOP_CLI_LAST_ARG] =
{ "NAT_ACCESS", FWKNOP_CLI_ARG_NAT_ACCESS }, { "NAT_ACCESS", FWKNOP_CLI_ARG_NAT_ACCESS },
{ "HTTP_USER_AGENT", FWKNOP_CLI_ARG_HTTP_USER_AGENT }, { "HTTP_USER_AGENT", FWKNOP_CLI_ARG_HTTP_USER_AGENT },
{ "RESOLVE_URL", FWKNOP_CLI_ARG_RESOLVE_URL }, { "RESOLVE_URL", FWKNOP_CLI_ARG_RESOLVE_URL },
{ "SERVER_RESOLVE_IPV4", FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4 },
{ "NAT_LOCAL", FWKNOP_CLI_ARG_NAT_LOCAL }, { "NAT_LOCAL", FWKNOP_CLI_ARG_NAT_LOCAL },
{ "NAT_RAND_PORT", FWKNOP_CLI_ARG_NAT_RAND_PORT }, { "NAT_RAND_PORT", FWKNOP_CLI_ARG_NAT_RAND_PORT },
{ "NAT_PORT", FWKNOP_CLI_ARG_NAT_PORT }, { "NAT_PORT", FWKNOP_CLI_ARG_NAT_PORT },
@ -1195,6 +1197,14 @@ parse_rc_param(fko_cli_options_t *options, const char *var_name, char * val)
} }
strlcpy(options->resolve_url, val, tmpint); strlcpy(options->resolve_url, val, tmpint);
} }
/* Resolve the SPA server (via DNS) - accept IPv4 addresses only ? */
else if (var->pos == FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4)
{
if (is_yes_str(val))
{
options->spa_server_resolve_ipv4 = 1;
}
}
/* wget command */ /* wget command */
else if (var->pos == FWKNOP_CLI_ARG_WGET_CMD) else if (var->pos == FWKNOP_CLI_ARG_WGET_CMD)
{ {
@ -1417,6 +1427,9 @@ add_single_var_to_rc(FILE* fhandle, short var_pos, fko_cli_options_t *options)
strlcpy(val, options->resolve_url, sizeof(val)); strlcpy(val, options->resolve_url, sizeof(val));
else; else;
break; break;
case FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4:
bool_to_yesno(options->spa_server_resolve_ipv4, val, sizeof(val));
break;
case FWKNOP_CLI_ARG_NAT_LOCAL : case FWKNOP_CLI_ARG_NAT_LOCAL :
bool_to_yesno(options->nat_local, val, sizeof(val)); bool_to_yesno(options->nat_local, val, sizeof(val));
break; break;
@ -2266,6 +2279,9 @@ config_init(fko_cli_options_t *options, int argc, char **argv)
strlcpy(options->resolve_url, optarg, rlen); strlcpy(options->resolve_url, optarg, rlen);
add_var_to_bitmask(FWKNOP_CLI_ARG_RESOLVE_URL, &var_bitmask); add_var_to_bitmask(FWKNOP_CLI_ARG_RESOLVE_URL, &var_bitmask);
break; break;
case SERVER_RESOLVE_IPV4:
options->spa_server_resolve_ipv4 = 1;
break;
case 'w': case 'w':
if(options->wget_bin != NULL) if(options->wget_bin != NULL)
free(options->wget_bin); free(options->wget_bin);
@ -2563,6 +2579,8 @@ usage(void)
" $HOME/fwknop.run file\n" " $HOME/fwknop.run file\n"
" --rc-file Specify path to the fwknop rc file (default\n" " --rc-file Specify path to the fwknop rc file (default\n"
" is $HOME/.fwknoprc)\n" " is $HOME/.fwknoprc)\n"
" --server-resolve-ipv4 Force IPv4 address resolution from DNS for\n"
" SPA server when using a hostname.\n"
" --save-rc-stanza Save command line arguments to the\n" " --save-rc-stanza Save command line arguments to the\n"
" $HOME/.fwknoprc stanza specified with the\n" " $HOME/.fwknoprc stanza specified with the\n"
" -n option.\n" " -n option.\n"

View File

@ -899,7 +899,8 @@ set_nat_access(fko_ctx_t ctx, fko_cli_options_t *options, const char * const acc
* family to either AF_INET or AF_INET6 */ * family to either AF_INET or AF_INET6 */
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
if (resolve_dest_adr(hostname, &hints, dst_ip_str, sizeof(dst_ip_str)) != 0) if (resolve_dst_addr(hostname, &hints,
dst_ip_str, sizeof(dst_ip_str), options) != 0)
{ {
log_msg(LOG_VERBOSITY_ERROR, "[*] Unable to resolve %s as an ip address", log_msg(LOG_VERBOSITY_ERROR, "[*] Unable to resolve %s as an ip address",
hostname); hostname);

View File

@ -164,6 +164,7 @@ typedef struct fko_cli_options
unsigned char save_rc_stanza; unsigned char save_rc_stanza;
unsigned char force_save_rc_stanza; unsigned char force_save_rc_stanza;
unsigned char stanza_list; unsigned char stanza_list;
int spa_server_resolve_ipv4;
int input_fd; int input_fd;

View File

@ -136,6 +136,17 @@ send_spa_packet_tcp_or_udp(const char *spa_data, const int sd_len,
} }
for (rp = result; rp != NULL; rp = rp->ai_next) { for (rp = result; rp != NULL; rp = rp->ai_next) {
/* Apply --server-resolve-ipv4 criteria
*/
if(options->spa_server_resolve_ipv4)
{
if(rp->ai_family != AF_INET)
{
log_msg(LOG_VERBOSITY_DEBUG, "Non-IPv4 resolution");
continue;
}
}
sock = socket(rp->ai_family, rp->ai_socktype, sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol); rp->ai_protocol);
if (sock < 0) if (sock < 0)
@ -703,7 +714,8 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options)
return res; return res;
#endif #endif
if (resolve_dest_adr(options->spa_server_str, &hints, ip_str, sizeof(ip_str)) != 0) if (resolve_dst_addr(options->spa_server_str,
&hints, ip_str, sizeof(ip_str), options) != 0)
{ {
log_msg(LOG_VERBOSITY_ERROR, "[*] Unable to resolve %s as an ip address", log_msg(LOG_VERBOSITY_ERROR, "[*] Unable to resolve %s as an ip address",
options->spa_server_str); options->spa_server_str);

View File

@ -148,17 +148,19 @@ get_in_addr(struct sockaddr *sa)
} }
/** /**
* @brief Resolve a domain name as an ip adress. * @brief Resolve a domain name as an IP address.
* *
* @param dns_str Name of the host to resolve. * @param dns_str Name of the host to resolve.
* @param hints Hints to reduce the number of result from getaddrinfo() * @param hints Hints to reduce the number of result from getaddrinfo()
* @param ip_str String where to store the resolve ip address * @param ip_str String where to store the resolve ip address
* @param ip_bufsize Number of bytes available in the ip_str buffer * @param ip_bufsize Number of bytes available in the ip_str buffer
* @param opts Client command line options
* *
* @return 0 if successful, 1 if an error occured. * @return 0 if successful, 1 if an error occured.
*/ */
int int
resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size_t ip_bufsize) resolve_dst_addr(const char *dns_str, struct addrinfo *hints,
char *ip_str, size_t ip_bufsize, fko_cli_options_t *opts)
{ {
int error; /* Function error return code */ int error; /* Function error return code */
struct addrinfo *result; /* Result of getaddrinfo() */ struct addrinfo *result; /* Result of getaddrinfo() */
@ -173,7 +175,7 @@ resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size
/* Try to resolve the host name */ /* Try to resolve the host name */
error = getaddrinfo(dns_str, NULL, hints, &result); error = getaddrinfo(dns_str, NULL, hints, &result);
if (error != 0) if (error != 0)
fprintf(stderr, "resolve_dest_adr() : %s\n", gai_strerror(error)); fprintf(stderr, "resolve_dst_addr() : %s\n", gai_strerror(error));
else else
{ {
@ -182,6 +184,17 @@ resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size
/* Go through the linked list of addrinfo structures */ /* Go through the linked list of addrinfo structures */
for (rp = result; rp != NULL; rp = rp->ai_next) for (rp = result; rp != NULL; rp = rp->ai_next)
{ {
/* Apply --server-resolve-ipv4 criteria
*/
if(opts->spa_server_resolve_ipv4)
{
if(rp->ai_family != AF_INET)
{
log_msg(LOG_VERBOSITY_DEBUG, "Non-IPv4 resolution");
continue;
}
}
memset(ip_str, 0, ip_bufsize); memset(ip_str, 0, ip_bufsize);
#if WIN32 && WINVER <= 0x0600 #if WIN32 && WINVER <= 0x0600
/* On older Windows systems (anything before Vista?), /* On older Windows systems (anything before Vista?),
@ -200,7 +213,7 @@ resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size
break; break;
} }
else else
log_msg(LOG_VERBOSITY_ERROR, "resolve_dest_adr() : inet_ntop (%d) - %s", log_msg(LOG_VERBOSITY_ERROR, "resolve_dst_addr() : inet_ntop (%d) - %s",
errno, strerror(errno)); errno, strerror(errno));
} }

View File

@ -56,7 +56,8 @@
void hex_dump(const unsigned char *data, const int size); void hex_dump(const unsigned char *data, const int size);
int set_file_perms(const char *file); int set_file_perms(const char *file);
int verify_file_perms_ownership(const char *file); int verify_file_perms_ownership(const char *file);
int resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size_t ip_bufsize); int resolve_dst_addr(const char *dns_str, struct addrinfo *hints,
char *ip_str, size_t ip_bufsize, fko_cli_options_t *opts);
short proto_inttostr(int proto, char *proto_str, size_t proto_size); short proto_inttostr(int proto, char *proto_str, size_t proto_size);
short proto_strtoint(const char *pr_str); short proto_strtoint(const char *pr_str);
int strtoargv(char *args_str, char **argv_new, int *argc_new, fko_cli_options_t *opts); int strtoargv(char *args_str, char **argv_new, int *argc_new, fko_cli_options_t *opts);

View File

@ -462,6 +462,11 @@ SPA OPTIONS
*-S, --source-port*='<port>':: *-S, --source-port*='<port>'::
Set the source port for outgoing SPA packet. Set the source port for outgoing SPA packet.
*--server-resolve-ipv4*::
This option forces the *fwknop* client to only accept an IPv4 address from
DNS when a hostname is used for the SPA server. This is necessary in some
cases where DNS may return both IPv6 and IPv4 addresses.
*-f, --fw-timeout*='<seconds>':: *-f, --fw-timeout*='<seconds>'::
Specify the length of time (seconds) that the remote firewall rule that Specify the length of time (seconds) that the remote firewall rule that
grants access to a service is to remain active. The default maintained by grants access to a service is to remain active. The default maintained by