blob: 3d78159a85c307d01532843de58be48b6681b209 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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/dns.h>
21#include <pjlib-util/errno.h>
22#include <pj/assert.h>
23#include <pj/errno.h>
24#include <pj/pool.h>
25#include <pj/sock.h>
26#include <pj/string.h>
27
28
29PJ_DEF(const char *) pj_dns_get_type_name(int type)
30{
31 switch (type) {
32 case PJ_DNS_TYPE_A: return "A";
33 case PJ_DNS_TYPE_AAAA: return "AAAA";
34 case PJ_DNS_TYPE_SRV: return "SRV";
35 case PJ_DNS_TYPE_NS: return "NS";
36 case PJ_DNS_TYPE_CNAME: return "CNAME";
37 case PJ_DNS_TYPE_PTR: return "PTR";
38 case PJ_DNS_TYPE_MX: return "MX";
39 case PJ_DNS_TYPE_TXT: return "TXT";
40 case PJ_DNS_TYPE_NAPTR: return "NAPTR";
41 }
42 return "(Unknown)";
43}
44
45
46static void write16(pj_uint8_t *p, pj_uint16_t val)
47{
48 p[0] = (pj_uint8_t)(val >> 8);
49 p[1] = (pj_uint8_t)(val & 0xFF);
50}
51
52
53/**
54 * Initialize a DNS query transaction.
55 */
56PJ_DEF(pj_status_t) pj_dns_make_query( void *packet,
57 unsigned *size,
58 pj_uint16_t id,
59 int qtype,
60 const pj_str_t *name)
61{
62 pj_uint8_t *query, *p = (pj_uint8_t*)packet;
63 const char *startlabel, *endlabel, *endname;
64 pj_size_t d;
65
66 /* Sanity check */
67 PJ_ASSERT_RETURN(packet && size && qtype && name, PJ_EINVAL);
68
69 /* Calculate total number of bytes required. */
70 d = sizeof(pj_dns_hdr) + name->slen + 4;
71
72 /* Check that size is sufficient. */
73 PJ_ASSERT_RETURN(*size >= d, PJLIB_UTIL_EDNSQRYTOOSMALL);
74
75 /* Initialize header */
76 pj_assert(sizeof(pj_dns_hdr)==12);
77 pj_bzero(p, sizeof(struct pj_dns_hdr));
78 write16(p+0, id);
79 write16(p+2, (pj_uint16_t)PJ_DNS_SET_RD(1));
80 write16(p+4, (pj_uint16_t)1);
81
82 /* Initialize query */
83 query = p = ((pj_uint8_t*)packet)+sizeof(pj_dns_hdr);
84
85 /* Tokenize name */
86 startlabel = endlabel = name->ptr;
87 endname = name->ptr + name->slen;
88 while (endlabel != endname) {
89 while (endlabel != endname && *endlabel != '.')
90 ++endlabel;
91 *p++ = (pj_uint8_t)(endlabel - startlabel);
92 pj_memcpy(p, startlabel, endlabel-startlabel);
93 p += (endlabel-startlabel);
94 if (endlabel != endname && *endlabel == '.')
95 ++endlabel;
96 startlabel = endlabel;
97 }
98 *p++ = '\0';
99
100 /* Set type */
101 write16(p, (pj_uint16_t)qtype);
102 p += 2;
103
104 /* Set class (IN=1) */
105 write16(p, 1);
106 p += 2;
107
108 /* Done, calculate length */
109 *size = (unsigned)(p - (pj_uint8_t*)packet);
110
111 return 0;
112}
113
114
115/* Get a name length (note: name consists of multiple labels and
116 * it may contain pointers when name compression is applied)
117 */
118static pj_status_t get_name_len(int rec_counter, const pj_uint8_t *pkt,
119 const pj_uint8_t *start, const pj_uint8_t *max,
120 int *parsed_len, int *name_len)
121{
122 const pj_uint8_t *p;
123 pj_status_t status;
124
125 /* Limit the number of recursion */
126 if (rec_counter > 10) {
127 /* Too many name recursion */
128 return PJLIB_UTIL_EDNSINNAMEPTR;
129 }
130
131 *name_len = *parsed_len = 0;
132 p = start;
133 while (*p) {
134 if ((*p & 0xc0) == 0xc0) {
135 /* Compression is found! */
136 int ptr_len = 0;
137 int dummy;
138 pj_uint16_t offset;
139
140 /* Get the 14bit offset */
141 pj_memcpy(&offset, p, 2);
142 offset ^= pj_htons((pj_uint16_t)(0xc0 << 8));
143 offset = pj_ntohs(offset);
144
145 /* Check that offset is valid */
146 if (offset >= max - pkt)
147 return PJLIB_UTIL_EDNSINNAMEPTR;
148
149 /* Get the name length from that offset. */
150 status = get_name_len(rec_counter+1, pkt, pkt + offset, max,
151 &dummy, &ptr_len);
152 if (status != PJ_SUCCESS)
153 return status;
154
155 *parsed_len += 2;
156 *name_len += ptr_len;
157
158 return PJ_SUCCESS;
159 } else {
160 unsigned label_len = *p;
161
162 /* Check that label length is valid */
163 if (pkt+label_len > max)
164 return PJLIB_UTIL_EDNSINNAMEPTR;
165
166 p += (label_len + 1);
167 *parsed_len += (label_len + 1);
168
169 if (*p != 0)
170 ++label_len;
171
172 *name_len += label_len;
173
174 if (p >= max)
175 return PJLIB_UTIL_EDNSINSIZE;
176 }
177 }
178 ++p;
179 (*parsed_len)++;
180
181 return PJ_SUCCESS;
182}
183
184
185/* Parse and copy name (note: name consists of multiple labels and
186 * it may contain pointers when compression is applied).
187 */
188static pj_status_t get_name(int rec_counter, const pj_uint8_t *pkt,
189 const pj_uint8_t *start, const pj_uint8_t *max,
190 pj_str_t *name)
191{
192 const pj_uint8_t *p;
193 pj_status_t status;
194
195 /* Limit the number of recursion */
196 if (rec_counter > 10) {
197 /* Too many name recursion */
198 return PJLIB_UTIL_EDNSINNAMEPTR;
199 }
200
201 p = start;
202 while (*p) {
203 if ((*p & 0xc0) == 0xc0) {
204 /* Compression is found! */
205 pj_uint16_t offset;
206
207 /* Get the 14bit offset */
208 pj_memcpy(&offset, p, 2);
209 offset ^= pj_htons((pj_uint16_t)(0xc0 << 8));
210 offset = pj_ntohs(offset);
211
212 /* Check that offset is valid */
213 if (offset >= max - pkt)
214 return PJLIB_UTIL_EDNSINNAMEPTR;
215
216 /* Retrieve the name from that offset. */
217 status = get_name(rec_counter+1, pkt, pkt + offset, max, name);
218 if (status != PJ_SUCCESS)
219 return status;
220
221 return PJ_SUCCESS;
222 } else {
223 unsigned label_len = *p;
224
225 /* Check that label length is valid */
226 if (pkt+label_len > max)
227 return PJLIB_UTIL_EDNSINNAMEPTR;
228
229 pj_memcpy(name->ptr + name->slen, p+1, label_len);
230 name->slen += label_len;
231
232 p += label_len + 1;
233 if (*p != 0) {
234 *(name->ptr + name->slen) = '.';
235 ++name->slen;
236 }
237
238 if (p >= max)
239 return PJLIB_UTIL_EDNSINSIZE;
240 }
241 }
242
243 return PJ_SUCCESS;
244}
245
246
247/* Parse query records. */
248static pj_status_t parse_query(pj_dns_parsed_query *q, pj_pool_t *pool,
249 const pj_uint8_t *pkt, const pj_uint8_t *start,
250 const pj_uint8_t *max, int *parsed_len)
251{
252 const pj_uint8_t *p = start;
253 int name_len, name_part_len;
254 pj_status_t status;
255
256 /* Get the length of the name */
257 status = get_name_len(0, pkt, start, max, &name_part_len, &name_len);
258 if (status != PJ_SUCCESS)
259 return status;
260
261 /* Allocate memory for the name */
262 q->name.ptr = (char*) pj_pool_alloc(pool, name_len+4);
263 q->name.slen = 0;
264
265 /* Get the name */
266 status = get_name(0, pkt, start, max, &q->name);
267 if (status != PJ_SUCCESS)
268 return status;
269
270 p = (start + name_part_len);
271
272 /* Get the type */
273 pj_memcpy(&q->type, p, 2);
274 q->type = pj_ntohs(q->type);
275 p += 2;
276
277 /* Get the class */
278 pj_memcpy(&q->dnsclass, p, 2);
279 q->dnsclass = pj_ntohs(q->dnsclass);
280 p += 2;
281
282 *parsed_len = (int)(p - start);
283
284 return PJ_SUCCESS;
285}
286
287
288/* Parse RR records */
289static pj_status_t parse_rr(pj_dns_parsed_rr *rr, pj_pool_t *pool,
290 const pj_uint8_t *pkt,
291 const pj_uint8_t *start, const pj_uint8_t *max,
292 int *parsed_len)
293{
294 const pj_uint8_t *p = start;
295 int name_len, name_part_len;
296 pj_status_t status;
297
298 /* Get the length of the name */
299 status = get_name_len(0, pkt, start, max, &name_part_len, &name_len);
300 if (status != PJ_SUCCESS)
301 return status;
302
303 /* Allocate memory for the name */
304 rr->name.ptr = (char*) pj_pool_alloc(pool, name_len+4);
305 rr->name.slen = 0;
306
307 /* Get the name */
308 status = get_name(0, pkt, start, max, &rr->name);
309 if (status != PJ_SUCCESS)
310 return status;
311
312 p = (start + name_part_len);
313
314 /* Check the size can accomodate next few fields. */
315 if (p+10 > max)
316 return PJLIB_UTIL_EDNSINSIZE;
317
318 /* Get the type */
319 pj_memcpy(&rr->type, p, 2);
320 rr->type = pj_ntohs(rr->type);
321 p += 2;
322
323 /* Get the class */
324 pj_memcpy(&rr->dnsclass, p, 2);
325 rr->dnsclass = pj_ntohs(rr->dnsclass);
326 p += 2;
327
328 /* Class MUST be IN */
329 if (rr->dnsclass != 1)
330 return PJLIB_UTIL_EDNSINCLASS;
331
332 /* Get TTL */
333 pj_memcpy(&rr->ttl, p, 4);
334 rr->ttl = pj_ntohl(rr->ttl);
335 p += 4;
336
337 /* Get rdlength */
338 pj_memcpy(&rr->rdlength, p, 2);
339 rr->rdlength = pj_ntohs(rr->rdlength);
340 p += 2;
341
342 /* Check that length is valid */
343 if (p + rr->rdlength > max)
344 return PJLIB_UTIL_EDNSINSIZE;
345
346 /* Parse some well known records */
347 if (rr->type == PJ_DNS_TYPE_A) {
348 pj_memcpy(&rr->rdata.a.ip_addr, p, 4);
349 p += 4;
350
351 } else if (rr->type == PJ_DNS_TYPE_AAAA) {
352 pj_memcpy(&rr->rdata.aaaa.ip_addr, p, 16);
353 p += 16;
354
355 } else if (rr->type == PJ_DNS_TYPE_CNAME ||
356 rr->type == PJ_DNS_TYPE_NS ||
357 rr->type == PJ_DNS_TYPE_PTR)
358 {
359
360 /* Get the length of the target name */
361 status = get_name_len(0, pkt, p, max, &name_part_len, &name_len);
362 if (status != PJ_SUCCESS)
363 return status;
364
365 /* Allocate memory for the name */
366 rr->rdata.cname.name.ptr = (char*) pj_pool_alloc(pool, name_len);
367 rr->rdata.cname.name.slen = 0;
368
369 /* Get the name */
370 status = get_name(0, pkt, p, max, &rr->rdata.cname.name);
371 if (status != PJ_SUCCESS)
372 return status;
373
374 p += name_part_len;
375
376 } else if (rr->type == PJ_DNS_TYPE_SRV) {
377
378 /* Priority */
379 pj_memcpy(&rr->rdata.srv.prio, p, 2);
380 rr->rdata.srv.prio = pj_ntohs(rr->rdata.srv.prio);
381 p += 2;
382
383 /* Weight */
384 pj_memcpy(&rr->rdata.srv.weight, p, 2);
385 rr->rdata.srv.weight = pj_ntohs(rr->rdata.srv.weight);
386 p += 2;
387
388 /* Port */
389 pj_memcpy(&rr->rdata.srv.port, p, 2);
390 rr->rdata.srv.port = pj_ntohs(rr->rdata.srv.port);
391 p += 2;
392
393 /* Get the length of the target name */
394 status = get_name_len(0, pkt, p, max, &name_part_len, &name_len);
395 if (status != PJ_SUCCESS)
396 return status;
397
398 /* Allocate memory for the name */
399 rr->rdata.srv.target.ptr = (char*) pj_pool_alloc(pool, name_len);
400 rr->rdata.srv.target.slen = 0;
401
402 /* Get the name */
403 status = get_name(0, pkt, p, max, &rr->rdata.srv.target);
404 if (status != PJ_SUCCESS)
405 return status;
406 p += name_part_len;
407
408 } else {
409 /* Copy the raw data */
410 rr->data = pj_pool_alloc(pool, rr->rdlength);
411 pj_memcpy(rr->data, p, rr->rdlength);
412
413 p += rr->rdlength;
414 }
415
416 *parsed_len = (int)(p - start);
417 return PJ_SUCCESS;
418}
419
420
421/*
422 * Parse raw DNS packet into DNS packet structure.
423 */
424PJ_DEF(pj_status_t) pj_dns_parse_packet( pj_pool_t *pool,
425 const void *packet,
426 unsigned size,
427 pj_dns_parsed_packet **p_res)
428{
429 pj_dns_parsed_packet *res;
430 const pj_uint8_t *start, *end;
431 pj_status_t status;
432 unsigned i;
433
434 /* Sanity checks */
435 PJ_ASSERT_RETURN(pool && packet && size && p_res, PJ_EINVAL);
436
437 /* Packet size must be at least as big as the header */
438 if (size < sizeof(pj_dns_hdr))
439 return PJLIB_UTIL_EDNSINSIZE;
440
441 /* Create the structure */
442 res = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_packet);
443
444 /* Copy the DNS header, and convert endianness to host byte order */
445 pj_memcpy(&res->hdr, packet, sizeof(pj_dns_hdr));
446 res->hdr.id = pj_ntohs(res->hdr.id);
447 res->hdr.flags = pj_ntohs(res->hdr.flags);
448 res->hdr.qdcount = pj_ntohs(res->hdr.qdcount);
449 res->hdr.anscount = pj_ntohs(res->hdr.anscount);
450 res->hdr.nscount = pj_ntohs(res->hdr.nscount);
451 res->hdr.arcount = pj_ntohs(res->hdr.arcount);
452
453 /* Mark start and end of payload */
454 start = ((const pj_uint8_t*)packet) + sizeof(pj_dns_hdr);
455 end = ((const pj_uint8_t*)packet) + size;
456
457 /* Parse query records (if any).
458 */
459 if (res->hdr.qdcount) {
460 res->q = (pj_dns_parsed_query*)
461 pj_pool_zalloc(pool, res->hdr.qdcount *
462 sizeof(pj_dns_parsed_query));
463 for (i=0; i<res->hdr.qdcount; ++i) {
464 int parsed_len = 0;
465
466 status = parse_query(&res->q[i], pool, (const pj_uint8_t*)packet,
467 start, end, &parsed_len);
468 if (status != PJ_SUCCESS)
469 return status;
470
471 start += parsed_len;
472 }
473 }
474
475 /* Parse answer, if any */
476 if (res->hdr.anscount) {
477 res->ans = (pj_dns_parsed_rr*)
478 pj_pool_zalloc(pool, res->hdr.anscount *
479 sizeof(pj_dns_parsed_rr));
480
481 for (i=0; i<res->hdr.anscount; ++i) {
482 int parsed_len;
483
484 status = parse_rr(&res->ans[i], pool, (const pj_uint8_t*)packet,
485 start, end, &parsed_len);
486 if (status != PJ_SUCCESS)
487 return status;
488
489 start += parsed_len;
490 }
491 }
492
493 /* Parse authoritative NS records, if any */
494 if (res->hdr.nscount) {
495 res->ns = (pj_dns_parsed_rr*)
496 pj_pool_zalloc(pool, res->hdr.nscount *
497 sizeof(pj_dns_parsed_rr));
498
499 for (i=0; i<res->hdr.nscount; ++i) {
500 int parsed_len;
501
502 status = parse_rr(&res->ns[i], pool, (const pj_uint8_t*)packet,
503 start, end, &parsed_len);
504 if (status != PJ_SUCCESS)
505 return status;
506
507 start += parsed_len;
508 }
509 }
510
511 /* Parse additional RR answer, if any */
512 if (res->hdr.arcount) {
513 res->arr = (pj_dns_parsed_rr*)
514 pj_pool_zalloc(pool, res->hdr.arcount *
515 sizeof(pj_dns_parsed_rr));
516
517 for (i=0; i<res->hdr.arcount; ++i) {
518 int parsed_len;
519
520 status = parse_rr(&res->arr[i], pool, (const pj_uint8_t*)packet,
521 start, end, &parsed_len);
522 if (status != PJ_SUCCESS)
523 return status;
524
525 start += parsed_len;
526 }
527 }
528
529 /* Looks like everything is okay */
530 *p_res = res;
531
532 return PJ_SUCCESS;
533}
534
535
536/* Perform name compression scheme.
537 * If a name is already in the nametable, when no need to duplicate
538 * the string with the pool, but rather just use the pointer there.
539 */
540static void apply_name_table( unsigned *count,
541 pj_str_t nametable[],
542 const pj_str_t *src,
543 pj_pool_t *pool,
544 pj_str_t *dst)
545{
546 unsigned i;
547
548 /* Scan strings in nametable */
549 for (i=0; i<*count; ++i) {
550 if (pj_stricmp(&nametable[i], src) == 0)
551 break;
552 }
553
554 /* If name is found in nametable, use the pointer in the nametable */
555 if (i != *count) {
556 dst->ptr = nametable[i].ptr;
557 dst->slen = nametable[i].slen;
558 return;
559 }
560
561 /* Otherwise duplicate the string, and insert new name in nametable */
562 pj_strdup(pool, dst, src);
563
564 if (*count < PJ_DNS_MAX_NAMES_IN_NAMETABLE) {
565 nametable[*count].ptr = dst->ptr;
566 nametable[*count].slen = dst->slen;
567
568 ++(*count);
569 }
570}
571
572static void copy_query(pj_pool_t *pool, pj_dns_parsed_query *dst,
573 const pj_dns_parsed_query *src,
574 unsigned *nametable_count,
575 pj_str_t nametable[])
576{
577 pj_memcpy(dst, src, sizeof(*src));
578 apply_name_table(nametable_count, nametable, &src->name, pool, &dst->name);
579}
580
581
582static void copy_rr(pj_pool_t *pool, pj_dns_parsed_rr *dst,
583 const pj_dns_parsed_rr *src,
584 unsigned *nametable_count,
585 pj_str_t nametable[])
586{
587 pj_memcpy(dst, src, sizeof(*src));
588 apply_name_table(nametable_count, nametable, &src->name, pool, &dst->name);
589
590 if (src->data) {
591 dst->data = pj_pool_alloc(pool, src->rdlength);
592 pj_memcpy(dst->data, src->data, src->rdlength);
593 }
594
595 if (src->type == PJ_DNS_TYPE_SRV) {
596 apply_name_table(nametable_count, nametable, &src->rdata.srv.target,
597 pool, &dst->rdata.srv.target);
598 } else if (src->type == PJ_DNS_TYPE_A) {
599 dst->rdata.a.ip_addr.s_addr = src->rdata.a.ip_addr.s_addr;
600 } else if (src->type == PJ_DNS_TYPE_AAAA) {
601 pj_memcpy(&dst->rdata.aaaa.ip_addr, &src->rdata.aaaa.ip_addr,
602 sizeof(pj_in6_addr));
603 } else if (src->type == PJ_DNS_TYPE_CNAME) {
604 pj_strdup(pool, &dst->rdata.cname.name, &src->rdata.cname.name);
605 } else if (src->type == PJ_DNS_TYPE_NS) {
606 pj_strdup(pool, &dst->rdata.ns.name, &src->rdata.ns.name);
607 } else if (src->type == PJ_DNS_TYPE_PTR) {
608 pj_strdup(pool, &dst->rdata.ptr.name, &src->rdata.ptr.name);
609 }
610}
611
612/*
613 * Duplicate DNS packet.
614 */
615PJ_DEF(void) pj_dns_packet_dup(pj_pool_t *pool,
616 const pj_dns_parsed_packet*p,
617 unsigned options,
618 pj_dns_parsed_packet **p_dst)
619{
620 pj_dns_parsed_packet *dst;
621 unsigned nametable_count = 0;
622#if PJ_DNS_MAX_NAMES_IN_NAMETABLE
623 pj_str_t nametable[PJ_DNS_MAX_NAMES_IN_NAMETABLE];
624#else
625 pj_str_t *nametable = NULL;
626#endif
627 unsigned i;
628
629 PJ_ASSERT_ON_FAIL(pool && p && p_dst, return);
630
631 /* Create packet and copy header */
632 *p_dst = dst = PJ_POOL_ZALLOC_T(pool, pj_dns_parsed_packet);
633 pj_memcpy(&dst->hdr, &p->hdr, sizeof(p->hdr));
634
635 /* Initialize section counts in the target packet to zero.
636 * If memory allocation fails during copying process, the target packet
637 * should have a correct section counts.
638 */
639 dst->hdr.qdcount = 0;
640 dst->hdr.anscount = 0;
641 dst->hdr.nscount = 0;
642 dst->hdr.arcount = 0;
643
644
645 /* Copy query section */
646 if (p->hdr.qdcount && (options & PJ_DNS_NO_QD)==0) {
647 dst->q = (pj_dns_parsed_query*)
648 pj_pool_alloc(pool, p->hdr.qdcount *
649 sizeof(pj_dns_parsed_query));
650 for (i=0; i<p->hdr.qdcount; ++i) {
651 copy_query(pool, &dst->q[i], &p->q[i],
652 &nametable_count, nametable);
653 ++dst->hdr.qdcount;
654 }
655 }
656
657 /* Copy answer section */
658 if (p->hdr.anscount && (options & PJ_DNS_NO_ANS)==0) {
659 dst->ans = (pj_dns_parsed_rr*)
660 pj_pool_alloc(pool, p->hdr.anscount *
661 sizeof(pj_dns_parsed_rr));
662 for (i=0; i<p->hdr.anscount; ++i) {
663 copy_rr(pool, &dst->ans[i], &p->ans[i],
664 &nametable_count, nametable);
665 ++dst->hdr.anscount;
666 }
667 }
668
669 /* Copy NS section */
670 if (p->hdr.nscount && (options & PJ_DNS_NO_NS)==0) {
671 dst->ns = (pj_dns_parsed_rr*)
672 pj_pool_alloc(pool, p->hdr.nscount *
673 sizeof(pj_dns_parsed_rr));
674 for (i=0; i<p->hdr.nscount; ++i) {
675 copy_rr(pool, &dst->ns[i], &p->ns[i],
676 &nametable_count, nametable);
677 ++dst->hdr.nscount;
678 }
679 }
680
681 /* Copy additional info section */
682 if (p->hdr.arcount && (options & PJ_DNS_NO_AR)==0) {
683 dst->arr = (pj_dns_parsed_rr*)
684 pj_pool_alloc(pool, p->hdr.arcount *
685 sizeof(pj_dns_parsed_rr));
686 for (i=0; i<p->hdr.arcount; ++i) {
687 copy_rr(pool, &dst->arr[i], &p->arr[i],
688 &nametable_count, nametable);
689 ++dst->hdr.arcount;
690 }
691 }
692}
693
694
695PJ_DEF(void) pj_dns_init_srv_rr( pj_dns_parsed_rr *rec,
696 const pj_str_t *res_name,
697 unsigned dnsclass,
698 unsigned ttl,
699 unsigned prio,
700 unsigned weight,
701 unsigned port,
702 const pj_str_t *target)
703{
704 pj_bzero(rec, sizeof(*rec));
705 rec->name = *res_name;
706 rec->type = PJ_DNS_TYPE_SRV;
707 rec->dnsclass = (pj_uint16_t) dnsclass;
708 rec->ttl = ttl;
709 rec->rdata.srv.prio = (pj_uint16_t) prio;
710 rec->rdata.srv.weight = (pj_uint16_t) weight;
711 rec->rdata.srv.port = (pj_uint16_t) port;
712 rec->rdata.srv.target = *target;
713}
714
715
716PJ_DEF(void) pj_dns_init_cname_rr( pj_dns_parsed_rr *rec,
717 const pj_str_t *res_name,
718 unsigned dnsclass,
719 unsigned ttl,
720 const pj_str_t *name)
721{
722 pj_bzero(rec, sizeof(*rec));
723 rec->name = *res_name;
724 rec->type = PJ_DNS_TYPE_CNAME;
725 rec->dnsclass = (pj_uint16_t) dnsclass;
726 rec->ttl = ttl;
727 rec->rdata.cname.name = *name;
728}
729
730
731PJ_DEF(void) pj_dns_init_a_rr( pj_dns_parsed_rr *rec,
732 const pj_str_t *res_name,
733 unsigned dnsclass,
734 unsigned ttl,
735 const pj_in_addr *ip_addr)
736{
737 pj_bzero(rec, sizeof(*rec));
738 rec->name = *res_name;
739 rec->type = PJ_DNS_TYPE_A;
740 rec->dnsclass = (pj_uint16_t) dnsclass;
741 rec->ttl = ttl;
742 rec->rdata.a.ip_addr = *ip_addr;
743}
744