blob: ebe466e900a37d33b76e49304bc22705e147d392 [file] [log] [blame]
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001/* $Id$ */
2/*
Nanang Izzuddina62ffc92011-05-05 06:14:19 +00003 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono0d7b4a82007-06-07 15:46:07 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pjlib-util.h>
21#include <pjlib.h>
22#include "test.h"
23
24
25#define THIS_FILE "srv_resolver_test.c"
26
Benny Prijono36430ad2007-06-11 16:56:26 +000027////////////////////////////////////////////////////////////////////////////
28/*
29 * TODO: create various invalid DNS packets.
30 */
31
32
33////////////////////////////////////////////////////////////////////////////
34
35
Benny Prijono0d7b4a82007-06-07 15:46:07 +000036#define ACTION_REPLY 0
37#define ACTION_IGNORE -1
38#define ACTION_CB -2
39
40static struct server_t
41{
42 pj_sock_t sock;
43 pj_uint16_t port;
44 pj_thread_t *thread;
45
46 /* Action:
47 * 0: reply with the response in resp.
48 * -1: ignore query (to simulate timeout).
49 * other: reply with that error
50 */
51 int action;
52
53 pj_dns_parsed_packet resp;
54 void (*action_cb)(const pj_dns_parsed_packet *pkt,
55 pj_dns_parsed_packet **p_res);
56
57 unsigned pkt_count;
58
59} g_server[2];
60
61static pj_pool_t *pool;
62static pj_dns_resolver *resolver;
63static pj_bool_t thread_quit;
64static pj_timer_heap_t *timer_heap;
65static pj_ioqueue_t *ioqueue;
66static pj_thread_t *poll_thread;
67static pj_sem_t *sem;
68static pj_dns_settings set;
69
Benny Prijono36430ad2007-06-11 16:56:26 +000070#define MAX_LABEL 32
71
72struct label_tab
Benny Prijono0d7b4a82007-06-07 15:46:07 +000073{
Benny Prijono36430ad2007-06-11 16:56:26 +000074 unsigned count;
Benny Prijono0d7b4a82007-06-07 15:46:07 +000075
Benny Prijono36430ad2007-06-11 16:56:26 +000076 struct {
77 unsigned pos;
78 pj_str_t label;
79 } a[MAX_LABEL];
80};
Benny Prijono0d7b4a82007-06-07 15:46:07 +000081
Benny Prijono36430ad2007-06-11 16:56:26 +000082static void write16(pj_uint8_t *p, pj_uint16_t val)
83{
84 p[0] = (pj_uint8_t)(val >> 8);
85 p[1] = (pj_uint8_t)(val & 0xFF);
Benny Prijono0d7b4a82007-06-07 15:46:07 +000086}
87
Benny Prijono36430ad2007-06-11 16:56:26 +000088static void write32(pj_uint8_t *p, pj_uint32_t val)
Benny Prijono0d7b4a82007-06-07 15:46:07 +000089{
Benny Prijono36430ad2007-06-11 16:56:26 +000090 val = pj_htonl(val);
91 pj_memcpy(p, &val, 4);
92}
93
94static int print_name(pj_uint8_t *pkt, int size,
95 pj_uint8_t *pos, const pj_str_t *name,
96 struct label_tab *tab)
97{
98 pj_uint8_t *p = pos;
99 const char *endlabel, *endname;
100 unsigned i;
101 pj_str_t label;
102
103 /* Check if name is in the table */
104 for (i=0; i<tab->count; ++i) {
105 if (pj_strcmp(&tab->a[i].label, name)==0)
106 break;
107 }
108
109 if (i != tab->count) {
110 write16(p, (pj_uint16_t)(tab->a[i].pos | (0xc0 << 8)));
111 return 2;
112 } else {
113 if (tab->count < MAX_LABEL) {
114 tab->a[tab->count].pos = (p-pkt);
115 tab->a[tab->count].label.ptr = (char*)(p+1);
116 tab->a[tab->count].label.slen = name->slen;
117 ++tab->count;
118 }
119 }
120
121 endlabel = name->ptr;
122 endname = name->ptr + name->slen;
123
124 label.ptr = (char*)name->ptr;
125
126 while (endlabel != endname) {
127
128 while (endlabel != endname && *endlabel != '.')
129 ++endlabel;
130
131 label.slen = (endlabel - label.ptr);
132
133 if (size < label.slen+1)
134 return -1;
135
136 *p = (pj_uint8_t)label.slen;
137 pj_memcpy(p+1, label.ptr, label.slen);
138
139 size -= (label.slen+1);
140 p += (label.slen+1);
141
142 if (endlabel != endname && *endlabel == '.')
143 ++endlabel;
144 label.ptr = (char*)endlabel;
145 }
146
147 if (size == 0)
148 return -1;
149
150 *p++ = '\0';
151
152 return p-pos;
153}
154
155static int print_rr(pj_uint8_t *pkt, int size, pj_uint8_t *pos,
156 const pj_dns_parsed_rr *rr, struct label_tab *tab)
157{
158 pj_uint8_t *p = pos;
159 int len;
160
161 len = print_name(pkt, size, pos, &rr->name, tab);
162 if (len < 0)
163 return -1;
164
165 p += len;
166 size -= len;
167
168 if (size < 8)
169 return -1;
170
171 pj_assert(rr->dnsclass == 1);
172
173 write16(p+0, (pj_uint16_t)rr->type); /* type */
174 write16(p+2, (pj_uint16_t)rr->dnsclass); /* class */
175 write32(p+4, rr->ttl); /* TTL */
176
177 p += 8;
178 size -= 8;
179
180 if (rr->type == PJ_DNS_TYPE_A) {
181
182 if (size < 6)
183 return -1;
184
185 /* RDLEN is 4 */
186 write16(p, 4);
187
188 /* Address */
189 pj_memcpy(p+2, &rr->rdata.a.ip_addr, 4);
190
191 p += 6;
192 size -= 6;
193
194 } else if (rr->type == PJ_DNS_TYPE_CNAME ||
195 rr->type == PJ_DNS_TYPE_NS ||
196 rr->type == PJ_DNS_TYPE_PTR) {
197
198 if (size < 4)
199 return -1;
200
201 len = print_name(pkt, size-2, p+2, &rr->rdata.cname.name, tab);
202 if (len < 0)
203 return -1;
204
205 write16(p, (pj_uint16_t)len);
206
207 p += (len + 2);
208 size -= (len + 2);
209
210 } else if (rr->type == PJ_DNS_TYPE_SRV) {
211
212 if (size < 10)
213 return -1;
214
215 write16(p+2, rr->rdata.srv.prio); /* Priority */
216 write16(p+4, rr->rdata.srv.weight); /* Weight */
217 write16(p+6, rr->rdata.srv.port); /* Port */
218
219 /* Target */
220 len = print_name(pkt, size-8, p+8, &rr->rdata.srv.target, tab);
221 if (len < 0)
222 return -1;
223
224 /* RDLEN */
225 write16(p, (pj_uint16_t)(len + 6));
226
227 p += (len + 8);
228 size -= (len + 8);
229
230 } else {
231 pj_assert(!"Not supported");
232 return -1;
233 }
234
235 return p-pos;
236}
237
238static int print_packet(const pj_dns_parsed_packet *rec, pj_uint8_t *pkt,
239 int size)
240{
241 pj_uint8_t *p = pkt;
242 struct label_tab tab;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000243 int i, len;
244
Benny Prijono36430ad2007-06-11 16:56:26 +0000245 tab.count = 0;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000246
Benny Prijono36430ad2007-06-11 16:56:26 +0000247#if 0
248 pj_enter_critical_section();
249 PJ_LOG(3,(THIS_FILE, "Sending response:"));
250 pj_dns_dump_packet(rec);
251 pj_leave_critical_section();
252#endif
253
254 pj_assert(sizeof(pj_dns_hdr)==12);
Benny Prijono1af6beb2007-08-16 11:26:10 +0000255 if (size < (int)sizeof(pj_dns_hdr))
Benny Prijono36430ad2007-06-11 16:56:26 +0000256 return -1;
257
258 /* Initialize header */
259 write16(p+0, rec->hdr.id);
260 write16(p+2, rec->hdr.flags);
261 write16(p+4, rec->hdr.qdcount);
262 write16(p+6, rec->hdr.anscount);
263 write16(p+8, rec->hdr.nscount);
264 write16(p+10, rec->hdr.arcount);
265
266 p = pkt + sizeof(pj_dns_hdr);
267 size -= sizeof(pj_dns_hdr);
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000268
269 /* Print queries */
270 for (i=0; i<rec->hdr.qdcount; ++i) {
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000271
Benny Prijono36430ad2007-06-11 16:56:26 +0000272 len = print_name(pkt, size, p, &rec->q[i].name, &tab);
273 if (len < 0)
274 return -1;
275
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000276 p += len;
Benny Prijono36430ad2007-06-11 16:56:26 +0000277 size -= len;
278
279 if (size < 4)
280 return -1;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000281
282 /* Set type */
Benny Prijono36430ad2007-06-11 16:56:26 +0000283 write16(p+0, (pj_uint16_t)rec->q[i].type);
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000284
285 /* Set class (IN=1) */
Benny Prijono36430ad2007-06-11 16:56:26 +0000286 pj_assert(rec->q[i].dnsclass == 1);
287 write16(p+2, rec->q[i].dnsclass);
288
289 p += 4;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000290 }
291
292 /* Print answers */
293 for (i=0; i<rec->hdr.anscount; ++i) {
Benny Prijono36430ad2007-06-11 16:56:26 +0000294 len = print_rr(pkt, size, p, &rec->ans[i], &tab);
295 if (len < 0)
296 return -1;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000297
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000298 p += len;
Benny Prijono36430ad2007-06-11 16:56:26 +0000299 size -= len;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000300 }
301
Benny Prijono36430ad2007-06-11 16:56:26 +0000302 /* Print NS records */
303 for (i=0; i<rec->hdr.nscount; ++i) {
304 len = print_rr(pkt, size, p, &rec->ns[i], &tab);
305 if (len < 0)
306 return -1;
307
308 p += len;
309 size -= len;
310 }
311
312 /* Print additional records */
313 for (i=0; i<rec->hdr.arcount; ++i) {
314 len = print_rr(pkt, size, p, &rec->arr[i], &tab);
315 if (len < 0)
316 return -1;
317
318 p += len;
319 size -= len;
320 }
321
322 return p - pkt;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000323}
324
325
326static int server_thread(void *p)
327{
328 struct server_t *srv = (struct server_t*)p;
329
330 while (!thread_quit) {
331 pj_fd_set_t rset;
332 pj_time_val timeout = {0, 500};
333 pj_sockaddr_in src_addr;
334 pj_dns_parsed_packet *req;
335 char pkt[1024];
336 pj_ssize_t pkt_len;
337 int rc, src_len;
338
339 PJ_FD_ZERO(&rset);
340 PJ_FD_SET(srv->sock, &rset);
341
342 rc = pj_sock_select(srv->sock+1, &rset, NULL, NULL, &timeout);
343 if (rc != 1)
344 continue;
345
346 src_len = sizeof(src_addr);
347 pkt_len = sizeof(pkt);
348 rc = pj_sock_recvfrom(srv->sock, pkt, &pkt_len, 0,
349 &src_addr, &src_len);
350 if (rc != 0) {
351 app_perror("Server error receiving packet", rc);
352 continue;
353 }
354
355 PJ_LOG(5,(THIS_FILE, "Server %d processing packet", srv - &g_server[0]));
356 srv->pkt_count++;
357
358 rc = pj_dns_parse_packet(pool, pkt, pkt_len, &req);
359 if (rc != PJ_SUCCESS) {
360 app_perror("server error parsing packet", rc);
361 continue;
362 }
363
Benny Prijono36430ad2007-06-11 16:56:26 +0000364 /* Verify packet */
365 pj_assert(req->hdr.qdcount == 1);
366 pj_assert(req->q[0].dnsclass == 1);
367
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000368 /* Simulate network RTT */
369 pj_thread_sleep(50);
370
371 if (srv->action == ACTION_IGNORE) {
372 continue;
373 } else if (srv->action == ACTION_REPLY) {
374 srv->resp.hdr.id = req->hdr.id;
Benny Prijono36430ad2007-06-11 16:56:26 +0000375 pkt_len = print_packet(&srv->resp, (pj_uint8_t*)pkt, sizeof(pkt));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000376 pj_sock_sendto(srv->sock, pkt, &pkt_len, 0, &src_addr, src_len);
377 } else if (srv->action == ACTION_CB) {
378 pj_dns_parsed_packet *resp;
379 (*srv->action_cb)(req, &resp);
380 resp->hdr.id = req->hdr.id;
Benny Prijono36430ad2007-06-11 16:56:26 +0000381 pkt_len = print_packet(resp, (pj_uint8_t*)pkt, sizeof(pkt));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000382 pj_sock_sendto(srv->sock, pkt, &pkt_len, 0, &src_addr, src_len);
383 } else if (srv->action > 0) {
384 req->hdr.flags |= PJ_DNS_SET_RCODE(srv->action);
Benny Prijono36430ad2007-06-11 16:56:26 +0000385 pkt_len = print_packet(req, (pj_uint8_t*)pkt, sizeof(pkt));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000386 pj_sock_sendto(srv->sock, pkt, &pkt_len, 0, &src_addr, src_len);
387 }
388 }
389
390 return 0;
391}
392
393static int poll_worker_thread(void *p)
394{
395 PJ_UNUSED_ARG(p);
396
397 while (!thread_quit) {
398 pj_time_val delay = {0, 100};
399 pj_timer_heap_poll(timer_heap, NULL);
400 pj_ioqueue_poll(ioqueue, &delay);
401 }
402
403 return 0;
404}
405
406static void destroy(void);
407
408static int init(void)
409{
410 pj_status_t status;
411 pj_str_t nameservers[2];
412 pj_uint16_t ports[2];
413 int i;
414
415 nameservers[0] = pj_str("127.0.0.1");
Nanang Izzuddin9522ff22008-12-19 15:08:44 +0000416 ports[0] = 5553;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000417 nameservers[1] = pj_str("127.0.0.1");
Nanang Izzuddin9522ff22008-12-19 15:08:44 +0000418 ports[1] = 5554;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000419
420 g_server[0].port = ports[0];
421 g_server[1].port = ports[1];
422
423 pool = pj_pool_create(mem, NULL, 2000, 2000, NULL);
424
425 status = pj_sem_create(pool, NULL, 0, 2, &sem);
426 pj_assert(status == PJ_SUCCESS);
427
428 for (i=0; i<2; ++i) {
429 pj_sockaddr_in addr;
430
Benny Prijono8ab968f2007-07-20 08:08:30 +0000431 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &g_server[i].sock);
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000432 if (status != PJ_SUCCESS)
433 return -10;
434
435 pj_sockaddr_in_init(&addr, NULL, (pj_uint16_t)g_server[i].port);
436
437 status = pj_sock_bind(g_server[i].sock, &addr, sizeof(addr));
438 if (status != PJ_SUCCESS)
439 return -20;
440
441 status = pj_thread_create(pool, NULL, &server_thread, &g_server[i],
442 0, 0, &g_server[i].thread);
443 if (status != PJ_SUCCESS)
444 return -30;
445 }
446
447 status = pj_timer_heap_create(pool, 16, &timer_heap);
448 pj_assert(status == PJ_SUCCESS);
449
450 status = pj_ioqueue_create(pool, 16, &ioqueue);
451 pj_assert(status == PJ_SUCCESS);
452
453 status = pj_dns_resolver_create(mem, NULL, 0, timer_heap, ioqueue, &resolver);
454 if (status != PJ_SUCCESS)
455 return -40;
456
457 pj_dns_resolver_get_settings(resolver, &set);
458 set.good_ns_ttl = 20;
459 set.bad_ns_ttl = 20;
460 pj_dns_resolver_set_settings(resolver, &set);
461
462 status = pj_dns_resolver_set_ns(resolver, 2, nameservers, ports);
463 pj_assert(status == PJ_SUCCESS);
464
465 status = pj_thread_create(pool, NULL, &poll_worker_thread, NULL, 0, 0, &poll_thread);
466 pj_assert(status == PJ_SUCCESS);
467
468 return 0;
469}
470
471
472static void destroy(void)
473{
474 int i;
475
476 thread_quit = PJ_TRUE;
477
478 for (i=0; i<2; ++i) {
479 pj_thread_join(g_server[i].thread);
480 pj_sock_close(g_server[i].sock);
481 }
482
483 pj_thread_join(poll_thread);
484
485 pj_dns_resolver_destroy(resolver, PJ_FALSE);
486 pj_ioqueue_destroy(ioqueue);
487 pj_timer_heap_destroy(timer_heap);
488
489 pj_sem_destroy(sem);
490 pj_pool_release(pool);
491}
492
493
494////////////////////////////////////////////////////////////////////////////
Benny Prijono36430ad2007-06-11 16:56:26 +0000495/* DNS A parser tests */
496static int a_parser_test(void)
497{
498 pj_dns_parsed_packet pkt;
499 pj_dns_a_record rec;
500 pj_status_t rc;
501
502 PJ_LOG(3,(THIS_FILE, " DNS A record parser tests"));
503
504 pkt.q = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_query);
505 pkt.ans = (pj_dns_parsed_rr*)
506 pj_pool_calloc(pool, 32, sizeof(pj_dns_parsed_rr));
507
508 /* Simple answer with direct A record, but with addition of
509 * a CNAME and another A to confuse the parser.
510 */
511 PJ_LOG(3,(THIS_FILE, " A RR with duplicate CNAME/A"));
512 pkt.hdr.flags = 0;
513 pkt.hdr.qdcount = 1;
514 pkt.q[0].type = PJ_DNS_TYPE_A;
515 pkt.q[0].dnsclass = 1;
516 pkt.q[0].name = pj_str("ahost");
517 pkt.hdr.anscount = 3;
518
519 /* This is the RR corresponding to the query */
520 pkt.ans[0].name = pj_str("ahost");
521 pkt.ans[0].type = PJ_DNS_TYPE_A;
522 pkt.ans[0].dnsclass = 1;
523 pkt.ans[0].ttl = 1;
524 pkt.ans[0].rdata.a.ip_addr.s_addr = 0x01020304;
525
526 /* CNAME to confuse the parser */
527 pkt.ans[1].name = pj_str("ahost");
528 pkt.ans[1].type = PJ_DNS_TYPE_CNAME;
529 pkt.ans[1].dnsclass = 1;
530 pkt.ans[1].ttl = 1;
531 pkt.ans[1].rdata.cname.name = pj_str("bhost");
532
533 /* DNS A RR to confuse the parser */
534 pkt.ans[2].name = pj_str("bhost");
535 pkt.ans[2].type = PJ_DNS_TYPE_A;
536 pkt.ans[2].dnsclass = 1;
537 pkt.ans[2].ttl = 1;
538 pkt.ans[2].rdata.a.ip_addr.s_addr = 0x0203;
539
540
541 rc = pj_dns_parse_a_response(&pkt, &rec);
542 pj_assert(rc == PJ_SUCCESS);
543 pj_assert(pj_strcmp2(&rec.name, "ahost")==0);
544 pj_assert(rec.alias.slen == 0);
545 pj_assert(rec.addr_count == 1);
546 pj_assert(rec.addr[0].s_addr == 0x01020304);
547
548 /* Answer with the target corresponds to a CNAME entry, but not
549 * as the first record, and with additions of some CNAME and A
550 * entries to confuse the parser.
551 */
552 PJ_LOG(3,(THIS_FILE, " CNAME RR with duplicate CNAME/A"));
553 pkt.hdr.flags = 0;
554 pkt.hdr.qdcount = 1;
555 pkt.q[0].type = PJ_DNS_TYPE_A;
556 pkt.q[0].dnsclass = 1;
557 pkt.q[0].name = pj_str("ahost");
558 pkt.hdr.anscount = 4;
559
560 /* This is the DNS A record for the alias */
561 pkt.ans[0].name = pj_str("ahostalias");
562 pkt.ans[0].type = PJ_DNS_TYPE_A;
563 pkt.ans[0].dnsclass = 1;
564 pkt.ans[0].ttl = 1;
565 pkt.ans[0].rdata.a.ip_addr.s_addr = 0x02020202;
566
567 /* CNAME entry corresponding to the query */
568 pkt.ans[1].name = pj_str("ahost");
569 pkt.ans[1].type = PJ_DNS_TYPE_CNAME;
570 pkt.ans[1].dnsclass = 1;
571 pkt.ans[1].ttl = 1;
572 pkt.ans[1].rdata.cname.name = pj_str("ahostalias");
573
574 /* Another CNAME to confuse the parser */
575 pkt.ans[2].name = pj_str("ahost");
576 pkt.ans[2].type = PJ_DNS_TYPE_CNAME;
577 pkt.ans[2].dnsclass = 1;
578 pkt.ans[2].ttl = 1;
579 pkt.ans[2].rdata.cname.name = pj_str("ahostalias2");
580
581 /* Another DNS A to confuse the parser */
582 pkt.ans[3].name = pj_str("ahostalias2");
583 pkt.ans[3].type = PJ_DNS_TYPE_A;
584 pkt.ans[3].dnsclass = 1;
585 pkt.ans[3].ttl = 1;
586 pkt.ans[3].rdata.a.ip_addr.s_addr = 0x03030303;
587
588 rc = pj_dns_parse_a_response(&pkt, &rec);
589 pj_assert(rc == PJ_SUCCESS);
590 pj_assert(pj_strcmp2(&rec.name, "ahost")==0);
591 pj_assert(pj_strcmp2(&rec.alias, "ahostalias")==0);
592 pj_assert(rec.addr_count == 1);
593 pj_assert(rec.addr[0].s_addr == 0x02020202);
594
595 /*
596 * No query section.
597 */
598 PJ_LOG(3,(THIS_FILE, " No query section"));
599 pkt.hdr.qdcount = 0;
600 pkt.hdr.anscount = 0;
601
602 rc = pj_dns_parse_a_response(&pkt, &rec);
603 pj_assert(rc == PJLIB_UTIL_EDNSINANSWER);
604
605 /*
606 * No answer section.
607 */
608 PJ_LOG(3,(THIS_FILE, " No answer section"));
609 pkt.hdr.flags = 0;
610 pkt.hdr.qdcount = 1;
611 pkt.q[0].type = PJ_DNS_TYPE_A;
612 pkt.q[0].dnsclass = 1;
613 pkt.q[0].name = pj_str("ahost");
614 pkt.hdr.anscount = 0;
615
616 rc = pj_dns_parse_a_response(&pkt, &rec);
617 pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC);
618
619 /*
620 * Answer doesn't match query.
621 */
622 PJ_LOG(3,(THIS_FILE, " Answer doesn't match query"));
623 pkt.hdr.flags = 0;
624 pkt.hdr.qdcount = 1;
625 pkt.q[0].type = PJ_DNS_TYPE_A;
626 pkt.q[0].dnsclass = 1;
627 pkt.q[0].name = pj_str("ahost");
628 pkt.hdr.anscount = 1;
629
630 /* An answer that doesn't match the query */
631 pkt.ans[0].name = pj_str("ahostalias");
632 pkt.ans[0].type = PJ_DNS_TYPE_A;
633 pkt.ans[0].dnsclass = 1;
634 pkt.ans[0].ttl = 1;
635 pkt.ans[0].rdata.a.ip_addr.s_addr = 0x02020202;
636
637 rc = pj_dns_parse_a_response(&pkt, &rec);
638 pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC);
639
640
641 /*
642 * DNS CNAME that doesn't have corresponding DNS A.
643 */
644 PJ_LOG(3,(THIS_FILE, " CNAME with no matching DNS A RR (1)"));
645 pkt.hdr.flags = 0;
646 pkt.hdr.qdcount = 1;
647 pkt.q[0].type = PJ_DNS_TYPE_A;
648 pkt.q[0].dnsclass = 1;
649 pkt.q[0].name = pj_str("ahost");
650 pkt.hdr.anscount = 1;
651
652 /* The CNAME */
653 pkt.ans[0].name = pj_str("ahost");
654 pkt.ans[0].type = PJ_DNS_TYPE_CNAME;
655 pkt.ans[0].dnsclass = 1;
656 pkt.ans[0].ttl = 1;
657 pkt.ans[0].rdata.cname.name = pj_str("ahostalias");
658
659 rc = pj_dns_parse_a_response(&pkt, &rec);
660 pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC);
661
662
663 /*
664 * DNS CNAME that doesn't have corresponding DNS A.
665 */
666 PJ_LOG(3,(THIS_FILE, " CNAME with no matching DNS A RR (2)"));
667 pkt.hdr.flags = 0;
668 pkt.hdr.qdcount = 1;
669 pkt.q[0].type = PJ_DNS_TYPE_A;
670 pkt.q[0].dnsclass = 1;
671 pkt.q[0].name = pj_str("ahost");
672 pkt.hdr.anscount = 2;
673
674 /* The CNAME */
675 pkt.ans[0].name = pj_str("ahost");
676 pkt.ans[0].type = PJ_DNS_TYPE_CNAME;
677 pkt.ans[0].dnsclass = 1;
678 pkt.ans[0].ttl = 1;
679 pkt.ans[0].rdata.cname.name = pj_str("ahostalias");
680
681 /* DNS A record, but the name doesn't match */
682 pkt.ans[1].name = pj_str("ahost");
683 pkt.ans[1].type = PJ_DNS_TYPE_A;
684 pkt.ans[1].dnsclass = 1;
685 pkt.ans[1].ttl = 1;
686 pkt.ans[1].rdata.a.ip_addr.s_addr = 0x01020304;
687
688 rc = pj_dns_parse_a_response(&pkt, &rec);
689 pj_assert(rc == PJLIB_UTIL_EDNSNOANSWERREC);
690
691 return 0;
692}
693
694
695////////////////////////////////////////////////////////////////////////////
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000696/* Simple DNS test */
697#define IP_ADDR0 0x00010203
698
699static void dns_callback(void *user_data,
700 pj_status_t status,
701 pj_dns_parsed_packet *resp)
702{
703 PJ_UNUSED_ARG(user_data);
704
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000705 pj_sem_post(sem);
Benny Prijono95b53402009-01-01 20:56:36 +0000706
707 PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return);
708 PJ_ASSERT_ON_FAIL(resp, return);
709 PJ_ASSERT_ON_FAIL(resp->hdr.anscount == 1, return);
710 PJ_ASSERT_ON_FAIL(resp->ans[0].type == PJ_DNS_TYPE_A, return);
711 PJ_ASSERT_ON_FAIL(resp->ans[0].rdata.a.ip_addr.s_addr == IP_ADDR0, return);
712
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000713}
714
715
716static int simple_test(void)
717{
718 pj_str_t name = pj_str("helloworld");
719 pj_dns_parsed_packet *r;
720 pj_status_t status;
721
Benny Prijono36430ad2007-06-11 16:56:26 +0000722 PJ_LOG(3,(THIS_FILE, " simple successful test"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000723
724 g_server[0].pkt_count = 0;
725 g_server[1].pkt_count = 0;
726
727 g_server[0].action = ACTION_REPLY;
728 r = &g_server[0].resp;
729 r->hdr.qdcount = 1;
730 r->hdr.anscount = 1;
731 r->q = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_query);
732 r->q[0].type = PJ_DNS_TYPE_A;
733 r->q[0].dnsclass = 1;
734 r->q[0].name = name;
735 r->ans = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_rr);
736 r->ans[0].type = PJ_DNS_TYPE_A;
737 r->ans[0].dnsclass = 1;
738 r->ans[0].name = name;
739 r->ans[0].rdata.a.ip_addr.s_addr = IP_ADDR0;
740
741 g_server[1].action = ACTION_REPLY;
742 r = &g_server[1].resp;
743 r->hdr.qdcount = 1;
744 r->hdr.anscount = 1;
745 r->q = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_query);
746 r->q[0].type = PJ_DNS_TYPE_A;
747 r->q[0].dnsclass = 1;
748 r->q[0].name = name;
749 r->ans = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_rr);
750 r->ans[0].type = PJ_DNS_TYPE_A;
751 r->ans[0].dnsclass = 1;
752 r->ans[0].name = name;
753 r->ans[0].rdata.a.ip_addr.s_addr = IP_ADDR0;
754
755 status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0,
756 &dns_callback, NULL, NULL);
757 if (status != PJ_SUCCESS)
758 return -1000;
759
760 pj_sem_wait(sem);
761 pj_thread_sleep(1000);
762
763
764 /* Both servers must get packet */
765 pj_assert(g_server[0].pkt_count == 1);
766 pj_assert(g_server[1].pkt_count == 1);
767
768 return 0;
769}
770
771
772////////////////////////////////////////////////////////////////////////////
773/* DNS nameserver fail-over test */
774
775static void dns_callback_1b(void *user_data,
776 pj_status_t status,
777 pj_dns_parsed_packet *resp)
778{
779 PJ_UNUSED_ARG(user_data);
780 PJ_UNUSED_ARG(resp);
781
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000782 pj_sem_post(sem);
Benny Prijono95b53402009-01-01 20:56:36 +0000783
784 PJ_ASSERT_ON_FAIL(status==PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_RCODE_NXDOMAIN),
785 return);
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000786}
787
788
789
790
791/* DNS test */
792static int dns_test(void)
793{
794 pj_str_t name = pj_str("name00");
795 pj_status_t status;
796
Benny Prijono36430ad2007-06-11 16:56:26 +0000797 PJ_LOG(3,(THIS_FILE, " simple error response test"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000798
799 g_server[0].pkt_count = 0;
800 g_server[1].pkt_count = 0;
801
802 g_server[0].action = PJ_DNS_RCODE_NXDOMAIN;
803 g_server[1].action = PJ_DNS_RCODE_NXDOMAIN;
804
805 status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0,
806 &dns_callback_1b, NULL, NULL);
807 if (status != PJ_SUCCESS)
808 return -1000;
809
810 pj_sem_wait(sem);
811 pj_thread_sleep(1000);
812
813 /* Now only server 0 should get packet, since both servers are
814 * in STATE_ACTIVE state
815 */
Benny Prijonod5233702010-01-13 13:09:45 +0000816 pj_assert((g_server[0].pkt_count == 1 && g_server[1].pkt_count == 0) ||
817 (g_server[1].pkt_count == 1 && g_server[0].pkt_count == 0));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000818
819 /* Wait to allow probing period to complete */
Benny Prijono36430ad2007-06-11 16:56:26 +0000820 PJ_LOG(3,(THIS_FILE, " waiting for active NS to expire (%d sec)",
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000821 set.good_ns_ttl));
822 pj_thread_sleep(set.good_ns_ttl * 1000);
823
824 /*
825 * Fail-over test
826 */
Benny Prijono36430ad2007-06-11 16:56:26 +0000827 PJ_LOG(3,(THIS_FILE, " failing server0"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000828 g_server[0].action = ACTION_IGNORE;
829 g_server[1].action = PJ_DNS_RCODE_NXDOMAIN;
830
831 g_server[0].pkt_count = 0;
832 g_server[1].pkt_count = 0;
833
834 name = pj_str("name01");
835 status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0,
836 &dns_callback_1b, NULL, NULL);
837 if (status != PJ_SUCCESS)
838 return -1000;
839
840 pj_sem_wait(sem);
841
842 /*
843 * Check that both servers still receive requests, since they are
844 * in probing state.
845 */
Benny Prijono36430ad2007-06-11 16:56:26 +0000846 PJ_LOG(3,(THIS_FILE, " checking both NS during probing period"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000847 g_server[0].action = ACTION_IGNORE;
848 g_server[1].action = PJ_DNS_RCODE_NXDOMAIN;
849
850 g_server[0].pkt_count = 0;
851 g_server[1].pkt_count = 0;
852
853 name = pj_str("name02");
854 status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0,
855 &dns_callback_1b, NULL, NULL);
856 if (status != PJ_SUCCESS)
857 return -1000;
858
859 pj_sem_wait(sem);
860 pj_thread_sleep(set.qretr_delay * set.qretr_count);
861
862 /* Both servers must get requests */
863 pj_assert(g_server[0].pkt_count >= 1);
864 pj_assert(g_server[1].pkt_count == 1);
865
866 /* Wait to allow probing period to complete */
Benny Prijono36430ad2007-06-11 16:56:26 +0000867 PJ_LOG(3,(THIS_FILE, " waiting for probing state to end (%d sec)",
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000868 set.qretr_delay *
869 (set.qretr_count+2) / 1000));
870 pj_thread_sleep(set.qretr_delay * (set.qretr_count + 2));
871
872
873 /*
874 * Now only server 1 should get requests.
875 */
Benny Prijono36430ad2007-06-11 16:56:26 +0000876 PJ_LOG(3,(THIS_FILE, " verifying only good NS is used"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000877 g_server[0].action = PJ_DNS_RCODE_NXDOMAIN;
878 g_server[1].action = PJ_DNS_RCODE_NXDOMAIN;
879
880 g_server[0].pkt_count = 0;
881 g_server[1].pkt_count = 0;
882
883 name = pj_str("name03");
884 status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0,
885 &dns_callback_1b, NULL, NULL);
886 if (status != PJ_SUCCESS)
887 return -1000;
888
889 pj_sem_wait(sem);
890 pj_thread_sleep(1000);
891
892 /* Both servers must get requests */
893 pj_assert(g_server[0].pkt_count == 0);
894 pj_assert(g_server[1].pkt_count == 1);
895
896 /* Wait to allow probing period to complete */
Benny Prijono36430ad2007-06-11 16:56:26 +0000897 PJ_LOG(3,(THIS_FILE, " waiting for active NS to expire (%d sec)",
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000898 set.good_ns_ttl));
899 pj_thread_sleep(set.good_ns_ttl * 1000);
900
901 /*
902 * Now fail server 1 to switch to server 0
903 */
904 g_server[0].action = PJ_DNS_RCODE_NXDOMAIN;
905 g_server[1].action = ACTION_IGNORE;
906
907 g_server[0].pkt_count = 0;
908 g_server[1].pkt_count = 0;
909
910 name = pj_str("name04");
911 status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0,
912 &dns_callback_1b, NULL, NULL);
913 if (status != PJ_SUCCESS)
914 return -1000;
915
916 pj_sem_wait(sem);
917
918 /* Wait to allow probing period to complete */
Benny Prijono36430ad2007-06-11 16:56:26 +0000919 PJ_LOG(3,(THIS_FILE, " waiting for probing state (%d sec)",
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000920 set.qretr_delay * (set.qretr_count+2) / 1000));
921 pj_thread_sleep(set.qretr_delay * (set.qretr_count + 2));
922
923 /*
924 * Now only server 0 should get requests.
925 */
Benny Prijono36430ad2007-06-11 16:56:26 +0000926 PJ_LOG(3,(THIS_FILE, " verifying good NS"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000927 g_server[0].action = PJ_DNS_RCODE_NXDOMAIN;
928 g_server[1].action = ACTION_IGNORE;
929
930 g_server[0].pkt_count = 0;
931 g_server[1].pkt_count = 0;
932
933 name = pj_str("name05");
934 status = pj_dns_resolver_start_query(resolver, &name, PJ_DNS_TYPE_A, 0,
935 &dns_callback_1b, NULL, NULL);
936 if (status != PJ_SUCCESS)
937 return -1000;
938
939 pj_sem_wait(sem);
940 pj_thread_sleep(1000);
941
Benny Prijono36430ad2007-06-11 16:56:26 +0000942 /* Only good NS should get request */
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000943 pj_assert(g_server[0].pkt_count == 1);
944 pj_assert(g_server[1].pkt_count == 0);
945
946
947 return 0;
948}
949
950
951////////////////////////////////////////////////////////////////////////////
952/* Resolver test, normal, with CNAME */
953#define IP_ADDR1 0x02030405
Benny Prijono36430ad2007-06-11 16:56:26 +0000954#define PORT1 50061
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000955
956static void action1_1(const pj_dns_parsed_packet *pkt,
957 pj_dns_parsed_packet **p_res)
958{
959 pj_dns_parsed_packet *res;
960 char *target = "sip.somedomain.com";
961
962 res = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_packet);
963
964 if (res->q == NULL) {
965 res->q = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_query);
966 }
967 if (res->ans == NULL) {
968 res->ans = (pj_dns_parsed_rr*)
969 pj_pool_calloc(pool, 4, sizeof(pj_dns_parsed_rr));
970 }
971
972 res->hdr.qdcount = 1;
973 res->q[0].type = pkt->q[0].type;
974 res->q[0].dnsclass = pkt->q[0].dnsclass;
975 res->q[0].name = pkt->q[0].name;
976
977 if (pkt->q[0].type == PJ_DNS_TYPE_SRV) {
978
979 pj_assert(pj_strcmp2(&pkt->q[0].name, "_sip._udp.somedomain.com")==0);
980
981 res->hdr.anscount = 1;
982 res->ans[0].type = PJ_DNS_TYPE_SRV;
983 res->ans[0].dnsclass = 1;
984 res->ans[0].name = res->q[0].name;
985 res->ans[0].ttl = 1;
986 res->ans[0].rdata.srv.prio = 1;
987 res->ans[0].rdata.srv.weight = 2;
Benny Prijono36430ad2007-06-11 16:56:26 +0000988 res->ans[0].rdata.srv.port = PORT1;
Benny Prijono0d7b4a82007-06-07 15:46:07 +0000989 res->ans[0].rdata.srv.target = pj_str(target);
990
991 } else if (pkt->q[0].type == PJ_DNS_TYPE_A) {
992 char *alias = "sipalias.somedomain.com";
993
994 pj_assert(pj_strcmp2(&res->q[0].name, target)==0);
995
996 res->hdr.anscount = 2;
997 res->ans[0].type = PJ_DNS_TYPE_CNAME;
998 res->ans[0].dnsclass = 1;
999 res->ans[0].ttl = 1000; /* resolver should select minimum TTL */
1000 res->ans[0].name = res->q[0].name;
1001 res->ans[0].rdata.cname.name = pj_str(alias);
1002
1003 res->ans[1].type = PJ_DNS_TYPE_A;
1004 res->ans[1].dnsclass = 1;
1005 res->ans[1].ttl = 1;
1006 res->ans[1].name = pj_str(alias);
1007 res->ans[1].rdata.a.ip_addr.s_addr = IP_ADDR1;
1008 }
1009
1010 *p_res = res;
1011}
1012
1013static void srv_cb_1(void *user_data,
1014 pj_status_t status,
1015 const pj_dns_srv_record *rec)
1016{
1017 PJ_UNUSED_ARG(user_data);
1018
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001019 pj_sem_post(sem);
Benny Prijono95b53402009-01-01 20:56:36 +00001020
1021 PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return);
1022 PJ_ASSERT_ON_FAIL(rec->count == 1, return);
1023 PJ_ASSERT_ON_FAIL(rec->entry[0].priority == 1, return);
1024 PJ_ASSERT_ON_FAIL(rec->entry[0].weight == 2, return);
1025 PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.name, "sip.somedomain.com")==0,
1026 return);
1027 PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.alias, "sipalias.somedomain.com")==0,
1028 return);
1029 PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].s_addr == IP_ADDR1, return);
1030 PJ_ASSERT_ON_FAIL(rec->entry[0].port == PORT1, return);
1031
1032
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001033}
1034
1035static void srv_cb_1b(void *user_data,
1036 pj_status_t status,
1037 const pj_dns_srv_record *rec)
1038{
1039 PJ_UNUSED_ARG(user_data);
1040
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001041 pj_sem_post(sem);
Benny Prijono95b53402009-01-01 20:56:36 +00001042
1043 PJ_ASSERT_ON_FAIL(status==PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_RCODE_NXDOMAIN),
1044 return);
1045 PJ_ASSERT_ON_FAIL(rec->count == 0, return);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001046}
1047
1048static int srv_resolver_test(void)
1049{
1050 pj_status_t status;
1051 pj_str_t domain = pj_str("somedomain.com");
1052 pj_str_t res_name = pj_str("_sip._udp.");
1053
1054 /* Successful scenario */
Benny Prijono36430ad2007-06-11 16:56:26 +00001055 PJ_LOG(3,(THIS_FILE, " srv_resolve(): success scenario"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001056
1057 g_server[0].action = ACTION_CB;
1058 g_server[0].action_cb = &action1_1;
1059 g_server[1].action = ACTION_CB;
1060 g_server[1].action_cb = &action1_1;
1061
1062 g_server[0].pkt_count = 0;
1063 g_server[1].pkt_count = 0;
1064
1065 status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, PJ_TRUE,
Benny Prijono36430ad2007-06-11 16:56:26 +00001066 NULL, &srv_cb_1, NULL);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001067 pj_assert(status == PJ_SUCCESS);
1068
1069 pj_sem_wait(sem);
1070
Benny Prijono36430ad2007-06-11 16:56:26 +00001071 /* Because of previous tests, only NS 1 should get the request */
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001072 pj_assert(g_server[0].pkt_count == 2); /* 2 because of SRV and A resolution */
1073 pj_assert(g_server[1].pkt_count == 0);
1074
1075
1076 /* Wait until cache expires and nameserver state moves out from STATE_PROBING */
Benny Prijono36430ad2007-06-11 16:56:26 +00001077 PJ_LOG(3,(THIS_FILE, " waiting for cache to expire (~15 secs).."));
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001078 pj_thread_sleep(1000 +
1079 ((set.qretr_count + 2) * set.qretr_delay));
1080
1081 /* Successful scenario */
Benny Prijono36430ad2007-06-11 16:56:26 +00001082 PJ_LOG(3,(THIS_FILE, " srv_resolve(): parallel queries"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001083 g_server[0].pkt_count = 0;
1084 g_server[1].pkt_count = 0;
1085
1086 status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, PJ_TRUE,
Benny Prijono36430ad2007-06-11 16:56:26 +00001087 NULL, &srv_cb_1, NULL);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001088 pj_assert(status == PJ_SUCCESS);
1089
1090
1091 status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, PJ_TRUE,
Benny Prijono36430ad2007-06-11 16:56:26 +00001092 NULL, &srv_cb_1, NULL);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001093 pj_assert(status == PJ_SUCCESS);
1094
1095 pj_sem_wait(sem);
1096 pj_sem_wait(sem);
1097
1098 /* Only server one should get a query */
1099 pj_assert(g_server[0].pkt_count == 2); /* 2 because of SRV and A resolution */
1100 pj_assert(g_server[1].pkt_count == 0);
1101
1102 /* Since TTL is one, subsequent queries should fail */
Benny Prijono36430ad2007-06-11 16:56:26 +00001103 PJ_LOG(3,(THIS_FILE, " srv_resolve(): cache expires scenario"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001104
1105
1106 pj_thread_sleep(1000);
1107
1108 g_server[0].action = PJ_DNS_RCODE_NXDOMAIN;
1109 g_server[1].action = PJ_DNS_RCODE_NXDOMAIN;
1110
1111 status = pj_dns_srv_resolve(&domain, &res_name, 5061, pool, resolver, PJ_TRUE,
Benny Prijono36430ad2007-06-11 16:56:26 +00001112 NULL, &srv_cb_1b, NULL);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001113 pj_assert(status == PJ_SUCCESS);
1114
1115 pj_sem_wait(sem);
1116
1117 return 0;
1118}
1119
1120
1121////////////////////////////////////////////////////////////////////////////
1122/* Fallback because there's no SRV in answer */
1123#define TARGET "domain2.com"
1124#define IP_ADDR2 0x02030405
Benny Prijono36430ad2007-06-11 16:56:26 +00001125#define PORT2 50062
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001126
1127static void action2_1(const pj_dns_parsed_packet *pkt,
1128 pj_dns_parsed_packet **p_res)
1129{
Benny Prijono36430ad2007-06-11 16:56:26 +00001130 pj_dns_parsed_packet *res;
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001131
Benny Prijono36430ad2007-06-11 16:56:26 +00001132 res = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_packet);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001133
Benny Prijono36430ad2007-06-11 16:56:26 +00001134 res->q = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_query);
1135 res->ans = (pj_dns_parsed_rr*)
1136 pj_pool_calloc(pool, 4, sizeof(pj_dns_parsed_rr));
1137
1138 res->hdr.qdcount = 1;
1139 res->q[0].type = pkt->q[0].type;
1140 res->q[0].dnsclass = pkt->q[0].dnsclass;
1141 res->q[0].name = pkt->q[0].name;
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001142
1143 if (pkt->q[0].type == PJ_DNS_TYPE_SRV) {
1144
1145 pj_assert(pj_strcmp2(&pkt->q[0].name, "_sip._udp." TARGET)==0);
1146
Benny Prijono36430ad2007-06-11 16:56:26 +00001147 res->hdr.anscount = 1;
1148 res->ans[0].type = PJ_DNS_TYPE_A; // <-- this will cause the fallback
1149 res->ans[0].dnsclass = 1;
1150 res->ans[0].name = res->q[0].name;
1151 res->ans[0].ttl = 1;
1152 res->ans[0].rdata.srv.prio = 1;
1153 res->ans[0].rdata.srv.weight = 2;
1154 res->ans[0].rdata.srv.port = PORT2;
1155 res->ans[0].rdata.srv.target = pj_str("sip01." TARGET);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001156
1157 } else if (pkt->q[0].type == PJ_DNS_TYPE_A) {
Benny Prijono36430ad2007-06-11 16:56:26 +00001158 char *alias = "sipalias01." TARGET;
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001159
Benny Prijono36430ad2007-06-11 16:56:26 +00001160 pj_assert(pj_strcmp2(&res->q[0].name, TARGET)==0);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001161
Benny Prijono36430ad2007-06-11 16:56:26 +00001162 res->hdr.anscount = 2;
1163 res->ans[0].type = PJ_DNS_TYPE_CNAME;
1164 res->ans[0].dnsclass = 1;
1165 res->ans[0].name = res->q[0].name;
1166 res->ans[0].ttl = 1;
1167 res->ans[0].rdata.cname.name = pj_str(alias);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001168
Benny Prijono36430ad2007-06-11 16:56:26 +00001169 res->ans[1].type = PJ_DNS_TYPE_A;
1170 res->ans[1].dnsclass = 1;
1171 res->ans[1].name = pj_str(alias);
1172 res->ans[1].ttl = 1;
1173 res->ans[1].rdata.a.ip_addr.s_addr = IP_ADDR2;
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001174 }
1175
Benny Prijono36430ad2007-06-11 16:56:26 +00001176 *p_res = res;
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001177}
1178
1179static void srv_cb_2(void *user_data,
1180 pj_status_t status,
1181 const pj_dns_srv_record *rec)
1182{
1183 PJ_UNUSED_ARG(user_data);
1184
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001185 pj_sem_post(sem);
Benny Prijono95b53402009-01-01 20:56:36 +00001186
1187 PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return);
1188 PJ_ASSERT_ON_FAIL(rec->count == 1, return);
1189 PJ_ASSERT_ON_FAIL(rec->entry[0].priority == 0, return);
1190 PJ_ASSERT_ON_FAIL(rec->entry[0].weight == 0, return);
1191 PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.name, TARGET)==0,
1192 return);
1193 PJ_ASSERT_ON_FAIL(pj_strcmp2(&rec->entry[0].server.alias, "sipalias01." TARGET)==0,
1194 return);
1195 PJ_ASSERT_ON_FAIL(rec->entry[0].server.addr[0].s_addr == IP_ADDR2, return);
1196 PJ_ASSERT_ON_FAIL(rec->entry[0].port == PORT2, return);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001197}
1198
1199static int srv_resolver_fallback_test(void)
1200{
1201 pj_status_t status;
1202 pj_str_t domain = pj_str(TARGET);
1203 pj_str_t res_name = pj_str("_sip._udp.");
1204
Benny Prijono36430ad2007-06-11 16:56:26 +00001205 PJ_LOG(3,(THIS_FILE, " srv_resolve(): fallback test"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001206
1207 g_server[0].action = ACTION_CB;
1208 g_server[0].action_cb = &action2_1;
1209 g_server[1].action = ACTION_CB;
1210 g_server[1].action_cb = &action2_1;
1211
Benny Prijono36430ad2007-06-11 16:56:26 +00001212 status = pj_dns_srv_resolve(&domain, &res_name, PORT2, pool, resolver, PJ_TRUE,
1213 NULL, &srv_cb_2, NULL);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001214 if (status != PJ_SUCCESS) {
Benny Prijono36430ad2007-06-11 16:56:26 +00001215 app_perror(" srv_resolve error", status);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001216 pj_assert(status == PJ_SUCCESS);
1217 }
1218
1219 pj_sem_wait(sem);
1220
1221 /* Subsequent query should just get the response from the cache */
Benny Prijono36430ad2007-06-11 16:56:26 +00001222 PJ_LOG(3,(THIS_FILE, " srv_resolve(): cache test"));
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001223 g_server[0].pkt_count = 0;
1224 g_server[1].pkt_count = 0;
1225
Benny Prijono36430ad2007-06-11 16:56:26 +00001226 status = pj_dns_srv_resolve(&domain, &res_name, PORT2, pool, resolver, PJ_TRUE,
1227 NULL, &srv_cb_2, NULL);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001228 if (status != PJ_SUCCESS) {
Benny Prijono36430ad2007-06-11 16:56:26 +00001229 app_perror(" srv_resolve error", status);
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001230 pj_assert(status == PJ_SUCCESS);
1231 }
1232
1233 pj_sem_wait(sem);
1234
1235 pj_assert(g_server[0].pkt_count == 0);
1236 pj_assert(g_server[1].pkt_count == 0);
1237
1238 return 0;
1239}
1240
1241
1242////////////////////////////////////////////////////////////////////////////
Benny Prijono36430ad2007-06-11 16:56:26 +00001243/* Too many SRV or A entries */
1244#define DOMAIN3 "d3"
1245#define SRV_COUNT3 (PJ_DNS_SRV_MAX_ADDR+1)
1246#define A_COUNT3 (PJ_DNS_MAX_IP_IN_A_REC+1)
1247#define PORT3 50063
1248#define IP_ADDR3 0x03030303
1249
1250static void action3_1(const pj_dns_parsed_packet *pkt,
1251 pj_dns_parsed_packet **p_res)
1252{
1253 pj_dns_parsed_packet *res;
1254 unsigned i;
1255
1256 res = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_packet);
1257
1258 if (res->q == NULL) {
1259 res->q = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_query);
1260 }
1261
1262 res->hdr.qdcount = 1;
1263 res->q[0].type = pkt->q[0].type;
1264 res->q[0].dnsclass = pkt->q[0].dnsclass;
1265 res->q[0].name = pkt->q[0].name;
1266
1267 if (pkt->q[0].type == PJ_DNS_TYPE_SRV) {
1268
1269 pj_assert(pj_strcmp2(&pkt->q[0].name, "_sip._udp." DOMAIN3)==0);
1270
1271 res->hdr.anscount = SRV_COUNT3;
1272 res->ans = (pj_dns_parsed_rr*)
1273 pj_pool_calloc(pool, SRV_COUNT3, sizeof(pj_dns_parsed_rr));
1274
1275 for (i=0; i<SRV_COUNT3; ++i) {
1276 char *target;
1277
1278 res->ans[i].type = PJ_DNS_TYPE_SRV;
1279 res->ans[i].dnsclass = 1;
1280 res->ans[i].name = res->q[0].name;
1281 res->ans[i].ttl = 1;
1282 res->ans[i].rdata.srv.prio = (pj_uint16_t)i;
1283 res->ans[i].rdata.srv.weight = 2;
1284 res->ans[i].rdata.srv.port = (pj_uint16_t)(PORT3+i);
1285
1286 target = (char*)pj_pool_alloc(pool, 16);
1287 sprintf(target, "sip%02d." DOMAIN3, i);
1288 res->ans[i].rdata.srv.target = pj_str(target);
1289 }
1290
1291 } else if (pkt->q[0].type == PJ_DNS_TYPE_A) {
1292
1293 //pj_assert(pj_strcmp2(&res->q[0].name, "sip." DOMAIN3)==0);
1294
1295 res->hdr.anscount = A_COUNT3;
1296 res->ans = (pj_dns_parsed_rr*)
1297 pj_pool_calloc(pool, A_COUNT3, sizeof(pj_dns_parsed_rr));
1298
1299 for (i=0; i<A_COUNT3; ++i) {
1300 res->ans[i].type = PJ_DNS_TYPE_A;
1301 res->ans[i].dnsclass = 1;
1302 res->ans[i].ttl = 1;
1303 res->ans[i].name = res->q[0].name;
1304 res->ans[i].rdata.a.ip_addr.s_addr = IP_ADDR3+i;
1305 }
1306 }
1307
1308 *p_res = res;
1309}
1310
1311static void srv_cb_3(void *user_data,
1312 pj_status_t status,
1313 const pj_dns_srv_record *rec)
1314{
1315 unsigned i;
1316
1317 PJ_UNUSED_ARG(user_data);
Benny Prijono95b53402009-01-01 20:56:36 +00001318 PJ_UNUSED_ARG(status);
1319 PJ_UNUSED_ARG(rec);
Benny Prijono36430ad2007-06-11 16:56:26 +00001320
1321 pj_assert(status == PJ_SUCCESS);
1322 pj_assert(rec->count == PJ_DNS_SRV_MAX_ADDR);
Benny Prijono95b53402009-01-01 20:56:36 +00001323
Benny Prijono36430ad2007-06-11 16:56:26 +00001324 for (i=0; i<PJ_DNS_SRV_MAX_ADDR; ++i) {
1325 unsigned j;
1326
1327 pj_assert(rec->entry[i].priority == i);
1328 pj_assert(rec->entry[i].weight == 2);
1329 //pj_assert(pj_strcmp2(&rec->entry[i].server.name, "sip." DOMAIN3)==0);
1330 pj_assert(rec->entry[i].server.alias.slen == 0);
1331 pj_assert(rec->entry[i].port == PORT3+i);
1332
1333 pj_assert(rec->entry[i].server.addr_count == PJ_DNS_MAX_IP_IN_A_REC);
1334
1335 for (j=0; j<PJ_DNS_MAX_IP_IN_A_REC; ++j) {
1336 pj_assert(rec->entry[i].server.addr[j].s_addr == IP_ADDR3+j);
1337 }
1338 }
1339
1340 pj_sem_post(sem);
1341}
1342
1343static int srv_resolver_many_test(void)
1344{
1345 pj_status_t status;
1346 pj_str_t domain = pj_str(DOMAIN3);
1347 pj_str_t res_name = pj_str("_sip._udp.");
1348
1349 /* Successful scenario */
1350 PJ_LOG(3,(THIS_FILE, " srv_resolve(): too many entries test"));
1351
1352 g_server[0].action = ACTION_CB;
1353 g_server[0].action_cb = &action3_1;
1354 g_server[1].action = ACTION_CB;
1355 g_server[1].action_cb = &action3_1;
1356
1357 g_server[0].pkt_count = 0;
1358 g_server[1].pkt_count = 0;
1359
1360 status = pj_dns_srv_resolve(&domain, &res_name, 1, pool, resolver, PJ_TRUE,
1361 NULL, &srv_cb_3, NULL);
1362 pj_assert(status == PJ_SUCCESS);
1363
1364 pj_sem_wait(sem);
1365
1366 return 0;
1367}
1368
1369
1370////////////////////////////////////////////////////////////////////////////
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001371
1372
1373int resolver_test(void)
1374{
1375 int rc;
1376
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001377 rc = init();
Nanang Izzuddin9522ff22008-12-19 15:08:44 +00001378 if (rc != 0)
1379 goto on_error;
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001380
Benny Prijono36430ad2007-06-11 16:56:26 +00001381 rc = a_parser_test();
1382 if (rc != 0)
1383 goto on_error;
1384
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001385 rc = simple_test();
1386 if (rc != 0)
1387 goto on_error;
1388
1389 rc = dns_test();
1390 if (rc != 0)
1391 goto on_error;
1392
1393 srv_resolver_test();
1394 srv_resolver_fallback_test();
Benny Prijono36430ad2007-06-11 16:56:26 +00001395 srv_resolver_many_test();
Benny Prijono0d7b4a82007-06-07 15:46:07 +00001396
1397 destroy();
1398 return 0;
1399
1400on_error:
1401 destroy();
1402 return rc;
1403}
1404
1405