/* return unique random ids between 1 and 65535 */ static unsigned short get_id(void) { unsigned short ret = 0; while (ret == 0) { ret = rand16(); /* scrap ids already in use */ if ((ret != 0) && lookup_frec(ret)) ret = 0; } return ret; }
/* sets new last_server */ void reply_query(int fd, int family, time_t now) { /* packet from peer server, extract data for cache, and send to original requester */ HEADER *header; union mysockaddr serveraddr; struct frec *forward; socklen_t addrlen = sizeof(serveraddr); ssize_t n = recvfrom(fd, daemon->packet, daemon->edns_pktsz, 0, &serveraddr.sa, &addrlen); size_t nn; struct server *server; /* packet buffer overwritten */ daemon->srv_save = NULL; /* Determine the address of the server replying so that we can mark that as good */ serveraddr.sa.sa_family = family; #ifdef HAVE_IPV6 if (serveraddr.sa.sa_family == AF_INET6) serveraddr.in6.sin6_flowinfo = 0; #endif /* spoof check: answer must come from known server, */ for (server = daemon->servers; server; server = server->next) if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) && sockaddr_isequal(&server->addr, &serveraddr)) break; header = (HEADER *)daemon->packet; if (!server || n < (int)sizeof(HEADER) || !header->qr || !(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff)))) return; server = forward->sentto; if ((header->rcode == SERVFAIL || header->rcode == REFUSED) && !(daemon->options & OPT_ORDER) && forward->forwardall == 0) /* for broken servers, attempt to send to another one. */ { unsigned char *pheader; size_t plen; int is_sign; /* recreate query from reply */ pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign); if (!is_sign) { header->ancount = htons(0); header->nscount = htons(0); header->arcount = htons(0); if ((nn = resize_packet(header, (size_t)n, pheader, plen))) { header->qr = 0; header->tc = 0; forward_query(-1, NULL, NULL, 0, header, nn, now, forward); return; } } } if ((forward->sentto->flags & SERV_TYPE) == 0) { if (header->rcode == SERVFAIL || header->rcode == REFUSED) server = NULL; else { struct server *last_server; /* find good server by address if possible, otherwise assume the last one we sent to */ for (last_server = daemon->servers; last_server; last_server = last_server->next) if (!(last_server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR)) && sockaddr_isequal(&last_server->addr, &serveraddr)) { server = last_server; break; } } if (!(daemon->options & OPT_ALL_SERVERS)) daemon->last_server = server; } /* If the answer is an error, keep the forward record in place in case we get a good reply from another server. Kill it when we've had replies from all to avoid filling the forwarding table when everything is broken */ if (forward->forwardall == 0 || --forward->forwardall == 1 || (header->rcode != REFUSED && header->rcode != SERVFAIL)) { if ((nn = process_reply(header, now, server, (size_t)n))) { header->id = htons(forward->orig_id); header->ra = 1; /* recursion if available */ send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn, &forward->source, &forward->dest, forward->iface); } free_frec(forward); /* cancel */ } }
/* returns new last_server */ struct server *reply_query(int fd, char *packet, char *dnamebuff, struct server *last_server,unsigned long *timetolive) { /* packet from peer server, extract data for cache, and send to original requester */ struct frec *forward; HEADER *header; int n = recv(fd, packet, PACKETSZ, 0); header = (HEADER *)packet; if (n >= (int)sizeof(HEADER) && header->qr) { if ((forward = lookup_frec(ntohs(header->id)))) { //if (header->rcode == NOERROR || header->rcode == NXDOMAIN) if (header->rcode == NOERROR) { /* ******* zg porting DWG814I Source code on 2006.11.06 ******* */ /* ******* To fixed cdrouterv3.3 item 333(dna_45) item 334(dns_45) failed bug ******* */ if(forward ->dnsMsgBufPtr != NULL) { free_dns_msg_buf(forward ->dnsMsgBufPtr); forward ->dnsMsgBufPtr = NULL; } /* ******* end by zg porting DWG814I Source code on 2006.11.06 ******* */ if (!forward->sentto->domain) last_server = forward->sentto; /* known good */ if (header->opcode == QUERY) { strncpy(query_name, dnamebuff, sizeof(query_name)); extract_addresses(header, (unsigned int)n, dnamebuff, timetolive); } header->id = htons(forward->orig_id); /* There's no point returning an upstream reply marked as truncated, since that will prod the resolver into moving to TCP - which we don't support. */ header->tc = 0; /* goodbye truncate */ sendto(forward->fd, packet, n, 0, &forward->source.sa, sa_len(&forward->source)); forward->new_id = 0; /* cancel */ } /* ******* zg porting DWG814I Source code on 2006.11.06 ******* */ /* ******* To fixed cdrouterv3.3 item 333(dna_45) item 334(dns_45) failed bug ******* */ else switch(header->rcode) { case SERVFAIL: case NOTIMP: case REFUSED: //DBG_printf("SERVER fail, not implement, refuse, try next server\n"); break; default: //DBG_printf("SERVER response general error, return it to client\n"); if(forward ->dnsMsgBufPtr != NULL) { free_dns_msg_buf(forward ->dnsMsgBufPtr); forward ->dnsMsgBufPtr = NULL; } header->id = htons(forward->orig_id); /* There's no point returning an upstream reply marked as truncated, since that will prod the resolver into moving to TCP - which we don't support. */ header->tc = 0; /* goodbye truncate */ sendto(forward->fd, packet, n, 0, &forward->source.sa, sa_len(&forward->source)); forward->new_id = 0; /* cancel */ break; } /* ******* end by zg porting DWG814I Source code on 2006.11.06 ******* */ } } return last_server; }