void DNSTaskResolvCallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { struct DNSTask *dnstask = (struct DNSTask *) arg; char *query; int id, qr, opcode, aa, tc, rd, ra, rcode; long len; unsigned int qdcount, ancount, nscount, arcount, i; const unsigned char *aptr; debug("LobjId:%d, Hostname %s", dnstask->task->LObjId, dnstask->task->Record.HostName); if (status != ARES_SUCCESS and status != ARES_ENODATA) { return; } /* Parse the answer header. */ id = DNS_HEADER_QID(abuf); qr = DNS_HEADER_QR(abuf); opcode = DNS_HEADER_OPCODE(abuf); aa = DNS_HEADER_AA(abuf); tc = DNS_HEADER_TC(abuf); rd = DNS_HEADER_RD(abuf); ra = DNS_HEADER_RA(abuf); rcode = DNS_HEADER_RCODE(abuf); qdcount = DNS_HEADER_QDCOUNT(abuf); ancount = DNS_HEADER_ANCOUNT(abuf); nscount = DNS_HEADER_NSCOUNT(abuf); arcount = DNS_HEADER_ARCOUNT(abuf); aptr = abuf + HFIXEDSZ; ares_expand_name(aptr, abuf, alen, &query, &len); for (i = 0; i < qdcount; i++) { aptr = skip_question(aptr, abuf, alen); if (aptr == NULL) return; } dnstask->task->code = STATE_ERROR; switch (dnstask->role) { case DNS_TASK: for (i = 0; i < ancount; i++) { debug("try %d %d ", dnstask->task->LObjId, ancount); aptr = CheckPatternAfterParseAnswer(dnstask, aptr, abuf, alen); if (aptr == NULL) break; } dnstask->task->callback(dnstask->task); break; } }
static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { struct qquery *qquery = (struct qquery *) arg; unsigned int ancount; int rcode; if (status != ARES_SUCCESS) qquery->callback(qquery->arg, status, timeouts, abuf, alen); else { /* Pull the response code and answer count from the packet. */ rcode = DNS_HEADER_RCODE(abuf); ancount = DNS_HEADER_ANCOUNT(abuf); /* Convert errors. */ switch (rcode) { case NOERROR: status = (ancount > 0) ? ARES_SUCCESS : ARES_ENODATA; break; case FORMERR: status = ARES_EFORMERR; break; case SERVFAIL: status = ARES_ESERVFAIL; break; case NXDOMAIN: status = ARES_ENOTFOUND; break; case NOTIMP: status = ARES_ENOTIMP; break; case REFUSED: status = ARES_EREFUSED; break; } qquery->callback(qquery->arg, status, timeouts, abuf, alen); } ares_free(qquery); }
static void callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { char *name = (char *) arg; int id, qr, opcode, aa, tc, rd, ra, rcode; unsigned int qdcount, ancount, nscount, arcount, i; const unsigned char *aptr; (void) timeouts; /* Display the query name if given. */ if (name) printf("Answer for query %s:\n", name); /* Display an error message if there was an error, but only stop if * we actually didn't get an answer buffer. */ if (status != ARES_SUCCESS) { printf("%s\n", ares_strerror(status)); if (!abuf) return; } /* Won't happen, but check anyway, for safety. */ if (alen < HFIXEDSZ) return; /* Parse the answer header. */ id = DNS_HEADER_QID(abuf); qr = DNS_HEADER_QR(abuf); opcode = DNS_HEADER_OPCODE(abuf); aa = DNS_HEADER_AA(abuf); tc = DNS_HEADER_TC(abuf); rd = DNS_HEADER_RD(abuf); ra = DNS_HEADER_RA(abuf); rcode = DNS_HEADER_RCODE(abuf); qdcount = DNS_HEADER_QDCOUNT(abuf); ancount = DNS_HEADER_ANCOUNT(abuf); nscount = DNS_HEADER_NSCOUNT(abuf); arcount = DNS_HEADER_ARCOUNT(abuf); /* Display the answer header. */ printf("id: %d\n", id); printf("flags: %s%s%s%s%s\n", qr ? "qr " : "", aa ? "aa " : "", tc ? "tc " : "", rd ? "rd " : "", ra ? "ra " : ""); printf("opcode: %d %s\n", opcode, opcodes[opcode]); printf("rcode: %d %s\n", rcode, rcodes[rcode]); printf("qdcount: %d\n", qdcount); printf("ancount: %d\n", ancount); printf("nscount: %d\n", nscount); printf("arcount: %d\n", arcount); /* Display the questions. */ printf("Questions:\n"); aptr = abuf + HFIXEDSZ; for (i = 0; i < qdcount; i++) { aptr = display_question(aptr, abuf, alen); if (aptr == NULL) return; } /* Display the answers. */ printf("Answers:\n"); for (i = 0; i < ancount; i++) { aptr = display_rr(aptr, abuf, alen); if (aptr == NULL) return; } /* Display the NS records. */ printf("NS records:\n"); for (i = 0; i < nscount; i++) { aptr = display_rr(aptr, abuf, alen); if (aptr == NULL) return; } /* Display the additional records. */ printf("Additional records:\n"); for (i = 0; i < arcount; i++) { aptr = display_rr(aptr, abuf, alen); if (aptr == NULL) return; } }
void dns_detail_callback(void *arg, int status, int timeouts, unsigned char *abuf, int alen) { int id, qr, opcode, aa, tc, rd, ra, rcode; unsigned int qdcount, ancount, nscount, arcount, i; const unsigned char *aptr; dns_resp_t *response = (dns_resp_t *) arg; clearstrbuffer(response->msgbuf); response->msgstatus = status; /* * Display an error message if there was an error, but only stop if * we actually didn't get an answer buffer. */ switch (status) { case ARES_SUCCESS: break; case ARES_ENODATA: addtobuffer(response->msgbuf, "No data returned from server\n"); if (!abuf) return; break; case ARES_EFORMERR: addtobuffer(response->msgbuf, "Server could not understand query\n"); if (!abuf) return; break; case ARES_ESERVFAIL: addtobuffer(response->msgbuf, "Server failed\n"); if (!abuf) return; break; case ARES_ENOTFOUND: addtobuffer(response->msgbuf, "Name not found\n"); if (!abuf) return; break; case ARES_ENOTIMP: addtobuffer(response->msgbuf, "Not implemented\n"); if (!abuf) return; break; case ARES_EREFUSED: addtobuffer(response->msgbuf, "Server refused query\n"); if (!abuf) return; break; case ARES_EBADNAME: addtobuffer(response->msgbuf, "Invalid name in query\n"); if (!abuf) return; break; case ARES_ETIMEOUT: addtobuffer(response->msgbuf, "Timeout\n"); if (!abuf) return; break; case ARES_ECONNREFUSED: addtobuffer(response->msgbuf, "Server unavailable\n"); if (!abuf) return; break; case ARES_ENOMEM: addtobuffer(response->msgbuf, "Out of memory\n"); if (!abuf) return; break; case ARES_EDESTRUCTION: addtobuffer(response->msgbuf, "Timeout (channel destroyed)\n"); if (!abuf) return; break; default: addtobuffer(response->msgbuf, "Undocumented ARES return code\n"); if (!abuf) return; break; } /* Won't happen, but check anyway, for safety. */ if (alen < HFIXEDSZ) return; /* Parse the answer header. */ id = DNS_HEADER_QID(abuf); qr = DNS_HEADER_QR(abuf); opcode = DNS_HEADER_OPCODE(abuf); aa = DNS_HEADER_AA(abuf); tc = DNS_HEADER_TC(abuf); rd = DNS_HEADER_RD(abuf); ra = DNS_HEADER_RA(abuf); rcode = DNS_HEADER_RCODE(abuf); qdcount = DNS_HEADER_QDCOUNT(abuf); ancount = DNS_HEADER_ANCOUNT(abuf); nscount = DNS_HEADER_NSCOUNT(abuf); arcount = DNS_HEADER_ARCOUNT(abuf); /* Display the answer header. */ sprintf(msg, "id: %d\n", id); addtobuffer(response->msgbuf, msg); sprintf(msg, "flags: %s%s%s%s%s\n", qr ? "qr " : "", aa ? "aa " : "", tc ? "tc " : "", rd ? "rd " : "", ra ? "ra " : ""); addtobuffer(response->msgbuf, msg); sprintf(msg, "opcode: %s\n", opcodes[opcode]); addtobuffer(response->msgbuf, msg); sprintf(msg, "rcode: %s\n", rcodes[rcode]); addtobuffer(response->msgbuf, msg); /* Display the questions. */ addtobuffer(response->msgbuf, "Questions:\n"); aptr = abuf + HFIXEDSZ; for (i = 0; i < qdcount; i++) { aptr = display_question(aptr, abuf, alen, response); if (aptr == NULL) return; } /* Display the answers. */ addtobuffer(response->msgbuf, "Answers:\n"); for (i = 0; i < ancount; i++) { aptr = display_rr(aptr, abuf, alen, response); if (aptr == NULL) return; } /* Display the NS records. */ addtobuffer(response->msgbuf, "NS records:\n"); for (i = 0; i < nscount; i++) { aptr = display_rr(aptr, abuf, alen, response); if (aptr == NULL) return; } /* Display the additional records. */ addtobuffer(response->msgbuf, "Additional records:\n"); for (i = 0; i < arcount; i++) { aptr = display_rr(aptr, abuf, alen, response); if (aptr == NULL) return; } return; }
/* parse reply record */ int evdns_parse_reply(unsigned char *buf, int nbuf, HOSTENT *hostent) { unsigned char *p = NULL, *end = NULL, *s = NULL, *ps = NULL; int i = 0, qdcount = 0, ancount = 0, nscount = 0, arcount = 0, qr = 0, opcode = 0, aa = 0, tc = 0, rd = 0, ra = 0, rcode = 0, type = 0, dnsclass = 0, ttl = 0, rrlen = 0; if(buf && nbuf > HFIXEDSZ) { hostent->naddrs = 0; hostent->nalias = 0; p = buf; end = buf + nbuf; hostent->qid = DNS_HEADER_QID(p); qr = DNS_HEADER_QR(p); opcode = DNS_HEADER_OPCODE(p); aa = DNS_HEADER_AA(p); tc = DNS_HEADER_TC(p); rd = DNS_HEADER_RD(p); ra = DNS_HEADER_RA(p); rcode = DNS_HEADER_RCODE(p); qdcount = DNS_HEADER_QDCOUNT(p); ancount = DNS_HEADER_ANCOUNT(p); nscount = DNS_HEADER_NSCOUNT(p); arcount = DNS_HEADER_ARCOUNT(p); p += HFIXEDSZ; /* Display the answer header. */ /* printf("id: %d\n", id); printf("flags: %s%s%s%s%s\n", qr ? "qr " : "", aa ? "aa " : "", tc ? "tc " : "", rd ? "rd " : "", ra ? "ra " : ""); printf("opcode: %s\n", opcodes[opcode]); printf("rcode: %s\n", rcodes[rcode]); fprintf(stdout, "qdcount:%d\nancount:%d\nnscount:%d\narcount:%d\n", qdcount, ancount, nscount, arcount); */ /* parse question */ for(i = 0; i < qdcount; i++) { ps = (unsigned char *)hostent->name; p = evdns_expand_name(p, buf, end, ps); /* Parse the question type and class. */ type = DNS_QUESTION_TYPE(p); dnsclass = DNS_QUESTION_CLASS(p); p += QFIXEDSZ; /* fprintf(stdout, "qname:%-15s", name); fprintf(stdout, "\tqtype:%d", type); fprintf(stdout, "\tqclass:%d\r\n", dnsclass); */ } /* parse A name */ for(i = 0; i < ancount; i++) { ps = (unsigned char *)hostent->alias[hostent->nalias++]; p = evdns_expand_name(p, buf, end, ps); type = DNS_RR_TYPE(p); dnsclass = DNS_RR_CLASS(p); ttl = DNS_RR_TTL(p); rrlen = DNS_RR_LEN(p); p += RRFIXEDSZ; /* fprintf(stdout, "name:%s type:%d dnsclass:%d ttl:%d rrlen:%d ", name, type, dnsclass, ttl, rrlen); */ /* addr name */ if(type == TYPE_ANAME) { hostent->addrs[hostent->naddrs++] = *((int *)p); } /* Canonical name */ else if(type == TYPE_CNAME) { ps = (unsigned char *)hostent->alias[hostent->nalias++]; s = evdns_expand_name(p, buf, end, ps); //fprintf(stdout, "cname:%s ", cname); } /* pointer */ else if(type == TYPE_PTR) { ps = (unsigned char *)hostent->alias[hostent->nalias++]; s = evdns_expand_name(p, buf, end, ps); //fprintf(stdout, "pointer:%s ", cname); } //fprintf(stdout, "\r\n"); p += rrlen; } return 0; } return -1; }
/* Handle an answer from a server. */ static void process_answer(ares_channel channel, unsigned char *abuf, int alen, int whichserver, int tcp, struct timeval *now) { int tc, rcode, packetsz; unsigned short id; struct query *query; struct list_node* list_head; struct list_node* list_node; /* If there's no room in the answer for a header, we can't do much * with it. */ if (alen < HFIXEDSZ) return; /* Grab the query ID, truncate bit, and response code from the packet. */ id = DNS_HEADER_QID(abuf); tc = DNS_HEADER_TC(abuf); rcode = DNS_HEADER_RCODE(abuf); /* Find the query corresponding to this packet. The queries are * hashed/bucketed by query id, so this lookup should be quick. Note that * both the query id and the questions must be the same; when the query id * wraps around we can have multiple outstanding queries with the same query * id, so we need to check both the id and question. */ query = NULL; list_head = &(channel->queries_by_qid[id % ARES_QID_TABLE_SIZE]); for (list_node = list_head->next; list_node != list_head; list_node = list_node->next) { struct query *q = list_node->data; if ((q->qid == id) && same_questions(q->qbuf, q->qlen, abuf, alen)) { query = q; break; } } if (!query) return; packetsz = PACKETSZ; /* If we use EDNS and server answers with one of these RCODES, the protocol * extension is not understood by the responder. We must retry the query * without EDNS enabled. */ if (channel->flags & ARES_FLAG_EDNS) { packetsz = channel->ednspsz; if (rcode == NOTIMP || rcode == FORMERR || rcode == SERVFAIL) { int qlen = alen - EDNSFIXEDSZ; channel->flags ^= ARES_FLAG_EDNS; query->tcplen -= EDNSFIXEDSZ; query->qlen -= EDNSFIXEDSZ; query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff); query->tcpbuf[1] = (unsigned char)(qlen & 0xff); DNS_HEADER_SET_ARCOUNT(query->tcpbuf + 2, 0); query->tcpbuf = realloc(query->tcpbuf, query->tcplen); ares__send_query(channel, query, now); return; }
/* If any TCP sockets select true for writing, write out queued data * we have for them. */ static void write_tcp_data_core(ares_channel channel, int server_idx, time_t now) { struct server_state *server; struct send_request *sendreq; #ifdef WIN32 WSABUF *vec; #else struct iovec *vec; #endif int n, count; server = &channel->servers[server_idx]; if (!server->qhead || server->tcp_socket == -1 ) return; /* Count the number of send queue items. */ n = 0; for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) n++; #ifdef WIN32 /* Allocate iovecs so we can send all our data at once. */ vec = malloc(n * sizeof(WSABUF)); if (vec) { int err; /* Fill in the iovecs and send. */ n = 0; for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) { vec[n].buf = (char *) sendreq->data; vec[n].len = sendreq->len; n++; } err = WSASend(server->tcp_socket, vec, n, &count,0,0,0 ); if ( err == SOCKET_ERROR ) { count =-1; } free(vec); #else /* Allocate iovecs so we can send all our data at once. */ vec = malloc(n * sizeof(struct iovec)); if (vec) { // int err; /* Fill in the iovecs and send. */ n = 0; for (sendreq = server->qhead; sendreq; sendreq = sendreq->next) { vec[n].iov_base = (char *) sendreq->data; vec[n].iov_len = sendreq->len; n++; } count = writev(server->tcp_socket, vec, n); free(vec); #endif if (count < 0) { handle_error(channel, server_idx, now); return; } /* Advance the send queue by as many bytes as we sent. */ while (count) { sendreq = server->qhead; if (count >= sendreq->len) { count -= sendreq->len; server->qhead = sendreq->next; free(sendreq); if (server->qhead == NULL) { server->qtail = NULL; assert(count==0); break; } } else { sendreq->data += count; sendreq->len -= count; break; } } } else { /* Can't allocate iovecs; just send the first request. */ sendreq = server->qhead; #ifndef UNDER_CE count = write(server->tcp_socket, sendreq->data, sendreq->len); #else count = send(server->tcp_socket, sendreq->data, sendreq->len,0); #endif if (count < 0) { handle_error(channel, server_idx, now); return; } /* Advance the send queue by as many bytes as we sent. */ if (count == sendreq->len) { server->qhead = sendreq->next; if (server->qhead == NULL) server->qtail = NULL; free(sendreq); } else { sendreq->data += count; sendreq->len -= count; } } if ( server->qhead==NULL && channel->poll_cb_func ) { (*(channel->poll_cb_func))( channel->poll_cb_data, channel, server_idx, server->tcp_socket, ARES_POLLACTION_WRITEOFF); } } static void write_tcp_data(ares_channel channel, fd_set *write_fds, time_t now) { struct server_state *server; int i; for (i = 0; i < channel->nservers; i++) { /* Make sure server has data to send and is selected in write_fds. */ server = &channel->servers[i]; if (!server->qhead || server->tcp_socket == -1 ) continue; if ( write_fds && !FD_ISSET(server->tcp_socket, write_fds)) continue; write_tcp_data_core(channel, i, now); } } /* If any TCP socket selects true for reading, read some data, * allocate a buffer if we finish reading the length word, and process * a packet if we finish reading one. */ static void read_tcp_data(ares_channel channel, int server_idx, fd_set *read_fds, time_t now) { struct server_state *server; int i, count; for (i = 0; i < channel->nservers; i++) { /* Make sure the server has a socket and is selected in read_fds. */ if ( server_idx>=0 && i != server_idx ) continue; server = &channel->servers[i]; if (server->tcp_socket == -1 ) continue; if (!FD_ISSET(server->tcp_socket, read_fds)) continue; if (server->tcp_lenbuf_pos != 2) { /* We haven't yet read a length word, so read that (or * what's left to read of it). */ #if defined UNDER_CE || defined WIN32 count = recv(server->tcp_socket, server->tcp_lenbuf + server->tcp_lenbuf_pos, 2 - server->tcp_lenbuf_pos,0); #else count = read(server->tcp_socket, server->tcp_lenbuf + server->tcp_lenbuf_pos, 2 - server->tcp_lenbuf_pos); #endif if (count <= 0) { handle_error(channel, i, now); continue; } server->tcp_lenbuf_pos += count; if (server->tcp_lenbuf_pos == 2) { /* We finished reading the length word. Decode the * length and allocate a buffer for the data. */ server->tcp_length = server->tcp_lenbuf[0] << 8 | server->tcp_lenbuf[1]; server->tcp_buffer = malloc(server->tcp_length); if (!server->tcp_buffer) handle_error(channel, i, now); server->tcp_buffer_pos = 0; } } else { /* Read data into the allocated buffer. */ #if defined UNDER_CE || defined WIN32 count = recv(server->tcp_socket, server->tcp_buffer + server->tcp_buffer_pos, server->tcp_length - server->tcp_buffer_pos,0); #else count = read(server->tcp_socket, server->tcp_buffer + server->tcp_buffer_pos, server->tcp_length - server->tcp_buffer_pos); #endif if (count <= 0) { handle_error(channel, i, now); continue; } server->tcp_buffer_pos += count; if (server->tcp_buffer_pos == server->tcp_length) { /* We finished reading this answer; process it and * prepare to read another length word. */ process_answer(channel, server->tcp_buffer, server->tcp_length, i, 1, now); free(server->tcp_buffer); server->tcp_buffer = NULL; server->tcp_lenbuf_pos = 0; } } } } /* If any UDP sockets select true for reading, process them. */ static void read_udp_packets(ares_channel channel, int server_idx, fd_set *read_fds, time_t now) { struct server_state *server; int i, count; unsigned char buf[PACKETSZ + 1]; for (i = 0; i < channel->nservers; i++) { if ( server_idx>=0 && i != server_idx ) continue; /* Make sure the server has a socket and is selected in read_fds. */ server = &channel->servers[i]; if ( (server->udp_socket == -1) ) continue; if ( read_fds && !FD_ISSET(server->udp_socket, read_fds) ) continue; assert( server->udp_socket != -1 ); count = recv(server->udp_socket, buf, sizeof(buf), 0); if (count <= 0) { #if defined(WIN32) //int err; //err = WSAGetLastError(); //err = errno; switch (getErrno()) { case WSAEWOULDBLOCK: if ( read_fds ) { // read_fds is only null when using epoll // which shouldn't happen under windows // don't know why CLR is here anyways FD_CLR(server->udp_socket, read_fds); } continue; case WSAECONNABORTED: break; case WSAECONNRESET: // got an ICMP error on a previous send break; } #endif handle_error(channel, i, now); } else { process_answer(channel, buf, count, i, 0, now); } } } /* If any queries have timed out, note the timeout and move them on. */ static void process_timeouts(ares_channel channel, time_t now) { struct query *query, *next; for (query = channel->queries; query; query = next) { next = query->next; if (query->timeout != 0 && now >= query->timeout) { //fprintf(stderr, "kennard:ares:process_timeouts: got timeout\n"); query->error_status = ARES_ETIMEOUT; next_server(channel, query, now); } } } /* Handle an answer from a server. */ static void process_answer(ares_channel channel, unsigned char *abuf, int alen, int whichserver, int tcp, time_t now) { int id, tc, rcode; struct query *query; /* If there's no room in the answer for a header, we can't do much * with it. */ if (alen < HFIXEDSZ) return; /* Grab the query ID, truncate bit, and response code from the packet. */ id = DNS_HEADER_QID(abuf); tc = DNS_HEADER_TC(abuf); rcode = DNS_HEADER_RCODE(abuf); /* Find the query corresponding to this packet. */ for (query = channel->queries; query; query = query->next) { if (query->qid == id) break; } if (!query) return; /* If we got a truncated UDP packet and are not ignoring truncation, * don't accept the packet, and switch the query to TCP if we hadn't * done so already. */ if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags & ARES_FLAG_IGNTC)) { if (!query->using_tcp) { query->using_tcp = 1; ares__send_query(channel, query, now); } return; } /* Limit alen to PACKETSZ if we aren't using TCP (only relevant if we * are ignoring truncation. */ if (alen > PACKETSZ && !tcp) alen = PACKETSZ; /* If we aren't passing through all error packets, discard packets * with SERVFAIL, NOTIMP, or REFUSED response codes. */ if (!(channel->flags & ARES_FLAG_NOCHECKRESP)) { if (rcode == SERVFAIL || rcode == NOTIMP || rcode == REFUSED) { query->skip_server[whichserver] = 1; if (query->server == whichserver) next_server(channel, query, now); return; } if (!same_questions((unsigned char*)query->qbuf, query->qlen, abuf, alen)) { if (query->server == whichserver) next_server(channel, query, now); return; } /* 'No such name' */ if ((channel->flags & ARES_FLAG_TRY_NEXT_SERVER_ON_RCODE3) && rcode == NXDOMAIN) { if (query->server == whichserver) { if (next_server_new_network(channel, query, now)) return; } } } end_query(channel, query, ARES_SUCCESS, abuf, alen); }