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

0001 /*
0002  * Copyright (C) 2005       Jeremie Miller
0003  * Copyright (C) 2005,2006  Justin Karneges
0004  *
0005  * Permission is hereby granted, free of charge, to any person obtaining a
0006  * copy of this software and associated documentation files (the
0007  * "Software"), to deal in the Software without restriction, including
0008  * without limitation the rights to use, copy, modify, merge, publish,
0009  * distribute, sublicense, and/or sell copies of the Software, and to
0010  * permit persons to whom the Software is furnished to do so, subject to
0011  * the following conditions:
0012  *
0013  * The above copyright notice and this permission notice shall be included
0014  * in all copies or substantial portions of the Software.
0015  *
0016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0017  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0018  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
0019  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
0020  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
0021  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
0022  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0023  */
0024 
0025 #include "jdns_mdnsd.h"
0026 
0027 #include <stdlib.h>
0028 #include <string.h>
0029 #ifdef WIN32
0030 # include <winsock2.h>
0031 #endif
0032 
0033 #define QTYPE_A     JDNS_RTYPE_A
0034 #define QTYPE_AAAA  JDNS_RTYPE_AAAA
0035 #define QTYPE_MX    JDNS_RTYPE_MX
0036 #define QTYPE_SRV   JDNS_RTYPE_SRV
0037 #define QTYPE_CNAME JDNS_RTYPE_CNAME
0038 #define QTYPE_PTR   JDNS_RTYPE_PTR
0039 #define QTYPE_TXT   JDNS_RTYPE_TXT
0040 #define QTYPE_HINFO JDNS_RTYPE_HINFO
0041 #define QTYPE_NS    JDNS_RTYPE_NS
0042 #define QTYPE_ANY   JDNS_RTYPE_ANY
0043 
0044 /* size of query/publish hashes */
0045 #define SPRIME 108
0046 /* size of cache hash */
0047 #define LPRIME 1009
0048 /* brute force garbage cleanup frequency, rarely needed (daily default) */
0049 #define GC 86400
0050 
0051 /* maximum number of items to cache.  if an attacker on the LAN advertises */
0052 /*   a million services, we don't want to crash our program trying to collect */
0053 /*   them all.  any dns records received beyond this max are ignored.  this */
0054 /*   means the attacker would succeed in DoS'ing the multicast dns network, */
0055 /*   but he wouldn't succeed in running our program out of memory. */
0056 #define MAX_CACHE 16384
0057 
0058 #define bzero(p, size) memset(p, 0, size)
0059 
0060 /* messy, but it's the best/simplest balance I can find at the moment
0061 Some internal data types, and a few hashes: querys, answers, cached, and records (published, unique and shared)
0062 Each type has different semantics for processing, both for timeouts, incoming, and outgoing I/O
0063 They inter-relate too, like records affect the querys they are relevant to
0064 Nice things about MDNS: we only publish once (and then ask asked), and only query once, then just expire records we've got cached
0065 */
0066 
0067 struct query
0068 {
0069     char *name;
0070     int type;
0071     unsigned long int nexttry;
0072     int tries;
0073     int (*answer)(mdnsda, void *);
0074     void *arg;
0075     struct query *next, *list;
0076 };
0077 
0078 struct unicast
0079 {
0080     int id;
0081     char ipv6;
0082     unsigned long int to;
0083     unsigned char to6[16];
0084     unsigned short int port;
0085     mdnsdr r;
0086     struct unicast *next;
0087 };
0088 
0089 struct cached
0090 {
0091     struct mdnsda_struct rr;
0092     struct query *q;
0093     struct cached *next;
0094 };
0095 
0096 struct mdnsdr_struct
0097 {
0098     struct mdnsda_struct rr;
0099     char unique; /* # of checks performed to ensure */
0100     int tries;
0101     void (*pubresult)(int, char *, int, void *);
0102     void *arg;
0103     struct mdnsdr_struct *next, *list;
0104 };
0105 
0106 struct mdnsd_struct
0107 {
0108     char shutdown;
0109     unsigned long int expireall, checkqlist;
0110     struct mytimeval now, sleep, pause, probe, publish;
0111     int class, frame;
0112     struct cached *cache[LPRIME];
0113     int cache_count;
0114     struct mdnsdr_struct *published[SPRIME], *probing, *a_now, *a_pause, *a_publish;
0115     struct unicast *uanswers;
0116     struct query *queries[SPRIME], *qlist;
0117     int (*cb_time_now)(struct mdnsd_struct *dp, void *arg);
0118     int (*cb_rand_int)(struct mdnsd_struct *dp, void *arg);
0119     void *cb_arg;
0120     int port;
0121 };
0122 
0123 void mygettimeofday(mdnsd d, struct mytimeval *tv)
0124 {
0125     /*struct timeval t; */
0126     /*gettimeofday(&t, 0); */
0127     /*tv->tv_sec = t.tv_sec; */
0128     /*tv->tv_usec = t.tv_usec; */
0129 
0130     int msec = d->cb_time_now(d, d->cb_arg);
0131     tv->tv_sec = msec / 1000;
0132     tv->tv_usec = (msec % 1000) * 1000;
0133 }
0134 
0135 void query_free(struct query *q)
0136 {
0137     jdns_free(q->name);
0138     jdns_free(q);
0139 }
0140 
0141 void mdnsda_content_free(struct mdnsda_struct *rr)
0142 {
0143     if(rr->name)
0144         jdns_free(rr->name);
0145     if(rr->rdata)
0146         jdns_free(rr->rdata);
0147     if(rr->rdname)
0148         jdns_free(rr->rdname);
0149 }
0150 
0151 int _namehash(const char *s)
0152 {
0153     const unsigned char *name = (const unsigned char *)s;
0154     unsigned long h = 0, g;
0155 
0156     while (*name)
0157     { /* do some fancy bitwanking on the string */
0158         h = (h << 4) + (unsigned long)(*name++);
0159         if ((g = (h & 0xF0000000UL))!=0)
0160             h ^= (g >> 24);
0161         h &= ~g;
0162     }
0163 
0164     return (int)h;
0165 }
0166 
0167 /* case-insensitive hash */
0168 int _namehash_nocase(const char *s)
0169 {
0170     int n, len;
0171     char *low = jdns_strdup(s);
0172     len = strlen(low);
0173     for(n = 0; n < len; ++n)
0174         low[n] = tolower(low[n]);
0175     n = _namehash(low);
0176     jdns_free(low);
0177     return n;
0178 }
0179 
0180 /* basic linked list and hash primitives */
0181 struct query *_q_next(mdnsd d, struct query *q, char *host, int type)
0182 {
0183     if(q == 0) q = d->queries[_namehash_nocase(host) % SPRIME];
0184     else q = q->next;
0185     for(;q != 0; q = q->next)
0186         if(q->type == type && jdns_domain_cmp((unsigned char *)q->name, (unsigned char *)host))
0187             return q;
0188     return 0;
0189 }
0190 struct cached *_c_next(mdnsd d, struct cached *c, char *host, int type)
0191 {
0192     if(c == 0) c = d->cache[_namehash_nocase(host) % LPRIME];
0193     else c = c->next;
0194     for(;c != 0; c = c->next)
0195         if((type == c->rr.type || type == 255) && jdns_domain_cmp(c->rr.name, (unsigned char *)host))
0196             return c;
0197     return 0;
0198 }
0199 mdnsdr _r_next(mdnsd d, mdnsdr r, char *host, int type)
0200 {
0201     if(r == 0) r = d->published[_namehash_nocase(host) % SPRIME];
0202     else r = r->next;
0203     for(;r != 0; r = r->next)
0204         if(type == r->rr.type && jdns_domain_cmp(r->rr.name, (unsigned char *)host))
0205             return r;
0206     return 0;
0207 }
0208 
0209 /*
0210 int _rr_len(mdnsda rr)
0211 {
0212     int len = 12;  // name is always compressed (dup of earlier), plus normal stuff
0213     if(rr->rdata) len += rr->rdlen;
0214     if(rr->rdname) len += strlen((char *)rr->rdname); // worst case 
0215     if(rr->ip) len += 4;
0216     if(rr->type == QTYPE_PTR) len += 6; // srv record stuff
0217     return len;
0218 }
0219 */
0220 
0221 /*
0222 int _a_match(struct resource *r, mdnsda a)
0223 { // compares new rdata with known a, painfully 
0224     if(strcmp((char *)r->name,(char *)a->name) || r->type != a->type) return 0;
0225     if(r->type == QTYPE_SRV && !strcmp((char *)r->known.srv.name,(char *)a->rdname) && a->srv.port == r->known.srv.port && a->srv.weight == r->known.srv.weight && a->srv.priority == r->known.srv.priority) return 1;
0226     if((r->type == QTYPE_PTR || r->type == QTYPE_NS || r->type == QTYPE_CNAME) && !strcmp((char *)a->rdname,(char *)r->known.ns.name)) return 1;
0227     if(r->rdlength == a->rdlen && !memcmp(r->rdata,a->rdata,r->rdlength)) return 1;
0228     return 0;
0229 }
0230 */
0231 
0232 int _a_match(const jdns_rr_t *r, mdnsda a)
0233 {
0234     if(r->type != a->type || !jdns_domain_cmp(r->owner, a->name))
0235         return 0;
0236     if(r->type == JDNS_RTYPE_SRV)
0237     {
0238         if(jdns_domain_cmp(r->data.server->name, a->rdname)
0239             && r->data.server->port == a->srv.port
0240             && r->data.server->priority == a->srv.priority
0241             && r->data.server->weight == a->srv.weight
0242         )
0243             return 1;
0244     }
0245     else if(r->type == JDNS_RTYPE_PTR || r->type == JDNS_RTYPE_NS || r->type == JDNS_RTYPE_CNAME)
0246     {
0247         if(jdns_domain_cmp(r->data.name, a->rdname))
0248             return 1;
0249     }
0250     else if(r->rdlength == a->rdlen && !memcmp(r->rdata, a->rdata, r->rdlength))
0251         return 1;
0252 
0253     return 0;
0254 }
0255 
0256 /* compare time values easily */
0257 int _tvdiff(struct mytimeval old, struct mytimeval new)
0258 {
0259     int udiff = 0;
0260     if(old.tv_sec != new.tv_sec) udiff = (new.tv_sec - old.tv_sec) * 1000000;
0261     return (new.tv_usec - old.tv_usec) + udiff;
0262 }
0263 
0264 /* make sure not already on the list, then insert */
0265 void _r_push(mdnsdr *list, mdnsdr r)
0266 {
0267     mdnsdr cur;
0268     for(cur = *list; cur != 0; cur = cur->list)
0269         if(cur == r) return;
0270     r->list = *list;
0271     *list = r;
0272 }
0273 
0274 /* set this r to probing, set next probe time */
0275 void _r_probe(mdnsd d, mdnsdr r)
0276 {
0277     (void)d;
0278     (void)r;
0279 }
0280 
0281 /* force any r out right away, if valid */
0282 void _r_publish(mdnsd d, mdnsdr r)
0283 {
0284     if(r->unique && r->unique < 5) return; /* probing already */
0285     r->tries = 0;
0286     d->publish.tv_sec = d->now.tv_sec; d->publish.tv_usec = d->now.tv_usec;
0287     _r_push(&d->a_publish,r);
0288 }
0289 
0290 /* send r out asap */
0291 void _r_send(mdnsd d, mdnsdr r)
0292 {
0293     /* removing record */
0294     if(r->rr.ttl == 0)
0295     {
0296         if(d->a_publish == r)
0297             d->a_publish = r->list;
0298         _r_push(&d->a_now, r);
0299         return;
0300     }
0301 
0302     if(r->tries < 4)
0303     { /* being published, make sure that happens soon */
0304         d->publish.tv_sec = d->now.tv_sec; d->publish.tv_usec = d->now.tv_usec;
0305         return;
0306     }
0307     if(r->unique)
0308     { /* known unique ones can be sent asap */
0309         _r_push(&d->a_now,r);
0310         return;
0311     }
0312     /* set d->pause.tv_usec to random 20-120 msec */
0313     d->pause.tv_sec = d->now.tv_sec;
0314     /*d->pause.tv_usec = d->now.tv_usec + ((d->now.tv_usec % 100) + 20) * 1000; */
0315     d->pause.tv_usec = d->now.tv_usec;
0316     d->pause.tv_usec += ((d->cb_rand_int(d, d->cb_arg) % 100) + 20) * 1000;
0317     _r_push(&d->a_pause,r);
0318 }
0319 
0320 /* create generic unicast response struct */
0321 void _u_push(mdnsd d, mdnsdr r, int id, const jdns_address_t *addr, unsigned short int port)
0322 {
0323     struct unicast *u;
0324     u = (struct unicast *)jdns_alloc(sizeof(struct unicast));
0325     bzero(u,sizeof(struct unicast));
0326     u->r = r;
0327     u->id = id;
0328     if(addr->isIpv6)
0329     {
0330         u->ipv6 = 1;
0331         memcpy(u->to6, addr->addr.v6, 16);
0332     }
0333     else
0334     {
0335         u->ipv6 = 0;
0336         u->to = addr->addr.v4;
0337     }
0338     u->port = port;
0339     u->next = d->uanswers;
0340     d->uanswers = u;
0341 }
0342 
0343 void _q_reset(mdnsd d, struct query *q)
0344 {
0345     struct cached *cur = 0;
0346     q->nexttry = 0;
0347     q->tries = 0;
0348     while((cur = _c_next(d,cur,q->name,q->type)))
0349         if(q->nexttry == 0 || cur->rr.ttl - 7 < q->nexttry) q->nexttry = cur->rr.ttl - 7;
0350     if(q->nexttry != 0 && q->nexttry < d->checkqlist) d->checkqlist = q->nexttry;
0351 }
0352 
0353 void _q_done(mdnsd d, struct query *q)
0354 { /* no more query, update all it's cached entries, remove from lists */
0355     struct cached *c = 0;
0356     struct query *cur;
0357     int i = _namehash_nocase(q->name) % SPRIME;
0358     while((c = _c_next(d,c,q->name,q->type))) c->q = 0;
0359     if(d->qlist == q) d->qlist = q->list;
0360     else {
0361         for(cur=d->qlist;cur->list != q;cur = cur->list);
0362         cur->list = q->list;
0363     }
0364     if(d->queries[i] == q) d->queries[i] = q->next;
0365     else {
0366         for(cur=d->queries[i];cur->next != q;cur = cur->next);
0367         cur->next = q->next;
0368     }
0369     query_free(q);
0370 }
0371 
0372 void _r_done(mdnsd d, mdnsdr r)
0373 { /* buh-bye, remove from hash and free */
0374     mdnsdr cur = 0;
0375     int i = _namehash_nocase((char *)r->rr.name) % SPRIME;
0376     if(d->a_now == r)
0377         d->a_now = r->list;
0378     if(d->a_pause == r)
0379         d->a_pause = r->list;
0380     if(d->a_publish == r)
0381         d->a_publish = r->list;
0382     if(d->published[i] == r) d->published[i] = r->next;
0383     else {
0384         for(cur=d->published[i];cur && cur->next != r;cur = cur->next);
0385         if(cur) cur->next = r->next;
0386     }
0387     mdnsda_content_free(&r->rr);
0388     jdns_free(r);
0389 }
0390 
0391 void _q_answer(mdnsd d, struct cached *c)
0392 { /* call the answer function with this cached entry */
0393     if(c->rr.ttl <= d->now.tv_sec) c->rr.ttl = 0;
0394     if(c->q->answer(&c->rr,c->q->arg) == -1) _q_done(d, c->q);
0395 }
0396 
0397 void _conflict(mdnsd d, mdnsdr r)
0398 {
0399     r->pubresult(0, (char *)r->rr.name,r->rr.type,r->arg);
0400     mdnsd_done(d,r);
0401 }
0402 
0403 void _published(mdnsd d, mdnsdr r)
0404 {
0405     (void)d;
0406     r->pubresult(1, (char *)r->rr.name,r->rr.type,r->arg);
0407 }
0408 
0409 void _c_expire(mdnsd d, struct cached **list)
0410 { /* expire any old entries in this list */
0411     struct cached *next, *cur = *list, *last = 0;
0412     while(cur != 0)
0413     {
0414         next = cur->next;
0415         if(d->now.tv_sec >= cur->rr.ttl)
0416         {
0417             if(last) last->next = next;
0418             if(*list == cur) *list = next; /* update list pointer if the first one expired */
0419             --(d->cache_count);
0420             if(cur->q) _q_answer(d,cur);
0421             mdnsda_content_free(&cur->rr);
0422             jdns_free(cur);
0423         }else{
0424             last = cur;
0425         }
0426         cur = next;
0427     }
0428 }
0429 
0430 /* brute force expire any old cached records */
0431 void _gc(mdnsd d)
0432 {
0433     int i;
0434     for(i=0;i<LPRIME;i++)
0435         if(d->cache[i]) _c_expire(d,&d->cache[i]);
0436     d->expireall = d->now.tv_sec + GC;
0437 }
0438 
0439 struct cached *_find_exact(mdnsd d, const jdns_rr_t *r)
0440 {
0441     struct cached *c = 0;
0442     while(1)
0443     {
0444         c = _c_next(d, c, (char *)r->owner, r->type);
0445         if(!c)
0446             break;
0447         if(_a_match(r, &c->rr))
0448             return c;
0449     }
0450     return 0;
0451 }
0452 
0453 void _cache(mdnsd d, const jdns_rr_t *r)
0454 {
0455     struct cached *c;
0456     int i = _namehash_nocase((char *)r->owner) % LPRIME;
0457     struct cached *same_value;
0458 
0459     /* do we already have it? */
0460     /*printf("cache: checking for entry: [%s] [%d]\n", r->owner, r->type); */
0461     same_value = _find_exact(d, r);
0462     if(same_value)
0463     {
0464         /*printf("already have entry of same value\n"); */
0465     }
0466 
0467     if(r->qclass == 32768 + d->class)
0468     { /* cache flush */
0469         /* simulate removal of all records for this question, */
0470         /*   except if the value hasn't changed */
0471         c = 0;
0472         while((c = _c_next(d,c,(char *)r->owner,r->type)))
0473         {
0474             if(c != same_value)
0475                 c->rr.ttl = 0;
0476         }
0477         _c_expire(d,&d->cache[i]);
0478 
0479         /* we may have expired same_value here, so check for it again */
0480         same_value = _find_exact(d, r);
0481     }
0482 
0483     if(r->ttl == 0)
0484     { /* process deletes */
0485         if(same_value)
0486             same_value->rr.ttl = 0;
0487         _c_expire(d,&d->cache[i]);
0488         return;
0489     }
0490 
0491     if(same_value)
0492     {
0493         /*printf("updating ttl only\n"); */
0494 
0495         /* only update ttl (this code directly copied from below) */
0496         same_value->rr.ttl = d->now.tv_sec + (r->ttl / 2) + 8;
0497         same_value->rr.real_ttl = r->ttl;
0498         return;
0499     }
0500 
0501     /*printf("cache: inserting entry:    [%s] [%d]\n", r->owner, r->type); */
0502     if(d->cache_count >= MAX_CACHE)
0503         return;
0504 
0505     c = (struct cached *)jdns_alloc(sizeof(struct cached));
0506     bzero(c,sizeof(struct cached));
0507     c->rr.name = (unsigned char *)jdns_strdup((char *)r->owner);
0508     c->rr.type = r->type;
0509     c->rr.ttl = d->now.tv_sec + (r->ttl / 2) + 8; /* XXX hack for now, BAD SPEC, start retrying just after half-waypoint, then expire */
0510     c->rr.real_ttl = r->ttl;
0511     c->rr.rdlen = r->rdlength;
0512     c->rr.rdata = jdns_copy_array(r->rdata, r->rdlength);
0513     switch(r->type)
0514     {
0515     case QTYPE_A:
0516         c->rr.ip = r->data.address->addr.v4;
0517         break;
0518     case QTYPE_NS:
0519     case QTYPE_CNAME:
0520     case QTYPE_PTR:
0521         c->rr.rdname = (unsigned char *)jdns_strdup((const char *)r->data.name);
0522         break;
0523     case QTYPE_SRV:
0524         c->rr.rdname = (unsigned char *)jdns_strdup((const char *)r->data.server->name);
0525         c->rr.srv.port = r->data.server->port;
0526         c->rr.srv.weight = r->data.server->weight;
0527         c->rr.srv.priority = r->data.server->priority;
0528         break;
0529     }
0530     c->next = d->cache[i];
0531     d->cache[i] = c;
0532     if((c->q = _q_next(d, 0, (char *)r->owner, r->type)))
0533         _q_answer(d,c);
0534     if(c->q && c->q->nexttry == 0)
0535     {
0536         /*printf("cache insert, but nexttry == 0\n"); */
0537         _q_reset(d,c->q);
0538         if(d->checkqlist == 0)
0539             d->checkqlist = c->q->nexttry;
0540         /*printf("after reset: q->nexttry=%d d->checkqlist=%d\n", c->q->nexttry, d->checkqlist); */
0541     }
0542 }
0543 
0544 /*
0545 void _a_copy(struct message *m, mdnsda a)
0546 {  copy the data bits only 
0547     if(a->rdata) { message_rdata_raw(m, a->rdata, a->rdlen); return; }
0548     if(a->ip) message_rdata_long(m, a->ip);
0549     if(a->type == QTYPE_SRV) message_rdata_srv(m, a->srv.priority, a->srv.weight, a->srv.port, a->rdname);
0550     else if(a->rdname) message_rdata_name(m, a->rdname);
0551 }
0552 */
0553 
0554 void _a_copyq(jdns_list_t *dest, unsigned char *name, unsigned short type, unsigned short class)
0555 {
0556     jdns_packet_question_t *q = jdns_packet_question_new();
0557     q->qname = jdns_string_new();
0558     jdns_string_set_cstr(q->qname, (char *)name);
0559     q->qtype = type;
0560     q->qclass = class;
0561     jdns_list_insert(dest, q, -1);
0562     jdns_packet_question_delete(q);
0563 }
0564 
0565 void _a_copy(jdns_list_t *dest, unsigned char *name, unsigned short type, unsigned short class, unsigned long int ttl, mdnsda a)
0566 {
0567     jdns_packet_resource_t *r = jdns_packet_resource_new();
0568     r->qname = jdns_string_new();
0569     jdns_string_set_cstr(r->qname, (char *)name);
0570     r->qtype = type;
0571     r->qclass = class;
0572     r->ttl = ttl;
0573     if(a->rdata)
0574         jdns_packet_resource_add_bytes(r, a->rdata, a->rdlen);
0575     else if(a->ip)
0576     {
0577         unsigned long int ip;
0578         ip = htonl(a->ip);
0579         jdns_packet_resource_add_bytes(r, (unsigned char *)&ip, 4);
0580     }
0581     else if(a->type == QTYPE_SRV)
0582     {
0583         unsigned short priority, weight, port;
0584         jdns_string_t *name;
0585         priority = htons(a->srv.priority);
0586         weight = htons(a->srv.weight);
0587         port = htons(a->srv.port);
0588         name = jdns_string_new();
0589         jdns_string_set_cstr(name, (const char *)a->rdname);
0590         jdns_packet_resource_add_bytes(r, (unsigned char *)&priority, 2);
0591         jdns_packet_resource_add_bytes(r, (unsigned char *)&weight, 2);
0592         jdns_packet_resource_add_bytes(r, (unsigned char *)&port, 2);
0593         jdns_packet_resource_add_name(r, name);
0594         jdns_string_delete(name);
0595     }
0596     else if(a->rdname)
0597     {
0598         jdns_string_t *name;
0599         name = jdns_string_new();
0600         jdns_string_set_cstr(name, (const char *)a->rdname);
0601         jdns_packet_resource_add_name(r, name);
0602         jdns_string_delete(name);
0603     }
0604     jdns_list_insert(dest, r, -1);
0605     jdns_packet_resource_delete(r);
0606 }
0607 
0608 /*
0609 int _r_out(mdnsd d, struct message *m, mdnsdr *list)
0610 { // copy a published record into an outgoing message 
0611     mdnsdr r; //, next; 
0612     int ret = 0;
0613     while((r = *list) != 0 && message_packet_len(m) + _rr_len(&r->rr) < d->frame)
0614     {
0615         *list = r->list;
0616         ret++;
0617         if(r->unique)
0618             message_an(m, r->rr.name, r->rr.type, (unsigned short)(d->class + 32768), r->rr.ttl);
0619         else
0620             message_an(m, r->rr.name, r->rr.type, (unsigned short)d->class, r->rr.ttl);
0621         _a_copy(m, &r->rr);
0622         if(r->rr.ttl == 0) _r_done(d,r);
0623     }
0624     return ret;
0625 }
0626 */
0627 
0628 int _r_out(mdnsd d, jdns_packet_t *m, mdnsdr *list)
0629 { /* copy a published record into an outgoing message */
0630     mdnsdr r; /*, next; */
0631     unsigned short class;
0632     int ret = 0;
0633     while((r = *list) != 0)
0634     {
0635         *list = r->list;
0636         ret++;
0637         class = r->unique ? d->class | 0x8000 : d->class;
0638         _a_copy(m->answerRecords, r->rr.name, r->rr.type, class, r->rr.ttl, &r->rr);
0639         if(r->rr.ttl == 0) _r_done(d,r);
0640     }
0641     return ret;
0642 }
0643 
0644 
0645 mdnsd mdnsd_new(int class, int frame, int port, int (*time_now)(mdnsd d, void *arg), int (*rand_int)(mdnsd d, void *arg), void *arg)
0646 {
0647     /*int i; */
0648     mdnsd d;
0649     d = (mdnsd)jdns_alloc(sizeof(struct mdnsd_struct));
0650     bzero(d,sizeof(struct mdnsd_struct));
0651     d->cb_time_now = time_now;
0652     d->cb_rand_int = rand_int;
0653     d->cb_arg = arg;
0654     mygettimeofday(d, &d->now);
0655     d->expireall = d->now.tv_sec + GC;
0656     d->class = class;
0657     d->frame = frame;
0658     d->cache_count = 0;
0659     d->port = port;
0660     return d;
0661 }
0662 
0663 void mdnsd_shutdown(mdnsd d)
0664 { /* shutting down, zero out ttl and push out all records */
0665     int i;
0666     mdnsdr cur,next;
0667     d->a_now = 0;
0668     for(i=0;i<SPRIME;i++)
0669         for(cur = d->published[i]; cur != 0;)
0670         {
0671             next = cur->next;
0672             cur->rr.ttl = 0;
0673             cur->list = d->a_now;
0674             d->a_now = cur;
0675             cur = next;
0676         }
0677     d->shutdown = 1;
0678 }
0679 
0680 void mdnsd_flush(mdnsd d)
0681 {
0682     /* set all querys to 0 tries */
0683     /* free whole cache */
0684     /* set all mdnsdr to probing */
0685     /* reset all answer lists */
0686 
0687     (void)d;
0688 }
0689 
0690 void mdnsd_free(mdnsd d)
0691 {
0692     int i;
0693 
0694     /* loop through all hashes, free everything */
0695     /* free answers if any */
0696 
0697     for(i = 0; i < LPRIME; ++i)
0698     {
0699         while(d->cache[i])
0700         {
0701             struct cached *cur = d->cache[i];
0702             d->cache[i] = cur->next;
0703             mdnsda_content_free(&cur->rr);
0704             jdns_free(cur);
0705         }
0706     }
0707 
0708     for(i = 0; i < SPRIME; ++i)
0709     {
0710         while(d->published[i])
0711         {
0712             struct mdnsdr_struct *cur = d->published[i];
0713             d->published[i] = cur->next;
0714             mdnsda_content_free(&cur->rr);
0715             jdns_free(cur);
0716         }
0717     }
0718 
0719     while(d->uanswers)
0720     {
0721         struct unicast *u = d->uanswers;
0722         d->uanswers = u->next;
0723         jdns_free(u);
0724     }
0725 
0726     for(i = 0; i < SPRIME; ++i)
0727     {
0728         while(d->queries[i])
0729         {
0730             struct query *cur = d->queries[i];
0731             d->queries[i] = cur->next;
0732             query_free(cur);
0733         }
0734     }
0735 
0736     jdns_free(d);
0737 }
0738 
0739 void mdnsd_in(mdnsd d, const jdns_packet_t *m, const jdns_response_t *resp, const jdns_address_t *addr, unsigned short int port)
0740 {
0741     int i, j;
0742     mdnsdr r = 0;
0743 
0744     if(d->shutdown) return;
0745 
0746     mygettimeofday(d, &d->now);
0747 
0748     if(m->opts.qr == 0)
0749     {
0750         for(i=0;i<m->questions->count;i++)
0751         { /* process each query */
0752             jdns_packet_question_t *pq = (jdns_packet_question_t *)m->questions->item[i];
0753 
0754             if(pq->qclass != d->class || (r = _r_next(d,0,(char *)pq->qname->data,pq->qtype)) == 0) continue;
0755 
0756             /* send the matching unicast reply */
0757             if(port != d->port) _u_push(d,r,m->id,addr,port);
0758 
0759             for(;r != 0; r = _r_next(d,r,(char *)pq->qname->data,pq->qtype))
0760             { /* check all of our potential answers */
0761                 if(r->unique && r->unique < 5)
0762                 { /* probing state, check for conflicts */
0763                     for(j=0;j<resp->authorityCount;j++)
0764                     { /* check all to-be answers against our own */
0765                         jdns_rr_t *ns = resp->authorityRecords[j];
0766                         if(pq->qtype != ns->type || !jdns_domain_cmp(pq->qname->data, ns->owner)) continue;
0767                         if(!_a_match(ns,&r->rr))
0768                         {
0769                             _conflict(d,r); /* answer isn't ours, conflict! */
0770 
0771                             /* r is invalid after conflict, start all over */
0772                             r = 0;
0773                             break;
0774                         }
0775                     }
0776                     continue;
0777                 }
0778                 for(j=0;j<resp->answerCount;j++)
0779                 { /* check the known answers for this question */
0780                     jdns_rr_t *an = resp->answerRecords[j];
0781                     if(pq->qtype != an->type || !jdns_domain_cmp(pq->qname->data, an->owner)) continue;
0782                     if(_a_match(an,&r->rr)) break; /* they already have this answer */
0783                 }
0784                 if(j == resp->answerCount) _r_send(d,r);
0785             }
0786         }
0787         return;
0788     }
0789 
0790     for(i=0;i<resp->answerCount;i++)
0791     { /* process each answer, check for a conflict, and cache */
0792         jdns_rr_t *an = resp->answerRecords[i];
0793         if((r = _r_next(d,0,(char *)an->owner,an->type)) != 0 && r->unique && _a_match(an,&r->rr) == 0) _conflict(d,r);
0794         _cache(d,an);
0795     }
0796 
0797     /* cache additional records */
0798     for(i=0;i<resp->additionalCount;i++)
0799     {
0800         jdns_rr_t *an = resp->additionalRecords[i];
0801         _cache(d,an);
0802     }
0803 }
0804 
0805 int mdnsd_out(mdnsd d, jdns_packet_t **_m, jdns_address_t **addr, unsigned short int *port)
0806 {
0807     mdnsdr r;
0808     int ret = 0;
0809     jdns_packet_t *m;
0810 
0811     mygettimeofday(d, &d->now);
0812     /*bzero(m,sizeof(struct message)); */
0813     m = jdns_packet_new();
0814 
0815     /* defaults, multicast */
0816     *port = 0; /*htons(5353); */
0817     *addr = 0;
0818     /* *ip = 0; //inet_addr("224.0.0.251"); */
0819     m->opts.qr = 1;
0820     m->opts.aa = 1;
0821 
0822     if(d->uanswers)
0823     { /* send out individual unicast answers */
0824         struct unicast *u = d->uanswers;
0825         d->uanswers = u->next;
0826         *port = u->port;
0827         /* *ip = u->to; */
0828         *addr = jdns_address_new();
0829         if(u->ipv6)
0830             jdns_address_set_ipv6(*addr, u->to6);
0831         else
0832             jdns_address_set_ipv4(*addr, u->to);
0833         m->id = u->id;
0834         _a_copyq(m->questions, u->r->rr.name, u->r->rr.type, (unsigned short)d->class);
0835         _a_copy(m->answerRecords, u->r->rr.name, u->r->rr.type, (unsigned short)d->class, u->r->rr.ttl, &u->r->rr);
0836         jdns_free(u);
0837         ret = 1;
0838         goto end;
0839     }
0840 
0841 /*printf("OUT: probing %X now %X pause %X publish %X\n",d->probing,d->a_now,d->a_pause,d->a_publish); */
0842 
0843     /* accumulate any immediate responses */
0844     if(d->a_now) { ret += _r_out(d, m, &d->a_now); }
0845 
0846     if(d->a_publish && _tvdiff(d->now,d->publish) <= 0)
0847     { /* check to see if it's time to send the publish retries (and unlink if done) */
0848         mdnsdr next, cur = d->a_publish, last = 0;
0849         unsigned short class;
0850         while(cur /*&& message_packet_len(m) + _rr_len(&cur->rr) < d->frame*/ )
0851         {
0852             next = cur->list;
0853             ret++; cur->tries++;
0854             class = cur->unique ? d->class | 0x8000 : d->class;
0855             _a_copy(m->answerRecords, cur->rr.name, cur->rr.type, class, cur->rr.ttl, &cur->rr);
0856 
0857             if(cur->rr.ttl != 0 && cur->tries < 4)
0858             {
0859                 last = cur;
0860                 cur = next;
0861                 continue;
0862             }
0863             if(d->a_publish == cur) d->a_publish = next;
0864             if(last) last->list = next;
0865             if(cur->rr.ttl == 0) _r_done(d,cur);
0866             cur = next;
0867         }
0868         if(d->a_publish)
0869         {
0870             d->publish.tv_sec = d->now.tv_sec + 2;
0871             d->publish.tv_usec = d->now.tv_usec;
0872         }
0873     }
0874 
0875     /* if we're in shutdown, we're done */
0876     if(d->shutdown)
0877         goto end;
0878 
0879     /* check if a_pause is ready */
0880     if(d->a_pause && _tvdiff(d->now, d->pause) <= 0) ret += _r_out(d, m, &d->a_pause);
0881 
0882     /* now process questions */
0883     if(ret)
0884         goto end;
0885     m->opts.qr = 0;
0886     m->opts.aa = 0;
0887 
0888     if(d->probing && _tvdiff(d->now,d->probe) <= 0)
0889     {
0890         mdnsdr last = 0;
0891         for(r = d->probing; r != 0;)
0892         { /* scan probe list to ask questions and process published */
0893             if(r->unique == 4)
0894             { /* done probing, publish */
0895                 mdnsdr next = r->list;
0896                 if(d->probing == r)
0897                     d->probing = r->list;
0898                 else
0899                     last->list = r->list;
0900                 r->list = 0;
0901                 r->unique = 5;
0902                 _r_publish(d,r);
0903                 _published(d,r);
0904                 r = next;
0905                 continue;
0906             }
0907             /*message_qd(m, r->rr.name, r->rr.type, (unsigned short)d->class); */
0908             _a_copyq(m->questions, r->rr.name, r->rr.type, (unsigned short)d->class);
0909             last = r;
0910             r = r->list;
0911         }
0912         for(r = d->probing; r != 0; last = r, r = r->list)
0913         { /* scan probe list again to append our to-be answers */
0914             r->unique++;
0915             _a_copy(m->authorityRecords, r->rr.name, r->rr.type, (unsigned short)d->class, r->rr.ttl, &r->rr);
0916             ret++;
0917         }
0918         if(ret)
0919         { /* process probes again in the future */
0920             d->probe.tv_sec = d->now.tv_sec;
0921             d->probe.tv_usec = d->now.tv_usec + 250000;
0922             goto end;
0923         }
0924     }
0925 
0926     if(d->checkqlist && d->now.tv_sec >= d->checkqlist)
0927     { /* process qlist for retries or expirations */
0928         struct query *q;
0929         struct cached *c;
0930         unsigned long int nextbest = 0;
0931 
0932         /* ask questions first, track nextbest time */
0933         for(q = d->qlist; q != 0; q = q->list)
0934             if(q->nexttry > 0 && q->nexttry <= d->now.tv_sec && q->tries < 3)
0935                 _a_copyq(m->questions, (unsigned char *)q->name, (unsigned short)q->type, (unsigned short)d->class);
0936             else if(q->nexttry > 0 && (nextbest == 0 || q->nexttry < nextbest))
0937                 nextbest = q->nexttry;
0938 
0939         /* include known answers, update questions */
0940         for(q = d->qlist; q != 0; q = q->list)
0941         {
0942             if(q->nexttry == 0 || q->nexttry > d->now.tv_sec) continue;
0943             if(q->tries == 3)
0944             { /* done retrying, expire and reset */
0945                 _c_expire(d,&d->cache[_namehash_nocase(q->name) % LPRIME]);
0946                 _q_reset(d,q);
0947                 continue;
0948             }
0949             ret++;
0950             q->nexttry = d->now.tv_sec + ++q->tries;
0951             if(nextbest == 0 || q->nexttry < nextbest)
0952                 nextbest = q->nexttry;
0953             /* if room, add all known good entries */
0954             c = 0;
0955             while((c = _c_next(d,c,q->name,q->type)) != 0 && c->rr.ttl > d->now.tv_sec + 8 /* && message_packet_len(m) + _rr_len(&c->rr) < d->frame */)
0956             {
0957                 _a_copy(m->answerRecords, (unsigned char *)q->name, (unsigned short)q->type, (unsigned short)d->class, (unsigned long int)(c->rr.ttl - d->now.tv_sec), &c->rr);
0958             }
0959         }
0960         d->checkqlist = nextbest;
0961     }
0962 
0963     if(d->now.tv_sec > d->expireall)
0964         _gc(d);
0965 
0966 end:
0967     if(ret)
0968         *_m = m;
0969     else
0970         jdns_packet_delete(m);
0971 
0972     return ret;
0973 }
0974 
0975 struct mytimeval *mdnsd_sleep(mdnsd d)
0976 {
0977     int sec, usec;
0978     /*mdnsdr r; */
0979     d->sleep.tv_sec = d->sleep.tv_usec = 0;
0980     #define RET while(d->sleep.tv_usec > 1000000) {d->sleep.tv_sec++;d->sleep.tv_usec -= 1000000;} return &d->sleep;
0981 
0982     /* first check for any immediate items to handle */
0983     if(d->uanswers || d->a_now) return &d->sleep;
0984 
0985     mygettimeofday(d, &d->now);
0986 
0987     if(d->a_pause)
0988     { /* then check for paused answers */
0989         if((usec = _tvdiff(d->now,d->pause)) > 0) d->sleep.tv_usec = usec;
0990         RET;
0991     }
0992 
0993     if(d->probing)
0994     { /* now check for probe retries */
0995         if((usec = _tvdiff(d->now,d->probe)) > 0) d->sleep.tv_usec = usec;
0996         RET;
0997     }
0998 
0999     if(d->a_publish)
1000     { /* now check for publish retries */
1001         if((usec = _tvdiff(d->now,d->publish)) > 0) d->sleep.tv_usec = usec;
1002         RET;
1003     }
1004 
1005     if(d->checkqlist)
1006     { /* also check for queries with known answer expiration/retry */
1007         if((sec = d->checkqlist - d->now.tv_sec) > 0) d->sleep.tv_sec = sec;
1008         RET;
1009     }
1010 
1011     /* last resort, next gc expiration */
1012     if((sec = d->expireall - d->now.tv_sec) > 0) d->sleep.tv_sec = sec;
1013     RET;
1014 }
1015 
1016 void mdnsd_query(mdnsd d, char *host, int type, int (*answer)(mdnsda a, void *arg), void *arg)
1017 {
1018     struct query *q;
1019     struct cached *cur = 0;
1020     int i = _namehash_nocase(host) % SPRIME;
1021     if(!(q = _q_next(d,0,host,type)))
1022     {
1023         if(!answer) return;
1024         q = (struct query *)jdns_alloc(sizeof(struct query));
1025         bzero(q,sizeof(struct query));
1026         q->name = jdns_strdup(host);
1027         q->type = type;
1028         q->next = d->queries[i];
1029         q->list = d->qlist;
1030         d->qlist = d->queries[i] = q;
1031         q->answer = answer;
1032         q->arg = arg;
1033         while((cur = _c_next(d,cur,q->name,q->type)))
1034         {
1035             cur->q = q; /* any cached entries should be associated */
1036             _q_answer(d,cur); /* and reported! */
1037         }
1038         _q_reset(d,q);
1039         q->nexttry = d->checkqlist = d->now.tv_sec; /* new questin, immediately send out */
1040     return;
1041     }
1042     if(!answer)
1043     { /* no answer means we don't care anymore */
1044         _q_done(d,q);
1045         return;
1046     }
1047     q->answer = answer;
1048     q->arg = arg;
1049 }
1050 
1051 mdnsda mdnsd_list(mdnsd d, char *host, int type, mdnsda last)
1052 {
1053     return (mdnsda)_c_next(d,(struct cached *)last,host,type);
1054 }
1055 
1056 mdnsdr mdnsd_shared(mdnsd d, char *host, int type, long int ttl)
1057 {
1058     int i = _namehash_nocase(host) % SPRIME;
1059     mdnsdr r;
1060     r = (mdnsdr)jdns_alloc(sizeof(struct mdnsdr_struct));
1061     bzero(r,sizeof(struct mdnsdr_struct));
1062     r->rr.name = (unsigned char *)jdns_strdup(host);
1063     r->rr.type = type;
1064     r->rr.ttl = ttl;
1065     r->next = d->published[i];
1066     d->published[i] = r;
1067     return r;
1068 }
1069 
1070 mdnsdr mdnsd_unique(mdnsd d, char *host, int type, long int ttl, void (*pubresult)(int result, char *host, int type, void *arg), void *arg)
1071 {
1072     mdnsdr r;
1073     r = mdnsd_shared(d,host,type,ttl);
1074     r->pubresult = pubresult;
1075     r->arg = arg;
1076     r->unique = 1;
1077     _r_push(&d->probing,r);
1078     d->probe.tv_sec = d->now.tv_sec;
1079     d->probe.tv_usec = d->now.tv_usec;
1080     return r;
1081 }
1082 
1083 void mdnsd_done(mdnsd d, mdnsdr r)
1084 {
1085     mdnsdr cur;
1086     if(r->unique && r->unique < 5)
1087     { /* probing yet, zap from that list first! */
1088         if(d->probing == r) d->probing = r->list;
1089         else {
1090             for(cur=d->probing;cur->list != r;cur = cur->list);
1091             cur->list = r->list;
1092         }
1093         _r_done(d,r);
1094         return;
1095     }
1096     r->rr.ttl = 0;
1097     _r_send(d,r);
1098 }
1099 
1100 void mdnsd_set_raw(mdnsd d, mdnsdr r, char *data, int len)
1101 {
1102     if(r->rr.rdata)
1103         jdns_free(r->rr.rdata);
1104     r->rr.rdata = jdns_copy_array((unsigned char*)data, len);
1105     r->rr.rdlen = len;
1106     _r_publish(d,r);
1107 }
1108 
1109 void mdnsd_set_host(mdnsd d, mdnsdr r, char *name)
1110 {
1111     jdns_free(r->rr.rdname);
1112     r->rr.rdname = (unsigned char *)jdns_strdup(name);
1113     _r_publish(d,r);
1114 }
1115 
1116 void mdnsd_set_ip(mdnsd d, mdnsdr r, unsigned long int ip)
1117 {
1118     r->rr.ip = ip;
1119     _r_publish(d,r);
1120 }
1121 
1122 void mdnsd_set_srv(mdnsd d, mdnsdr r, int priority, int weight, int port, char *name)
1123 {
1124     r->rr.srv.priority = priority;
1125     r->rr.srv.weight = weight;
1126     r->rr.srv.port = port;
1127     mdnsd_set_host(d,r,name);
1128 }