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

View File

@ -124,6 +124,7 @@ enum
FWKNOP_CLI_ARG_NAT_ACCESS,
FWKNOP_CLI_ARG_HTTP_USER_AGENT,
FWKNOP_CLI_ARG_RESOLVE_URL,
FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4,
FWKNOP_CLI_ARG_NAT_LOCAL,
FWKNOP_CLI_ARG_NAT_RAND_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 },
{ "HTTP_USER_AGENT", FWKNOP_CLI_ARG_HTTP_USER_AGENT },
{ "RESOLVE_URL", FWKNOP_CLI_ARG_RESOLVE_URL },
{ "SERVER_RESOLVE_IPV4", FWKNOP_CLI_ARG_SERVER_RESOLVE_IPV4 },
{ "NAT_LOCAL", FWKNOP_CLI_ARG_NAT_LOCAL },
{ "NAT_RAND_PORT", FWKNOP_CLI_ARG_NAT_RAND_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);
}
/* 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 */
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));
else;
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 :
bool_to_yesno(options->nat_local, val, sizeof(val));
break;
@ -2266,6 +2279,9 @@ config_init(fko_cli_options_t *options, int argc, char **argv)
strlcpy(options->resolve_url, optarg, rlen);
add_var_to_bitmask(FWKNOP_CLI_ARG_RESOLVE_URL, &var_bitmask);
break;
case SERVER_RESOLVE_IPV4:
options->spa_server_resolve_ipv4 = 1;
break;
case 'w':
if(options->wget_bin != NULL)
free(options->wget_bin);
@ -2563,6 +2579,8 @@ usage(void)
" $HOME/fwknop.run file\n"
" --rc-file Specify path to the fwknop rc file (default\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"
" $HOME/.fwknoprc stanza specified with the\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 */
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",
hostname);

View File

@ -164,6 +164,7 @@ typedef struct fko_cli_options
unsigned char save_rc_stanza;
unsigned char force_save_rc_stanza;
unsigned char stanza_list;
int spa_server_resolve_ipv4;
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) {
/* 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,
rp->ai_protocol);
if (sock < 0)
@ -703,7 +714,8 @@ send_spa_packet(fko_ctx_t ctx, fko_cli_options_t *options)
return res;
#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",
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 hints Hints to reduce the number of result from getaddrinfo()
* @param ip_str String where to store the resolve ip address
* @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.
*/
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 */
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 */
error = getaddrinfo(dns_str, NULL, hints, &result);
if (error != 0)
fprintf(stderr, "resolve_dest_adr() : %s\n", gai_strerror(error));
fprintf(stderr, "resolve_dst_addr() : %s\n", gai_strerror(error));
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 */
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);
#if WIN32 && WINVER <= 0x0600
/* On older Windows systems (anything before Vista?),
@ -195,12 +208,12 @@ resolve_dest_adr(const char *dns_str, struct addrinfo *hints, char *ip_str, size
sai_remote = (struct sockaddr_in *)get_in_addr((struct sockaddr *)(rp->ai_addr));
if (inet_ntop(rp->ai_family, sai_remote, ip_str, ip_bufsize) != NULL)
#endif
{
{
error = 0;
break;
}
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));
}

View File

@ -56,7 +56,8 @@
void hex_dump(const unsigned char *data, const int size);
int set_file_perms(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_strtoint(const char *pr_str);
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>'::
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>'::
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