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