• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws-api-test-async-dns
3  *
4  * Written in 2019 by Andy Green <andy@warmcat.com>
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 
12 #include <libwebsockets.h>
13 #include <signal.h>
14 
15 static int interrupted, dtest, ok, fail, _exp = 26;
16 struct lws_context *context;
17 
18 /*
19  * These are used to test the apis to parse and print ipv4 / ipv6 literal
20  * address strings for various cases.
21  *
22  * Expected error cases are not used to test the ip data -> string api.
23  */
24 
25 static const struct ipparser_tests {
26 	const char	*test;
27 	int		rlen;
28 	const char	*emit_test;
29 	int		emit_len;
30 	uint8_t		b[16];
31 } ipt[] = {
32 	{ "2001:db8:85a3:0:0: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 
37 	{ "2001:db8:85a3::8a2e:370:7334", 16,
38 	  "2001:db8:85a3::8a2e:370:7334", 28,
39 		{ 0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00,
40 		  0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34 } },
41 
42 	{ "::1", 16, "::1", 3,
43 			{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
44 
45 	{ "::",  16, "::", 2,
46 			{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
47 
48 	{ "::ffff:192.0.2.128", 16,  "::ffff:192.0.2.128", 18,
49 		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 		  0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x02, 0x80 } },
51 
52 	{ "cats", -1, "", 0,
53 			{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
54 
55 	{ "onevalid.bogus.warmcat.com", -1, "", 0,
56 			{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
57 
58 	{ "1.cat.dog.com", -1, "", 0,
59 			{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
60 
61 	{ ":::1", -8, "", 0,
62 			{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
63 
64 	{ "0:0::0:1", 16, "::1", 3,
65 			{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
66 
67 	{ "1.2.3.4", 4, "1.2.3.4", 7, { 1, 2, 3, 4 } },
68 };
69 
70 static const struct async_dns_tests {
71 	const char *dns_name;
72 	int recordtype;
73 	int addrlen;
74 	uint8_t ads[16];
75 } adt[] = {
76 	{ "warmcat.com", LWS_ADNS_RECORD_A, 4,
77 		{ 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
78 	{ "libwebsockets.org", LWS_ADNS_RECORD_A, 4,
79 		{ 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
80 	{ "doesntexist", LWS_ADNS_RECORD_A, 0,
81 		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
82 	{ "localhost", LWS_ADNS_RECORD_A, 4,
83 		{ 127, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
84 	{ "ipv4only.warmcat.com", LWS_ADNS_RECORD_A, 4,
85 		{ 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
86 	{ "onevalid.bogus.warmcat.com", LWS_ADNS_RECORD_A, 4,
87 		{ 46, 105, 127, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
88 #if defined(LWS_WITH_IPV6)
89 	{ "warmcat.com", LWS_ADNS_RECORD_AAAA, 16, /* check ipv6 */
90 		{ 0x20, 0x01, 0x41, 0xd0, 0x00, 0x02, 0xee, 0x93,
91 				0, 0, 0, 0, 0, 0, 0, 1, } },
92 	{ "ipv6only.warmcat.com", LWS_ADNS_RECORD_AAAA, 16, /* check ipv6 */
93 		{ 0x20, 0x01, 0x41, 0xd0, 0x00, 0x02, 0xee, 0x93,
94 				0, 0, 0, 0, 0, 0, 0, 1, } },
95 #endif
96 };
97 
98 static lws_sorted_usec_list_t sul;
99 
100 struct lws *
101 cb1(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n,
102     void *opaque);
103 
104 static void
next_test_cb(lws_sorted_usec_list_t * sul)105 next_test_cb(lws_sorted_usec_list_t *sul)
106 {
107 	int m;
108 
109 	lwsl_notice("%s: querying %s\n", __func__, adt[dtest].dns_name);
110 
111 	m = lws_async_dns_query(context, 0,
112 				adt[dtest].dns_name,
113 				(adns_query_type_t)adt[dtest].recordtype, cb1, NULL,
114 				context);
115 	if (m != LADNS_RET_CONTINUING && m != LADNS_RET_FOUND && m != LADNS_RET_FAILED_WSI_CLOSED) {
116 		lwsl_err("%s: adns 1: %s failed: %d\n", __func__, adt[dtest].dns_name, m);
117 		interrupted = 1;
118 	}
119 }
120 
121 struct lws *
cb1(struct lws * wsi_unused,const char * ads,const struct addrinfo * a,int n,void * opaque)122 cb1(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n,
123     void *opaque)
124 {
125 	const struct addrinfo *ac = a;
126 	int ctr = 0, alen;
127 	uint8_t *addr;
128 	char buf[64];
129 
130 	dtest++;
131 
132 	if (!ac)
133 		lwsl_warn("%s: no results\n", __func__);
134 
135 	/* dump the results */
136 
137 	while (ac) {
138 		if (ac->ai_family == AF_INET) {
139 			addr = (uint8_t *)&(((struct sockaddr_in *)
140 					ac->ai_addr)->sin_addr.s_addr);
141 			alen = 4;
142 		} else {
143 			addr = (uint8_t *)&(((struct sockaddr_in6 *)
144 					ac->ai_addr)->sin6_addr.s6_addr);
145 			alen = 16;
146 		}
147 		strcpy(buf, "unknown");
148 		lws_write_numeric_address(addr, alen, buf, sizeof(buf));
149 
150 		lwsl_warn("%s: %d: %s %d %s\n", __func__, ctr++, ads, alen, buf);
151 
152 		ac = ac->ai_next;
153 	}
154 
155 	ac = a;
156 	while (ac) {
157 		if (ac->ai_family == AF_INET) {
158 			addr = (uint8_t *)&(((struct sockaddr_in *)
159 					ac->ai_addr)->sin_addr.s_addr);
160 			alen = 4;
161 		} else {
162 #if defined(LWS_WITH_IPV6)
163 			addr = (uint8_t *)&(((struct sockaddr_in6 *)
164 					ac->ai_addr)->sin6_addr.s6_addr);
165 			alen = 16;
166 #else
167 			goto again;
168 #endif
169 		}
170 		if (alen == adt[dtest - 1].addrlen &&
171 		    !memcmp(adt[dtest - 1].ads, addr, (unsigned int)alen)) {
172 			ok++;
173 			goto next;
174 		}
175 #if !defined(LWS_WITH_IPV6)
176 again:
177 #endif
178 		ac = ac->ai_next;
179 	}
180 
181 	/* testing for NXDOMAIN? */
182 
183 	if (!a && !adt[dtest - 1].addrlen) {
184 		ok++;
185 		goto next;
186 	}
187 
188 	lwsl_err("%s: dns test %d: no match\n", __func__, dtest);
189 	fail++;
190 
191 next:
192 	lws_async_dns_freeaddrinfo(&a);
193 	if (dtest == (int)LWS_ARRAY_SIZE(adt))
194 		interrupted = 1;
195 	else
196 		lws_sul_schedule(context, 0, &sul, next_test_cb, 1);
197 
198 	return NULL;
199 }
200 
201 static lws_sorted_usec_list_t sul_l;
202 
203 struct lws *
cb_loop(struct lws * wsi_unused,const char * ads,const struct addrinfo * a,int n,void * opaque)204 cb_loop(struct lws *wsi_unused, const char *ads, const struct addrinfo *a, int n,
205 		void *opaque)
206 {
207 	if (!a) {
208 		lwsl_err("%s: no results\n", __func__);
209 		return NULL;
210 	}
211 
212 	lwsl_notice("%s: addrinfo %p\n", __func__, a);\
213 	lws_async_dns_freeaddrinfo(&a);
214 
215 	return NULL;
216 }
217 
218 
219 static void
sul_retry_l(struct lws_sorted_usec_list * sul)220 sul_retry_l(struct lws_sorted_usec_list *sul)
221 {
222 	int m;
223 
224 	lwsl_user("%s: starting new query\n", __func__);
225 
226 	m = lws_async_dns_query(context, 0, "warmcat.com",
227 				    (adns_query_type_t)LWS_ADNS_RECORD_A,
228 				    cb_loop, NULL, context);
229 	switch (m) {
230 	case LADNS_RET_FAILED_WSI_CLOSED:
231 		lwsl_warn("%s: LADNS_RET_FAILED_WSI_CLOSED "
232 			  "(== from cache / success in this test)\n", __func__);
233 		break;
234 	case LADNS_RET_NXDOMAIN:
235 		lwsl_warn("%s: LADNS_RET_NXDOMAIN\n", __func__);
236 		break;
237 	case LADNS_RET_TIMEDOUT:
238 		lwsl_warn("%s: LADNS_RET_TIMEDOUT\n", __func__);
239 		break;
240 	case LADNS_RET_FAILED:
241 		lwsl_warn("%s: LADNS_RET_FAILED\n", __func__);
242 		break;
243 	case LADNS_RET_FOUND:
244 		lwsl_warn("%s: LADNS_RET_FOUND\n", __func__);
245 		break;
246 	case LADNS_RET_CONTINUING:
247 		lwsl_warn("%s: LADNS_RET_CONTINUING\n", __func__);
248 		break;
249 	}
250 
251 	lws_sul_schedule(context, 0, &sul_l, sul_retry_l, 5 * LWS_US_PER_SEC);
252 }
253 
sigint_handler(int sig)254 void sigint_handler(int sig)
255 {
256 	interrupted = 1;
257 }
258 
259 int
main(int argc,const char ** argv)260 main(int argc, const char **argv)
261 {
262 	int n = 1, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
263 	struct lws_context_creation_info info;
264 	const char *p;
265 
266 	/* the normal lws init */
267 
268 	signal(SIGINT, sigint_handler);
269 
270 	if ((p = lws_cmdline_option(argc, argv, "-d")))
271 		logs = atoi(p);
272 
273 	lws_set_log_level(logs, NULL);
274 	lwsl_user("LWS API selftest: Async DNS\n");
275 
276 	memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
277 	info.port = CONTEXT_PORT_NO_LISTEN;
278 	info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
279 
280 	context = lws_create_context(&info);
281 	if (!context) {
282 		lwsl_err("lws init failed\n");
283 		return 1;
284 	}
285 
286 	if (lws_cmdline_option(argc, argv, "-l")) {
287 		lws_sul_schedule(context, 0, &sul_l, sul_retry_l, LWS_US_PER_SEC);
288 		goto evloop;
289 	}
290 
291 
292 	/* ip address parser tests */
293 
294 	for (n = 0; n < (int)LWS_ARRAY_SIZE(ipt); n++) {
295 		uint8_t u[16];
296 		int m = lws_parse_numeric_address(ipt[n].test, u, sizeof(u));
297 
298 		if (m != ipt[n].rlen) {
299 			lwsl_err("%s: fail %s ret %d\n",
300 					__func__, ipt[n].test, m);
301 			fail++;
302 			continue;
303 		}
304 
305 		if (m > 0) {
306 			if (memcmp(ipt[n].b, u, (unsigned int)m)) {
307 				lwsl_err("%s: fail %s compare\n", __func__,
308 						ipt[n].test);
309 				lwsl_hexdump_notice(u, (unsigned int)m);
310 				fail++;
311 				continue;
312 			}
313 		}
314 		ok++;
315 	}
316 
317 	/* ip address formatter tests */
318 
319 	for (n = 0; n < (int)LWS_ARRAY_SIZE(ipt); n++) {
320 		char buf[64];
321 		int m;
322 
323 		/* don't attempt to reverse the ones that are meant to fail */
324 		if (ipt[n].rlen < 0)
325 			continue;
326 
327 		m = lws_write_numeric_address(ipt[n].b, ipt[n].rlen, buf,
328 						sizeof(buf));
329 		if (m != ipt[n].emit_len) {
330 			lwsl_err("%s: fail %s ret %d\n",
331 					__func__, ipt[n].emit_test, m);
332 			fail++;
333 			continue;
334 		}
335 
336 		if (m > 0) {
337 			if (strcmp(ipt[n].emit_test, buf)) {
338 				lwsl_err("%s: fail %s compare\n", __func__,
339 						ipt[n].test);
340 				lwsl_hexdump_notice(buf, (unsigned int)m);
341 				fail++;
342 				continue;
343 			}
344 		}
345 		ok++;
346 	}
347 
348 #if !defined(LWS_WITH_IPV6)
349 	_exp -= 2;
350 #endif
351 
352 	/* kick off the async dns tests */
353 
354 	lws_sul_schedule(context, 0, &sul, next_test_cb, 1);
355 
356 evloop:
357 	/* the usual lws event loop */
358 
359 	n = 1;
360 	while (n >= 0 && !interrupted)
361 		n = lws_service(context, 0);
362 
363 	lws_context_destroy(context);
364 
365 	if (fail || ok != _exp)
366 		lwsl_user("Completed: PASS: %d / %d, FAIL: %d\n", ok, _exp,
367 				fail);
368 	else
369 		lwsl_user("Completed: ALL PASS: %d / %d\n", ok, _exp);
370 
371 	return !(ok == _exp && !fail);
372 }
373