--- a/hyper-v.tools.hv.hv_kvp_daemon.c +++ b/hyper-v.tools.hv.hv_kvp_daemon.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -677,6 +678,83 @@ static void kvp_process_ipconfig_file(ch pclose(file); } +static bool kvp_verify_ip_address(void *address_string) +{ + char verify_buf[sizeof(struct in6_addr)]; + + if (inet_pton(AF_INET, address_string, verify_buf) == 1) + return true; + if (inet_pton(AF_INET6, address_string, verify_buf) == 1) + return true; + return false; +} + +static void kvp_extract_routes(void **output, size_t *output_len, char *line) +{ + static const char needle[] = "via "; + char *match, *haystack = line; + + while ((match = strstr(haystack, needle))) { + char *address, *end; + + /* Address starts after needle. */ + address = match + strlen(needle); + + /* The char following address is a space or end of line. */ + end = strpbrk(address, " \t\\"); + if (!end) + end = address + strlen(address) + 1; + + /* Enough room for address and semicolon. */ + if (*output_len >= (end - address) + 1) { + memcpy(*output, address, end - address); + /* Terminate string for verification. */ + memcpy(*output + (end - address), "", 1); + if (kvp_verify_ip_address(*output)) { + /* Advance output buffer. */ + *output += end - address; + *output_len -= end - address; + + /* Each address needs a trailing semicolon. */ + memcpy(*output, ";", 1); + *output += 1; + *output_len -= 1; + } + } + haystack = end; + } +} + +static void kvp_get_gateway(void *buffer, size_t buffer_len) +{ + static const char needle[] = "default "; + FILE *f; + void *output = buffer; + char *line = NULL; + size_t alloc_size = 0, output_len = buffer_len - 1; + ssize_t num_chars; + + /* Show route information in a single line, for each address family */ + f = popen("ip --oneline -4 route show;exec ip --oneline -6 route show", "r"); + while ((num_chars = getline(&line, &alloc_size, f)) > 0) { + /* Skip short lines. */ + if (num_chars <= strlen(needle)) + continue; + /* Skip lines without default route. */ + if (memcmp(line, needle, strlen(needle))) + continue; + /* Remove trailing newline to simplify further parsing. */ + if (line[num_chars - 1] == '\n') + line[num_chars - 1] = '\0'; + /* Search routes after match. */ + kvp_extract_routes(&output, &output_len, line + strlen(needle)); + } + /* Convert buffer into C-String. */ + memcpy(output, "", 1); + free(line); + pclose(f); +} + static void kvp_get_ipconfig_info(char *if_name, struct hv_kvp_ipaddr_value *buffer) { @@ -684,32 +762,7 @@ static void kvp_get_ipconfig_info(char * char dhcp_info[128]; char *p; FILE *file; - - /* - * Get the address of default gateway (ipv4). - */ - sprintf(cmd, "%s %s", "ip route show dev", if_name); - strcat(cmd, " | awk '/default/ {print $3 }'"); - - /* - * Execute the command to gather gateway info. - */ - kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, - (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0); - - /* - * Get the address of default gateway (ipv6). - */ - sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name); - strcat(cmd, " | awk '/default/ {print $3 }'"); - - /* - * Execute the command to gather gateway info (ipv6). - */ - kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, - (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1); - - + kvp_get_gateway(buffer->gate_way, sizeof(buffer->gate_way)); /* * Gather the DNS state. * Since there is no standard way to get this information @@ -1335,6 +1335,7 @@ kvp_get_domain_name(char *buffer, int le struct addrinfo hints, *info ; int error = 0; + return; gethostname(buffer, length); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */ @@ -1572,6 +1573,12 @@ int main(int argc, char *argv[]) switch (hv_msg->body.kvp_enum_data.index) { case FullyQualifiedDomainName: + /* + * The API is undocumented. + * The Host can not possibly care about DNS within the guest network + * The time it takes to get the hostname is much shorter than a DNS lookup. + */ + gethostname(full_domain_name, sizeof(full_domain_name)); strcpy(key_value, full_domain_name); strcpy(key_name, "FullyQualifiedDomainName"); break;