File indexing completed on 2024-05-19 04:06:38

0001 /*
0002  * Copyright (C) 2005-2008  Justin Karneges
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the
0006  * "Software"), to deal in the Software without restriction, including
0007  * without limitation the rights to use, copy, modify, merge, publish,
0008  * distribute, sublicense, and/or sell copies of the Software, and to
0009  * permit persons to whom the Software is furnished to do so, subject to
0010  * the following conditions:
0011  *
0012  * The above copyright notice and this permission notice shall be included
0013  * in all copies or substantial portions of the Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
0018  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
0019  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
0020  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
0021  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0022  */
0023 
0024 #include "jdns_p.h"
0025 
0026 #include "jdns_packet.h"
0027 
0028 #ifdef WIN32
0029 # include <winsock2.h>
0030 #endif
0031 
0032 /*---------------------------------------------------------------------------- */
0033 /* misc */
0034 /*---------------------------------------------------------------------------- */
0035 void *jdns_alloc(int size)
0036 {
0037     return malloc(size);
0038 }
0039 
0040 void *jdns_realloc(void *p, int size)
0041 {
0042     return realloc(p, size);
0043 }
0044 
0045 void jdns_free(void *p)
0046 {
0047     free(p);
0048 }
0049 
0050 char *jdns_strdup(const char *s)
0051 {
0052     char *p;
0053     int len;
0054 
0055     len = strlen(s) + 1; /* the zero */
0056     p = (char *)jdns_alloc(len);
0057     memcpy(p, s, len);
0058     return p;
0059 }
0060 
0061 unsigned char *jdns_copy_array(const unsigned char *src, int size)
0062 {
0063     unsigned char *out;
0064     if(size <= 0)
0065         return 0;
0066     out = (unsigned char *)jdns_alloc(size);
0067     memcpy(out, src, size);
0068     return out;
0069 }
0070 
0071 int jdns_domain_cmp(const unsigned char *a, const unsigned char *b)
0072 {
0073     int n;
0074     int len_a;
0075 
0076     /* case-insensitive compare */
0077     len_a = _ustrlen(a);
0078     if(len_a != (int)_ustrlen(b))
0079         return 0;
0080 
0081     for(n = 0; n < len_a; ++n)
0082     {
0083         if(tolower(a[n]) != tolower(b[n]))
0084             return 0;
0085     }
0086     return 1;
0087 }
0088 
0089 int jdns_sprintf_s(char *str, int n, const char *format, ...)
0090 {
0091     int ret;
0092     va_list ap;
0093     va_start(ap, format);
0094     ret = jdns_vsprintf_s(str, n, format, ap);
0095     va_end(ap);
0096     return ret;
0097 }
0098 
0099 int jdns_vsprintf_s(char *str, int n, const char *format, va_list ap)
0100 {
0101 #if defined(_MSC_VER) && _MSC_VER >= 1400
0102     return vsprintf_s(str, n, format, ap);
0103 #else
0104     (void)n;
0105     return vsprintf(str, format, ap);
0106 #endif
0107 }
0108 
0109 FILE *jdns_fopen(const char *path, const char *mode)
0110 {
0111 #if defined(_MSC_VER) && _MSC_VER >= 1400
0112     FILE *fp;
0113     if(fopen_s(&fp, path, mode) != 0)
0114         return 0;
0115     return fp;
0116 #else
0117     return fopen(path, mode);
0118 #endif
0119 }
0120 
0121 jdns_string_t *jdns_getenv(const char *name)
0122 {
0123 #if defined(_MSC_VER) && _MSC_VER >= 1400
0124     jdns_string_t *out;
0125     char *dest;
0126     size_t size;
0127     int sizei;
0128     errno_t ret;
0129     ret = getenv_s(&size, 0, 0, name);
0130     if(ret != 0 || size == 0)
0131         return 0;
0132     sizei = (int)size;
0133     dest = (char *)jdns_alloc(sizei);
0134     ret = getenv_s(&size, dest, size, name);
0135     if(ret != 0)
0136     {
0137         free(dest);
0138         return 0;
0139     }
0140     out = jdns_string_new();
0141     out->size = sizei - 1;
0142     out->data = dest; /* must be zero-terminated, which it is */
0143     return out;
0144 #else
0145     jdns_string_t *out;
0146     char *val;
0147     val = getenv(name);
0148     if(!val)
0149         return 0;
0150     out = jdns_string_new();
0151     jdns_string_set_cstr(out, val);
0152     return out;
0153 #endif
0154 }
0155 
0156 char *jdns_strcpy(char *dst, const char *src)
0157 {
0158 #if defined(_MSC_VER) && _MSC_VER >= 1400
0159     int len;
0160     /* deliberately unsafe */
0161     len = strlen(src);
0162     if(strcpy_s(dst, len + 1, src) != 0)
0163         return 0;
0164     return dst;
0165 #else
0166     return strcpy(dst, src);
0167 #endif
0168 }
0169 
0170 /*---------------------------------------------------------------------------- */
0171 /* jdns_object */
0172 /*---------------------------------------------------------------------------- */
0173 void *jdns_object_new(int size, void (*dtor)(void *), void *(*cctor)(const void *))
0174 {
0175     jdns_object_t *a = (jdns_object_t *)jdns_alloc(size);
0176     memset(a, 0, size);
0177     a->dtor = dtor;
0178     a->cctor = cctor;
0179     return a;
0180 }
0181 
0182 void *jdns_object_copy(const void *a)
0183 {
0184     return ((const jdns_object_t *)a)->cctor(a);
0185 }
0186 
0187 void jdns_object_delete(void *a)
0188 {
0189     ((jdns_object_t *)a)->dtor(a);
0190 }
0191 
0192 void jdns_object_free(void *a)
0193 {
0194     jdns_free(a);
0195 }
0196 
0197 /*---------------------------------------------------------------------------- */
0198 /* jdns_list */
0199 /*---------------------------------------------------------------------------- */
0200 jdns_list_t *jdns_list_new()
0201 {
0202     jdns_list_t *a = JDNS_OBJECT_NEW(jdns_list);
0203     a->count = 0;
0204     a->item = 0;
0205     a->valueList = 0;
0206     a->autoDelete = 0;
0207     return a;
0208 }
0209 
0210 jdns_list_t *jdns_list_copy(const jdns_list_t *a)
0211 {
0212     jdns_list_t *c = jdns_list_new();
0213 
0214     /* note: copying a list with autoDelete should not ever be done. */
0215     /*   heck, let's not even allow it.  return an empty list. */
0216     if(a->autoDelete)
0217         return c;
0218 
0219     c->valueList = a->valueList;
0220 
0221     /* copy the items */
0222     if(a->item)
0223     {
0224         int n;
0225         c->count = a->count;
0226         c->item = (void **)jdns_alloc(sizeof(void *) * c->count);
0227         if(a->valueList)
0228         {
0229             /* deep copy */
0230             for(n = 0; n < c->count; ++n)
0231                 c->item[n] = jdns_object_copy(a->item[n]);
0232         }
0233         else
0234         {
0235             /* just the pointer */
0236             for(n = 0; n < c->count; ++n)
0237                 c->item[n] = a->item[n];
0238         }
0239     }
0240     return c;
0241 }
0242 
0243 void jdns_list_delete(jdns_list_t *a)
0244 {
0245     if(!a)
0246         return;
0247     jdns_list_clear(a);
0248     jdns_object_free(a);
0249 }
0250 
0251 void jdns_list_clear(jdns_list_t *a)
0252 {
0253     if(a->item)
0254     {
0255         /* delete the items if necessary */
0256         if(a->valueList || a->autoDelete)
0257         {
0258             int n;
0259             for(n = 0; n < a->count; ++n)
0260                 jdns_object_delete(a->item[n]);
0261         }
0262         jdns_free(a->item);
0263         a->item = 0;
0264         a->count = 0;
0265     }
0266 }
0267 
0268 void jdns_list_insert(jdns_list_t *a, void *item, int pos)
0269 {
0270     /* make memory */
0271     if(!a->item)
0272         a->item = (void **)jdns_alloc(sizeof(void *));
0273     else
0274         a->item = (void **)jdns_realloc(a->item, sizeof(void *) * (a->count + 1));
0275 
0276     /* prepare position */
0277     if(pos != -1)
0278         memmove(a->item + pos + 1, a->item + pos, (a->count - pos) * sizeof(void *));
0279     else
0280         pos = a->count;
0281 
0282     /* insert it */
0283     if(a->valueList)
0284         a->item[pos] = jdns_object_copy(item);
0285     else
0286         a->item[pos] = item;
0287     ++a->count;
0288 }
0289 
0290 void jdns_list_insert_value(jdns_list_t *a, const void *item, int pos)
0291 {
0292     jdns_list_insert(a, (void *)item, pos);
0293 }
0294 
0295 void jdns_list_remove(jdns_list_t *a, void *item)
0296 {
0297     int n;
0298     int pos = -1;
0299     for(n = 0; n < a->count; ++n)
0300     {
0301         if(a->item[n] == item)
0302         {
0303             pos = n;
0304             break;
0305         }
0306     }
0307     if(pos == -1)
0308         return;
0309 
0310     jdns_list_remove_at(a, pos);
0311 }
0312 
0313 void jdns_list_remove_at(jdns_list_t *a, int pos)
0314 {
0315     if(pos < 0 || pos >= a->count)
0316         return;
0317 
0318     /* delete the item if necessary */
0319     if(a->valueList || a->autoDelete)
0320         jdns_object_delete(a->item[pos]);
0321 
0322     /* free the position */
0323     if(a->count > 1)
0324     {
0325         memmove(a->item + pos, a->item + pos + 1, (a->count - pos - 1) * sizeof(void *));
0326         --a->count;
0327     }
0328     else
0329     {
0330         jdns_free(a->item);
0331         a->item = 0;
0332         a->count = 0;
0333     }
0334 }
0335 
0336 /*---------------------------------------------------------------------------- */
0337 /* jdns_string */
0338 /*---------------------------------------------------------------------------- */
0339 jdns_string_t *jdns_string_new()
0340 {
0341     jdns_string_t *s = JDNS_OBJECT_NEW(jdns_string);
0342     s->data = 0;
0343     s->size = 0;
0344     return s;
0345 }
0346 
0347 jdns_string_t *jdns_string_copy(const jdns_string_t *s)
0348 {
0349     jdns_string_t *c = jdns_string_new();
0350     if(s->data)
0351         jdns_string_set(c, s->data, s->size);
0352     return c;
0353 }
0354 
0355 void jdns_string_delete(jdns_string_t *s)
0356 {
0357     if(!s)
0358         return;
0359     if(s->data)
0360         jdns_free(s->data);
0361     jdns_object_free(s);
0362 }
0363 
0364 void jdns_string_set(jdns_string_t *s, const unsigned char *str, int str_len)
0365 {
0366     if(s->data)
0367         jdns_free(s->data);
0368     s->data = (unsigned char *)jdns_alloc(str_len + 1);
0369     memcpy(s->data, str, str_len);
0370     s->data[str_len] = 0;
0371     s->size = str_len;
0372 }
0373 
0374 void jdns_string_set_cstr(jdns_string_t *s, const char *str)
0375 {
0376     jdns_string_set(s, (const unsigned char *)str, strlen(str));
0377 }
0378 
0379 int jdns_string_indexOf(const jdns_string_t *s, unsigned char c, int pos)
0380 {
0381     int n;
0382     for(n = pos; n < s->size; ++n)
0383     {
0384         if(s->data[n] == c)
0385             return n;
0386     }
0387     return -1;
0388 }
0389 
0390 jdns_stringlist_t *jdns_string_split(const jdns_string_t *s, unsigned char sep)
0391 {
0392     int at, n, len;
0393     jdns_string_t *str;
0394     jdns_stringlist_t *out;
0395 
0396     at = 0;
0397     out = jdns_stringlist_new();
0398     while(at < s->size)
0399     {
0400         n = jdns_string_indexOf(s, sep, at);
0401         if(n == -1)
0402             n = s->size;
0403         len = n - at;
0404         /* FIXME: should we allow empty items? */
0405         /*if(len == 0) */
0406         /*  break; */
0407         str = jdns_string_new();
0408         jdns_string_set(str, s->data + at, len);
0409         jdns_stringlist_append(out, str);
0410         jdns_string_delete(str);
0411         at = n + 1; /* skip over separator */
0412     }
0413     return out;
0414 }
0415 
0416 /*---------------------------------------------------------------------------- */
0417 /* jdns_stringlist */
0418 /*---------------------------------------------------------------------------- */
0419 jdns_stringlist_t *jdns_stringlist_new()
0420 {
0421     jdns_list_t *a = jdns_list_new();
0422     a->valueList = 1;
0423     return (jdns_stringlist_t *)a;
0424 }
0425 
0426 jdns_stringlist_t *jdns_stringlist_copy(const jdns_stringlist_t *a)
0427 {
0428     return (jdns_stringlist_t *)jdns_list_copy((const jdns_list_t *)a);
0429 }
0430 
0431 void jdns_stringlist_delete(jdns_stringlist_t *a)
0432 {
0433     jdns_list_delete((jdns_list_t *)a);
0434     /* note: no need to call jdns_object_free() here */
0435 }
0436 
0437 void jdns_stringlist_append(jdns_stringlist_t *a, const jdns_string_t *str)
0438 {
0439     jdns_list_insert_value((jdns_list_t *)a, str, -1);
0440 }
0441 
0442 /*---------------------------------------------------------------------------- */
0443 /* jdns_address */
0444 /*---------------------------------------------------------------------------- */
0445 jdns_address_t *jdns_address_new()
0446 {
0447     jdns_address_t *a = alloc_type(jdns_address_t);
0448     a->isIpv6 = 0;
0449     a->addr.v4 = 0;
0450     a->c_str = jdns_strdup("");
0451     return a;
0452 }
0453 
0454 jdns_address_t *jdns_address_copy(const jdns_address_t *a)
0455 {
0456     jdns_address_t *c = jdns_address_new();
0457     if(a->isIpv6)
0458         jdns_address_set_ipv6(c, a->addr.v6);
0459     else
0460         jdns_address_set_ipv4(c, a->addr.v4);
0461     return c;
0462 }
0463 
0464 void jdns_address_delete(jdns_address_t *a)
0465 {
0466     if(!a)
0467         return;
0468     if(a->isIpv6)
0469         jdns_free(a->addr.v6);
0470     jdns_free(a->c_str);
0471     jdns_free(a);
0472 }
0473 
0474 void jdns_address_set_ipv4(jdns_address_t *a, unsigned long int ipv4)
0475 {
0476     if(a->isIpv6)
0477         jdns_free(a->addr.v6);
0478     jdns_free(a->c_str);
0479     a->isIpv6 = 0;
0480     a->addr.v4 = ipv4;
0481     a->c_str = (char *)jdns_alloc(16); /* max size (3 * 4 + 3 + 1) */
0482     jdns_sprintf_s(a->c_str, 16, "%d.%d.%d.%d",
0483         (unsigned char)((ipv4 >> 24) & 0xff),
0484         (unsigned char)((ipv4 >> 16) & 0xff),
0485         (unsigned char)((ipv4 >>  8) & 0xff),
0486         (unsigned char)((ipv4)       & 0xff));
0487 }
0488 
0489 void jdns_address_set_ipv6(jdns_address_t *a, const unsigned char *ipv6)
0490 {
0491     int n;
0492     unsigned char *p;
0493     unsigned short word[8];
0494     if(a->isIpv6)
0495         jdns_free(a->addr.v6);
0496     jdns_free(a->c_str);
0497     a->isIpv6 = 1;
0498     a->addr.v6 = (unsigned char *)jdns_alloc(16);
0499     memcpy(a->addr.v6, ipv6, 16);
0500     p = (unsigned char *)a->addr.v6;
0501     a->c_str = (char *)jdns_alloc(40); /* max size (8 * 4 + 7 + 1) */
0502     /* each word in a 16-byte ipv6 address is network byte order */
0503     for(n = 0; n < 8; ++n)
0504         word[n] = ((unsigned short)(p[n * 2]) << 8) + (unsigned short)(p[n * 2 + 1]);
0505     jdns_sprintf_s(a->c_str, 40, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X", word[0], word[1], word[2], word[3], word[4], word[5], word[6], word[7]);
0506 }
0507 
0508 int jdns_address_set_cstr(jdns_address_t *a, const char *str)
0509 {
0510     int slen = strlen(str);
0511 
0512     /* ipv6 */
0513     if(strchr(str, ':'))
0514     {
0515         jdns_string_t *in;
0516         jdns_stringlist_t *list;
0517         unsigned char ipv6[16];
0518         int n, at, count, fill;
0519 
0520         in = jdns_string_new();
0521         jdns_string_set_cstr(in, str);
0522         list = jdns_string_split(in, ':');
0523         jdns_string_delete(in);
0524 
0525         /* a confusing outputting-backwards parser adapted from qt */
0526 
0527         count = list->count;
0528 
0529         if(count < 3 || count > 8)
0530             goto error;
0531 
0532         at = 16;
0533         fill = 9 - count;
0534         for(n = count - 1; n >= 0; --n)
0535         {
0536             if(at <= 0)
0537                 goto error;
0538 
0539             if(list->item[n]->size == 0)
0540             {
0541                 if(n == count - 1)
0542                 {
0543                     if(list->item[n - 1]->size != 0)
0544                         goto error;
0545                     ipv6[--at] = 0;
0546                     ipv6[--at] = 0;
0547                 }
0548                 else if(n == 0)
0549                 {
0550                     if(list->item[n + 1]->size != 0)
0551                         goto error;
0552                     ipv6[--at] = 0;
0553                     ipv6[--at] = 0;
0554                 }
0555                 else
0556                 {
0557                     int i;
0558                     for(i = 0; i < fill; ++i)
0559                     {
0560                         if(at <= 0)
0561                             goto error;
0562                         ipv6[--at] = 0;
0563                         ipv6[--at] = 0;
0564                     }
0565                 }
0566             }
0567             else
0568             {
0569                 if(jdns_string_indexOf(list->item[n], '.', 0) == -1)
0570                 {
0571                     int x;
0572                     x = strtol((const char *)list->item[n]->data, NULL, 16);
0573                     if(x < 0 || x > 0xffff)
0574                         goto error;
0575                     ipv6[--at] = x & 0xff;
0576                     ipv6[--at] = (x >> 8) & 0xff;
0577                 }
0578                 else
0579                 {
0580                     jdns_address_t *v4;
0581 
0582                     if(n != count - 1)
0583                         goto error;
0584 
0585                     v4 = jdns_address_new();
0586                     if(!jdns_address_set_cstr(v4, (char *)list->item[n]->data))
0587                     {
0588                         jdns_address_delete(v4);
0589                         goto error;
0590                     }
0591 
0592                     ipv6[--at] = (unsigned char)(v4->addr.v4 & 0xff);
0593                     ipv6[--at] = (unsigned char)((v4->addr.v4 >> 8) & 0xff);
0594                     ipv6[--at] = (unsigned char)((v4->addr.v4 >> 16) & 0xff);
0595                     ipv6[--at] = (unsigned char)((v4->addr.v4 >> 24) & 0xff);
0596                     jdns_address_delete(v4);
0597                     --fill;
0598                 }
0599             }
0600         }
0601         jdns_stringlist_delete(list);
0602 
0603         jdns_address_set_ipv6(a, ipv6);
0604         return 1;
0605 
0606 error:
0607         jdns_stringlist_delete(list);
0608         return 0;
0609     }
0610     else if(strchr(str, '.'))
0611     {
0612         unsigned char b[4];
0613         int x;
0614         unsigned long int ipv4;
0615         int at;
0616         char *part;
0617         int len;
0618         const char *p, *p2;
0619 
0620         p = str;
0621         at = 0;
0622         while(1)
0623         {
0624             p2 = strchr(p, '.');
0625             if(!p2)
0626                 p2 = str + slen;
0627             len = p2 - p;
0628 
0629             /* convert the section into a byte */
0630             part = (char *)jdns_alloc(len + 1);
0631             memcpy(part, p, len);
0632             part[len] = 0;
0633             x = strtol(part, NULL, 10);
0634             jdns_free(part);
0635             if(x < 0 || x > 0xff)
0636                 break;
0637             b[at++] = (unsigned char)x;
0638 
0639             /* done? */
0640             if(p2 >= str + slen)
0641                 break;
0642 
0643             /* skip over the separator */
0644             p = p2 + 1;
0645         }
0646         if(at != 4)
0647             return 0;
0648 
0649         ipv4 = 0;
0650         ipv4 += b[0];
0651         ipv4 <<= 8;
0652         ipv4 += b[1];
0653         ipv4 <<= 8;
0654         ipv4 += b[2];
0655         ipv4 <<= 8;
0656         ipv4 += b[3];
0657 
0658         jdns_address_set_ipv4(a, ipv4);
0659         return 1;
0660     }
0661     else
0662         return 0;
0663 }
0664 
0665 int jdns_address_cmp(const jdns_address_t *a, const jdns_address_t *b)
0666 {
0667     /* same protocol? */
0668     if(a->isIpv6 != b->isIpv6)
0669         return 0;
0670     if(a->isIpv6)
0671     {
0672         int n;
0673         for(n = 0; n < 16; ++n)
0674         {
0675             if(a->addr.v6[n] != b->addr.v6[n])
0676                 break;
0677         }
0678         if(n == 16)
0679             return 1;
0680     }
0681     else
0682     {
0683         if(a->addr.v4 == b->addr.v4)
0684             return 1;
0685     }
0686     return 0;
0687 }
0688 
0689 /* FF02::FB */
0690 unsigned char jdns_multicast_addr6_value_v6[] =
0691 {
0692     0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0693     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb
0694 };
0695 
0696 jdns_address_t *jdns_address_multicast4_new()
0697 {
0698     jdns_address_t *a = jdns_address_new();
0699     jdns_address_set_ipv4(a, 0xe00000fb);
0700     return a;
0701 }
0702 
0703 jdns_address_t *jdns_address_multicast6_new()
0704 {
0705     jdns_address_t *a = jdns_address_new();
0706     jdns_address_set_ipv6(a, jdns_multicast_addr6_value_v6);
0707     return a;
0708 }
0709 
0710 /*---------------------------------------------------------------------------- */
0711 /* jdns_server */
0712 /*---------------------------------------------------------------------------- */
0713 jdns_server_t *jdns_server_new()
0714 {
0715     jdns_server_t *s = alloc_type(jdns_server_t);
0716     s->name = 0;
0717     s->port = 0;
0718     s->priority = 0;
0719     s->weight = 0;
0720     return s;
0721 }
0722 
0723 jdns_server_t *jdns_server_copy(const jdns_server_t *s)
0724 {
0725     jdns_server_t *c = jdns_server_new();
0726     if(s->name)
0727         c->name = _ustrdup(s->name);
0728     c->port = s->port;
0729     c->priority = s->priority;
0730     c->weight = s->weight;
0731     return c;
0732 }
0733 
0734 void jdns_server_delete(jdns_server_t *s)
0735 {
0736     if(!s)
0737         return;
0738     if(s->name)
0739         jdns_free(s->name);
0740     jdns_object_free(s);
0741 }
0742 
0743 void jdns_server_set_name(jdns_server_t *s, const unsigned char *name)
0744 {
0745     if(s->name)
0746         jdns_free(s->name);
0747     s->name = _ustrdup(name);
0748 }
0749 
0750 /*---------------------------------------------------------------------------- */
0751 /* jdns_nameserver */
0752 /*---------------------------------------------------------------------------- */
0753 jdns_nameserver_t *jdns_nameserver_new()
0754 {
0755     jdns_nameserver_t *a = alloc_type(jdns_nameserver_t);
0756     a->address = 0;
0757     a->port = -1;
0758     return a;
0759 }
0760 
0761 jdns_nameserver_t *jdns_nameserver_copy(const jdns_nameserver_t *a)
0762 {
0763     jdns_nameserver_t *c = jdns_nameserver_new();
0764     if(a->address)
0765         c->address = jdns_address_copy(a->address);
0766     c->port = a->port;
0767     return c;
0768 }
0769 
0770 void jdns_nameserver_delete(jdns_nameserver_t *a)
0771 {
0772     if(!a)
0773         return;
0774     jdns_address_delete(a->address);
0775     jdns_free(a);
0776 }
0777 
0778 void jdns_nameserver_set(jdns_nameserver_t *a, const jdns_address_t *addr, int port)
0779 {
0780     if(a->address)
0781         jdns_address_delete(a->address);
0782     a->address = jdns_address_copy(addr);
0783     a->port = port;
0784 }
0785 
0786 /*---------------------------------------------------------------------------- */
0787 /* jdns_nameserverlist */
0788 /*---------------------------------------------------------------------------- */
0789 jdns_nameserverlist_t *jdns_nameserverlist_new()
0790 {
0791     jdns_nameserverlist_t *a = alloc_type(jdns_nameserverlist_t);
0792     a->count = 0;
0793     a->item = 0;
0794     return a;
0795 }
0796 
0797 jdns_nameserverlist_t *jdns_nameserverlist_copy(const jdns_nameserverlist_t *a)
0798 {
0799     int n;
0800     jdns_nameserverlist_t *c = jdns_nameserverlist_new();
0801     if(a->item)
0802     {
0803         c->item = (jdns_nameserver_t **)jdns_alloc(sizeof(jdns_nameserver_t *) * a->count);
0804         c->count = a->count;
0805         for(n = 0; n < c->count; ++n)
0806             c->item[n] = jdns_nameserver_copy(a->item[n]);
0807     }
0808     return c;
0809 }
0810 
0811 void jdns_nameserverlist_delete(jdns_nameserverlist_t *a)
0812 {
0813     int n;
0814     if(!a)
0815         return;
0816     if(a->item)
0817     {
0818         for(n = 0; n < a->count; ++n)
0819             jdns_nameserver_delete(a->item[n]);
0820         jdns_free(a->item);
0821     }
0822     jdns_free(a);
0823 }
0824 
0825 void jdns_nameserverlist_append(jdns_nameserverlist_t *a, const jdns_address_t *addr, int port)
0826 {
0827     if(!a->item)
0828         a->item = (jdns_nameserver_t **)jdns_alloc(sizeof(jdns_nameserver_t *));
0829     else
0830         a->item = (jdns_nameserver_t **)jdns_realloc(a->item, sizeof(jdns_nameserver_t *) * (a->count + 1));
0831     a->item[a->count] = jdns_nameserver_new();
0832     jdns_nameserver_set(a->item[a->count], addr, port);
0833     ++a->count;
0834 }
0835 
0836 /*---------------------------------------------------------------------------- */
0837 /* jdns_dnshost */
0838 /*---------------------------------------------------------------------------- */
0839 jdns_dnshost_t *jdns_dnshost_new()
0840 {
0841     jdns_dnshost_t *a = alloc_type(jdns_dnshost_t);
0842     a->name = 0;
0843     a->address = 0;
0844     return a;
0845 }
0846 
0847 jdns_dnshost_t *jdns_dnshost_copy(const jdns_dnshost_t *a)
0848 {
0849     jdns_dnshost_t *c = jdns_dnshost_new();
0850     if(a->name)
0851         c->name = jdns_string_copy(a->name);
0852     if(a->address)
0853         c->address = jdns_address_copy(a->address);
0854     return c;
0855 }
0856 
0857 void jdns_dnshost_delete(jdns_dnshost_t *a)
0858 {
0859     if(!a)
0860         return;
0861     jdns_string_delete(a->name);
0862     jdns_address_delete(a->address);
0863     jdns_free(a);
0864 }
0865 
0866 /*---------------------------------------------------------------------------- */
0867 /* jdns_dnshostlist */
0868 /*---------------------------------------------------------------------------- */
0869 jdns_dnshostlist_t *jdns_dnshostlist_new()
0870 {
0871     jdns_dnshostlist_t *a = alloc_type(jdns_dnshostlist_t);
0872     a->count = 0;
0873     a->item = 0;
0874     return a;
0875 }
0876 
0877 jdns_dnshostlist_t *jdns_dnshostlist_copy(const jdns_dnshostlist_t *a)
0878 {
0879     int n;
0880     jdns_dnshostlist_t *c = jdns_dnshostlist_new();
0881     if(a->item)
0882     {
0883         c->item = (jdns_dnshost_t **)jdns_alloc(sizeof(jdns_dnshost_t *) * a->count);
0884         c->count = a->count;
0885         for(n = 0; n < c->count; ++n)
0886             c->item[n] = jdns_dnshost_copy(a->item[n]);
0887     }
0888     return c;
0889 }
0890 
0891 void jdns_dnshostlist_delete(jdns_dnshostlist_t *a)
0892 {
0893     int n;
0894     if(!a)
0895         return;
0896     if(a->item)
0897     {
0898         for(n = 0; n < a->count; ++n)
0899             jdns_dnshost_delete(a->item[n]);
0900         jdns_free(a->item);
0901     }
0902     jdns_free(a);
0903 }
0904 
0905 void jdns_dnshostlist_append(jdns_dnshostlist_t *a, const jdns_dnshost_t *host)
0906 {
0907     if(!a->item)
0908         a->item = (jdns_dnshost_t **)jdns_alloc(sizeof(jdns_dnshost_t *));
0909     else
0910         a->item = (jdns_dnshost_t **)jdns_realloc(a->item, sizeof(jdns_dnshost_t *) * (a->count + 1));
0911     a->item[a->count] = jdns_dnshost_copy(host);
0912     ++a->count;
0913 }
0914 
0915 /*---------------------------------------------------------------------------- */
0916 /* jdns_dnsparams */
0917 /*---------------------------------------------------------------------------- */
0918 jdns_dnsparams_t *jdns_dnsparams_new()
0919 {
0920     jdns_dnsparams_t *a = alloc_type(jdns_dnsparams_t);
0921     a->nameservers = jdns_nameserverlist_new();
0922     a->domains = jdns_stringlist_new();
0923     a->hosts = jdns_dnshostlist_new();
0924     return a;
0925 }
0926 
0927 jdns_dnsparams_t *jdns_dnsparams_copy(jdns_dnsparams_t *a)
0928 {
0929     jdns_dnsparams_t *c = jdns_dnsparams_new();
0930     c->nameservers = jdns_nameserverlist_copy(a->nameservers);
0931     c->domains = jdns_stringlist_copy(a->domains);
0932     c->hosts = jdns_dnshostlist_copy(a->hosts);
0933     return c;
0934 }
0935 
0936 void jdns_dnsparams_delete(jdns_dnsparams_t *a)
0937 {
0938     if(!a)
0939         return;
0940     jdns_nameserverlist_delete(a->nameservers);
0941     jdns_stringlist_delete(a->domains);
0942     jdns_dnshostlist_delete(a->hosts);
0943     jdns_free(a);
0944 }
0945 
0946 void jdns_dnsparams_append_nameserver(jdns_dnsparams_t *a, const jdns_address_t *addr, int port)
0947 {
0948     jdns_nameserverlist_append(a->nameservers, addr, port);
0949 }
0950 
0951 void jdns_dnsparams_append_domain(jdns_dnsparams_t *a, const jdns_string_t *domain)
0952 {
0953     jdns_stringlist_append(a->domains, domain);
0954 }
0955 
0956 void jdns_dnsparams_append_host(jdns_dnsparams_t *a, const jdns_string_t *name, const jdns_address_t *address)
0957 {
0958     jdns_dnshost_t *h = jdns_dnshost_new();
0959     h->name = jdns_string_copy(name);
0960     h->address = jdns_address_copy(address);
0961     jdns_dnshostlist_append(a->hosts, h);
0962     jdns_dnshost_delete(h);
0963 }
0964 
0965 /*---------------------------------------------------------------------------- */
0966 /* jdns_rr */
0967 /*---------------------------------------------------------------------------- */
0968 void _jdns_rr_data_reset(jdns_rr_t *r)
0969 {
0970     if(r->rdata)
0971     {
0972         jdns_free(r->rdata);
0973         r->rdata = 0;
0974     }
0975     r->rdlength = 0;
0976 
0977     if(r->haveKnown)
0978     {
0979         switch(r->type)
0980         {
0981             case JDNS_RTYPE_A:
0982             case JDNS_RTYPE_AAAA:
0983                 jdns_address_delete(r->data.address);
0984                 break;
0985             case JDNS_RTYPE_MX:
0986             case JDNS_RTYPE_SRV:
0987                 jdns_server_delete(r->data.server);
0988                 break;
0989             case JDNS_RTYPE_CNAME:
0990             case JDNS_RTYPE_PTR:
0991             case JDNS_RTYPE_NS:
0992                 jdns_free(r->data.name);
0993                 break;
0994             case JDNS_RTYPE_TXT:
0995                 jdns_stringlist_delete(r->data.texts);
0996                 break;
0997             case JDNS_RTYPE_HINFO:
0998                 jdns_string_delete(r->data.hinfo.cpu);
0999                 jdns_string_delete(r->data.hinfo.os);
1000                 break;
1001             default:
1002                 break;
1003         };
1004         r->haveKnown = 0;
1005     }
1006     r->type = -1;
1007 }
1008 
1009 void _jdns_rr_data_copy(const jdns_rr_t *r, jdns_rr_t *c)
1010 {
1011     c->type = r->type;
1012     c->qclass = r->qclass;
1013     c->rdlength = r->rdlength;
1014     c->rdata = jdns_copy_array(r->rdata, r->rdlength);
1015 
1016     if(r->haveKnown)
1017     {
1018         switch(r->type)
1019         {
1020             case JDNS_RTYPE_A:
1021             case JDNS_RTYPE_AAAA:
1022                 c->data.address = jdns_address_copy(r->data.address);
1023                 break;
1024             case JDNS_RTYPE_MX:
1025             case JDNS_RTYPE_SRV:
1026                 c->data.server = jdns_server_copy(r->data.server);
1027                 break;
1028             case JDNS_RTYPE_CNAME:
1029             case JDNS_RTYPE_PTR:
1030             case JDNS_RTYPE_NS:
1031                 c->data.name = _ustrdup(r->data.name);
1032                 break;
1033             case JDNS_RTYPE_TXT:
1034                 c->data.texts = jdns_stringlist_copy(r->data.texts);
1035                 break;
1036             case JDNS_RTYPE_HINFO:
1037                 c->data.hinfo.cpu = jdns_string_copy(r->data.hinfo.cpu);
1038                 c->data.hinfo.os = jdns_string_copy(r->data.hinfo.os);
1039                 break;
1040             default:
1041                 break;
1042         };
1043         c->haveKnown = 1;
1044     }
1045 }
1046 
1047 jdns_rr_t *jdns_rr_new()
1048 {
1049     jdns_rr_t *r = alloc_type(jdns_rr_t);
1050     r->owner = 0;
1051     r->ttl = 0;
1052     r->type = -1;
1053     r->qclass = 0;
1054     r->rdata = 0;
1055     r->rdlength = 0;
1056     r->haveKnown = 0;
1057     return r;
1058 }
1059 
1060 jdns_rr_t *jdns_rr_copy(const jdns_rr_t *r)
1061 {
1062     jdns_rr_t *c = jdns_rr_new();
1063     if(r->owner)
1064         c->owner = _ustrdup(r->owner);
1065     c->ttl = r->ttl;
1066     _jdns_rr_data_copy(r, c);
1067     return c;
1068 }
1069 
1070 void jdns_rr_delete(jdns_rr_t *r)
1071 {
1072     if(!r)
1073         return;
1074     if(r->owner)
1075         jdns_free(r->owner);
1076     _jdns_rr_data_reset(r);
1077     jdns_free(r);
1078 }
1079 
1080 void jdns_rr_set_owner(jdns_rr_t *r, const unsigned char *name)
1081 {
1082     if(r->owner)
1083         jdns_free(r->owner);
1084     r->owner = _ustrdup(name);
1085 }
1086 
1087 void jdns_rr_set_record(jdns_rr_t *r, int type, const unsigned char *rdata, int rdlength)
1088 {
1089     _jdns_rr_data_reset(r);
1090     r->type = type;
1091     r->rdlength = rdlength;
1092     r->rdata = jdns_copy_array(rdata, rdlength);
1093 }
1094 
1095 void jdns_rr_set_A(jdns_rr_t *r, const jdns_address_t *address)
1096 {
1097     _jdns_rr_data_reset(r);
1098     r->type = JDNS_RTYPE_A;
1099     r->haveKnown = 1;
1100     r->data.address = jdns_address_copy(address);
1101 }
1102 
1103 void jdns_rr_set_AAAA(jdns_rr_t *r, const jdns_address_t *address)
1104 {
1105     _jdns_rr_data_reset(r);
1106     r->type = JDNS_RTYPE_AAAA;
1107     r->haveKnown = 1;
1108     r->data.address = jdns_address_copy(address);
1109 }
1110 
1111 void jdns_rr_set_MX(jdns_rr_t *r, const unsigned char *name, int priority)
1112 {
1113     jdns_server_t *s = jdns_server_new();
1114     jdns_server_set_name(s, name);
1115     s->priority = priority;
1116 
1117     _jdns_rr_data_reset(r);
1118     r->type = JDNS_RTYPE_MX;
1119     r->haveKnown = 1;
1120     r->data.server = s;
1121 }
1122 
1123 void jdns_rr_set_SRV(jdns_rr_t *r, const unsigned char *name, int port, int priority, int weight)
1124 {
1125     jdns_server_t *s = jdns_server_new();
1126     jdns_server_set_name(s, name);
1127     s->port = port;
1128     s->priority = priority;
1129     s->weight = weight;
1130 
1131     _jdns_rr_data_reset(r);
1132     r->type = JDNS_RTYPE_SRV;
1133     r->haveKnown = 1;
1134     r->data.server = s;
1135 }
1136 
1137 void jdns_rr_set_CNAME(jdns_rr_t *r, const unsigned char *name)
1138 {
1139     _jdns_rr_data_reset(r);
1140     r->type = JDNS_RTYPE_CNAME;
1141     r->haveKnown = 1;
1142     r->data.name = _ustrdup(name);
1143 }
1144 
1145 void jdns_rr_set_PTR(jdns_rr_t *r, const unsigned char *name)
1146 {
1147     _jdns_rr_data_reset(r);
1148     r->type = JDNS_RTYPE_PTR;
1149     r->haveKnown = 1;
1150     r->data.name = _ustrdup(name);
1151 }
1152 
1153 void jdns_rr_set_TXT(jdns_rr_t *r, const jdns_stringlist_t *texts)
1154 {
1155     _jdns_rr_data_reset(r);
1156     r->type = JDNS_RTYPE_TXT;
1157     r->haveKnown = 1;
1158     r->data.texts = jdns_stringlist_copy(texts);
1159 }
1160 
1161 void jdns_rr_set_HINFO(jdns_rr_t *r, const jdns_string_t *cpu, const jdns_string_t *os)
1162 {
1163     _jdns_rr_data_reset(r);
1164     r->type = JDNS_RTYPE_HINFO;
1165     r->haveKnown = 1;
1166     r->data.hinfo.cpu = jdns_string_copy(cpu);
1167     r->data.hinfo.os = jdns_string_copy(os);
1168 }
1169 
1170 void jdns_rr_set_NS(jdns_rr_t *r, const unsigned char *name)
1171 {
1172     _jdns_rr_data_reset(r);
1173     r->type = JDNS_RTYPE_NS;
1174     r->haveKnown = 1;
1175     r->data.name = _ustrdup(name);
1176 }
1177 
1178 int jdns_rr_verify(const jdns_rr_t *r)
1179 {
1180     if(r->type == -1)
1181         return 0;
1182 
1183     if(!jdns_packet_name_isvalid(r->owner, _ustrlen(r->owner)))
1184         return 0;
1185 
1186     switch(r->type)
1187     {
1188         case JDNS_RTYPE_MX:
1189         case JDNS_RTYPE_SRV:
1190         {
1191             /* consider it valid if we don't have a known to check */
1192             if(!r->haveKnown)
1193                 return 1;
1194             if(!jdns_packet_name_isvalid(r->data.server->name, _ustrlen(r->data.server->name)))
1195                 return 0;
1196             break;
1197         }
1198         case JDNS_RTYPE_CNAME:
1199         case JDNS_RTYPE_PTR:
1200         case JDNS_RTYPE_NS:
1201         {
1202             if(!r->haveKnown)
1203                 return 1;
1204             if(!jdns_packet_name_isvalid(r->data.name, _ustrlen(r->data.name)))
1205                 return 0;
1206             break;
1207         }
1208         case JDNS_RTYPE_TXT:
1209         {
1210             int n;
1211             if(!r->haveKnown)
1212                 return 1;
1213             for(n = 0; n < r->data.texts->count; ++n)
1214             {
1215                 if(r->data.texts->item[n]->size > 255)
1216                     return 0;
1217             }
1218             break;
1219         }
1220         case JDNS_RTYPE_HINFO:
1221         {
1222             if(!r->haveKnown)
1223                 return 1;
1224             if(r->data.hinfo.cpu->size > 255)
1225                 return 0;
1226             if(r->data.hinfo.os->size > 255)
1227                 return 0;
1228             break;
1229         }
1230     }
1231 
1232     return 1;
1233 }
1234 
1235 static jdns_string_t *read_name_at_end(const jdns_packet_resource_t *pr, const jdns_packet_t *ref, int _at)
1236 {
1237     jdns_string_t *name;
1238     int at;
1239     at = _at;
1240     if(!jdns_packet_resource_read_name(pr, ref, &at, &name))
1241         return 0;
1242     if(at != pr->rdlength)
1243     {
1244         jdns_string_delete(name);
1245         return 0;
1246     }
1247     return name;
1248 }
1249 
1250 static jdns_string_t *read_text_string(const jdns_packet_resource_t *pr, int *_at)
1251 {
1252     jdns_string_t *out;
1253     int at, len;
1254     at = *_at;
1255     if(at + 1 > pr->rdlength)
1256         return 0;
1257     len = pr->rdata[at++];
1258     if(at + len > pr->rdlength)
1259         return 0;
1260     out = jdns_string_new();
1261     jdns_string_set(out, pr->rdata + at, len);
1262     at += len;
1263     *_at = at;
1264     return out;
1265 }
1266 
1267 /* if the type is known, then it must be parsed properly */
1268 /* if the type is unknown, then that's ok */
1269 /* rdata is always copied, known or not */
1270 jdns_rr_t *jdns_rr_from_resource(const jdns_packet_resource_t *pr, const jdns_packet_t *ref)
1271 {
1272     jdns_rr_t *rr = 0;
1273 
1274     if(pr->qtype == JDNS_RTYPE_ANY)
1275         return 0;
1276 
1277     switch(pr->qtype)
1278     {
1279         case JDNS_RTYPE_A:
1280         {
1281             jdns_address_t *addr;
1282             unsigned long int ip;
1283             if(pr->rdlength != 4)
1284                 break;
1285             memcpy(&ip, pr->rdata, 4);
1286             ip = ntohl(ip);
1287             addr = jdns_address_new();
1288             jdns_address_set_ipv4(addr, ip);
1289             rr = jdns_rr_new();
1290             jdns_rr_set_A(rr, addr);
1291             jdns_address_delete(addr);
1292             break;
1293         }
1294         case JDNS_RTYPE_AAAA:
1295         {
1296             jdns_address_t *addr;
1297             if(pr->rdlength != 16)
1298                 break;
1299             addr = jdns_address_new();
1300             jdns_address_set_ipv6(addr, pr->rdata);
1301             rr = jdns_rr_new();
1302             jdns_rr_set_AAAA(rr, addr);
1303             jdns_address_delete(addr);
1304             break;
1305         }
1306         case JDNS_RTYPE_MX:
1307         {
1308             unsigned short priority;
1309             jdns_string_t *name;
1310             if(pr->rdlength < 2)
1311                 break;
1312             memcpy(&priority, pr->rdata, 2);
1313             priority = ntohs(priority);
1314             name = read_name_at_end(pr, ref, 2);
1315             if(!name)
1316                 break;
1317             rr = jdns_rr_new();
1318             jdns_rr_set_MX(rr, name->data, priority);
1319             jdns_string_delete(name);
1320             break;
1321         }
1322         case JDNS_RTYPE_SRV:
1323         {
1324             unsigned short priority, weight, port;
1325             jdns_string_t *name;
1326             if(pr->rdlength < 6)
1327                 break;
1328             memcpy(&priority, pr->rdata, 2);
1329             priority = ntohs(priority);
1330             memcpy(&weight, pr->rdata + 2, 2);
1331             weight = ntohs(weight);
1332             memcpy(&port, pr->rdata + 4, 2);
1333             port = ntohs(port);
1334             name = read_name_at_end(pr, ref, 6);
1335             if(!name)
1336                 break;
1337             rr = jdns_rr_new();
1338             jdns_rr_set_SRV(rr, name->data, port, priority, weight);
1339             jdns_string_delete(name);
1340             break;
1341         }
1342         case JDNS_RTYPE_CNAME:
1343         {
1344             jdns_string_t *name;
1345             name = read_name_at_end(pr, ref, 0);
1346             if(!name)
1347                 break;
1348             rr = jdns_rr_new();
1349             jdns_rr_set_CNAME(rr, name->data);
1350             jdns_string_delete(name);
1351             break;
1352         }
1353         case JDNS_RTYPE_PTR:
1354         {
1355             jdns_string_t *name;
1356             name = read_name_at_end(pr, ref, 0);
1357             if(!name)
1358                 break;
1359             rr = jdns_rr_new();
1360             jdns_rr_set_PTR(rr, name->data);
1361             jdns_string_delete(name);
1362             break;
1363         }
1364         case JDNS_RTYPE_TXT:
1365         {
1366             jdns_stringlist_t *texts;
1367             jdns_string_t *str;
1368             int at, error;
1369             texts = jdns_stringlist_new();
1370             at = 0;
1371             error = 0;
1372             while(at < pr->rdlength)
1373             {
1374                 str = read_text_string(pr, &at);
1375                 if(!str)
1376                 {
1377                     error = 1;
1378                     break;
1379                 }
1380                 jdns_stringlist_append(texts, str);
1381                 jdns_string_delete(str);
1382             }
1383             if(error)
1384             {
1385                 jdns_stringlist_delete(texts);
1386                 break;
1387             }
1388             rr = jdns_rr_new();
1389             jdns_rr_set_TXT(rr, texts);
1390             jdns_stringlist_delete(texts);
1391             break;
1392         }
1393         case JDNS_RTYPE_HINFO:
1394         {
1395             jdns_string_t *cpu, *os;
1396             int at;
1397             at = 0;
1398             cpu = read_text_string(pr, &at);
1399             if(!cpu)
1400                 break;
1401             os = read_text_string(pr, &at);
1402             if(!os)
1403             {
1404                 jdns_string_delete(cpu);
1405                 break;
1406             }
1407             if(at != pr->rdlength)
1408             {
1409                 jdns_string_delete(cpu);
1410                 jdns_string_delete(os);
1411                 break;
1412             }
1413             rr = jdns_rr_new();
1414             jdns_rr_set_HINFO(rr, cpu, os);
1415             jdns_string_delete(cpu);
1416             jdns_string_delete(os);
1417             break;
1418         }
1419         case JDNS_RTYPE_NS:
1420         {
1421             jdns_string_t *name;
1422             name = read_name_at_end(pr, ref, 0);
1423             if(!name)
1424                 break;
1425             rr = jdns_rr_new();
1426             jdns_rr_set_NS(rr, name->data);
1427             jdns_string_delete(name);
1428             break;
1429         }
1430         default:
1431         {
1432             rr = jdns_rr_new();
1433             rr->type = pr->qtype;
1434             break;
1435         }
1436     }
1437 
1438     if(rr)
1439     {
1440         rr->qclass = pr->qclass;
1441         rr->owner = _ustrdup(pr->qname->data);
1442         rr->ttl = (int)pr->ttl; /* pr->ttl is 31-bits, cast is safe */
1443         rr->rdlength = pr->rdlength;
1444         rr->rdata = jdns_copy_array(pr->rdata, pr->rdlength);
1445     }
1446 
1447     return rr;
1448 }
1449 
1450 /*---------------------------------------------------------------------------- */
1451 /* jdns_response */
1452 /*---------------------------------------------------------------------------- */
1453 #define ARRAY_DELETE(array, count, dtor) \
1454     { \
1455         if(count > 0) \
1456         { \
1457             int n; \
1458             for(n = 0; n < count; ++n) \
1459                 dtor(array[n]); \
1460         } \
1461         jdns_free(array); \
1462         array = 0; \
1463         count = 0; \
1464     }
1465 
1466 #define ARRAY_COPY(type, array_src, count_src, array_dest, count_dest, cctor) \
1467     { \
1468         if(count_src > 0) \
1469         { \
1470             int n; \
1471             count_dest = count_src; \
1472             array_dest = (type **)jdns_alloc(sizeof(type *) * count_dest); \
1473             for(n = 0; n < count_dest; ++n) \
1474                 array_dest[n] = cctor(array_src[n]); \
1475         } \
1476     }
1477 
1478 #define ARRAY_APPEND(type, array, count, item) \
1479     { \
1480         if(!array) \
1481             array = (type **)jdns_alloc(sizeof(type *)); \
1482         else \
1483             array = (type **)jdns_realloc(array, sizeof(type *) * (count + 1)); \
1484         array[count] = item; \
1485         ++count; \
1486     }
1487 
1488 jdns_response_t *jdns_response_new()
1489 {
1490     jdns_response_t *r = alloc_type(jdns_response_t);
1491     r->answerCount = 0;
1492     r->answerRecords = 0;
1493     r->authorityCount = 0;
1494     r->authorityRecords = 0;
1495     r->additionalCount = 0;
1496     r->additionalRecords = 0;
1497     return r;
1498 }
1499 
1500 jdns_response_t *jdns_response_copy(const jdns_response_t *r)
1501 {
1502     jdns_response_t *c = jdns_response_new();
1503     ARRAY_COPY(jdns_rr_t, r->answerRecords, r->answerCount, c->answerRecords, c->answerCount, jdns_rr_copy);
1504     ARRAY_COPY(jdns_rr_t, r->authorityRecords, r->authorityCount, c->authorityRecords, c->authorityCount, jdns_rr_copy);
1505     ARRAY_COPY(jdns_rr_t, r->additionalRecords, r->additionalCount, c->additionalRecords, c->additionalCount, jdns_rr_copy);
1506     return c;
1507 }
1508 
1509 void jdns_response_delete(jdns_response_t *r)
1510 {
1511     if(!r)
1512         return;
1513     ARRAY_DELETE(r->answerRecords, r->answerCount, jdns_rr_delete);
1514     ARRAY_DELETE(r->authorityRecords, r->authorityCount, jdns_rr_delete);
1515     ARRAY_DELETE(r->additionalRecords, r->additionalCount, jdns_rr_delete);
1516     jdns_free(r);
1517 }
1518 
1519 void jdns_response_append_answer(jdns_response_t *r, const jdns_rr_t *rr)
1520 {
1521     ARRAY_APPEND(jdns_rr_t, r->answerRecords, r->answerCount, jdns_rr_copy(rr));
1522 }
1523 
1524 void jdns_response_append_authority(jdns_response_t *r, const jdns_rr_t *rr)
1525 {
1526     ARRAY_APPEND(jdns_rr_t, r->authorityRecords, r->authorityCount, jdns_rr_copy(rr));
1527 }
1528 
1529 void jdns_response_append_additional(jdns_response_t *r, const jdns_rr_t *rr)
1530 {
1531     ARRAY_APPEND(jdns_rr_t, r->additionalRecords, r->additionalCount, jdns_rr_copy(rr));
1532 }
1533 
1534 void jdns_response_remove_extra(jdns_response_t *r)
1535 {
1536     ARRAY_DELETE(r->authorityRecords, r->authorityCount, jdns_rr_delete);
1537     ARRAY_DELETE(r->additionalRecords, r->additionalCount, jdns_rr_delete);
1538 }
1539 
1540 void jdns_response_remove_answer(jdns_response_t *r, int pos)
1541 {
1542     jdns_rr_t *rr = r->answerRecords[pos];
1543     jdns_rr_delete(rr);
1544 
1545     /* free the position */
1546     if(r->answerCount > 1)
1547     {
1548         memmove(r->answerRecords + pos, r->answerRecords + pos + 1, (r->answerCount - pos - 1) * sizeof(void *));
1549         --r->answerCount;
1550     }
1551     else
1552     {
1553         jdns_free(r->answerRecords);
1554         r->answerRecords = 0;
1555         r->answerCount = 0;
1556     }
1557 }