Esempio n. 1
0
/* 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;
}
Esempio n. 2
0
/* 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 */
    }
}
Esempio n. 3
0
/* 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;
}