Last active
February 19, 2024 20:42
-
-
Save jay/0fe0db29305184d63b7914acb3eae820 to your computer and use it in GitHub Desktop.
Use getaddrinfo to retrieve addresses the same way libcurl does.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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