1 //libcurl internal punycode converter
2 #ifdef _WIN32
3 int jeroen_win32_idn_to_ascii(const char *in, char **out);
4 #endif
5 
6 //needed to expose inet_ntop
7 #ifndef _WIN32_WINNT
8 #define _WIN32_WINNT 0x0600
9 #endif
10 
11 //getaddrinfo is an extension (not C99)
12 #if !defined(_WIN32) && !defined(__sun) && !defined(_POSIX_C_SOURCE)
13 #define _POSIX_C_SOURCE 200112L
14 #endif
15 
16 #include <Rinternals.h>
17 #include <string.h>
18 
19 #ifdef _WIN32
20 #include <winsock2.h>
21 #include <ws2tcpip.h>
22 #else
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <netdb.h>
26 #include <arpa/inet.h>
27 #endif
28 
R_nslookup(SEXP hostname,SEXP ipv4_only)29 SEXP R_nslookup(SEXP hostname, SEXP ipv4_only) {
30   /* Because gethostbyname() is deprecated */
31   struct addrinfo hints = {0};
32   if(asLogical(ipv4_only))
33     hints.ai_family = AF_INET; //only allow ipv4
34   struct addrinfo *addr;
35   const char * hoststr = CHAR(STRING_ELT(hostname, 0));
36 #ifdef _WIN32
37   if(Rf_getCharCE(STRING_ELT(hostname, 0)) == CE_UTF8){
38     char * punycode;
39     if(jeroen_win32_idn_to_ascii(hoststr, &punycode))
40       hoststr = punycode;
41   }
42 #endif
43   if(getaddrinfo(hoststr, NULL, &hints, &addr))
44     return R_NilValue;
45 
46   // count number of hits
47   int len = 0;
48   struct addrinfo * cur = addr;
49   while(cur != NULL){
50     len++;
51     cur = cur->ai_next;
52   }
53 
54   //allocate output
55   SEXP out = PROTECT(allocVector(STRSXP, len));
56 
57   //extract the values
58   cur = addr;
59   for(size_t i = 0; i < len; i++) {
60     struct sockaddr *sa = cur->ai_addr;
61 
62     /* IPv4 vs v6 */
63     char ip[INET6_ADDRSTRLEN];
64     if (sa->sa_family == AF_INET) {
65       struct sockaddr_in *sa_in = (struct sockaddr_in*) sa;
66       inet_ntop(AF_INET, &(sa_in->sin_addr), ip, INET_ADDRSTRLEN);
67     } else {
68       struct sockaddr_in6 *sa_in = (struct sockaddr_in6*) sa;
69       inet_ntop(AF_INET6, &(sa_in->sin6_addr), ip, INET6_ADDRSTRLEN);
70     }
71     SET_STRING_ELT(out, i, mkChar(ip));
72     cur = cur->ai_next;
73   }
74   UNPROTECT(1);
75   freeaddrinfo(addr);
76   return out;
77 }
78