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 }