int rfc1035MessageUnpack(const char *buf, size_t sz, rfc1035_message ** answer) { int off = 0; int i; int nr = 0; rfc1035_message *msg; rfc1035_rr *recs; rfc1035_query *querys; msg = (rfc1035_message*) acl_mycalloc(1, sizeof(*msg)); if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) { RFC1035_UNPACK_DEBUG; rfc1035SetErrno(rfc1035_unpack_error); acl_myfree(msg); return -rfc1035_unpack_error; } rfc1035_errno = 0; rfc1035_error_message = NULL; i = (int) msg->qdcount; if (i != 1) { /* This can not be an answer to our queries.. */ RFC1035_UNPACK_DEBUG; rfc1035SetErrno(rfc1035_unpack_error); acl_myfree(msg); return -rfc1035_unpack_error; } querys = msg->query = (rfc1035_query*) acl_mycalloc((int) msg->qdcount, sizeof(*querys)); for (i = 0; i < (int) msg->qdcount; i++) { if (rfc1035QueryUnpack(buf, sz, &off, &querys[i])) { RFC1035_UNPACK_DEBUG; rfc1035SetErrno(rfc1035_unpack_error); rfc1035MessageDestroy(msg); return -rfc1035_unpack_error; } } *answer = msg; if (msg->rcode) { RFC1035_UNPACK_DEBUG; rfc1035SetErrno((int) msg->rcode); return -((int) msg->rcode); } if (msg->ancount == 0) return 0; recs = msg->answer = (rfc1035_rr*) acl_mycalloc((int) msg->ancount, sizeof(*recs)); for (i = 0; i < (int) msg->ancount; i++) { if (off >= (int) sz) { /* corrupt packet */ RFC1035_UNPACK_DEBUG; break; } if (rfc1035RRUnpack(buf, sz, &off, &recs[i])) { /* corrupt RR */ RFC1035_UNPACK_DEBUG; break; } nr++; } if (nr == 0) { /* * we expected to unpack some answers (ancount != 0), but * didn't actually get any. */ rfc1035MessageDestroy(msg); *answer = NULL; rfc1035SetErrno(rfc1035_unpack_error); return -rfc1035_unpack_error; } if (msg->nscount > 0) { //rfc1035NSUnpack(buf, sz, &off); } if (msg->arcount > 0) { //rfc1035ARUnpack(buf, sz, &off); } return nr; }
static void idnsGrokReply(const char *buf, size_t sz) { int n; rfc1035_message *message = NULL; idns_query *q; n = rfc1035MessageUnpack(buf, sz, &message); if (message == NULL) { debug(78, 2) ("idnsGrokReply: Malformed DNS response\n"); return; } debug(78, 3) ("idnsGrokReply: ID %#hx, %d answers\n", message->id, n); q = idnsFindQuery(message->id); if (q == NULL) { debug(78, 3) ("idnsGrokReply: Late response\n"); rfc1035MessageDestroy(message); return; } if (rfc1035QueryCompare(&q->query, message->query) != 0) { debug(78, 3) ("idnsGrokReply: Query mismatch (%s != %s)\n", q->query.name, message->query->name); rfc1035MessageDestroy(message); return; } dlinkDelete(&q->lru, &lru_list); if (message->tc && q->tcp_socket == -1) { debug(78, 2) ("idnsGrokReply: Response for %s truncated. Retrying using TCP\n", message->query->name); rfc1035MessageDestroy(message); idnsRetryTcp(q); return; } idnsRcodeCount(n, q->attempt); q->error = NULL; if (n < 0) { debug(78, 3) ("idnsGrokReply: error %s (%d)\n", rfc1035_error_message, rfc1035_errno); q->error = rfc1035_error_message; q->rcode = -n; if (q->rcode == 2 && ++q->attempt < MAX_ATTEMPT) { /* * RCODE 2 is "Server failure - The name server was * unable to process this query due to a problem with * the name server." */ rfc1035MessageDestroy(message); q->start_t = current_time; q->id = idnsQueryID(); rfc1035SetQueryID(q->buf, q->id); idnsSendQuery(q); return; } if (q->rcode == 3 && q->do_searchpath && q->attempt < MAX_ATTEMPT) { strcpy(q->name, q->orig); if (q->domain < npc) { strcat(q->name, "."); strcat(q->name, searchpath[q->domain].domain); debug(78, 3) ("idnsGrokReply: searchpath used for %s\n", q->name); q->domain++; } else { q->attempt++; } rfc1035MessageDestroy(message); if (q->hash.key) { hash_remove_link(idns_lookup_hash, &q->hash); q->hash.key = NULL; } q->start_t = current_time; q->id = idnsQueryID(); rfc1035SetQueryID(q->buf, q->id); q->sz = rfc1035BuildAQuery(q->name, q->buf, sizeof(q->buf), q->id, &q->query); idnsCacheQuery(q); idnsSendQuery(q); return; } } idnsCallback(q, message->answer, n, q->error); rfc1035MessageDestroy(message); idnsTcpCleanup(q); cbdataFree(q); }