File indexing completed on 2024-05-19 04:06:36
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 <time.h> 0027 #ifdef WIN32 0028 # include <winsock2.h> 0029 #endif 0030 0031 #include "jdns_packet.h" 0032 #include "jdns_mdnsd.h" 0033 0034 #define JDNS_UDP_UNI_OUT_MAX 512 0035 #define JDNS_UDP_UNI_IN_MAX 16384 0036 #define JDNS_UDP_MUL_OUT_MAX 9000 0037 #define JDNS_UDP_MUL_IN_MAX 16384 0038 0039 /* cache no more than 7 days */ 0040 #define JDNS_TTL_MAX (86400 * 7) 0041 #define JDNS_CACHE_MAX 16384 0042 #define JDNS_CNAME_MAX 16 0043 #define JDNS_QUERY_MAX 4096 0044 0045 /*---------------------------------------------------------------------------- */ 0046 /* util */ 0047 /*---------------------------------------------------------------------------- */ 0048 0049 /* declare this here, but implement it later after we define jdns_session_t */ 0050 static void _debug_line(jdns_session_t *s, const char *format, ...); 0051 0052 static unsigned char _hex_nibble(unsigned char c) 0053 { 0054 if(c <= 9) 0055 return '0' + c; 0056 else if(c <= 15) 0057 return 'a' + (c - 10); 0058 else 0059 return '?'; 0060 } 0061 0062 static void _hex_byte(unsigned char c, unsigned char *dest) 0063 { 0064 dest[0] = _hex_nibble((unsigned char)(c >> 4)); 0065 dest[1] = _hex_nibble((unsigned char)(c & 0x0f)); 0066 } 0067 0068 static jdns_string_t *_make_printable(const unsigned char *str, int size) 0069 { 0070 unsigned char *buf; 0071 int n, i; 0072 jdns_string_t *out; 0073 0074 if(size == 0) 0075 { 0076 out = jdns_string_new(); 0077 jdns_string_set_cstr(out, ""); 0078 return out; 0079 } 0080 0081 /* make room for the largest possible result */ 0082 buf = (unsigned char *)malloc(size * 4); 0083 i = 0; 0084 for(n = 0; n < size; ++n) 0085 { 0086 unsigned char c = str[n]; 0087 if(c == '\\') 0088 { 0089 buf[i++] = '\\'; 0090 buf[i++] = '\\'; 0091 } 0092 else if(c >= 0x20 && c < 0x7f) 0093 { 0094 buf[i++] = c; 0095 } 0096 else 0097 { 0098 buf[i++] = '\\'; 0099 buf[i++] = 'x'; 0100 _hex_byte(c, buf + i); 0101 i += 2; 0102 } 0103 } 0104 0105 out = jdns_string_new(); 0106 jdns_string_set(out, buf, i); 0107 free(buf); 0108 return out; 0109 } 0110 0111 static jdns_string_t *_make_printable_str(const jdns_string_t *str) 0112 { 0113 return _make_printable(str->data, str->size); 0114 } 0115 0116 static jdns_string_t *_make_printable_cstr(const char *str) 0117 { 0118 return _make_printable((const unsigned char *)str, strlen(str)); 0119 } 0120 0121 static unsigned char *_fix_input(const unsigned char *in) 0122 { 0123 unsigned char *out; 0124 int len; 0125 0126 /* truncate */ 0127 len = _ustrlen(in); 0128 if(len > 254) 0129 len = 254; 0130 0131 /* add a dot to the end if needed */ 0132 if(in[len - 1] != '.' && len < 254) 0133 { 0134 out = (unsigned char *)malloc(len + 2); /* a dot and a zero */ 0135 memcpy(out, in, len); 0136 out[len] = '.'; 0137 out[len+1] = 0; 0138 ++len; 0139 } 0140 else 0141 { 0142 out = (unsigned char *)malloc(len + 1); /* a zero */ 0143 memcpy(out, in, len); 0144 out[len] = 0; 0145 } 0146 0147 return out; 0148 } 0149 0150 static const char *_qtype2str(int qtype) 0151 { 0152 const char *str; 0153 switch(qtype) 0154 { 0155 case JDNS_RTYPE_A: str = "A"; break; 0156 case JDNS_RTYPE_AAAA: str = "AAAA"; break; 0157 case JDNS_RTYPE_MX: str = "MX"; break; 0158 case JDNS_RTYPE_SRV: str = "SRV"; break; 0159 case JDNS_RTYPE_CNAME: str = "CNAME"; break; 0160 case JDNS_RTYPE_PTR: str = "PTR"; break; 0161 case JDNS_RTYPE_TXT: str = "TXT"; break; 0162 case JDNS_RTYPE_HINFO: str = "HINFO"; break; 0163 case JDNS_RTYPE_NS: str = "NS"; break; 0164 case JDNS_RTYPE_ANY: str = "ANY"; break; 0165 default: str = ""; break; 0166 } 0167 return str; 0168 } 0169 0170 static jdns_response_t *_packet2response(const jdns_packet_t *packet, const unsigned char *qname, int qtype, int classmask) 0171 { 0172 int n; 0173 jdns_response_t *r; 0174 0175 r = jdns_response_new(); 0176 for(n = 0; n < packet->answerRecords->count; ++n) 0177 { 0178 jdns_packet_resource_t *res = (jdns_packet_resource_t *)packet->answerRecords->item[n]; 0179 jdns_rr_t *rr; 0180 int put_in_answer; 0181 if((res->qclass & classmask) != 0x0001) 0182 continue; 0183 rr = jdns_rr_from_resource(res, packet); 0184 if(!rr) 0185 continue; 0186 /* if qname is set, restrict answers to those that match */ 0187 /* the question */ 0188 put_in_answer = 1; 0189 if(qname) 0190 { 0191 /* name must match. type must either match or be CNAME, */ 0192 /* unless the query was for any type */ 0193 if((qtype != JDNS_RTYPE_ANY && res->qtype != qtype && res->qtype != JDNS_RTYPE_CNAME) || !jdns_domain_cmp(res->qname->data, qname)) 0194 { 0195 /* put unusable records in additional section */ 0196 put_in_answer = 0; 0197 } 0198 } 0199 if(put_in_answer) 0200 jdns_response_append_answer(r, rr); 0201 else 0202 jdns_response_append_additional(r, rr); 0203 jdns_rr_delete(rr); 0204 } 0205 for(n = 0; n < packet->authorityRecords->count; ++n) 0206 { 0207 jdns_packet_resource_t *res = (jdns_packet_resource_t *)packet->authorityRecords->item[n]; 0208 jdns_rr_t *rr; 0209 if((res->qclass & classmask) != 0x0001) 0210 continue; 0211 rr = jdns_rr_from_resource(res, packet); 0212 if(!rr) 0213 continue; 0214 jdns_response_append_authority(r, rr); 0215 jdns_rr_delete(rr); 0216 } 0217 for(n = 0; n < packet->additionalRecords->count; ++n) 0218 { 0219 jdns_packet_resource_t *res = (jdns_packet_resource_t *)packet->additionalRecords->item[n]; 0220 jdns_rr_t *rr; 0221 if((res->qclass & classmask) != 0x0001) 0222 continue; 0223 rr = jdns_rr_from_resource(res, packet); 0224 if(!rr) 0225 continue; 0226 jdns_response_append_additional(r, rr); 0227 jdns_rr_delete(rr); 0228 } 0229 return r; 0230 } 0231 0232 /* size must be 1 to 16 */ 0233 static void _print_hexdump_line(jdns_session_t *s, const unsigned char *buf, int size) 0234 { 0235 char line[67]; /* 3 * 16 + 2 + 16 + zero byte */ 0236 int n; 0237 0238 memset(line, ' ', 66); 0239 line[66] = 0; 0240 if(size > 16) 0241 size = 16; 0242 for(n = 0; n < size; ++n) 0243 { 0244 unsigned char c = buf[n]; 0245 _hex_byte(c, ((unsigned char *)line) + n * 3); 0246 line[n * 3 + 2] = ' '; 0247 if(c >= 0x20 && c < 0x7f) 0248 line[50 + n] = c; 0249 else 0250 line[50 + n] = '.'; 0251 } 0252 _debug_line(s, " %s", line); 0253 } 0254 0255 static void _print_hexdump(jdns_session_t *s, const unsigned char *buf, int size) 0256 { 0257 int n; 0258 int lines; 0259 int at, len; 0260 0261 lines = size / 16; 0262 if(size % 16 != 0) 0263 ++lines; 0264 for(n = 0; n < lines; ++n) 0265 { 0266 at = n * 16; 0267 if(at + 16 <= size) 0268 len = 16; 0269 else 0270 len = size - at; 0271 _print_hexdump_line(s, buf + at, len); 0272 } 0273 } 0274 0275 static void _print_packet_resources(jdns_session_t *s, const jdns_list_t *reslist) 0276 { 0277 int n; 0278 for(n = 0; n < reslist->count; ++n) 0279 { 0280 jdns_packet_resource_t *r; 0281 jdns_string_t *str; 0282 r = (jdns_packet_resource_t *)reslist->item[n]; 0283 str = _make_printable_str(r->qname); 0284 _debug_line(s, " %04x/%04x [%s] ttl=%ld size=%d", r->qclass, r->qtype, str->data, r->ttl, r->rdlength); 0285 jdns_string_delete(str); 0286 } 0287 } 0288 0289 static void _print_packet(jdns_session_t *s, const jdns_packet_t *packet) 0290 { 0291 int n; 0292 _debug_line(s, "Packet:"); 0293 _debug_line(s, " id: %d", packet->id); 0294 _debug_line(s, " opts: qr:%d, opcode:%d, aa:%d, tc:%d, rd:%d, ra:%d, z:%d, rcode:%d", 0295 packet->opts.qr, packet->opts.opcode, packet->opts.aa, packet->opts.tc, 0296 packet->opts.rd, packet->opts.ra, packet->opts.z, packet->opts.rcode); 0297 _debug_line(s, " qdcount=%d, ancount=%d, nscount=%d, arcount=%d", 0298 packet->qdcount, packet->ancount, packet->nscount, packet->arcount); 0299 if(packet->questions->count > 0) 0300 { 0301 _debug_line(s, " questions: (class/type name)"); 0302 for(n = 0; n < packet->questions->count; ++n) 0303 { 0304 jdns_packet_question_t *q; 0305 jdns_string_t *str; 0306 q = (jdns_packet_question_t *)packet->questions->item[n]; 0307 str = _make_printable_str(q->qname); 0308 _debug_line(s, " %04x/%04x [%s]", q->qclass, q->qtype, str->data); 0309 jdns_string_delete(str); 0310 } 0311 } 0312 if(packet->answerRecords->count > 0) 0313 { 0314 _debug_line(s, " answerRecords: (class/type owner ttl size)"); 0315 _print_packet_resources(s, packet->answerRecords); 0316 } 0317 if(packet->authorityRecords->count > 0) 0318 { 0319 _debug_line(s, " authorityRecords: (class/type owner ttl size)"); 0320 _print_packet_resources(s, packet->authorityRecords); 0321 } 0322 if(packet->additionalRecords->count > 0) 0323 { 0324 _debug_line(s, " additionalRecords: (class/type owner ttl size)"); 0325 _print_packet_resources(s, packet->additionalRecords); 0326 } 0327 } 0328 0329 static void _print_rr(jdns_session_t *s, const jdns_rr_t *rr, const unsigned char *owner) 0330 { 0331 int n; 0332 jdns_string_t *ownerstr; 0333 0334 ownerstr = jdns_string_new(); 0335 0336 /* not the expected owner? */ 0337 if(!owner || !jdns_domain_cmp(owner, rr->owner)) 0338 { 0339 unsigned char *buf; 0340 jdns_string_t *str = _make_printable_cstr((const char *)rr->owner); 0341 buf = (unsigned char *)malloc(str->size + 3); /* " [%s]" */ 0342 buf[0] = ' '; 0343 buf[1] = '['; 0344 memcpy(buf + 2, str->data, str->size); 0345 buf[str->size + 2] = ']'; 0346 jdns_string_set(ownerstr, buf, str->size + 3); 0347 jdns_string_delete(str); 0348 free(buf); 0349 } 0350 else 0351 jdns_string_set_cstr(ownerstr, ""); 0352 0353 switch(rr->type) 0354 { 0355 case JDNS_RTYPE_A: 0356 { 0357 _debug_line(s, " A: [%s] (ttl=%d)%s", rr->data.address->c_str, rr->ttl, ownerstr->data); 0358 break; 0359 } 0360 case JDNS_RTYPE_AAAA: 0361 { 0362 _debug_line(s, " AAAA: [%s] (ttl=%d)%s", rr->data.address->c_str, rr->ttl, ownerstr->data); 0363 break; 0364 } 0365 case JDNS_RTYPE_MX: 0366 { 0367 jdns_string_t *str = _make_printable_cstr((const char *)rr->data.server->name); 0368 _debug_line(s, " MX: [%s] priority=%d (ttl=%d)%s", str->data, rr->data.server->priority, rr->ttl, ownerstr->data); 0369 jdns_string_delete(str); 0370 break; 0371 } 0372 case JDNS_RTYPE_SRV: 0373 { 0374 jdns_string_t *str = _make_printable_cstr((const char *)rr->data.server->name); 0375 _debug_line(s, " SRV: [%s] port=%d priority=%d weight=%d (ttl=%d)%s", str->data, rr->data.server->port, rr->data.server->priority, rr->data.server->weight, rr->ttl, ownerstr->data); 0376 jdns_string_delete(str); 0377 break; 0378 } 0379 case JDNS_RTYPE_CNAME: 0380 { 0381 jdns_string_t *str = _make_printable_cstr((const char *)rr->data.name); 0382 _debug_line(s, " CNAME: [%s] (ttl=%d)%s", str->data, rr->ttl, ownerstr->data); 0383 jdns_string_delete(str); 0384 break; 0385 } 0386 case JDNS_RTYPE_PTR: 0387 { 0388 jdns_string_t *str = _make_printable_cstr((const char *)rr->data.name); 0389 _debug_line(s, " PTR: [%s] (ttl=%d)%s", str->data, rr->ttl, ownerstr->data); 0390 jdns_string_delete(str); 0391 break; 0392 } 0393 case JDNS_RTYPE_TXT: 0394 { 0395 _debug_line(s, " TXT: count=%d (ttl=%d)%s", rr->data.texts->count, rr->ttl, ownerstr->data); 0396 for(n = 0; n < rr->data.texts->count; ++n) 0397 { 0398 jdns_string_t *str, *pstr; 0399 str = rr->data.texts->item[n]; 0400 pstr = _make_printable_str(str); 0401 _debug_line(s, " len=%d [%s]", str->size, pstr->data); 0402 jdns_string_delete(pstr); 0403 } 0404 break; 0405 } 0406 case JDNS_RTYPE_HINFO: 0407 { 0408 jdns_string_t *cpu, *os; 0409 cpu = _make_printable_str(rr->data.hinfo.cpu); 0410 os = _make_printable_str(rr->data.hinfo.os); 0411 _debug_line(s, " HINFO: [%s] [%s] (ttl=%d)%s", cpu->data, os->data, rr->ttl, ownerstr->data); 0412 jdns_string_delete(cpu); 0413 jdns_string_delete(os); 0414 break; 0415 } 0416 case JDNS_RTYPE_NS: 0417 { 0418 jdns_string_t *str = _make_printable_cstr((const char *)rr->data.name); 0419 _debug_line(s, " NS: [%s] (ttl=%d)%s", str->data, rr->ttl, ownerstr->data); 0420 jdns_string_delete(str); 0421 break; 0422 } 0423 default: 0424 { 0425 _debug_line(s, " Unknown (%d): %d bytes (ttl=%d)%s", rr->type, rr->rdlength, rr->ttl, ownerstr->data); 0426 break; 0427 } 0428 } 0429 jdns_string_delete(ownerstr); 0430 } 0431 0432 static void _print_records(jdns_session_t *s, const jdns_response_t *r, const unsigned char *owner) 0433 { 0434 int n; 0435 _debug_line(s, "Records:"); 0436 _debug_line(s, " Answer Records: %d", r->answerCount); 0437 for(n = 0; n < r->answerCount; ++n) 0438 _print_rr(s, r->answerRecords[n], owner); 0439 _debug_line(s, " Authority Records: %d", r->authorityCount); 0440 for(n = 0; n < r->authorityCount; ++n) 0441 _print_rr(s, r->authorityRecords[n], owner); 0442 _debug_line(s, " Additional Records: %d", r->additionalCount); 0443 for(n = 0; n < r->additionalCount; ++n) 0444 _print_rr(s, r->additionalRecords[n], owner); 0445 } 0446 0447 static int _min(int a, int b) 0448 { 0449 return (a < b) ? a : b; 0450 } 0451 0452 /*---------------------------------------------------------------------------- */ 0453 /* jdns_event */ 0454 /*---------------------------------------------------------------------------- */ 0455 jdns_event_t *jdns_event_new() 0456 { 0457 jdns_event_t *e = alloc_type(jdns_event_t); 0458 e->response = 0; 0459 return e; 0460 } 0461 0462 void jdns_event_delete(jdns_event_t *e) 0463 { 0464 if(!e) 0465 return; 0466 jdns_response_delete(e->response); 0467 jdns_free(e); 0468 } 0469 0470 /*---------------------------------------------------------------------------- */ 0471 /* jdns - internal types */ 0472 /*---------------------------------------------------------------------------- */ 0473 typedef struct list_item 0474 { 0475 void (*dtor)(void *); 0476 } list_item_t; 0477 0478 typedef struct list 0479 { 0480 int count; 0481 list_item_t **item; 0482 } list_t; 0483 0484 list_t *list_new() 0485 { 0486 list_t *l = alloc_type(list_t); 0487 l->count = 0; 0488 l->item = 0; 0489 return l; 0490 } 0491 0492 void list_delete(list_t *l) 0493 { 0494 int n; 0495 if(!l) 0496 return; 0497 for(n = 0; n < l->count; ++n) 0498 l->item[n]->dtor(l->item[n]); 0499 if(l->item) 0500 free(l->item); 0501 jdns_free(l); 0502 } 0503 0504 void list_insert(list_t *l, void *item, int pos) 0505 { 0506 list_item_t *i = (list_item_t *)item; 0507 if(!l->item) 0508 l->item = (list_item_t **)malloc(sizeof(list_item_t *)); 0509 else 0510 l->item = (list_item_t **)realloc(l->item, sizeof(list_item_t *) * (l->count + 1)); 0511 if(pos != -1) 0512 memmove(l->item + pos + 1, l->item + pos, (l->count - pos) * sizeof(list_item_t *)); 0513 else 0514 pos = l->count; 0515 l->item[pos] = i; 0516 ++l->count; 0517 } 0518 0519 void list_remove(list_t *l, void *item) 0520 { 0521 int n; 0522 list_item_t *i = (list_item_t *)item; 0523 int pos = -1; 0524 for(n = 0; n < l->count; ++n) 0525 { 0526 if(l->item[n] == i) 0527 { 0528 pos = n; 0529 break; 0530 } 0531 } 0532 if(pos == -1) 0533 return; 0534 0535 i->dtor(i); 0536 if(l->count > 1) 0537 { 0538 memmove(l->item + pos, l->item + pos + 1, (l->count - pos - 1) * sizeof(list_item_t *)); 0539 --l->count; 0540 } 0541 else 0542 { 0543 free(l->item); 0544 l->item = 0; 0545 l->count = 0; 0546 } 0547 } 0548 0549 typedef struct name_server 0550 { 0551 void (*dtor)(struct name_server *); 0552 int id; 0553 jdns_address_t *address; 0554 int port; 0555 } name_server_t; 0556 0557 void name_server_delete(name_server_t *ns); 0558 0559 name_server_t *name_server_new() 0560 { 0561 name_server_t *ns = alloc_type(name_server_t); 0562 ns->dtor = name_server_delete; 0563 ns->address = 0; 0564 return ns; 0565 } 0566 0567 void name_server_delete(name_server_t *ns) 0568 { 0569 if(!ns) 0570 return; 0571 jdns_address_delete(ns->address); 0572 jdns_free(ns); 0573 } 0574 0575 int _intarray_indexOf(int *array, int count, int val) 0576 { 0577 int n; 0578 for(n = 0; n < count; ++n) 0579 { 0580 if(array[n] == val) 0581 return n; 0582 } 0583 return -1; 0584 } 0585 0586 int _intarray_add(int **array, int *count, int val) 0587 { 0588 int *p; 0589 if(!*array) 0590 p = (int *)malloc(sizeof(int)); 0591 else 0592 p = (int *)realloc(*array, sizeof(int) * (*count + 1)); 0593 if(!p) 0594 return 0; 0595 *array = p; 0596 (*array)[*count] = val; 0597 ++(*count); 0598 return 1; 0599 } 0600 0601 void _intarray_remove(int **array, int *count, int pos) 0602 { 0603 int *p; 0604 if(*count > 1) 0605 { 0606 memmove(*array + pos, *array + pos + 1, (*count - pos - 1) * sizeof(int)); 0607 --(*count); 0608 p = (int *)realloc(*array, sizeof(int) * (*count)); 0609 if(p) 0610 *array = p; 0611 } 0612 else 0613 { 0614 free(*array); 0615 *array = 0; 0616 *count = 0; 0617 } 0618 } 0619 0620 typedef struct query 0621 { 0622 void (*dtor)(struct query *); 0623 0624 int id; 0625 0626 /* user request ids */ 0627 int req_ids_count; 0628 int *req_ids; 0629 0630 /* packet id */ 0631 int dns_id; 0632 0633 /* what we are looking up */ 0634 unsigned char *qname; 0635 int qtype; 0636 0637 /* how many transmission attempts we have done. note this */ 0638 /* is not actually how many packets have been sent, since */ 0639 /* it is possible for the first transmission to send many */ 0640 /* at once. this variable lets us decide when to give up. */ 0641 /* (idea taken from qdns). */ 0642 /* set to -1 to deactivate (stop sending packets) */ 0643 int step; 0644 0645 /* which nameservers we've tried (stored as a list of ids) */ 0646 int servers_tried_count; 0647 int *servers_tried; 0648 0649 /* which servers we shouldn't try again */ 0650 int servers_failed_count; 0651 int *servers_failed; 0652 0653 /* flag to indicate whether or not we've tried all available */ 0654 /* nameservers already. this means that all future */ 0655 /* transmissions are likely repeats, and should be slowed */ 0656 /* down. */ 0657 int retrying; 0658 0659 /* holds a timeout for the next step (time_start == -1 means no timer) */ 0660 int time_start; 0661 int time_next; 0662 0663 /* whether or not to look in the cache for this query */ 0664 int trycache; 0665 0666 /* cname subquerying. only cname_parent or cname_child may be set, */ 0667 /* never both. */ 0668 int cname_chain_count; 0669 struct query *cname_parent; 0670 struct query *cname_child; 0671 0672 /* accumulates known multicast records to prevent duplicates */ 0673 jdns_response_t *mul_known; 0674 } query_t; 0675 0676 void query_delete(query_t *q); 0677 0678 query_t *query_new() 0679 { 0680 query_t *q = alloc_type(query_t); 0681 q->dtor = query_delete; 0682 q->req_ids_count = 0; 0683 q->req_ids = 0; 0684 q->qname = 0; 0685 q->servers_tried_count = 0; 0686 q->servers_tried = 0; 0687 q->servers_failed_count = 0; 0688 q->servers_failed = 0; 0689 q->cname_chain_count = 0; 0690 q->cname_parent = 0; 0691 q->cname_child = 0; 0692 q->mul_known = 0; 0693 return q; 0694 } 0695 0696 void query_delete(query_t *q) 0697 { 0698 if(!q) 0699 return; 0700 if(q->req_ids) 0701 free(q->req_ids); 0702 if(q->qname) 0703 free(q->qname); 0704 if(q->servers_tried) 0705 free(q->servers_tried); 0706 if(q->servers_failed) 0707 free(q->servers_failed); 0708 jdns_response_delete(q->mul_known); 0709 jdns_free(q); 0710 } 0711 0712 int query_have_req_id(const query_t *q, int req_id) 0713 { 0714 if(_intarray_indexOf(q->req_ids, q->req_ids_count, req_id) != -1) 0715 return 1; 0716 return 0; 0717 } 0718 0719 void query_add_req_id(query_t *q, int req_id) 0720 { 0721 _intarray_add(&q->req_ids, &q->req_ids_count, req_id); 0722 } 0723 0724 void query_remove_req_id(query_t *q, int req_id) 0725 { 0726 int pos; 0727 0728 pos = _intarray_indexOf(q->req_ids, q->req_ids_count, req_id); 0729 if(pos != -1) 0730 _intarray_remove(&q->req_ids, &q->req_ids_count, pos); 0731 } 0732 0733 int query_server_tried(const query_t *q, int ns_id) 0734 { 0735 if(_intarray_indexOf(q->servers_tried, q->servers_tried_count, ns_id) != -1) 0736 return 1; 0737 return 0; 0738 } 0739 0740 void query_add_server_tried(query_t *q, int ns_id) 0741 { 0742 _intarray_add(&q->servers_tried, &q->servers_tried_count, ns_id); 0743 } 0744 0745 int query_server_failed(const query_t *q, int ns_id); 0746 0747 void query_clear_servers_tried(query_t *q) 0748 { 0749 int n; 0750 0751 /* all failed servers must continue to be considered tried servers, so */ 0752 /* only clear tried servers that haven't failed */ 0753 for(n = 0; n < q->servers_tried_count; ++n) 0754 { 0755 if(!query_server_failed(q, q->servers_tried[n])) 0756 { 0757 _intarray_remove(&q->servers_tried, &q->servers_tried_count, n); 0758 --n; /* adjust position */ 0759 } 0760 } 0761 } 0762 0763 int query_server_failed(const query_t *q, int ns_id) 0764 { 0765 if(_intarray_indexOf(q->servers_failed, q->servers_failed_count, ns_id) != -1) 0766 return 1; 0767 return 0; 0768 } 0769 0770 void query_add_server_failed(query_t *q, int ns_id) 0771 { 0772 _intarray_add(&q->servers_failed, &q->servers_failed_count, ns_id); 0773 } 0774 0775 void query_name_server_gone(query_t *q, int ns_id) 0776 { 0777 int pos; 0778 0779 pos = _intarray_indexOf(q->servers_tried, q->servers_tried_count, ns_id); 0780 if(pos != -1) 0781 _intarray_remove(&q->servers_tried, &q->servers_tried_count, pos); 0782 0783 pos = _intarray_indexOf(q->servers_failed, q->servers_failed_count, ns_id); 0784 if(pos != -1) 0785 _intarray_remove(&q->servers_failed, &q->servers_failed_count, pos); 0786 } 0787 0788 typedef struct datagram 0789 { 0790 void (*dtor)(struct datagram *); 0791 int handle; 0792 jdns_address_t *dest_address; 0793 int dest_port; 0794 unsigned char *data; 0795 int size; 0796 0797 /* query association */ 0798 query_t *query; 0799 int query_send_type; /* 0 == normal, 1 == first step send-all */ 0800 0801 /* name server association */ 0802 int ns_id; 0803 } datagram_t; 0804 0805 void datagram_delete(datagram_t *a); 0806 0807 datagram_t *datagram_new() 0808 { 0809 datagram_t *a = alloc_type(datagram_t); 0810 a->dtor = datagram_delete; 0811 a->dest_address = 0; 0812 a->data = 0; 0813 a->size = 0; 0814 a->query = 0; 0815 return a; 0816 } 0817 0818 void datagram_delete(datagram_t *a) 0819 { 0820 if(!a) 0821 return; 0822 jdns_address_delete(a->dest_address); 0823 if(a->data) 0824 free(a->data); 0825 jdns_free(a); 0826 } 0827 0828 typedef struct cache_item 0829 { 0830 void (*dtor)(struct cache_item *); 0831 unsigned char *qname; 0832 int qtype; 0833 int time_start; 0834 int ttl; 0835 jdns_rr_t *record; /* if zero, nxdomain is assumed */ 0836 } cache_item_t; 0837 0838 void cache_item_delete(cache_item_t *e); 0839 0840 cache_item_t *cache_item_new() 0841 { 0842 cache_item_t *a = alloc_type(cache_item_t); 0843 a->dtor = cache_item_delete; 0844 a->qname = 0; 0845 a->record = 0; 0846 return a; 0847 } 0848 0849 void cache_item_delete(cache_item_t *a) 0850 { 0851 if(!a) 0852 return; 0853 if(a->qname) 0854 free(a->qname); 0855 jdns_rr_delete(a->record); 0856 jdns_free(a); 0857 } 0858 0859 typedef struct event 0860 { 0861 void (*dtor)(struct event *); 0862 jdns_event_t *event; 0863 } event_t; 0864 0865 void event_delete(event_t *e); 0866 0867 event_t *event_new() 0868 { 0869 event_t *e = alloc_type(event_t); 0870 e->dtor = event_delete; 0871 e->event = 0; 0872 return e; 0873 } 0874 0875 void event_delete(event_t *e) 0876 { 0877 if(!e) 0878 return; 0879 jdns_event_delete(e->event); 0880 jdns_free(e); 0881 } 0882 0883 typedef struct published_item 0884 { 0885 void (*dtor)(struct published_item *); 0886 int id; 0887 int mode; 0888 unsigned char *qname; 0889 int qtype; 0890 mdnsdr rec; 0891 jdns_rr_t *rr; 0892 } published_item_t; 0893 0894 void published_item_delete(published_item_t *a); 0895 0896 published_item_t *published_item_new() 0897 { 0898 published_item_t *a = alloc_type(published_item_t); 0899 a->dtor = published_item_delete; 0900 a->qname = 0; 0901 a->rec = 0; 0902 a->rr = 0; 0903 return a; 0904 } 0905 0906 void published_item_delete(published_item_t *a) 0907 { 0908 if(!a) 0909 return; 0910 if(a->qname) 0911 free(a->qname); 0912 jdns_rr_delete(a->rr); 0913 jdns_free(a); 0914 } 0915 0916 /*---------------------------------------------------------------------------- */ 0917 /* jdns */ 0918 /*---------------------------------------------------------------------------- */ 0919 struct jdns_session 0920 { 0921 jdns_callbacks_t cb; 0922 int mode; 0923 int shutdown; 0924 int next_qid; 0925 int next_req_id; 0926 int last_time; 0927 int next_timer; 0928 int next_name_server_id; 0929 int handle; 0930 int handle_readable, handle_writable; 0931 int port; 0932 list_t *name_servers; 0933 list_t *queries; 0934 list_t *outgoing; 0935 list_t *events; 0936 list_t *cache; 0937 0938 /* for blocking req_ids from reuse until user explicitly releases */ 0939 int do_hold_req_ids; 0940 int held_req_ids_count; 0941 int *held_req_ids; 0942 0943 /* mdns */ 0944 mdnsd mdns; 0945 list_t *published; 0946 jdns_address_t *maddr; 0947 }; 0948 0949 jdns_session_t *jdns_session_new(jdns_callbacks_t *callbacks) 0950 { 0951 jdns_session_t *s = alloc_type(jdns_session_t); 0952 memcpy(&s->cb, callbacks, sizeof(jdns_callbacks_t)); 0953 s->shutdown = 0; 0954 s->next_qid = 0; 0955 s->next_req_id = 1; 0956 s->last_time = 0; 0957 s->next_timer = 0; 0958 s->next_name_server_id = 0; 0959 s->handle = 0; 0960 s->handle_readable = 0; 0961 s->handle_writable = 1; 0962 s->port = 0; 0963 s->name_servers = list_new(); 0964 s->queries = list_new(); 0965 s->outgoing = list_new(); 0966 s->events = list_new(); 0967 s->cache = list_new(); 0968 0969 s->do_hold_req_ids = 0; 0970 s->held_req_ids_count = 0; 0971 s->held_req_ids = 0; 0972 0973 s->mdns = 0; 0974 s->published = list_new(); 0975 s->maddr = 0; 0976 0977 return s; 0978 } 0979 0980 void jdns_session_delete(jdns_session_t *s) 0981 { 0982 if(!s) 0983 return; 0984 if(s->handle) 0985 s->cb.udp_unbind(s, s->cb.app, s->handle); 0986 list_delete(s->name_servers); 0987 list_delete(s->queries); 0988 list_delete(s->outgoing); 0989 list_delete(s->events); 0990 list_delete(s->cache); 0991 0992 if(s->held_req_ids) 0993 free(s->held_req_ids); 0994 0995 if(s->mdns) 0996 mdnsd_free(s->mdns); 0997 0998 list_delete(s->published); 0999 jdns_address_delete(s->maddr); 1000 1001 free(s); 1002 } 1003 1004 /* declare some internal functions */ 1005 static int _callback_time_now(mdnsd d, void *arg); 1006 static int _callback_rand_int(mdnsd d, void *arg); 1007 1008 static void _append_event(jdns_session_t *s, jdns_event_t *event); 1009 static void _append_event_and_hold_id(jdns_session_t *s, jdns_event_t *event); 1010 static void _remove_name_server_datagrams(jdns_session_t *s, int ns_id); 1011 static void _remove_query_datagrams(jdns_session_t *s, const query_t *q); 1012 1013 static int _unicast_query(jdns_session_t *s, const unsigned char *name, int qtype); 1014 static void _unicast_cancel(jdns_session_t *s, query_t *q); 1015 static int _multicast_query(jdns_session_t *s, const unsigned char *name, int qtype); 1016 static void _multicast_cancel(jdns_session_t *s, int req_id); 1017 static int _multicast_publish(jdns_session_t *s, int mode, const jdns_rr_t *rr); 1018 static void _multicast_update_publish(jdns_session_t *s, int id, const jdns_rr_t *rr); 1019 static void _multicast_cancel_publish(jdns_session_t *s, int id); 1020 static void _multicast_flush(jdns_session_t *s); 1021 1022 static int jdns_step_unicast(jdns_session_t *s, int now); 1023 static int jdns_step_multicast(jdns_session_t *s, int now); 1024 1025 static void _hold_req_id(jdns_session_t *s, int req_id) 1026 { 1027 int pos; 1028 1029 /* make sure we don't hold an id twice */ 1030 pos = _intarray_indexOf(s->held_req_ids, s->held_req_ids_count, req_id); 1031 if(pos != -1) 1032 return; 1033 1034 _intarray_add(&s->held_req_ids, &s->held_req_ids_count, req_id); 1035 } 1036 1037 static void _unhold_req_id(jdns_session_t *s, int req_id) 1038 { 1039 int pos; 1040 1041 pos = _intarray_indexOf(s->held_req_ids, s->held_req_ids_count, req_id); 1042 if(pos != -1) 1043 _intarray_remove(&s->held_req_ids, &s->held_req_ids_count, pos); 1044 } 1045 1046 static void _set_hold_ids_enabled(jdns_session_t *s, int enabled) 1047 { 1048 if(enabled && !s->do_hold_req_ids) 1049 { 1050 s->do_hold_req_ids = 1; 1051 } 1052 else if(!enabled && s->do_hold_req_ids) 1053 { 1054 s->do_hold_req_ids = 0; 1055 1056 if(s->held_req_ids) 1057 free(s->held_req_ids); 1058 s->held_req_ids = 0; 1059 s->held_req_ids_count = 0; 1060 } 1061 } 1062 1063 static int _int_wrap(int *src, int start) 1064 { 1065 int x; 1066 x = (*src)++; 1067 if(*src < start) 1068 *src = start; 1069 return x; 1070 } 1071 1072 /* starts at 0 */ 1073 static int get_next_qid(jdns_session_t *s) 1074 { 1075 int n, id; 1076 id = -1; 1077 while(id == -1) 1078 { 1079 id = _int_wrap(&s->next_qid, 0); 1080 for(n = 0; n < s->queries->count; ++n) 1081 { 1082 if(((query_t *)s->queries->item[n])->id == id) 1083 { 1084 id = -1; 1085 break; 1086 } 1087 } 1088 } 1089 return id; 1090 } 1091 1092 /* starts at 1 */ 1093 static int get_next_req_id(jdns_session_t *s) 1094 { 1095 int n, k, id; 1096 id = -1; 1097 while(id == -1) 1098 { 1099 id = _int_wrap(&s->next_req_id, 1); 1100 1101 /* no query using this? */ 1102 for(n = 0; n < s->queries->count; ++n) 1103 { 1104 query_t *q = (query_t *)s->queries->item[n]; 1105 for(k = 0; k < q->req_ids_count; ++k) 1106 { 1107 if(q->req_ids[k] == id) 1108 { 1109 id = -1; 1110 break; 1111 } 1112 } 1113 if(id == -1) 1114 break; 1115 } 1116 1117 /* no publish using this? */ 1118 for(n = 0; n < s->published->count; ++n) 1119 { 1120 if(((published_item_t *)s->published->item[n])->id == id) 1121 { 1122 id = -1; 1123 break; 1124 } 1125 } 1126 1127 /* successful unicast queries or any kind of error result in */ 1128 /* events for actions that are no longer active. we need */ 1129 /* to make sure ids for these actions are not reassigned */ 1130 /* until the user explicitly releases them */ 1131 for(n = 0; n < s->held_req_ids_count; ++n) 1132 { 1133 if(s->held_req_ids[n] == id) 1134 { 1135 id = -1; 1136 break; 1137 } 1138 } 1139 } 1140 return id; 1141 } 1142 1143 /* random number fitting in 16 bits */ 1144 static int get_next_dns_id(jdns_session_t *s) 1145 { 1146 int n, id, active_ids; 1147 active_ids = 0; 1148 id = -1; 1149 while(id == -1) 1150 { 1151 /* use random number for dns id */ 1152 id = s->cb.rand_int(s, s->cb.app) & 0xffff; 1153 1154 for(n = 0; n < s->queries->count; ++n) 1155 { 1156 query_t *q = (query_t *)s->queries->item[n]; 1157 if(q->dns_id != -1) 1158 { 1159 ++active_ids; 1160 if(active_ids >= JDNS_QUERY_MAX) 1161 return -1; 1162 1163 if(q->dns_id == id) 1164 { 1165 id = -1; 1166 break; 1167 } 1168 } 1169 } 1170 } 1171 return id; 1172 } 1173 1174 /* starts at 0 */ 1175 static int get_next_name_server_id(jdns_session_t *s) 1176 { 1177 int n, id; 1178 id = -1; 1179 while(id == -1) 1180 { 1181 id = _int_wrap(&s->next_name_server_id, 0); 1182 for(n = 0; n < s->name_servers->count; ++n) 1183 { 1184 if(((name_server_t *)s->name_servers->item[n])->id == id) 1185 { 1186 id = -1; 1187 break; 1188 } 1189 } 1190 } 1191 return id; 1192 } 1193 1194 int jdns_init_unicast(jdns_session_t *s, const jdns_address_t *addr, int port) 1195 { 1196 int ret; 1197 s->mode = 0; 1198 ret = s->cb.udp_bind(s, s->cb.app, addr, port, 0); 1199 if(ret <= 0) 1200 return 0; 1201 s->handle = ret; 1202 s->port = port; 1203 return 1; 1204 } 1205 1206 int jdns_init_multicast(jdns_session_t *s, const jdns_address_t *addr, int port, const jdns_address_t *maddr) 1207 { 1208 int ret; 1209 s->mode = 1; 1210 ret = s->cb.udp_bind(s, s->cb.app, addr, port, maddr); 1211 if(ret <= 0) 1212 return 0; 1213 s->handle = ret; 1214 s->port = port; 1215 s->maddr = jdns_address_copy(maddr); 1216 1217 /* class 1. note: frame size is ignored by the jdns version of mdnsd */ 1218 s->mdns = mdnsd_new(0x0001, 1000, s->port, _callback_time_now, _callback_rand_int, s); 1219 return 1; 1220 } 1221 1222 void jdns_shutdown(jdns_session_t *s) 1223 { 1224 if(s->shutdown == 0) 1225 s->shutdown = 1; /* request shutdown */ 1226 } 1227 1228 void jdns_set_nameservers(jdns_session_t *s, const jdns_nameserverlist_t *nslist) 1229 { 1230 int n, k; 1231 1232 /* removed? */ 1233 for(k = 0; k < s->name_servers->count; ++k) 1234 { 1235 name_server_t *ns = (name_server_t *)(s->name_servers->item[k]); 1236 int found = 0; 1237 for(n = 0; n < nslist->count; ++n) 1238 { 1239 jdns_nameserver_t *i = (jdns_nameserver_t *)nslist->item[n]; 1240 if(jdns_address_cmp(ns->address, i->address) && ns->port == i->port) 1241 { 1242 found = 1; 1243 break; 1244 } 1245 } 1246 if(!found) 1247 { 1248 int i; 1249 int ns_id; 1250 1251 /* remove any pending packets to this nameserver */ 1252 _remove_name_server_datagrams(s, ns->id); 1253 1254 _debug_line(s, "ns [%s:%d] (id=%d) removed", ns->address->c_str, ns->port, ns->id); 1255 ns_id = ns->id; 1256 list_remove(s->name_servers, ns); 1257 --k; /* adjust position */ 1258 for(i = 0; i < s->queries->count; ++i) 1259 query_name_server_gone((query_t *)s->queries->item[i], ns_id); 1260 } 1261 } 1262 1263 /* added? */ 1264 for(n = 0; n < nslist->count; ++n) 1265 { 1266 name_server_t *ns; 1267 jdns_nameserver_t *i; 1268 int found; 1269 1270 i = (jdns_nameserver_t *)nslist->item[n]; 1271 found = 0; 1272 for(k = 0; k < s->name_servers->count; ++k) 1273 { 1274 ns = (name_server_t *)(s->name_servers->item[k]); 1275 if(jdns_address_cmp(ns->address, i->address) && ns->port == i->port) 1276 { 1277 found = 1; 1278 break; 1279 } 1280 } 1281 if(found) 1282 { 1283 _debug_line(s, "ns [%s:%d] (id=%d) still present", ns->address->c_str, ns->port, ns->id); 1284 } 1285 else 1286 { 1287 ns = name_server_new(); 1288 ns->id = get_next_name_server_id(s); 1289 ns->address = jdns_address_copy(i->address); 1290 ns->port = i->port; 1291 list_insert(s->name_servers, ns, -1); 1292 _debug_line(s, "ns [%s:%d] (id=%d) added", ns->address->c_str, ns->port, ns->id); 1293 } 1294 } 1295 1296 /* no nameservers? */ 1297 if(nslist->count == 0) 1298 { 1299 _debug_line(s, "nameserver count is zero, invalidating any queries"); 1300 1301 /* invalidate all of the queries! */ 1302 for(n = 0; n < s->queries->count; ++n) 1303 { 1304 query_t *q = (query_t *)s->queries->item[n]; 1305 1306 /* report event to any requests listening */ 1307 for(k = 0; k < q->req_ids_count; ++k) 1308 { 1309 jdns_event_t *event = jdns_event_new(); 1310 event->type = JDNS_EVENT_RESPONSE; 1311 event->id = q->req_ids[k]; 1312 event->status = JDNS_STATUS_TIMEOUT; 1313 _append_event_and_hold_id(s, event); 1314 } 1315 1316 /* this line is probably redundant, but just for */ 1317 /* consistency we'll do it... */ 1318 _remove_query_datagrams(s, q); 1319 1320 list_remove(s->queries, q); 1321 --n; /* adjust position */ 1322 } 1323 } 1324 } 1325 1326 void jdns_probe(jdns_session_t *s) 1327 { 1328 if(s->mode != 1) 1329 return; 1330 1331 _multicast_flush(s); 1332 } 1333 1334 int jdns_query(jdns_session_t *s, const unsigned char *name, int rtype) 1335 { 1336 if(s->mode == 0) 1337 return _unicast_query(s, name, rtype); 1338 else 1339 return _multicast_query(s, name, rtype); 1340 } 1341 1342 static void _remove_events(jdns_session_t *s, int event_type, int id) 1343 { 1344 int n; 1345 for(n = 0; n < s->events->count; ++n) 1346 { 1347 event_t *e = (event_t *)s->events->item[n]; 1348 if(e->event->type == event_type && e->event->id == id) 1349 { 1350 list_remove(s->events, e); 1351 --n; /* adjust position */ 1352 } 1353 } 1354 } 1355 1356 void jdns_cancel_query(jdns_session_t *s, int id) 1357 { 1358 int n; 1359 1360 _unhold_req_id(s, id); 1361 1362 /* remove any events associated with the query. this avoids any */ 1363 /* possibility that stale events from one query are mistaken to be */ 1364 /* events resulting from a later query that happened to reuse the */ 1365 /* id. it also means we don't deliver events for cancelled queries, */ 1366 /* which can simplify application logic. */ 1367 _remove_events(s, JDNS_EVENT_RESPONSE, id); 1368 1369 /* multicast */ 1370 if(s->mode == 1) 1371 { 1372 _multicast_cancel(s, id); 1373 return; 1374 } 1375 1376 /* unicast */ 1377 for(n = 0; n < s->queries->count; ++n) 1378 { 1379 query_t *q = (query_t *)s->queries->item[n]; 1380 if(query_have_req_id(q, id)) 1381 { 1382 query_remove_req_id(q, id); 1383 1384 /* note: calling _unicast_cancel might remove an item */ 1385 /* from s->queries, thereby screwing up our iterator */ 1386 /* position, but that's ok because we just break */ 1387 /* anyway. */ 1388 1389 /* if no one else is depending on this request, then take action */ 1390 if(q->req_ids_count == 0 && !q->cname_parent) 1391 { 1392 /* remove a possible cname child */ 1393 if(q->cname_child && q->cname_child->req_ids_count == 0) 1394 { 1395 q->cname_child->cname_parent = 0; 1396 _unicast_cancel(s, q->cname_child); 1397 q->cname_child = 0; 1398 } 1399 1400 _unicast_cancel(s, q); 1401 } 1402 break; 1403 } 1404 } 1405 } 1406 1407 int jdns_publish(jdns_session_t *s, int mode, const jdns_rr_t *rr) 1408 { 1409 return _multicast_publish(s, mode, rr); 1410 } 1411 1412 void jdns_update_publish(jdns_session_t *s, int id, const jdns_rr_t *rr) 1413 { 1414 _multicast_update_publish(s, id, rr); 1415 } 1416 1417 void jdns_cancel_publish(jdns_session_t *s, int id) 1418 { 1419 _unhold_req_id(s, id); 1420 1421 _remove_events(s, JDNS_EVENT_PUBLISH, id); 1422 1423 _multicast_cancel_publish(s, id); 1424 } 1425 1426 int jdns_step(jdns_session_t *s) 1427 { 1428 int now, passed; 1429 int ret; 1430 1431 /* session is shut down */ 1432 if(s->shutdown == 2) 1433 return 0; 1434 1435 now = s->cb.time_now(s, s->cb.app); 1436 passed = now - s->last_time; 1437 1438 _debug_line(s, "passed: %d", passed); 1439 1440 if(s->mode == 0) 1441 ret = jdns_step_unicast(s, now); 1442 else 1443 ret = jdns_step_multicast(s, now); 1444 1445 s->last_time = now; 1446 return ret; 1447 } 1448 1449 int jdns_next_timer(jdns_session_t *s) 1450 { 1451 return s->next_timer; 1452 } 1453 1454 void jdns_set_handle_readable(jdns_session_t *s, int handle) 1455 { 1456 (void)handle; 1457 s->handle_readable = 1; 1458 } 1459 1460 void jdns_set_handle_writable(jdns_session_t *s, int handle) 1461 { 1462 (void)handle; 1463 s->handle_writable = 1; 1464 } 1465 1466 jdns_event_t *jdns_next_event(jdns_session_t *s) 1467 { 1468 jdns_event_t *event = 0; 1469 if(s->events->count > 0) 1470 { 1471 event_t *e = (event_t *)s->events->item[0]; 1472 event = e->event; 1473 e->event = 0; 1474 list_remove(s->events, e); 1475 } 1476 return event; 1477 } 1478 1479 void jdns_set_hold_ids_enabled(jdns_session_t *s, int enabled) 1480 { 1481 _set_hold_ids_enabled(s, enabled); 1482 } 1483 1484 /*---------------------------------------------------------------------------- */ 1485 /* jdns - internal functions */ 1486 /*---------------------------------------------------------------------------- */ 1487 1488 /* we don't have vsnprintf on windows, so don't pass anything enormous to */ 1489 /* this function. the plan is that no line should exceed 1000 bytes, */ 1490 /* although _print_rr() might get close. a 2048 byte buffer should be */ 1491 /* plenty then. */ 1492 void _debug_line(jdns_session_t *s, const char *format, ...) 1493 { 1494 char *buf = (char *)malloc(2048); 1495 va_list ap; 1496 va_start(ap, format); 1497 jdns_vsprintf_s(buf, 2048, format, ap); 1498 va_end(ap); 1499 s->cb.debug_line(s, s->cb.app, buf); 1500 free(buf); 1501 } 1502 1503 int _callback_time_now(mdnsd d, void *arg) 1504 { 1505 jdns_session_t *s = (jdns_session_t *)arg; 1506 (void)d; 1507 /* offset the time, mdnsd doesn't like starting at 0 */ 1508 return s->cb.time_now(s, s->cb.app) + 120 * 1000; 1509 } 1510 1511 int _callback_rand_int(mdnsd d, void *arg) 1512 { 1513 jdns_session_t *s = (jdns_session_t *)arg; 1514 (void)d; 1515 return s->cb.rand_int(s, s->cb.app); 1516 } 1517 1518 void _append_event(jdns_session_t *s, jdns_event_t *event) 1519 { 1520 event_t *e = event_new(); 1521 e->event = event; 1522 list_insert(s->events, e, -1); 1523 } 1524 1525 void _append_event_and_hold_id(jdns_session_t *s, jdns_event_t *event) 1526 { 1527 if(s->do_hold_req_ids) 1528 _hold_req_id(s, event->id); 1529 _append_event(s, event); 1530 } 1531 1532 void _remove_name_server_datagrams(jdns_session_t *s, int ns_id) 1533 { 1534 int n; 1535 for(n = 0; n < s->outgoing->count; ++n) 1536 { 1537 datagram_t *a = (datagram_t *)s->outgoing->item[n]; 1538 if(a->ns_id == ns_id) 1539 { 1540 list_remove(s->outgoing, a); 1541 --n; /* adjust position */ 1542 } 1543 } 1544 } 1545 1546 void _remove_query_datagrams(jdns_session_t *s, const query_t *q) 1547 { 1548 int n; 1549 for(n = 0; n < s->outgoing->count; ++n) 1550 { 1551 datagram_t *a = (datagram_t *)s->outgoing->item[n]; 1552 if(a->query == q) 1553 { 1554 list_remove(s->outgoing, a); 1555 --n; /* adjust position */ 1556 } 1557 } 1558 } 1559 1560 void _process_message(jdns_session_t *s, jdns_packet_t *p, int now, query_t *q, name_server_t *ns); 1561 1562 /* return 1 if 'q' should be deleted, 0 if not */ 1563 int _process_response(jdns_session_t *s, jdns_response_t *r, int nxdomain, query_t *q); 1564 1565 jdns_response_t *_cache_get_response(jdns_session_t *s, const unsigned char *qname, int qtype, int *_lowest_timeleft) 1566 { 1567 int n; 1568 int lowest_timeleft = -1; 1569 int now = s->cb.time_now(s, s->cb.app); 1570 jdns_response_t *r = 0; 1571 for(n = 0; n < s->cache->count; ++n) 1572 { 1573 cache_item_t *i = (cache_item_t *)s->cache->item[n]; 1574 if(jdns_domain_cmp(i->qname, qname) && i->qtype == qtype) 1575 { 1576 int passed, timeleft; 1577 1578 if(!r) 1579 r = jdns_response_new(); 1580 1581 if(i->record) 1582 jdns_response_append_answer(r, jdns_rr_copy(i->record)); 1583 1584 passed = now - i->time_start; 1585 timeleft = (i->ttl * 1000) - passed; 1586 if(lowest_timeleft == -1 || timeleft < lowest_timeleft) 1587 lowest_timeleft = timeleft; 1588 } 1589 } 1590 if(_lowest_timeleft) 1591 *_lowest_timeleft = lowest_timeleft; 1592 return r; 1593 } 1594 1595 query_t *_get_query(jdns_session_t *s, const unsigned char *qname, int qtype, int unique) 1596 { 1597 int n; 1598 query_t *q; 1599 jdns_string_t *str; 1600 1601 if(!unique) 1602 { 1603 /* check for existing queries */ 1604 for(n = 0; n < s->queries->count; ++n) 1605 { 1606 q = (query_t *)s->queries->item[n]; 1607 if(jdns_domain_cmp(q->qname, qname) && q->qtype == qtype) 1608 { 1609 /* if it is inactive, just nuke it */ 1610 if(q->step == -1) 1611 { 1612 _remove_query_datagrams(s, q); 1613 list_remove(s->queries, q); 1614 --n; /* adjust position */ 1615 } 1616 /* otherwise, latch onto the first one we find */ 1617 else 1618 { 1619 str = _make_printable_cstr((const char *)q->qname); 1620 _debug_line(s, "[%d] reusing query for: [%s] [%s]", q->id, _qtype2str(qtype), str->data); 1621 jdns_string_delete(str); 1622 return q; 1623 } 1624 } 1625 } 1626 } 1627 1628 q = query_new(); 1629 q->id = get_next_qid(s); 1630 q->qname = _ustrdup(qname); 1631 q->qtype = qtype; 1632 q->step = 0; 1633 q->dns_id = -1; 1634 q->time_start = 0; 1635 q->time_next = 0; 1636 q->trycache = 1; 1637 q->retrying = 0; 1638 list_insert(s->queries, q, -1); 1639 1640 str = _make_printable_cstr((const char *)q->qname); 1641 _debug_line(s, "[%d] querying: [%s] [%s]", q->id, _qtype2str(qtype), str->data); 1642 jdns_string_delete(str); 1643 return q; 1644 } 1645 1646 int _unicast_query(jdns_session_t *s, const unsigned char *name, int qtype) 1647 { 1648 unsigned char *qname; 1649 query_t *q; 1650 int req_id; 1651 jdns_string_t *str; 1652 1653 str = _make_printable_cstr((const char *)name); 1654 _debug_line(s, "query input: [%s]", str->data); 1655 jdns_string_delete(str); 1656 1657 qname = _fix_input(name); 1658 1659 q = _get_query(s, qname, qtype, 0); 1660 req_id = get_next_req_id(s); 1661 query_add_req_id(q, req_id); 1662 free(qname); 1663 return req_id; 1664 } 1665 1666 void _unicast_cancel(jdns_session_t *s, query_t *q) 1667 { 1668 /* didn't even do a step yet? just remove it */ 1669 if(q->step == 0) 1670 { 1671 _remove_query_datagrams(s, q); 1672 list_remove(s->queries, q); 1673 } 1674 /* otherwise, just deactivate */ 1675 else 1676 { 1677 /* deactivate and remain in the background for */ 1678 /* 1 minute. this will allow us to cache a */ 1679 /* reply, even if the user is not currently */ 1680 /* interested. */ 1681 q->step = -1; 1682 q->time_start = s->cb.time_now(s, s->cb.app); 1683 q->time_next = 60000; 1684 } 1685 } 1686 1687 void _queue_packet(jdns_session_t *s, query_t *q, const name_server_t *ns, int recurse, int query_send_type) 1688 { 1689 jdns_packet_t *packet; 1690 datagram_t *a; 1691 1692 packet = jdns_packet_new(); 1693 packet->id = q->dns_id; 1694 packet->opts.rd = recurse; /* recursion desired */ 1695 { 1696 jdns_packet_question_t *question = jdns_packet_question_new(); 1697 question->qname = jdns_string_new(); 1698 jdns_string_set_cstr(question->qname, (const char *)q->qname); 1699 question->qtype = q->qtype; 1700 question->qclass = 0x0001; 1701 jdns_list_insert(packet->questions, question, -1); 1702 jdns_packet_question_delete(question); 1703 } 1704 if(!jdns_packet_export(packet, JDNS_UDP_UNI_OUT_MAX)) 1705 { 1706 _debug_line(s, "outgoing packet export error, not sending"); 1707 jdns_packet_delete(packet); 1708 return; 1709 } 1710 1711 a = datagram_new(); 1712 a->handle = s->handle; 1713 a->dest_address = jdns_address_copy(ns->address); 1714 a->dest_port = ns->port; 1715 a->data = jdns_copy_array(packet->raw_data, packet->raw_size); 1716 a->size = packet->raw_size; 1717 a->query = q; 1718 a->query_send_type = query_send_type; 1719 a->ns_id = ns->id; 1720 1721 jdns_packet_delete(packet); 1722 1723 list_insert(s->outgoing, a, -1); 1724 } 1725 1726 /* return 1 if packets still need to be written */ 1727 int _unicast_do_writes(jdns_session_t *s, int now); 1728 1729 /* return 1 if packets still need to be read */ 1730 int _unicast_do_reads(jdns_session_t *s, int now); 1731 1732 int jdns_step_unicast(jdns_session_t *s, int now) 1733 { 1734 int n; 1735 int need_read = 0; 1736 int need_write = 0; 1737 int smallest_time = -1; 1738 int flags; 1739 1740 if(s->shutdown == 1) 1741 { 1742 jdns_event_t *event = jdns_event_new(); 1743 event->type = JDNS_EVENT_SHUTDOWN; 1744 _append_event(s, event); 1745 s->shutdown = 2; 1746 return 0; 1747 } 1748 1749 /* expire cached items */ 1750 for(n = 0; n < s->cache->count; ++n) 1751 { 1752 cache_item_t *i = (cache_item_t *)s->cache->item[n]; 1753 if(now >= i->time_start + (i->ttl * 1000)) 1754 { 1755 jdns_string_t *str = _make_printable_cstr((const char *)i->qname); 1756 _debug_line(s, "cache exp [%s]", str->data); 1757 jdns_string_delete(str); 1758 list_remove(s->cache, i); 1759 --n; /* adjust position */ 1760 } 1761 } 1762 1763 need_write = _unicast_do_writes(s, now); 1764 need_read = _unicast_do_reads(s, now); 1765 1766 /* calculate next timer (based on queries and cache) */ 1767 for(n = 0; n < s->queries->count; ++n) 1768 { 1769 query_t *q = (query_t *)(s->queries->item[n]); 1770 if(q->time_start != -1) 1771 { 1772 int qpassed = now - q->time_start; 1773 int timeleft = q->time_next - qpassed; 1774 if(timeleft < 0) 1775 timeleft = 0; 1776 1777 if(smallest_time == -1 || timeleft < smallest_time) 1778 smallest_time = timeleft; 1779 } 1780 } 1781 for(n = 0; n < s->cache->count; ++n) 1782 { 1783 cache_item_t *i = (cache_item_t *)(s->cache->item[n]); 1784 int passed = now - i->time_start; 1785 int timeleft = (i->ttl * 1000) - passed; 1786 if(timeleft < 0) 1787 timeleft = 0; 1788 1789 if(smallest_time == -1 || timeleft < smallest_time) 1790 smallest_time = timeleft; 1791 } 1792 1793 flags = 0; 1794 if(smallest_time != -1) 1795 { 1796 flags |= JDNS_STEP_TIMER; 1797 s->next_timer = smallest_time; 1798 1799 /* offset it a little bit, so that the user doesn't call */ 1800 /* us too early, resulting in a no-op and another timer */ 1801 /* of 1 millisecond. */ 1802 s->next_timer += 2; 1803 } 1804 if(need_read || need_write) 1805 flags |= JDNS_STEP_HANDLE; 1806 return flags; 1807 } 1808 1809 int _unicast_do_writes(jdns_session_t *s, int now) 1810 { 1811 int need_write = 0; 1812 int n, k; 1813 1814 for(n = 0; n < s->queries->count; ++n) 1815 { 1816 query_t *q; 1817 int qpassed, timeleft; 1818 int giveup; 1819 name_server_t *ns; 1820 int already_sending; 1821 1822 q = (query_t *)s->queries->item[n]; 1823 1824 /* nothing to do */ 1825 if(q->time_start == -1) 1826 continue; 1827 1828 qpassed = now - q->time_start; 1829 timeleft = q->time_next - qpassed; 1830 if(timeleft < 0) 1831 timeleft = 0; 1832 _debug_line(s, "[%d] time_start/next=%d/%d (left=%d)", q->id, q->time_start, q->time_next, timeleft); 1833 if(timeleft > 0) 1834 continue; 1835 1836 if(q->trycache) 1837 { 1838 /* is it cached? */ 1839 int lowest_timeleft; 1840 int qtype = q->qtype; 1841 jdns_response_t *r; 1842 1843 r = _cache_get_response(s, q->qname, qtype, &lowest_timeleft); 1844 1845 /* not found? try cname */ 1846 if(!r) 1847 { 1848 qtype = JDNS_RTYPE_CNAME; 1849 r = _cache_get_response(s, q->qname, qtype, &lowest_timeleft); 1850 } 1851 1852 if(r) 1853 { 1854 int nxdomain; 1855 1856 _debug_line(s, "[%d] using cached answer", q->id); 1857 1858 /* are any of the records about to expire in 3 minutes? */ 1859 /* assume the client is interested in this record and */ 1860 /* query it again "in the background" */ 1861 if(lowest_timeleft < (3 * 60 * 1000)) 1862 { 1863 query_t *new_q; 1864 1865 _debug_line(s, "requerying for cached item about to expire"); 1866 1867 new_q = _get_query(s, q->qname, q->qtype, 1); 1868 new_q->retrying = 1; /* slow it down */ 1869 new_q->trycache = 0; /* don't use the cache for this */ 1870 } 1871 1872 nxdomain = r->answerCount == 0 ? 1 : 0; 1873 if(_process_response(s, r, nxdomain, q)) 1874 { 1875 _remove_query_datagrams(s, q); 1876 list_remove(s->queries, q); 1877 --n; /* adjust position */ 1878 } 1879 continue; 1880 } 1881 } 1882 1883 /* inactive */ 1884 if(q->step == -1) 1885 { 1886 /* time up on an inactive query? remove it */ 1887 _debug_line(s, "removing inactive query"); 1888 _remove_query_datagrams(s, q); 1889 list_remove(s->queries, q); 1890 --n; /* adjust position */ 1891 continue; 1892 } 1893 1894 giveup = 0; 1895 1896 /* too many tries, give up */ 1897 if(q->step == 8) 1898 giveup = 1; 1899 1900 /* no nameservers, give up */ 1901 /* (this would happen if someone removed all nameservers */ 1902 /* during a query) */ 1903 if(s->name_servers->count == 0) 1904 giveup = 1; 1905 1906 if(giveup) 1907 { 1908 /* report event to any requests listening */ 1909 for(k = 0; k < q->req_ids_count; ++k) 1910 { 1911 jdns_event_t *event = jdns_event_new(); 1912 event->type = JDNS_EVENT_RESPONSE; 1913 event->id = q->req_ids[k]; 1914 event->status = JDNS_STATUS_TIMEOUT; 1915 _append_event_and_hold_id(s, event); 1916 } 1917 1918 /* report error to parent */ 1919 if(q->cname_parent) 1920 { 1921 /* report event to any requests listening */ 1922 query_t *cq = q->cname_parent; 1923 for(k = 0; k < cq->req_ids_count; ++k) 1924 { 1925 jdns_event_t *event = jdns_event_new(); 1926 event->type = JDNS_EVENT_RESPONSE; 1927 event->id = cq->req_ids[k]; 1928 event->status = JDNS_STATUS_TIMEOUT; 1929 _append_event_and_hold_id(s, event); 1930 } 1931 list_remove(s->queries, cq); 1932 } 1933 1934 _remove_query_datagrams(s, q); 1935 list_remove(s->queries, q); 1936 --n; /* adjust position */ 1937 continue; 1938 } 1939 1940 /* assign a packet id if we don't have one yet */ 1941 if(q->dns_id == -1) 1942 { 1943 q->dns_id = get_next_dns_id(s); 1944 1945 /* couldn't get an id? */ 1946 if(q->dns_id == -1) 1947 { 1948 _debug_line(s, "unable to reserve packet id"); 1949 1950 /* report event to any requests listening */ 1951 for(k = 0; k < q->req_ids_count; ++k) 1952 { 1953 jdns_event_t *event = jdns_event_new(); 1954 event->type = JDNS_EVENT_RESPONSE; 1955 event->id = q->req_ids[k]; 1956 event->status = JDNS_STATUS_ERROR; 1957 _append_event_and_hold_id(s, event); 1958 } 1959 1960 /* report error to parent */ 1961 if(q->cname_parent) 1962 { 1963 /* report event to any requests listening */ 1964 query_t *cq = q->cname_parent; 1965 for(k = 0; k < cq->req_ids_count; ++k) 1966 { 1967 jdns_event_t *event = jdns_event_new(); 1968 event->type = JDNS_EVENT_RESPONSE; 1969 event->id = cq->req_ids[k]; 1970 event->status = JDNS_STATUS_ERROR; 1971 _append_event_and_hold_id(s, event); 1972 } 1973 list_remove(s->queries, cq); 1974 } 1975 1976 _remove_query_datagrams(s, q); 1977 list_remove(s->queries, q); 1978 --n; /* adjust position */ 1979 continue; 1980 } 1981 } 1982 1983 /* out of name servers? */ 1984 if(q->servers_tried_count == s->name_servers->count) 1985 { 1986 /* clear the 'tried' list, and start over in retry mode */ 1987 query_clear_servers_tried(q); 1988 q->retrying = 1; 1989 } 1990 1991 /* find a nameserver that has not been tried */ 1992 ns = 0; 1993 for(k = 0; k < s->name_servers->count; ++k) 1994 { 1995 name_server_t *i = (name_server_t *)s->name_servers->item[k]; 1996 if(!query_server_tried(q, i->id)) 1997 { 1998 ns = i; 1999 break; 2000 } 2001 } 2002 2003 /* in theory, it is not possible for 'ns' to be null here */ 2004 2005 /* don't send the packet if there is already one in the queue */ 2006 already_sending = 0; 2007 for(k = 0; k < s->outgoing->count; ++k) 2008 { 2009 datagram_t *a = (datagram_t *)s->outgoing->item[k]; 2010 if(a->query == q && a->query_send_type == 0) 2011 { 2012 already_sending = 1; 2013 break; 2014 } 2015 } 2016 2017 /* send the query, with recursion desired, normal query_send_type */ 2018 if(!already_sending) 2019 _queue_packet(s, q, ns, 1, 0); 2020 2021 query_add_server_tried(q, ns->id); 2022 2023 /* if there is one query, then do a trick on the first step */ 2024 /*if(s->queries->count == 1 && q->step == 0 && !q->retrying) 2025 { 2026 // query all other servers non-recursively 2027 // note: if sending fails, there is no retry 2028 for(k = 0; k < s->name_servers->count; ++k) 2029 { 2030 name_server_t *i = (name_server_t *)s->name_servers->item[k]; 2031 if(!query_server_tried(q, i->id)) 2032 { 2033 // last arg sets first-step query_send_type 2034 _queue_packet(s, q, i, 0, 1); 2035 } 2036 } 2037 }*/ 2038 2039 /* out of name servers? */ 2040 if(q->servers_tried_count == s->name_servers->count) 2041 { 2042 /* clear the 'tried' list, and start over in retry mode */ 2043 query_clear_servers_tried(q); 2044 q->retrying = 1; 2045 } 2046 2047 q->time_start = now; 2048 q->time_next = q->retrying ? 1500 : 800; 2049 ++q->step; 2050 } 2051 2052 /* try to send queued outgoing packets */ 2053 for(n = 0; n < s->outgoing->count; ++n) 2054 { 2055 datagram_t *a = (datagram_t *)s->outgoing->item[n]; 2056 int ret; 2057 2058 if(!s->handle_writable) 2059 { 2060 need_write = 1; 2061 break; 2062 } 2063 2064 _debug_line(s, "SEND %s:%d (size=%d)", a->dest_address->c_str, a->dest_port, a->size); 2065 _print_hexdump(s, a->data, a->size); 2066 2067 ret = s->cb.udp_write(s, s->cb.app, a->handle, a->dest_address, a->dest_port, a->data, a->size); 2068 if(ret == 0) 2069 { 2070 s->handle_writable = 0; 2071 need_write = 1; 2072 break; 2073 } 2074 2075 list_remove(s->outgoing, a); 2076 --n; /* adjust position */ 2077 } 2078 2079 return need_write; 2080 } 2081 2082 void _cache_add(jdns_session_t *s, const unsigned char *qname, int qtype, int time_start, int ttl, const jdns_rr_t *record) 2083 { 2084 cache_item_t *i; 2085 jdns_string_t *str; 2086 if(ttl == 0) 2087 return; 2088 if(s->cache->count >= JDNS_CACHE_MAX) 2089 return; 2090 i = cache_item_new(); 2091 i->qname = _ustrdup(qname); 2092 i->qtype = qtype; 2093 i->time_start = time_start; 2094 i->ttl = ttl; 2095 if(record) 2096 i->record = jdns_rr_copy(record); 2097 list_insert(s->cache, i, -1); 2098 2099 str = _make_printable_cstr((const char *)i->qname); 2100 _debug_line(s, "cache add [%s] for %d seconds", str->data, i->ttl); 2101 jdns_string_delete(str); 2102 } 2103 2104 void _cache_remove_all_of_kind(jdns_session_t *s, const unsigned char *qname, int qtype) 2105 { 2106 int n; 2107 for(n = 0; n < s->cache->count; ++n) 2108 { 2109 cache_item_t *i = (cache_item_t *)s->cache->item[n]; 2110 if(jdns_domain_cmp(i->qname, qname) && i->qtype == qtype) 2111 { 2112 jdns_string_t *str = _make_printable_cstr((const char *)i->qname); 2113 _debug_line(s, "cache del [%s]", str->data); 2114 jdns_string_delete(str); 2115 list_remove(s->cache, i); 2116 --n; /* adjust position */ 2117 } 2118 } 2119 } 2120 2121 int _unicast_do_reads(jdns_session_t *s, int now) 2122 { 2123 int need_read; 2124 int n, k; 2125 2126 /* let's always ask for reads, just so the user doesn't have to */ 2127 /* worry about what should happen to incoming packets otherwise */ 2128 need_read = 1; 2129 2130 if(!s->handle_readable) 2131 return need_read; 2132 2133 while(1) 2134 { 2135 unsigned char buf[JDNS_UDP_UNI_IN_MAX]; 2136 int bufsize = JDNS_UDP_UNI_IN_MAX; 2137 int ret; 2138 jdns_packet_t *packet; 2139 jdns_address_t *addr; 2140 int port; 2141 query_t *q; 2142 name_server_t *ns; 2143 2144 addr = jdns_address_new(); 2145 ret = s->cb.udp_read(s, s->cb.app, s->handle, addr, &port, buf, &bufsize); 2146 2147 /* no packet? */ 2148 if(ret == 0) 2149 { 2150 s->handle_readable = 0; 2151 jdns_address_delete(addr); 2152 break; 2153 } 2154 2155 _debug_line(s, "RECV %s:%d (size=%d)", addr->c_str, port, bufsize); 2156 _print_hexdump(s, buf, bufsize); 2157 2158 if(!jdns_packet_import(&packet, buf, bufsize)) 2159 { 2160 _debug_line(s, "error parsing packet / too large"); 2161 2162 jdns_address_delete(addr); 2163 continue; 2164 } 2165 2166 _print_packet(s, packet); 2167 2168 if(s->queries->count == 0) 2169 { 2170 _debug_line(s, "we have no queries"); 2171 2172 jdns_address_delete(addr); 2173 continue; 2174 } 2175 2176 /* who does it belong to? */ 2177 q = 0; 2178 ns = 0; 2179 for(n = 0; n < s->queries->count; ++n) 2180 { 2181 query_t *i = (query_t *)s->queries->item[n]; 2182 if(i->dns_id == -1) 2183 continue; 2184 2185 if(i->dns_id == packet->id) 2186 { 2187 q = i; 2188 break; 2189 } 2190 } 2191 2192 if(q) 2193 { 2194 /* what name server did it come from? */ 2195 for(k = 0; k < s->name_servers->count; ++k) 2196 { 2197 name_server_t *i = (name_server_t *)s->name_servers->item[k]; 2198 if(jdns_address_cmp(i->address, addr) && i->port == port) 2199 { 2200 ns = i; 2201 break; 2202 } 2203 } 2204 2205 /* none? maybe that's because we're using unicast */ 2206 /* over multicast, where responses always come */ 2207 /* from an unexpected address */ 2208 if(!ns && s->name_servers->count > 0) 2209 { 2210 name_server_t *i; 2211 jdns_address_t *m4, *m6; 2212 2213 i = (name_server_t *)s->name_servers->item[0]; 2214 m4 = jdns_address_multicast4_new(); 2215 m6 = jdns_address_multicast6_new(); 2216 if(jdns_address_cmp(i->address, m4) || jdns_address_cmp(i->address, m6)) 2217 ns = i; 2218 jdns_address_delete(m4); 2219 jdns_address_delete(m6); 2220 } 2221 2222 /* if there is no suitable name server, don't accept */ 2223 /* as a reply */ 2224 if(!ns) 2225 q = 0; 2226 } 2227 2228 jdns_address_delete(addr); 2229 2230 /* no queries? eat the packet */ 2231 if(!q) 2232 { 2233 _debug_line(s, "no such query for packet"); 2234 jdns_packet_delete(packet); 2235 continue; 2236 } 2237 2238 _process_message(s, packet, now, q, ns); 2239 jdns_packet_delete(packet); 2240 } 2241 2242 return need_read; 2243 } 2244 2245 void _process_message(jdns_session_t *s, jdns_packet_t *packet, int now, query_t *q, name_server_t *ns) 2246 { 2247 int n; 2248 int authoritative; 2249 int truncated; 2250 int recursion_desired; 2251 int answer_section_ok; 2252 int nxdomain; 2253 jdns_response_t *r; 2254 2255 if(packet->opts.opcode != 0) 2256 { 2257 _debug_line(s, "opcode != 0, discarding"); 2258 return; 2259 } 2260 2261 /* we don't test RA (recursion available) */ 2262 /* we don't test the extra Z fields */ 2263 2264 authoritative = packet->opts.aa; 2265 truncated = packet->opts.tc; 2266 recursion_desired = packet->opts.rd; 2267 answer_section_ok = 0; 2268 if(packet->qdcount == packet->questions->count && packet->ancount == packet->answerRecords->count) 2269 answer_section_ok = 1; 2270 nxdomain = 0; 2271 2272 r = 0; 2273 2274 /* nxdomain */ 2275 if(packet->opts.rcode == 3) 2276 { 2277 r = jdns_response_new(); 2278 nxdomain = 1; 2279 } 2280 /* normal */ 2281 else if(packet->opts.rcode == 0) 2282 { 2283 int at_least_something; 2284 int success; 2285 2286 r = _packet2response(packet, q->qname, q->qtype, 0xffff); 2287 at_least_something = 0; 2288 if(r->answerCount > 0) 2289 at_least_something = 1; 2290 _print_records(s, r, q->qname); 2291 2292 success = 0; 2293 if(at_least_something) 2294 { 2295 success = 1; 2296 } 2297 else 2298 { 2299 /* note: why does qdns care about recursion_desired here? */ 2300 if(authoritative && recursion_desired) 2301 success = 1; 2302 } 2303 2304 if(!success) 2305 { 2306 jdns_response_delete(r); 2307 r = 0; 2308 } 2309 } 2310 2311 /* caching */ 2312 if(r) 2313 { 2314 if(nxdomain) 2315 { 2316 /* cache nxdomain for 1 minute */ 2317 if(q->qtype != JDNS_RTYPE_ANY) 2318 { 2319 _cache_remove_all_of_kind(s, q->qname, q->qtype); 2320 _cache_add(s, q->qname, q->qtype, now, 60, 0); 2321 } 2322 } 2323 else 2324 { 2325 int cache_answers; 2326 int cache_additional; 2327 2328 /* clear past items */ 2329 _cache_remove_all_of_kind(s, q->qname, q->qtype); 2330 2331 cache_answers = 1; 2332 cache_additional = 1; 2333 2334 /* if truncated, we may not want to cache */ 2335 if(truncated) 2336 { 2337 cache_additional = 0; 2338 if(!answer_section_ok) 2339 cache_answers = 0; 2340 } 2341 2342 if(cache_answers) 2343 { 2344 for(n = 0; n < r->answerCount; ++n) 2345 { 2346 jdns_rr_t *record = r->answerRecords[n]; 2347 _cache_add(s, q->qname, record->type, now, _min(record->ttl, JDNS_TTL_MAX), record); 2348 } 2349 } 2350 2351 if(cache_additional) 2352 { 2353 for(n = 0; n < r->additionalCount; ++n) 2354 { 2355 jdns_rr_t *record = r->additionalRecords[n]; 2356 _cache_add(s, record->owner, record->type, now, _min(record->ttl, JDNS_TTL_MAX), record); 2357 } 2358 } 2359 } 2360 } 2361 2362 /* don't pass authority/additional records upwards */ 2363 if(r) 2364 jdns_response_remove_extra(r); 2365 2366 /* this server returned an error? */ 2367 if(!r && ns) 2368 { 2369 /* all failed servers must also be considered tried servers, */ 2370 /* so mark as tried if necessary. this can happen if the */ 2371 /* tried list is cleared (to perform retrying) and then an */ 2372 /* error is received */ 2373 if(!query_server_tried(q, ns->id)) 2374 query_add_server_tried(q, ns->id); 2375 2376 query_add_server_failed(q, ns->id); 2377 } 2378 2379 if(_process_response(s, r, nxdomain, q)) 2380 { 2381 _remove_query_datagrams(s, q); 2382 list_remove(s->queries, q); 2383 } 2384 2385 jdns_response_delete(r); 2386 } 2387 2388 int _process_response(jdns_session_t *s, jdns_response_t *r, int nxdomain, query_t *q) 2389 { 2390 int k; 2391 2392 /* error */ 2393 if(!r) 2394 { 2395 int all_errored; 2396 2397 /* if not all servers have errored, ignore error */ 2398 all_errored = 1; 2399 for(k = 0; k < s->name_servers->count; ++k) 2400 { 2401 name_server_t *ns = (name_server_t *)s->name_servers->item[k]; 2402 if(!query_server_failed(q, ns->id)) 2403 { 2404 all_errored = 0; 2405 break; 2406 } 2407 } 2408 if(!all_errored) 2409 return 0; 2410 2411 /* report event to any requests listening */ 2412 for(k = 0; k < q->req_ids_count; ++k) 2413 { 2414 jdns_event_t *event = jdns_event_new(); 2415 event->type = JDNS_EVENT_RESPONSE; 2416 event->id = q->req_ids[k]; 2417 event->status = JDNS_STATUS_ERROR; 2418 _append_event_and_hold_id(s, event); 2419 } 2420 2421 /* report error to parent */ 2422 if(q->cname_parent) 2423 { 2424 /* report event to any requests listening */ 2425 query_t *cq = q->cname_parent; 2426 for(k = 0; k < cq->req_ids_count; ++k) 2427 { 2428 jdns_event_t *event = jdns_event_new(); 2429 event->type = JDNS_EVENT_RESPONSE; 2430 event->id = cq->req_ids[k]; 2431 event->status = JDNS_STATUS_ERROR; 2432 _append_event_and_hold_id(s, event); 2433 } 2434 list_remove(s->queries, cq); 2435 } 2436 2437 return 1; 2438 } 2439 /* nxdomain */ 2440 else if(nxdomain) 2441 { 2442 /* report event to any requests listening */ 2443 for(k = 0; k < q->req_ids_count; ++k) 2444 { 2445 jdns_event_t *event = jdns_event_new(); 2446 event->type = JDNS_EVENT_RESPONSE; 2447 event->id = q->req_ids[k]; 2448 event->status = JDNS_STATUS_NXDOMAIN; 2449 _append_event_and_hold_id(s, event); 2450 } 2451 2452 /* report error to parent */ 2453 if(q->cname_parent) 2454 { 2455 /* report event to any requests listening */ 2456 query_t *cq = q->cname_parent; 2457 for(k = 0; k < cq->req_ids_count; ++k) 2458 { 2459 jdns_event_t *event = jdns_event_new(); 2460 event->type = JDNS_EVENT_RESPONSE; 2461 event->id = cq->req_ids[k]; 2462 event->status = JDNS_STATUS_ERROR; 2463 _append_event_and_hold_id(s, event); 2464 } 2465 list_remove(s->queries, cq); 2466 } 2467 2468 return 1; 2469 } 2470 2471 /* all we got was a cname that we didn't ask for? */ 2472 if(r->answerCount == 1 && r->answerRecords[0]->type == JDNS_RTYPE_CNAME && q->qtype != JDNS_RTYPE_CNAME) 2473 { 2474 query_t *new_q; 2475 2476 _debug_line(s, "all we got was a cname, following the chain ..."); 2477 2478 /* max chain count, bail */ 2479 if(q->cname_chain_count >= JDNS_CNAME_MAX) 2480 { 2481 /* report event to any requests listening */ 2482 for(k = 0; k < q->req_ids_count; ++k) 2483 { 2484 jdns_event_t *event = jdns_event_new(); 2485 event->type = JDNS_EVENT_RESPONSE; 2486 event->id = q->req_ids[k]; 2487 event->status = JDNS_STATUS_ERROR; 2488 _append_event_and_hold_id(s, event); 2489 } 2490 2491 /* report error to parent */ 2492 if(q->cname_parent) 2493 { 2494 /* report event to any requests listening */ 2495 query_t *cq = q->cname_parent; 2496 for(k = 0; k < cq->req_ids_count; ++k) 2497 { 2498 jdns_event_t *event = jdns_event_new(); 2499 event->type = JDNS_EVENT_RESPONSE; 2500 event->id = cq->req_ids[k]; 2501 event->status = JDNS_STATUS_ERROR; 2502 _append_event_and_hold_id(s, event); 2503 } 2504 list_remove(s->queries, cq); 2505 } 2506 2507 return 1; 2508 } 2509 2510 new_q = _get_query(s, r->answerRecords[0]->data.name, q->qtype, 1); 2511 2512 /* is the current query a child query? (has a parent) */ 2513 if(q->cname_parent) 2514 { 2515 /* if so, then set new_q as the new child */ 2516 new_q->cname_chain_count = q->cname_chain_count + 1; 2517 new_q->cname_parent = q->cname_parent; 2518 new_q->cname_parent->cname_child = new_q; 2519 2520 /* and delete the current query */ 2521 return 1; 2522 } 2523 else 2524 { 2525 /* otherwise, the current query becomes a parent, with */ 2526 /* new_q set as the child */ 2527 new_q->cname_chain_count = q->cname_chain_count + 1; 2528 new_q->cname_parent = q; 2529 q->cname_child = new_q; 2530 q->time_start = -1; 2531 q->dns_id = -1; /* don't handle responses */ 2532 } 2533 } 2534 2535 /* if this query now has a child, then don't report events or delete */ 2536 if(q->cname_child) 2537 return 0; 2538 2539 /* report event to any requests listening */ 2540 for(k = 0; k < q->req_ids_count; ++k) 2541 { 2542 jdns_event_t *event = jdns_event_new(); 2543 event->type = JDNS_EVENT_RESPONSE; 2544 event->id = q->req_ids[k]; 2545 event->status = JDNS_STATUS_SUCCESS; 2546 event->response = jdns_response_copy(r); 2547 _append_event_and_hold_id(s, event); 2548 } 2549 2550 /* report to parent */ 2551 if(q->cname_parent) 2552 { 2553 /* report event to any requests listening */ 2554 query_t *cq = q->cname_parent; 2555 for(k = 0; k < cq->req_ids_count; ++k) 2556 { 2557 jdns_event_t *event = jdns_event_new(); 2558 event->type = JDNS_EVENT_RESPONSE; 2559 event->id = cq->req_ids[k]; 2560 event->status = JDNS_STATUS_SUCCESS; 2561 event->response = jdns_response_copy(r); 2562 _append_event_and_hold_id(s, event); 2563 } 2564 list_remove(s->queries, cq); 2565 } 2566 2567 return 1; 2568 } 2569 2570 /*---------------------------------------------------------------------------- */ 2571 /* jdns - multicast */ 2572 /*---------------------------------------------------------------------------- */ 2573 static jdns_rr_t *_mdnsda2rr(mdnsda a) 2574 { 2575 jdns_rr_t *rr; 2576 2577 if(a->type == JDNS_RTYPE_ANY) 2578 return 0; 2579 2580 /* for AAAA, TXT and HINFO, run the raw rdata through jdns_rr's parser */ 2581 if(a->type == JDNS_RTYPE_AAAA || a->type == JDNS_RTYPE_TXT || a->type == JDNS_RTYPE_HINFO) 2582 { 2583 jdns_packet_resource_t *pr = jdns_packet_resource_new(); 2584 pr->qname = jdns_string_new(); 2585 jdns_string_set_cstr(pr->qname, (const char *)a->name); 2586 pr->qtype = a->type; 2587 pr->qclass = 0x0001; /* class is always 1 for us */ 2588 if(a->ttl == 0) 2589 pr->ttl = 0; 2590 else 2591 pr->ttl = a->real_ttl; 2592 pr->rdata = jdns_copy_array(a->rdata, a->rdlen); 2593 pr->rdlength = a->rdlen; 2594 2595 /* we don't need a reference for these types */ 2596 rr = jdns_rr_from_resource(pr, 0); 2597 } 2598 /* else, pull the values out of 'a' directly */ 2599 else 2600 { 2601 rr = jdns_rr_new(); 2602 rr->owner = _ustrdup(a->name); 2603 rr->qclass = 0x0001; /* class is always 1 for us */ 2604 if(a->ttl == 0) 2605 rr->ttl = 0; 2606 else 2607 rr->ttl = a->real_ttl; 2608 2609 switch(a->type) 2610 { 2611 case JDNS_RTYPE_A: 2612 { 2613 jdns_address_t *addr = jdns_address_new(); 2614 jdns_address_set_ipv4(addr, a->ip); 2615 jdns_rr_set_A(rr, addr); 2616 jdns_address_delete(addr); 2617 break; 2618 } 2619 case JDNS_RTYPE_AAAA: 2620 { 2621 /* covered earlier */ 2622 break; 2623 } 2624 case JDNS_RTYPE_MX: 2625 { 2626 /* don't care about MX */ 2627 jdns_rr_delete(rr); 2628 rr = 0; 2629 break; 2630 } 2631 case JDNS_RTYPE_SRV: 2632 { 2633 jdns_rr_set_SRV(rr, a->rdname, a->srv.port, a->srv.priority, a->srv.weight); 2634 break; 2635 } 2636 case JDNS_RTYPE_CNAME: 2637 { 2638 jdns_rr_set_CNAME(rr, a->rdname); 2639 break; 2640 } 2641 case JDNS_RTYPE_PTR: 2642 { 2643 jdns_rr_set_PTR(rr, a->rdname); 2644 break; 2645 } 2646 case JDNS_RTYPE_TXT: 2647 { 2648 /* covered earlier */ 2649 break; 2650 } 2651 case JDNS_RTYPE_HINFO: 2652 { 2653 /* covered earlier */ 2654 break; 2655 } 2656 case JDNS_RTYPE_NS: 2657 { 2658 /* don't care about NS */ 2659 jdns_rr_delete(rr); 2660 rr = 0; 2661 break; 2662 } 2663 default: 2664 { 2665 jdns_rr_set_record(rr, a->type, a->rdata, a->rdlen); 2666 break; 2667 } 2668 } 2669 } 2670 2671 return rr; 2672 } 2673 2674 static int _cmp_rdata(const jdns_rr_t *a, const jdns_rr_t *b) 2675 { 2676 if(a->rdlength != b->rdlength) 2677 return 0; 2678 if(memcmp(a->rdata, b->rdata, a->rdlength) != 0) 2679 return 0; 2680 return 1; 2681 } 2682 2683 static int _cmp_rr(const jdns_rr_t *a, const jdns_rr_t *b) 2684 { 2685 if(a->type != b->type) 2686 return 0; 2687 if(!jdns_domain_cmp(a->owner, b->owner)) 2688 return 0; 2689 switch(a->type) 2690 { 2691 case JDNS_RTYPE_A: 2692 if(!jdns_address_cmp(a->data.address, b->data.address)) 2693 return 0; 2694 break; 2695 case JDNS_RTYPE_AAAA: 2696 if(!_cmp_rdata(a, b)) 2697 return 0; 2698 break; 2699 case JDNS_RTYPE_MX: 2700 /* unsupported */ 2701 return 0; 2702 case JDNS_RTYPE_SRV: 2703 if(a->data.server->port != b->data.server->port 2704 || a->data.server->priority != b->data.server->priority 2705 || a->data.server->weight != b->data.server->weight 2706 || !jdns_domain_cmp(a->data.server->name, b->data.server->name) 2707 ) 2708 return 0; 2709 break; 2710 case JDNS_RTYPE_CNAME: 2711 if(!jdns_domain_cmp(a->data.name, b->data.name)) 2712 return 0; 2713 break; 2714 case JDNS_RTYPE_PTR: 2715 if(!jdns_domain_cmp(a->data.name, b->data.name)) 2716 return 0; 2717 break; 2718 case JDNS_RTYPE_TXT: 2719 if(!_cmp_rdata(a, b)) 2720 return 0; 2721 break; 2722 case JDNS_RTYPE_HINFO: 2723 if(!_cmp_rdata(a, b)) 2724 return 0; 2725 break; 2726 case JDNS_RTYPE_NS: 2727 /* unsupported */ 2728 return 0; 2729 default: 2730 if(!_cmp_rdata(a, b)) 2731 return 0; 2732 break; 2733 } 2734 return 1; 2735 } 2736 2737 int _multicast_query_ans(mdnsda a, void *arg) 2738 { 2739 int n; 2740 jdns_session_t *s; 2741 query_t *q; 2742 jdns_response_t *r; 2743 jdns_rr_t *rr; 2744 jdns_event_t *event; 2745 2746 s = (jdns_session_t *)arg; 2747 2748 /* what query is this for? */ 2749 q = 0; 2750 for(n = 0; n < s->queries->count; ++n) 2751 { 2752 query_t *i = (query_t *)s->queries->item[n]; 2753 if((i->qtype == JDNS_RTYPE_ANY || i->qtype == a->type) && jdns_domain_cmp(i->qname, a->name)) 2754 { 2755 q = i; 2756 break; 2757 } 2758 } 2759 2760 /* note: this can't happen, but we'll check anyway */ 2761 if(!q) 2762 { 2763 _debug_line(s, "no such multicast query"); 2764 return 0; 2765 } 2766 2767 rr = _mdnsda2rr(a); 2768 if(!rr) 2769 return 0; 2770 2771 /* add/remove as a known */ 2772 if(rr->ttl == 0) 2773 { 2774 for(n = 0; n < q->mul_known->answerCount; ++n) 2775 { 2776 jdns_rr_t *k = q->mul_known->answerRecords[n]; 2777 if(_cmp_rr(k, rr)) 2778 { 2779 jdns_response_remove_answer(q->mul_known, n); 2780 break; 2781 } 2782 } 2783 } 2784 else 2785 jdns_response_append_answer(q->mul_known, rr); 2786 2787 r = jdns_response_new(); 2788 jdns_response_append_answer(r, rr); 2789 jdns_rr_delete(rr); 2790 2791 /* report event to any requests listening */ 2792 for(n = 0; n < q->req_ids_count; ++n) 2793 { 2794 event = jdns_event_new(); 2795 event->type = JDNS_EVENT_RESPONSE; 2796 event->id = q->req_ids[n]; 2797 event->status = JDNS_STATUS_SUCCESS; 2798 event->response = jdns_response_copy(r); 2799 _append_event(s, event); 2800 } 2801 2802 jdns_response_delete(r); 2803 return 0; 2804 } 2805 2806 query_t *_get_multicast_query(jdns_session_t *s, const unsigned char *qname, int qtype) 2807 { 2808 int n; 2809 query_t *q; 2810 jdns_string_t *str; 2811 2812 /* check for existing queries */ 2813 for(n = 0; n < s->queries->count; ++n) 2814 { 2815 q = (query_t *)s->queries->item[n]; 2816 if(jdns_domain_cmp(q->qname, qname) && q->qtype == qtype) 2817 { 2818 str = _make_printable_cstr((const char *)q->qname); 2819 _debug_line(s, "[%d] reusing query for: [%s] [%s]", q->id, _qtype2str(qtype), str->data); 2820 jdns_string_delete(str); 2821 return q; 2822 } 2823 } 2824 2825 q = query_new(); 2826 q->id = get_next_qid(s); 2827 q->qname = _ustrdup(qname); 2828 q->qtype = qtype; 2829 q->step = 0; 2830 q->mul_known = jdns_response_new(); 2831 list_insert(s->queries, q, -1); 2832 2833 str = _make_printable_cstr((const char *)q->qname); 2834 _debug_line(s, "[%d] querying: [%s] [%s]", q->id, _qtype2str(qtype), str->data); 2835 jdns_string_delete(str); 2836 return q; 2837 } 2838 2839 int _multicast_query(jdns_session_t *s, const unsigned char *name, int qtype) 2840 { 2841 unsigned char *qname; 2842 query_t *q; 2843 int req_id; 2844 jdns_string_t *str; 2845 2846 str = _make_printable_cstr((const char *)name); 2847 _debug_line(s, "query input: [%s]", str->data); 2848 jdns_string_delete(str); 2849 2850 /* add a dot to the end if needed */ 2851 qname = _fix_input(name); 2852 2853 q = _get_multicast_query(s, qname, qtype); 2854 req_id = get_next_req_id(s); 2855 query_add_req_id(q, req_id); 2856 free(qname); 2857 2858 /* start the mdnsd_query if necessary */ 2859 if(q->step == 0) 2860 { 2861 q->step = 1; 2862 mdnsd_query(s->mdns, (char *)q->qname, q->qtype, _multicast_query_ans, s); 2863 } 2864 else 2865 { 2866 int n; 2867 2868 /* report the knowns */ 2869 for(n = 0; n < q->mul_known->answerCount; ++n) 2870 { 2871 const jdns_rr_t *rr; 2872 jdns_response_t *r; 2873 jdns_event_t *event; 2874 2875 rr = q->mul_known->answerRecords[n]; 2876 r = jdns_response_new(); 2877 jdns_response_append_answer(r, rr); 2878 2879 event = jdns_event_new(); 2880 event->type = JDNS_EVENT_RESPONSE; 2881 event->id = req_id; 2882 event->status = JDNS_STATUS_SUCCESS; 2883 event->response = r; 2884 _append_event(s, event); 2885 } 2886 } 2887 return req_id; 2888 } 2889 2890 void _multicast_cancel(jdns_session_t *s, int req_id) 2891 { 2892 int n; 2893 for(n = 0; n < s->queries->count; ++n) 2894 { 2895 query_t *q = (query_t *)s->queries->item[n]; 2896 if(query_have_req_id(q, req_id)) 2897 { 2898 query_remove_req_id(q, req_id); 2899 2900 /* if no one else is depending on this request, then take action */ 2901 if(q->req_ids_count == 0) 2902 { 2903 mdnsd_query(s->mdns, (char *)q->qname, q->qtype, NULL, 0); 2904 list_remove(s->queries, q); 2905 } 2906 break; 2907 } 2908 } 2909 } 2910 2911 void _multicast_pubresult(int result, char *name, int type, void *arg) 2912 { 2913 jdns_session_t *s; 2914 published_item_t *pub; 2915 jdns_event_t *event; 2916 int n; 2917 2918 s = (jdns_session_t *)arg; 2919 2920 /* find the associated pub item */ 2921 pub = 0; 2922 for(n = 0; n < s->published->count; ++n) 2923 { 2924 published_item_t *i = (published_item_t *)s->published->item[n]; 2925 if(strcmp((char *)i->qname, name) == 0 && i->qtype == type) 2926 { 2927 pub = i; 2928 break; 2929 } 2930 } 2931 2932 /* note: this can't happen, but we'll check anyway */ 2933 if(!pub) 2934 { 2935 _debug_line(s, "no such multicast published item"); 2936 return; 2937 } 2938 2939 if(result == 1) 2940 { 2941 jdns_string_t *str = _make_printable_cstr(name); 2942 _debug_line(s, "published name %s for type %d", str->data, type); 2943 jdns_string_delete(str); 2944 2945 event = jdns_event_new(); 2946 event->type = JDNS_EVENT_PUBLISH; 2947 event->id = pub->id; 2948 event->status = JDNS_STATUS_SUCCESS; 2949 _append_event(s, event); 2950 } 2951 else 2952 { 2953 jdns_string_t *str = _make_printable_cstr(name); 2954 _debug_line(s, "conflicting name detected %s for type %d", str->data, type); 2955 jdns_string_delete(str); 2956 2957 event = jdns_event_new(); 2958 event->type = JDNS_EVENT_PUBLISH; 2959 event->id = pub->id; 2960 event->status = JDNS_STATUS_CONFLICT; 2961 _append_event_and_hold_id(s, event); 2962 2963 /* remove the item */ 2964 list_remove(s->published, pub); 2965 } 2966 } 2967 2968 static jdns_string_t *_create_text(const jdns_stringlist_t *texts) 2969 { 2970 jdns_string_t *out; 2971 int n; 2972 int total; 2973 unsigned char *buf; 2974 2975 buf = 0; 2976 total = 0; 2977 for(n = 0; n < texts->count; ++n) 2978 total += texts->item[n]->size + 1; 2979 if(total > 0) 2980 { 2981 int at = 0; 2982 buf = (unsigned char *)malloc(total); 2983 for(n = 0; n < texts->count; ++n) 2984 { 2985 unsigned int len = texts->item[n]->size; 2986 buf[at++] = len; 2987 memcpy(buf + at, texts->item[n]->data, len); 2988 at += len; 2989 } 2990 } 2991 2992 out = jdns_string_new(); 2993 if(buf) 2994 { 2995 out->data = buf; 2996 out->size = total; 2997 } 2998 else 2999 jdns_string_set_cstr(out, ""); 3000 return out; 3001 } 3002 3003 static void _publish_applyrr_unknown(jdns_session_t *s, mdnsdr r, const jdns_rr_t *rr) 3004 { 3005 /* for unsupported/unknown, just take the rdata */ 3006 /* note: for this to work, the app must explicitly set the rdata. */ 3007 /* if the record is MX or some other known but unsupported record */ 3008 /* type, setting the known fields is not enough */ 3009 mdnsd_set_raw(s->mdns, r, (char *)rr->rdata, rr->rdlength); 3010 } 3011 3012 static int _publish_applyrr(jdns_session_t *s, mdnsdr r, const jdns_rr_t *rr) 3013 { 3014 if(!rr->haveKnown) 3015 { 3016 _publish_applyrr_unknown(s, r, rr); 3017 return 1; 3018 } 3019 3020 /* jdns_mdnsd supports: A, AAAA, SRV, CNAME, PTR, TXT, and HINFO */ 3021 switch(rr->type) 3022 { 3023 case JDNS_RTYPE_A: 3024 { 3025 unsigned long int ip_net = htonl(rr->data.address->addr.v4); 3026 mdnsd_set_raw(s->mdns, r, (char *)&ip_net, 4); 3027 break; 3028 } 3029 case JDNS_RTYPE_AAAA: 3030 { 3031 mdnsd_set_raw(s->mdns, r, (char *)rr->data.address->addr.v6, 16); 3032 break; 3033 } 3034 case JDNS_RTYPE_SRV: 3035 { 3036 mdnsd_set_srv(s->mdns, r, rr->data.server->priority, rr->data.server->weight, rr->data.server->port, (char *)rr->data.server->name); 3037 break; 3038 } 3039 case JDNS_RTYPE_CNAME: 3040 { 3041 mdnsd_set_host(s->mdns, r, (char *)rr->data.name); 3042 break; 3043 } 3044 case JDNS_RTYPE_PTR: 3045 { 3046 mdnsd_set_host(s->mdns, r, (char *)rr->data.name); 3047 break; 3048 } 3049 case JDNS_RTYPE_TXT: 3050 { 3051 jdns_string_t *out = _create_text(rr->data.texts); 3052 mdnsd_set_raw(s->mdns, r, (char *)out->data, out->size); 3053 jdns_string_delete(out); 3054 break; 3055 } 3056 case JDNS_RTYPE_HINFO: 3057 { 3058 jdns_string_t *out; 3059 jdns_stringlist_t *list; 3060 3061 list = jdns_stringlist_new(); 3062 jdns_stringlist_append(list, rr->data.hinfo.cpu); 3063 jdns_stringlist_append(list, rr->data.hinfo.os); 3064 out = _create_text(list); 3065 jdns_stringlist_delete(list); 3066 3067 mdnsd_set_raw(s->mdns, r, (char *)out->data, out->size); 3068 jdns_string_delete(out); 3069 break; 3070 } 3071 default: 3072 { 3073 _publish_applyrr_unknown(s, r, rr); 3074 break; 3075 } 3076 } 3077 3078 return 1; 3079 } 3080 3081 static void report_published(jdns_session_t *s, published_item_t *pub) 3082 { 3083 jdns_event_t *event; 3084 jdns_string_t *str; 3085 3086 str = _make_printable_cstr((char *)pub->qname); 3087 _debug_line(s, "published name %s for type %d", str->data, pub->qtype); 3088 jdns_string_delete(str); 3089 3090 event = jdns_event_new(); 3091 event->type = JDNS_EVENT_PUBLISH; 3092 event->id = pub->id; 3093 event->status = JDNS_STATUS_SUCCESS; 3094 _append_event(s, event); 3095 } 3096 3097 int _multicast_publish(jdns_session_t *s, int mode, const jdns_rr_t *rr) 3098 { 3099 mdnsdr r; 3100 published_item_t *pub; 3101 int next_id; 3102 jdns_event_t *event; 3103 int n; 3104 3105 r = 0; 3106 next_id = get_next_req_id(s); 3107 3108 /* see if we have an item with this name+type combination already */ 3109 pub = 0; 3110 for(n = 0; n < s->published->count; ++n) 3111 { 3112 published_item_t *i = (published_item_t *)s->published->item[n]; 3113 if(i->qtype == rr->type && jdns_domain_cmp(i->qname, rr->owner)) 3114 { 3115 pub = i; 3116 break; 3117 } 3118 } 3119 if(pub) 3120 goto error; 3121 3122 if(!jdns_rr_verify(rr)) 3123 goto error; 3124 3125 if(mode == JDNS_PUBLISH_UNIQUE) 3126 r = mdnsd_unique(s->mdns, (char *)rr->owner, rr->type, rr->ttl, _multicast_pubresult, s); 3127 else 3128 r = mdnsd_shared(s->mdns, (char *)rr->owner, rr->type, rr->ttl); 3129 3130 if(!_publish_applyrr(s, r, rr)) 3131 goto error; 3132 3133 pub = published_item_new(); 3134 pub->id = next_id; 3135 pub->mode = mode; 3136 pub->qname = _ustrdup(rr->owner); 3137 pub->qtype = rr->type; 3138 pub->rec = r; 3139 pub->rr = jdns_rr_copy(rr); 3140 list_insert(s->published, pub, -1); 3141 3142 /* mdnsd doesn't report publish events for shared, so do that here */ 3143 if(mode == JDNS_PUBLISH_SHARED) 3144 report_published(s, pub); 3145 3146 return pub->id; 3147 3148 error: 3149 _debug_line(s, "attempt to publish record, malformed, unsupported, or duplicate type"); 3150 3151 if(r) 3152 { 3153 /* don't publish */ 3154 mdnsd_done(s->mdns, r); 3155 } 3156 3157 /* send an error to the app */ 3158 event = jdns_event_new(); 3159 event->type = JDNS_EVENT_PUBLISH; 3160 event->id = next_id; 3161 event->status = JDNS_STATUS_ERROR; 3162 _append_event_and_hold_id(s, event); 3163 3164 return next_id; 3165 } 3166 3167 void _multicast_update_publish(jdns_session_t *s, int id, const jdns_rr_t *rr) 3168 { 3169 mdnsdr r; 3170 published_item_t *pub; 3171 int qtype; 3172 int n; 3173 3174 pub = 0; 3175 for(n = 0; n < s->published->count; ++n) 3176 { 3177 published_item_t *i = (published_item_t *)s->published->item[n]; 3178 if(i->id == id) 3179 { 3180 pub = i; 3181 break; 3182 } 3183 } 3184 if(!pub) 3185 return; 3186 3187 qtype = pub->qtype; 3188 r = pub->rec; 3189 3190 /* expire existing record. this is mostly needed for shared records */ 3191 /* since unique records already have the cache flush bit and that */ 3192 /* should achieve the same result. however, since Apple expires */ 3193 /* unique records before updates, so will we. */ 3194 mdnsd_done(s->mdns, r); 3195 if(pub->mode == JDNS_PUBLISH_UNIQUE) 3196 r = mdnsd_unique(s->mdns, (char *)pub->rr->owner, pub->rr->type, rr->ttl, _multicast_pubresult, s); 3197 else 3198 r = mdnsd_shared(s->mdns, (char *)pub->rr->owner, pub->rr->type, rr->ttl); 3199 pub->rec = r; 3200 3201 if(!_publish_applyrr(s, r, rr)) 3202 { 3203 _debug_line(s, "attempt to update_publish an unsupported type"); 3204 return; 3205 } 3206 } 3207 3208 void _multicast_cancel_publish(jdns_session_t *s, int id) 3209 { 3210 int n; 3211 for(n = 0; n < s->published->count; ++n) 3212 { 3213 published_item_t *i = (published_item_t *)s->published->item[n]; 3214 if(i->id == id) 3215 { 3216 mdnsd_done(s->mdns, i->rec); 3217 list_remove(s->published, i); 3218 break; 3219 } 3220 } 3221 } 3222 3223 void _multicast_flush(jdns_session_t *s) 3224 { 3225 int n; 3226 3227 /* to flush, we make like our queries and published items are all new. */ 3228 /* we'll do this by destroying/creating the mdnsd object again (so it */ 3229 /* is fresh) and then reapply all queries and published items to it. */ 3230 3231 /* start over with mdnsd */ 3232 mdnsd_free(s->mdns); 3233 s->mdns = mdnsd_new(0x0001, 1000, s->port, _callback_time_now, _callback_rand_int, s); 3234 3235 /* attempt to publish again */ 3236 for(n = 0; n < s->published->count; ++n) 3237 { 3238 published_item_t *i; 3239 mdnsdr r; 3240 3241 i = (published_item_t *)s->published->item[n]; 3242 if(i->mode == JDNS_PUBLISH_UNIQUE) 3243 r = mdnsd_unique(s->mdns, (char *)i->rr->owner, i->rr->type, i->rr->ttl, _multicast_pubresult, s); 3244 else 3245 r = mdnsd_shared(s->mdns, (char *)i->rr->owner, i->rr->type, i->rr->ttl); 3246 _publish_applyrr(s, r, i->rr); 3247 i->rec = r; 3248 } 3249 3250 /* restore the queries */ 3251 for(n = 0; n < s->queries->count; ++n) 3252 { 3253 query_t *q = (query_t *)s->queries->item[n]; 3254 3255 /* issue the query */ 3256 mdnsd_query(s->mdns, (char *)q->qname, q->qtype, _multicast_query_ans, s); 3257 } 3258 } 3259 3260 int jdns_step_multicast(jdns_session_t *s, int now) 3261 { 3262 int need_read, need_write, smallest_time; 3263 struct mytimeval *tv; 3264 jdns_packet_t *packet; 3265 int flags; 3266 3267 /* not used */ 3268 (void)now; 3269 3270 need_read = 0; 3271 need_write = 0; 3272 3273 if(s->shutdown == 1) 3274 mdnsd_shutdown(s->mdns); 3275 3276 while(1) 3277 { 3278 jdns_address_t *addr; 3279 unsigned short int port; 3280 int ret; 3281 unsigned char *buf; 3282 int buf_len; 3283 3284 if(!mdnsd_out(s->mdns, &packet, &addr, &port)) 3285 break; 3286 3287 if(!s->handle_writable) 3288 { 3289 need_write = 1; 3290 jdns_address_delete(addr); 3291 break; 3292 } 3293 3294 if(!jdns_packet_export(packet, JDNS_UDP_MUL_OUT_MAX)) 3295 { 3296 _debug_line(s, "outgoing packet export error, not sending"); 3297 jdns_packet_delete(packet); 3298 continue; 3299 } 3300 3301 buf = packet->raw_data; 3302 buf_len = packet->raw_size; 3303 3304 /* multicast */ 3305 if(!addr) 3306 { 3307 addr = jdns_address_copy(s->maddr); 3308 port = s->port; 3309 } 3310 3311 _debug_line(s, "SEND %s:%d (size=%d)", addr->c_str, port, buf_len); 3312 _print_hexdump(s, buf, buf_len); 3313 3314 ret = s->cb.udp_write(s, s->cb.app, s->handle, addr, port, buf, buf_len); 3315 3316 jdns_address_delete(addr); 3317 jdns_packet_delete(packet); 3318 3319 /* if we can't write the packet, oh well */ 3320 if(ret == 0) 3321 { 3322 s->handle_writable = 0; 3323 need_write = 1; 3324 break; 3325 } 3326 } 3327 3328 if(s->shutdown == 1) 3329 { 3330 jdns_event_t *event = jdns_event_new(); 3331 event->type = JDNS_EVENT_SHUTDOWN; 3332 _append_event(s, event); 3333 s->shutdown = 2; 3334 return 0; 3335 } 3336 3337 /* let's always ask for reads, just so the user doesn't have to */ 3338 /* worry about what should happen to incoming packets otherwise */ 3339 need_read = 1; 3340 3341 if(s->handle_readable) 3342 { 3343 while(1) 3344 { 3345 unsigned char buf[JDNS_UDP_MUL_IN_MAX]; 3346 int bufsize = JDNS_UDP_MUL_IN_MAX; 3347 int ret; 3348 jdns_address_t *addr; 3349 int port; 3350 jdns_response_t *r; 3351 3352 addr = jdns_address_new(); 3353 ret = s->cb.udp_read(s, s->cb.app, s->handle, addr, &port, buf, &bufsize); 3354 3355 /* no packet? */ 3356 if(ret == 0) 3357 { 3358 s->handle_readable = 0; 3359 jdns_address_delete(addr); 3360 break; 3361 } 3362 3363 _debug_line(s, "RECV %s:%d (size=%d)", addr->c_str, port, bufsize); 3364 _print_hexdump(s, buf, bufsize); 3365 3366 if(!jdns_packet_import(&packet, buf, bufsize)) 3367 { 3368 _debug_line(s, "error parsing packet / too large"); 3369 3370 jdns_address_delete(addr); 3371 continue; 3372 } 3373 3374 _print_packet(s, packet); 3375 3376 r = _packet2response(packet, 0, 0, 0x7fff); 3377 _print_records(s, r, 0); 3378 3379 mdnsd_in(s->mdns, packet, r, addr, (unsigned short)port); 3380 3381 jdns_address_delete(addr); 3382 jdns_packet_delete(packet); 3383 jdns_response_delete(r); 3384 } 3385 } 3386 3387 tv = mdnsd_sleep(s->mdns); 3388 smallest_time = tv->tv_sec * 1000 + tv->tv_usec / 1000; 3389 3390 flags = 0; 3391 if(smallest_time != -1) 3392 { 3393 flags |= JDNS_STEP_TIMER; 3394 s->next_timer = smallest_time; 3395 3396 /* offset it a little bit, so that the user doesn't call */ 3397 /* us too early, resulting in a no-op and another timer */ 3398 /* of 1 millisecond. */ 3399 s->next_timer += 2; 3400 } 3401 if(need_read || need_write) 3402 flags |= JDNS_STEP_HANDLE; 3403 return flags; 3404 }