/* Test case for AI_V4MAPPED/AI_ALL and getaddrinfo(). */ #include #include #include #include #include #include #include #include #include static int print_getaddrinfo (struct addrinfo *res0) { struct addrinfo *res; for (res = res0; res; res = res->ai_next) { if (res->ai_canonname) printf ("canonname=%s\n", res->ai_canonname); if (res->ai_family == AF_INET) { char buf[INET6_ADDRSTRLEN]; struct sockaddr_in *sin = (struct sockaddr_in *) res->ai_addr; const char *ip = inet_ntop (res->ai_family, &sin->sin_addr.s_addr, buf, sizeof (buf)); printf ("ai_family=AF_INET\n"); printf ("ai_addr=%s\n", ip); } else if (res->ai_family == AF_INET6) { char buf[INET6_ADDRSTRLEN]; struct sockaddr_in6 *sin = (struct sockaddr_in6 *) res->ai_addr; const char *ip = inet_ntop (res->ai_family, (void *) &sin->sin6_addr, buf, sizeof (buf)); printf ("ai_family=AF_INET6\n"); printf ("ai_addr=%s\n", ip); } else printf ("ai_family=%i\n", res->ai_family); } return 0; } static struct addrinfo * call_getaddrinfo (const char *name, int af, int flags) { struct addrinfo hints, *res; int error; hints.ai_family = af; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = flags; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; error = getaddrinfo (name, NULL, &hints, &res); if (error) { fprintf (stderr, "%s\n", gai_strerror (error)); return NULL; } return res; } int main (int argc, char *argv[]) { int errors = 0; struct addrinfo *res; /* hostname, which has only one IPv4 address. */ const char *ipv4only_host = "www.gnu.org"; /* hostname, which has one IPv4 and one IPv6 address. */ const char *ipv4ipv6_host = "wwwprod.ipv6.bieringer.de"; printf ("Using getaddrinfo (%s, AF_INET, AI_CANONNAME):\n", ipv4only_host); res = call_getaddrinfo (ipv4only_host, AF_INET, AI_CANONNAME); if (res == NULL) { printf ("ERROR: getaddrinfo should return an entry\n"); ++errors; } else { if (res->ai_next != NULL) { printf ("ERROR: getaddrinfo should return only one entry\n"); ++errors; } if (res->ai_family != AF_INET) { printf ("ERROR: %d is not AF_INET\n", res->ai_family); ++errors; } if (res->ai_canonname == NULL) { printf ("ERROR: ai_canonname is not set\n"); ++errors; } print_getaddrinfo (res); freeaddrinfo (res); } printf ("Using getaddrinfo (%s, AF_INET6, AI_CANONNAME):\n", ipv4ipv6_host); res = call_getaddrinfo (ipv4ipv6_host, AF_INET6, AI_CANONNAME); if (res == NULL) { printf ("ERROR: getaddrinfo should return an entry\n"); ++errors; } else { if (res->ai_next != NULL) { printf ("ERROR: test should return only one entry\n"); ++errors; } if (res->ai_family != AF_INET6) { printf ("ERROR: %d is not AF_INET6\n", res->ai_family); ++errors; } if (res->ai_canonname == NULL) { printf ("ERROR: ai_canonname is not set\n"); ++errors; } print_getaddrinfo (res); freeaddrinfo (res); } printf ("Using getaddrinfo (%s, AF_INET6, AI_CANONNAME|AI_V4MAPPED):\n", ipv4only_host); res = call_getaddrinfo (ipv4only_host, AF_INET6, AI_CANONNAME | AI_V4MAPPED); if (res == NULL) { printf ("ERROR: getaddrinfo should return an entry\n"); ++errors; } else { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) res->ai_addr; if (res->ai_next != NULL) { printf ("ERROR: test should return only one entry\n"); ++errors; } if (res->ai_family != AF_INET6) { printf ("ERROR: %d is not AF_INET6\n", res->ai_family); ++errors; } if (!IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32)) { printf ("ERROR: No IPv6 mapped IPv4 address returned\n"); ++errors; } if (res->ai_canonname == NULL) { printf ("ERROR: ai_canonname is not set\n"); ++errors; } print_getaddrinfo (res); freeaddrinfo (res); } printf ("Using getaddrinfo (%s, AF_INET6, AI_CANONNAME|AI_V4MAPPED):\n", ipv4ipv6_host); res = call_getaddrinfo (ipv4ipv6_host, AF_INET6, AI_CANONNAME | AI_V4MAPPED); if (res == NULL) { printf ("ERROR: getaddrinfo should return an entry\n"); ++errors; } else { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) res->ai_addr; if (res->ai_next != NULL) { printf ("ERROR: test should return only one entry\n"); ++errors; } if (res->ai_family != AF_INET6) { printf ("ERROR: %d is not AF_INET6\n", res->ai_family); ++errors; } if (IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32)) { printf ("ERROR: getaddrinfo returns a IPv6 mapped IPv4 address\n"); ++errors; } if (res->ai_canonname == NULL) { printf ("ERROR: ai_canonname is not set\n"); ++errors; } print_getaddrinfo (res); freeaddrinfo (res); } printf ("Using getaddrinfo (%s, AF_INET6, AI_CANONNAME|AI_V4MAPPED|AI_ALL):\n", ipv4ipv6_host); res = call_getaddrinfo (ipv4ipv6_host, AF_INET6, AI_CANONNAME | AI_V4MAPPED | AI_ALL); if (res == NULL) { printf ("ERROR: getaddrinfo should return an entry\n"); ++errors; } else { struct addrinfo *res0; int found_ipv4 = 0, found_ipv6 = 0; if (res->ai_next == NULL || res->ai_next->ai_next != NULL) { printf ("ERROR: test should return exact two entries\n"); ++errors; } for (res0 = res; res0; res0 = res0->ai_next) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) res0->ai_addr; if (res0->ai_family != AF_INET6) { printf ("ERROR: %d is not AF_INET6\n", res->ai_family); ++errors; } if (IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32)) ++found_ipv4; else ++found_ipv6; } if (found_ipv4 != 1) { printf ("ERROR: we should got one IPv6 mapped IPv4 address, but we got %d\n", found_ipv4); ++errors; } if (found_ipv6 != 1) { printf ("ERROR: we should got one IPv6 address, but we got %d\n", found_ipv6); ++errors; } print_getaddrinfo (res); freeaddrinfo (res); } return errors; }