main.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * lws-api-test-async-dns
  3. *
  4. * Written in 2019 by Andy Green <[email protected]>
  5. *
  6. * This file is made available under the Creative Commons CC0 1.0
  7. * Universal Public Domain Dedication.
  8. *
  9. * This api test confirms various kinds of async dns apis
  10. */
  11. #include <libwebsockets.h>
  12. #include <signal.h>
  13. static int interrupted, dtest, ok, fail, _exp = 26;
  14. struct lws_context *context;
  15. /*
  16. * These are used to test the apis to parse and print ipv4 / ipv6 literal
  17. * address strings for various cases.
  18. *
  19. * Expected error cases are not used to test the ip data -> string api.
  20. */
  21. static const struct ipparser_tests {
  22. const char *test;
  23. int rlen;
  24. const char *emit_test;
  25. int emit_len;
  26. uint8_t b[16];
  27. } ipt[] = {
  28. { "2001:db8:85a3:0:0:8a2e:370:7334", 16,
  29. "2001:db8:85a3::8a2e:370:7334", 28,
  30. { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00,
  31. 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 } },
  32. { "2001:db8:85a3::8a2e:370:7334", 16,
  33. "2001:db8:85a3::8a2e:370:7334", 28,
  34. { 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00,
  35. 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 } },
  36. { "::1", 16, "::1", 3,
  37. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
  38. { "::", 16, "::", 2,
  39. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
  40. { "::ffff:192.0.2.128", 16, "::ffff:192.0.2.128", 18,
  41. { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  42. 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x02, 0x80 } },
  43. { "cats", -1, "", 0,
  44. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
  45. { "onevalid.bogus.warmcat.com", -1, "", 0,
  46. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
  47. { "1.cat.dog.com", -1, "", 0,
  48. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
  49. { ":::1", -8, "", 0,
  50. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
  51. { "0:0::0:1", 16, "::1", 3,
  52. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
  53. { "1.2.3.4", 4, "1.2.3.4", 7, { 1, 2, 3, 4 } },
  54. };
  55. static const struct async_dns_tests {
  56. const char *dns_name;
  57. int recordtype;
  58. int addrlen;
  59. uint8_t ads[16];
  60. } adt[] = {
  61. { "warmcat.com", LWS_ADNS_RECORD_A, 4,
  62. { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
  63. { "libwebsockets.org", LWS_ADNS_RECORD_A, 4,
  64. { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
  65. { "doesntexist", LWS_ADNS_RECORD_A, 0,
  66. { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
  67. { "localhost", LWS_ADNS_RECORD_A, 4,
  68. { 127, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
  69. { "ipv4only.warmcat.com", LWS_ADNS_RECORD_A, 4,
  70. { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
  71. { "onevalid.bogus.warmcat.com", LWS_ADNS_RECORD_A, 4,
  72. { 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
  73. #if defined(LWS_WITH_IPV6)
  74. { "warmcat.com", LWS_ADNS_RECORD_AAAA, 16, /* check ipv6 */
  75. { 0x20, 0x01, 0x41, 0xd0, 0x00, 0x02, 0xee, 0x93,
  76. 0, 0, 0, 0, 0, 0, 0, 0, } },
  77. { "ipv6only.warmcat.com", LWS_ADNS_RECORD_AAAA, 16, /* check ipv6 */
  78. { 0x20, 0x01, 0x41, 0xd0, 0x00, 0x02, 0xee, 0x93,
  79. 0, 0, 0, 0, 0, 0, 0, 0, } },
  80. #endif
  81. };
  82. static lws_sorted_usec_list_t sul;
  83. struct lws *
  84. cb1(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n,
  85. void *opaque);
  86. static void
  87. next_test_cb(lws_sorted_usec_list_t *sul)
  88. {
  89. int m;
  90. lwsl_notice("%s: querying %s\n", __func__, adt[dtest].dns_name);
  91. m = lws_async_dns_query(context, 0,
  92. adt[dtest].dns_name,
  93. adt[dtest].recordtype, cb1, NULL,
  94. context);
  95. if (m != LADNS_RET_CONTINUING && m != LADNS_RET_FOUND) {
  96. lwsl_err("%s: adns 1 failed: %d\n", __func__, m);
  97. interrupted = 1;
  98. }
  99. }
  100. struct lws *
  101. cb1(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n,
  102. void *opaque)
  103. {
  104. const struct addrinfo *ac = a;
  105. int ctr = 0, alen;
  106. uint8_t *addr;
  107. char buf[64];
  108. dtest++;
  109. if (!ac)
  110. lwsl_warn("%s: no results\n", __func__);
  111. /* dump the results */
  112. while (ac) {
  113. if (ac->ai_family == AF_INET) {
  114. addr = (uint8_t *)&(((struct sockaddr_in *)
  115. ac->ai_addr)->sin_addr.s_addr);
  116. alen = 4;
  117. } else {
  118. addr = (uint8_t *)&(((struct sockaddr_in6 *)
  119. ac->ai_addr)->sin6_addr.s6_addr);
  120. alen = 16;
  121. }
  122. strcpy(buf, "unknown");
  123. lws_write_numeric_address(addr, alen, buf, sizeof(buf));
  124. lwsl_warn("%s: %d: %s %d %s\n", __func__, ctr++, ads, alen, buf);
  125. ac = ac->ai_next;
  126. }
  127. ac = a;
  128. while (ac) {
  129. if (ac->ai_family == AF_INET) {
  130. addr = (uint8_t *)&(((struct sockaddr_in *)
  131. ac->ai_addr)->sin_addr.s_addr);
  132. alen = 4;
  133. } else {
  134. #if defined(LWS_WITH_IPV6)
  135. addr = (uint8_t *)&(((struct sockaddr_in6 *)
  136. ac->ai_addr)->sin6_addr.s6_addr);
  137. alen = 16;
  138. #else
  139. goto again;
  140. #endif
  141. }
  142. if (alen == adt[dtest - 1].addrlen &&
  143. !memcmp(adt[dtest - 1].ads, addr, alen)) {
  144. ok++;
  145. goto next;
  146. }
  147. #if !defined(LWS_WITH_IPV6)
  148. again:
  149. #endif
  150. ac = ac->ai_next;
  151. }
  152. /* testing for NXDOMAIN? */
  153. if (!a && !adt[dtest - 1].addrlen) {
  154. ok++;
  155. goto next;
  156. }
  157. lwsl_err("%s: dns test %d: no match\n", __func__, dtest);
  158. fail++;
  159. next:
  160. lws_async_dns_freeaddrinfo(&a);
  161. if (dtest == (int)LWS_ARRAY_SIZE(adt))
  162. interrupted = 1;
  163. else
  164. lws_sul_schedule(context, 0, &sul, next_test_cb, 1);
  165. return NULL;
  166. }
  167. void sigint_handler(int sig)
  168. {
  169. interrupted = 1;
  170. }
  171. int
  172. main(int argc, const char **argv)
  173. {
  174. int n = 1, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
  175. struct lws_context_creation_info info;
  176. const char *p;
  177. /* the normal lws init */
  178. signal(SIGINT, sigint_handler);
  179. if ((p = lws_cmdline_option(argc, argv, "-d")))
  180. logs = atoi(p);
  181. lws_set_log_level(logs, NULL);
  182. lwsl_user("LWS API selftest: Async DNS\n");
  183. memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
  184. info.port = CONTEXT_PORT_NO_LISTEN;
  185. info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
  186. context = lws_create_context(&info);
  187. if (!context) {
  188. lwsl_err("lws init failed\n");
  189. return 1;
  190. }
  191. /* ip address parser tests */
  192. for (n = 0; n < (int)LWS_ARRAY_SIZE(ipt); n++) {
  193. uint8_t u[16];
  194. int m = lws_parse_numeric_address(ipt[n].test, u, sizeof(u));
  195. if (m != ipt[n].rlen) {
  196. lwsl_err("%s: fail %s ret %d\n",
  197. __func__, ipt[n].test, m);
  198. fail++;
  199. continue;
  200. }
  201. if (m > 0) {
  202. if (memcmp(ipt[n].b, u, m)) {
  203. lwsl_err("%s: fail %s compare\n", __func__,
  204. ipt[n].test);
  205. lwsl_hexdump_notice(u, m);
  206. fail++;
  207. continue;
  208. }
  209. }
  210. ok++;
  211. }
  212. /* ip address formatter tests */
  213. for (n = 0; n < (int)LWS_ARRAY_SIZE(ipt); n++) {
  214. char buf[64];
  215. int m;
  216. /* don't attempt to reverse the ones that are meant to fail */
  217. if (ipt[n].rlen < 0)
  218. continue;
  219. m = lws_write_numeric_address(ipt[n].b, ipt[n].rlen, buf,
  220. sizeof(buf));
  221. if (m != ipt[n].emit_len) {
  222. lwsl_err("%s: fail %s ret %d\n",
  223. __func__, ipt[n].emit_test, m);
  224. fail++;
  225. continue;
  226. }
  227. if (m > 0) {
  228. if (strcmp(ipt[n].emit_test, buf)) {
  229. lwsl_err("%s: fail %s compare\n", __func__,
  230. ipt[n].test);
  231. lwsl_hexdump_notice(buf, m);
  232. fail++;
  233. continue;
  234. }
  235. }
  236. ok++;
  237. }
  238. #if !defined(LWS_WITH_IPV6)
  239. _exp -= 2;
  240. #endif
  241. /* kick off the async dns tests */
  242. lws_sul_schedule(context, 0, &sul, next_test_cb, 1);
  243. /* the usual lws event loop */
  244. n = 1;
  245. while (n >= 0 && !interrupted)
  246. n = lws_service(context, 0);
  247. lws_context_destroy(context);
  248. if (fail || ok != _exp)
  249. lwsl_user("Completed: PASS: %d / %d, FAIL: %d\n", ok, _exp,
  250. fail);
  251. else
  252. lwsl_user("Completed: ALL PASS: %d / %d\n", ok, _exp);
  253. return !(ok == _exp && !fail);
  254. }