Skip to content

Instantly share code, notes, and snippets.

@jay
Last active February 19, 2024 20:42
Show Gist options
  • Save jay/0fe0db29305184d63b7914acb3eae820 to your computer and use it in GitHub Desktop.
Save jay/0fe0db29305184d63b7914acb3eae820 to your computer and use it in GitHub Desktop.
Use getaddrinfo to retrieve addresses the same way libcurl does.
/* Use getaddrinfo to retrieve addresses the same way libcurl does.
Usage: getaddrinfo [-u] [-4|-6] [--] <host> [service|port]
curl bug report:
'Cannot resolve named proxy host when configured with async DNS'
https://github.com/curl/curl/issues/12955
* Copyright (C) 2024 Jay Satiro <[email protected]>
https://curl.se/docs/copyright.html
https://gist.github.com/jay/0fe0db29305184d63b7914acb3eae820
*/
#define _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib")
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifndef _WIN32
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif
void usage_and_exit(void)
{
fprintf(stderr,
"\nUsage: getaddrinfo [-u] [-4|-6] [--] <hostname> [service|port]\n"
"\n -4 Family AF_INET (IPv4) instead of AF_UNSPEC (unspecified).\n"
"\n -6 Family AF_INET6 (IPv6) instead of AF_UNSPEC (unspecified).\n"
"\n -u Socktype SOCK_DGRAM instead of SOCK_STREAM.\n"
"\n"
"This program uses getaddrinfo to retrieve addresses the same way libcurl \n"
"does.\n"
"\n"
"Windows' getaddrinfo implementation internally defaults to AI_ADDRCONFIG \n"
"and does not return addresses unless there is a configured \"global\" \n"
"address of the same family type on the local system. In practice this \n"
"means Windows won't return IPv6 addresses unless the local system has a \n"
"global IPv6 address.\n"
/*
Windows' getaddrinfo internally defaults to flag AI_ADDRCONFIG unless AI_ALL is
used. If there is no configured IPv6 global address on the local system then
AI_ALL works to retrieve IPv6 addresses but only if the hostname has both IPv4
and IPv6 addresses. If the hostname has only IPv6 addresses then Windows still
returns no data. libcurl does not use AI_ALL so this information doesn't need
to be shown in usage.
*/
"\n"
"Written for https://github.com/curl/curl/issues/12955\n\n");
exit(1);
}
int main(int argc, char *argv[])
{
int i, err;
struct addrinfo hints = {0, }, *res;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
for(i = 1; i < argc && argv[i][0] == '-'; ++i) {
if(argv[i][1] == '-' && !argv[i][2]) {
++i;
break;
}
else if(argv[i][1] == '4' && !argv[i][2])
hints.ai_family = AF_INET;
else if(argv[i][1] == '6' && !argv[i][2])
hints.ai_family = AF_INET6;
else if(argv[i][1] == 'u' && !argv[i][2])
hints.ai_socktype = SOCK_DGRAM;
else {
fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
usage_and_exit();
}
}
if(i >= argc)
usage_and_exit();
#ifdef _WIN32
{
WSADATA wsaData;
err = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(err) {
fprintf(stderr, "WSAStartup failure: (%d) %s\n",
err, gai_strerror(err));
exit(1);
}
}
#endif
err = getaddrinfo(argv[i], argv[i + 1], &hints, &res);
if(err) {
fprintf(stderr, "getaddrinfo failure: (%d) %s\n", err,
#ifdef EAI_SYSTEM
(err == EAI_SYSTEM) ? strerror(errno) :
#endif
gai_strerror(err));
exit(1);
}
for(; res; res = res->ai_next) {
void *data;
char buf[INET6_ADDRSTRLEN];
if(res->ai_family == AF_INET)
data = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
else if(res->ai_family == AF_INET6)
data = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
else
continue;
if(!inet_ntop(res->ai_family, data, buf, sizeof(buf))) {
const char *errmsg;
#ifdef _WIN32
err = WSAGetLastError();
errmsg = gai_strerror(err);
#else
err = errno;
errmsg = strerror(err);
#endif
fprintf(stderr, "inet_ntop failure: (%d) %s\n",
err, errmsg);
exit(1);
}
printf("%s\n", buf);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment