Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjlib-util / src / pjlib-util / dns.c
1 /* $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
29 PJ_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
46 static 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  */
56 PJ_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     unsigned 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 = 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  */
118 static 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  */
188 static 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. */
248 static 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 */
289 static 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  */
424 PJ_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  */
540 static 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
572 static 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
582 static 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  */
615 PJ_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
695 PJ_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
716 PJ_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
731 PJ_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