/libparistraceroute/address.c

https://github.com/libparistraceroute/libparistraceroute · C · 342 lines · 269 code · 56 blank · 17 comment · 34 complexity · cdbba9906feb8a534c693397af289358 MD5 · raw file

  1. #include "use.h"
  2. #include "config.h"
  3. #include <stdio.h> // perror
  4. #include <stdlib.h> // malloc
  5. #include <errno.h> // errno, ENOMEM, EINVAL
  6. #include <string.h> // memcpy
  7. #include <netdb.h> // getnameinfo, getaddrinfo
  8. #include <sys/socket.h> // getnameinfo, getaddrinfo, sockaddr_*
  9. #include <netinet/in.h> // INET_ADDRSTRLEN, INET6_ADDRSTRLEN
  10. #include <arpa/inet.h> // inet_pton
  11. #ifndef AI_IDN
  12. # define AI_IDN 0x0000
  13. #endif
  14. #include "address.h"
  15. #ifdef USE_CACHE
  16. # include "containers/map.h"
  17. static map_t * cache_ip_hostname = NULL;
  18. static void __cache_ip_hostname_create() __attribute__((constructor));
  19. static void __cache_ip_hostname_free() __attribute__((destructor));
  20. static void str_dump(const char * s) {
  21. printf("%s (%p)", s, s);
  22. }
  23. static void __cache_ip_hostname_create() {
  24. cache_ip_hostname = map_create(
  25. address_dup, address_free, address_dump, address_compare,
  26. strdup, free, str_dump
  27. );
  28. }
  29. static void __cache_ip_hostname_free() {
  30. if (cache_ip_hostname) map_free(cache_ip_hostname);
  31. }
  32. #endif
  33. static void ip_fprintf(FILE * out, int family, const void * ip, char * buffer, size_t buffer_len) {
  34. if (inet_ntop(family, ip, buffer, buffer_len)) {
  35. fprintf(out, "%s", buffer);
  36. } else {
  37. fprintf(out, "???");
  38. }
  39. }
  40. int ip_from_string(int family, const char * hostname, ip_t * ip) {
  41. struct addrinfo hints,
  42. * ai,
  43. * res = NULL;
  44. int ret;
  45. void * addr;
  46. size_t addr_len;
  47. // Initialize hints
  48. memset(&hints, 0, sizeof(hints));
  49. hints.ai_family = family;
  50. hints.ai_flags = AI_IDN;
  51. // Convert string hostname / IP into a sequence of addrinfo instances
  52. if ((ret = getaddrinfo(hostname, NULL, &hints, &res)) != 0) {
  53. goto ERROR_GETADDRINFO;
  54. }
  55. // Find the first addrinfo with the appropriate family
  56. for (ai = res; ai; ai = ai->ai_next) {
  57. if (ai->ai_family == family) break;
  58. }
  59. // Not found! Pass the last addrinfo
  60. if (!ai) ai = res;
  61. // Extract from sockaddr the address where is stored the IP
  62. switch (family) {
  63. #ifdef USE_IPV4
  64. case AF_INET:
  65. addr = &(((struct sockaddr_in *) ai->ai_addr)->sin_addr);
  66. addr_len = sizeof(ipv4_t);
  67. break;
  68. #endif
  69. #ifdef USE_IPV6
  70. case AF_INET6:
  71. addr = &(((struct sockaddr_in6 *) ai->ai_addr)->sin6_addr);
  72. addr_len = sizeof(ipv6_t);
  73. break;
  74. #endif
  75. default:
  76. fprintf(stderr, "ip_from_string: Invalid family\n");
  77. ret = EINVAL;
  78. goto ERROR_FAMILY;
  79. }
  80. // Fill the address_t structure
  81. memcpy(ip, addr, addr_len);
  82. ERROR_FAMILY:
  83. freeaddrinfo(res);
  84. ERROR_GETADDRINFO:
  85. return ret;
  86. }
  87. #ifdef USE_IPV4
  88. void ipv4_fprintf(FILE * out, const ipv4_t * ipv4) {
  89. char buffer[INET_ADDRSTRLEN];
  90. ip_fprintf(out, AF_INET, ipv4, buffer, INET_ADDRSTRLEN);
  91. }
  92. void ipv4_dump(const ipv4_t * ipv4) {
  93. ipv4_fprintf(stdout, ipv4);
  94. }
  95. #endif
  96. #ifdef USE_IPV6
  97. void ipv6_fprintf(FILE * out, const ipv6_t * ipv6) {
  98. char buffer[INET6_ADDRSTRLEN];
  99. ip_fprintf(out, AF_INET6, ipv6, buffer, INET6_ADDRSTRLEN);
  100. }
  101. void ipv6_dump(const ipv6_t * ipv6) {
  102. ipv6_fprintf(stdout, ipv6);
  103. }
  104. #endif
  105. void address_fprintf(FILE * out, const address_t * address) {
  106. char buffer[INET6_ADDRSTRLEN];
  107. ip_fprintf(out, address->family, &address->ip, buffer, INET6_ADDRSTRLEN);
  108. }
  109. void address_dump(const address_t * address) {
  110. address_fprintf(stdout, address);
  111. }
  112. bool address_guess_family(const char * str_ip, int * pfamily) {
  113. struct addrinfo hints,
  114. * result;
  115. int err ;
  116. memset(&hints, 0, sizeof(struct addrinfo));
  117. hints.ai_family = AF_UNSPEC; // Allow IPv4 or IPv6
  118. hints.ai_socktype = SOCK_DGRAM;
  119. hints.ai_flags = AI_PASSIVE;
  120. if ((err = getaddrinfo(str_ip, NULL, &hints, &result)) != 0) {
  121. fprintf(stderr, "%s", gai_strerror(err));
  122. goto ERR_GETADDRINFO;
  123. }
  124. if (!result) goto ERR_NO_RESULT;
  125. /*
  126. printf("==>\n");
  127. for (rp = result; rp != NULL; rp = rp->ai_next) {
  128. printf("family = %d\n", rp->ai_family);
  129. }
  130. */
  131. // We retrieve family from the first result
  132. *pfamily = result->ai_family;
  133. freeaddrinfo(result);
  134. return true;
  135. ERR_NO_RESULT:
  136. ERR_GETADDRINFO:
  137. fprintf(stderr, "Invalid address (%s): %s\n", str_ip, gai_strerror(err));
  138. return false;
  139. }
  140. int address_from_string(int family, const char * hostname, address_t * address) {
  141. address->family = family;
  142. return ip_from_string(family, hostname, &address->ip);
  143. }
  144. address_t * address_create() {
  145. return malloc(sizeof(address_t));
  146. }
  147. void address_free(address_t * address) {
  148. if (address) free(address);
  149. }
  150. address_t * address_dup(const address_t * address) {
  151. address_t * dup;
  152. if ((dup = address_create())) {
  153. memcpy(dup, address, sizeof(address_t));
  154. }
  155. return dup;
  156. }
  157. int address_compare(const address_t * x, const address_t * y) {
  158. size_t i, address_size;
  159. const uint8_t * px = NULL,
  160. * py = NULL;
  161. if (x->family < y->family) return -1;
  162. if (x->family > y->family) return 1;
  163. address_size = address_get_size(x);
  164. switch (x->family) {
  165. #ifdef USE_IPV4
  166. case AF_INET:
  167. px = (const uint8_t *) &x->ip.ipv4;
  168. py = (const uint8_t *) &y->ip.ipv4;
  169. break;
  170. #endif
  171. #ifdef USE_IPV6
  172. case AF_INET6:
  173. px = (const uint8_t *) &x->ip.ipv6;
  174. py = (const uint8_t *) &y->ip.ipv6;
  175. break;
  176. #endif
  177. }
  178. for (i = 0; (i < address_size) && (*px++ == *py++); i++);
  179. return *--px - *--py;
  180. }
  181. int address_to_string(const address_t * address, char ** pbuffer)
  182. {
  183. struct sockaddr * sa;
  184. #ifdef USE_IPV4
  185. struct sockaddr_in sa4;
  186. #endif
  187. #ifdef USE_IPV6
  188. struct sockaddr_in6 sa6;
  189. #endif
  190. socklen_t socket_size;
  191. int ret = -1;
  192. size_t buffer_size;
  193. switch (address->family) {
  194. #ifdef USE_IPV4
  195. case AF_INET:
  196. sa = (struct sockaddr *) &sa4;
  197. memset(sa, 0, sizeof(struct sockaddr_in));
  198. sa4.sin_family = address->family;
  199. socket_size = sizeof(struct sockaddr_in);
  200. sa4.sin_addr = address->ip.ipv4;
  201. buffer_size = INET_ADDRSTRLEN;
  202. break;
  203. #endif
  204. #ifdef USE_IPV6
  205. case AF_INET6:
  206. sa = (struct sockaddr *) &sa6;
  207. memset(sa, 0, sizeof(struct sockaddr_in6));
  208. sa6.sin6_family = address->family;
  209. socket_size = sizeof(struct sockaddr_in6);
  210. memcpy(&sa6.sin6_addr, &address->ip.ipv6, sizeof(ipv6_t));
  211. buffer_size = INET6_ADDRSTRLEN;
  212. break;
  213. #endif
  214. default:
  215. *pbuffer = NULL;
  216. fprintf(stderr, "address_to_string: Family not supported (family = %d)\n", address->family);
  217. goto ERR_INVALID_FAMILY;
  218. }
  219. if (!(*pbuffer = malloc(buffer_size))) {
  220. goto ERR_MALLOC;
  221. }
  222. if ((ret = getnameinfo(sa, socket_size, *pbuffer, buffer_size, NULL, 0, NI_NUMERICHOST)) != 0) {
  223. fprintf(stderr, "address_to_string: %s", gai_strerror(ret));
  224. goto ERR_GETNAMEINFO;
  225. }
  226. return ret;
  227. ERR_GETNAMEINFO:
  228. free(*pbuffer);
  229. ERR_INVALID_FAMILY:
  230. ERR_MALLOC:
  231. return ret;
  232. }
  233. size_t address_get_size(const address_t * address) {
  234. switch (address->family) {
  235. #ifdef USE_IPV4
  236. case AF_INET: return sizeof(ipv4_t);
  237. #endif
  238. #ifdef USE_IPV6
  239. case AF_INET6: return sizeof(ipv6_t);
  240. #endif
  241. default:
  242. fprintf(stderr, "address_get_size: Invalid family\n");
  243. break;
  244. }
  245. return 0;
  246. }
  247. bool address_resolv(const address_t * address, char ** phostname, int mask_cache)
  248. {
  249. struct hostent * hp;
  250. bool found = false;
  251. const void * data;
  252. if (!address) goto ERR_INVALID_PARAMETER;
  253. #ifdef USE_CACHE
  254. if (cache_ip_hostname && (mask_cache & CACHE_READ)) {
  255. found = map_find(cache_ip_hostname, address, &data); //phostname);
  256. if (found) {
  257. // We've to strdup the cached value, otherwise the function
  258. // calling address_resolv will erase this cached value.
  259. *phostname = strdup(data);
  260. }
  261. }
  262. #endif
  263. #ifdef USE_CACHE
  264. if (!found) {
  265. #endif
  266. if (!(hp = gethostbyaddr(&address->ip, address_get_size(address), address->family))) {
  267. // see h_error
  268. goto ERR_GETHOSTBYADDR;
  269. }
  270. if (!(*phostname = strdup(hp->h_name))) {
  271. goto ERR_STRDUP;
  272. }
  273. #ifdef USE_CACHE
  274. if (mask_cache & CACHE_WRITE) {
  275. map_update(cache_ip_hostname, address, *phostname);
  276. }
  277. }
  278. #endif
  279. return true;
  280. ERR_GETHOSTBYADDR:
  281. // This is to avoid to get errno set to 22 (EINVAL) if the DNS lookup fails.
  282. errno = 0;
  283. ERR_STRDUP:
  284. ERR_INVALID_PARAMETER:
  285. return false;
  286. }