Exemplo n.º 1
0
static int forward_query(int udpfd, union mysockaddr *udpaddr,
			 struct all_addr *dst_addr, unsigned int dst_iface,
			 HEADER *header, size_t plen, time_t now, struct frec *forward)
{
  char *domain = NULL;
  int type = 0;
  struct all_addr *addrp = NULL;
  unsigned int crc = questions_crc(header, plen, daemon->namebuff);
  unsigned short flags = 0;
  unsigned short gotname = extract_request(header, plen, daemon->namebuff, NULL);
  struct server *start = NULL;
    
  /* may be no servers available. */
  if (!daemon->servers)
    forward = NULL;
  else if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
    {
      /* retry on existing query, send to all available servers  */
      domain = forward->sentto->domain;
      forward->sentto->failed_queries++;
      if (!(daemon->options & OPT_ORDER))
	{
	  forward->forwardall = 1;
	  daemon->last_server = NULL;
	}
      type = forward->sentto->flags & SERV_TYPE;
      if (!(start = forward->sentto->next))
	start = daemon->servers; /* at end of list, recycle */
      header->id = htons(forward->new_id);
    }
  else 
    {
      if (gotname)
	flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
      
      if (!flags && !(forward = get_new_frec(now, NULL)))
	/* table full - server failure. */
	flags = F_NEG;
      
      if (forward)
	{
	  /* force unchanging id for signed packets */
	  int is_sign;
	  find_pseudoheader(header, plen, NULL, NULL, &is_sign);
	  
	  forward->source = *udpaddr;
	  forward->dest = *dst_addr;
	  forward->iface = dst_iface;
	  forward->orig_id = ntohs(header->id);
	  forward->new_id = get_id(is_sign, forward->orig_id, crc);
	  forward->fd = udpfd;
	  forward->crc = crc;
	  forward->forwardall = 0;
	  header->id = htons(forward->new_id);

	  /* In strict_order mode, or when using domain specific servers
	     always try servers in the order specified in resolv.conf,
	     otherwise, use the one last known to work. */
	  
	  if (type != 0  || (daemon->options & OPT_ORDER))
	    start = daemon->servers;
	  else if (!(start = daemon->last_server) ||
		   daemon->forwardcount++ > FORWARD_TEST ||
		   difftime(now, daemon->forwardtime) > FORWARD_TIME)
	    {
	      start = daemon->servers;
	      forward->forwardall = 1;
	      daemon->forwardcount = 0;
	      daemon->forwardtime = now;
	    }
	}
    }

  /* check for send errors here (no route to host) 
     if we fail to send to all nameservers, send back an error
     packet straight away (helps modem users when offline)  */
  
  if (!flags && forward)
    {
      struct server *firstsentto = start;
      int forwarded = 0;

      while (1)
	{ 
	  /* only send to servers dealing with our domain.
	     domain may be NULL, in which case server->domain 
	     must be NULL also. */
	  
	  if (type == (start->flags & SERV_TYPE) &&
	      (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
	      !(start->flags & SERV_LITERAL_ADDRESS))
	    {
	      int fd;

	      /* find server socket to use, may need to get random one. */
	      if (start->sfd)
		fd = start->sfd->fd;
	      else 
		{
#ifdef HAVE_IPV6
		  if (start->addr.sa.sa_family == AF_INET6)
		    {
		      if (!forward->rfd6 &&
			  !(forward->rfd6 = allocate_rfd(AF_INET6)))
			break;
		      daemon->rfd_save = forward->rfd6;
		      fd = forward->rfd6->fd;
		    }
		  else
#endif
		    {
		      if (!forward->rfd4 &&
			  !(forward->rfd4 = allocate_rfd(AF_INET)))
			break;
		      daemon->rfd_save = forward->rfd4;
		      fd = forward->rfd4->fd;
		    }

#ifdef ANDROID
		  // Mark the socket so it goes out on the correct network. Note
		  // that we never clear the mark, only re-set it the next time we
		  // allocate a new random fd. This is because we buffer DNS
		  // queries (in daemon->srv_save, daemon->packet_len) and socket
		  // file descriptors (in daemon->rfd_save) with the expectation of
		  // being able to use them again.
		  //
		  // Server fds are marked separately in allocate_sfd.
		  setsockopt(fd, SOL_SOCKET, SO_MARK, &start->mark, sizeof(start->mark));
#endif
		}

	      if (sendto(fd, (char *)header, plen, 0,
			 &start->addr.sa,
			 sa_len(&start->addr)) == -1)
		{
		  if (retry_send())
		    continue;
		}
	      else
		{
		  /* Keep info in case we want to re-send this packet */
		  daemon->srv_save = start;
		  daemon->packet_len = plen;
		  
		  if (!gotname)
		    strcpy(daemon->namebuff, "query");
		  if (start->addr.sa.sa_family == AF_INET)
		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&start->addr.in.sin_addr, NULL); 
#ifdef HAVE_IPV6
		  else
		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&start->addr.in6.sin6_addr, NULL);
#endif 
		  start->queries++;
		  forwarded = 1;
		  forward->sentto = start;
		  if (!forward->forwardall) 
		    break;
		  forward->forwardall++;
		}
	    } 
	  
	  if (!(start = start->next))
 	    start = daemon->servers;
	  
	  if (start == firstsentto)
	    break;
	}
      
      if (forwarded)
	return 1;
      
      /* could not send on, prepare to return */ 
      header->id = htons(forward->orig_id);
      free_frec(forward); /* cancel */
    }	  
  
  /* could not send on, return empty answer or address if known for whole domain */
  if (udpfd != -1)
    {
      plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
      send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
    }

  return 0;
}
Exemplo n.º 2
0
/* returns new last_server */	
static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *udpaddr,
			  struct all_addr *dst_addr, unsigned int dst_iface,
			  HEADER *header, size_t plen, time_t now, struct frec *forward)
{
  char *domain = NULL;
  int type = 0;
  struct all_addr *addrp = NULL;
  unsigned int crc = questions_crc(header, plen, daemon->namebuff);
  unsigned short flags = 0;
  unsigned short gotname = extract_request(header, plen, daemon->namebuff, NULL);
  struct server *start = NULL;
    
  /* may be no servers available. */
  if (!daemon->servers)
    forward = NULL;
  else if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
    {
      /* retry on existing query, send to all available servers  */
      domain = forward->sentto->domain;
      if (!(daemon->options & OPT_ORDER))
	{
	  forward->forwardall = 1;
	  daemon->last_server = NULL;
	}
      type = forward->sentto->flags & SERV_TYPE;
      if (!(start = forward->sentto->next))
	start = daemon->servers; /* at end of list, recycle */
      header->id = htons(forward->new_id);
    }
  else 
    {
      if (gotname)
	flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
      
      if (!flags && !(forward = get_new_frec(daemon, now, NULL)))
	/* table full - server failure. */
	flags = F_NEG;
      
      if (forward)
	{
	  forward->source = *udpaddr;
	  forward->dest = *dst_addr;
	  forward->iface = dst_iface;
	  forward->new_id = get_id();
	  forward->fd = udpfd;
	  forward->orig_id = ntohs(header->id);
	  forward->crc = crc;
	  forward->forwardall = 0;
	  header->id = htons(forward->new_id);

	  /* In strict_order mode, or when using domain specific servers
	     always try servers in the order specified in resolv.conf,
	     otherwise, use the one last known to work. */
	  
	  if (type != 0  || (daemon->options & OPT_ORDER))
	    start = daemon->servers;
	  else if (!(start = daemon->last_server))
	    {
	      start = daemon->servers;
	      forward->forwardall = 1;
	    }
	}
    }

  /* check for send errors here (no route to host) 
     if we fail to send to all nameservers, send back an error
     packet straight away (helps modem users when offline)  */
  
  if (!flags && forward)
    {
      struct server *firstsentto = start;
      int forwarded = 0;

      while (1)
	{ 
	  /* only send to servers dealing with our domain.
	     domain may be NULL, in which case server->domain 
	     must be NULL also. */
	  
	  if (type == (start->flags & SERV_TYPE) &&
	      (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
	      !(start->flags & SERV_LITERAL_ADDRESS))
	    {
	      if (sendto(start->sfd->fd, (char *)header, plen, 0,
			 &start->addr.sa,
			 sa_len(&start->addr)) == -1)
		{
		  if (retry_send())
		    continue;
		}
	      else
		{
		  /* Keep info in case we want to re-send this packet */
		  daemon->srv_save = start;
		  daemon->packet_len = plen;
		  
		  if (!gotname)
		    strcpy(daemon->namebuff, "query");
		  if (start->addr.sa.sa_family == AF_INET)
		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&start->addr.in.sin_addr, 0,
			      NULL, 0); 
#ifdef HAVE_IPV6
		  else
		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&start->addr.in6.sin6_addr, 0,
			      NULL, 0);
#endif 
		  forwarded = 1;
		  forward->sentto = start;
		  if (!forward->forwardall) 
		    break;
		  forward->forwardall++;
		}
	    } 
	  
	  if (!(start = start->next))
 	    start = daemon->servers;
	  
	  if (start == firstsentto)
	    break;
	}
      
      if (forwarded)
	  return;
      
      /* could not send on, prepare to return */ 
      header->id = htons(forward->orig_id);
      forward->new_id = 0; /* cancel */
    }	  
  
  /* could not send on, return empty answer or address if known for whole domain */
  if (udpfd != -1)
    {
      plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
      send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
    }

  return;
}
Exemplo n.º 3
0
static int forward_query(int udpfd, union mysockaddr *udpaddr,
			 struct all_addr *dst_addr, unsigned int dst_iface,
			 struct dns_header *header, size_t plen, time_t now, struct frec *forward)
{
  char *domain = NULL;
  int type = 0, norebind = 0;
  struct all_addr *addrp = NULL;
  unsigned int crc = questions_crc(header, plen, daemon->namebuff);
  unsigned int flags = 0;
  unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
  struct server *start = NULL;
  
  /* RFC 4035: sect 4.6 para 2 */
  header->hb4 &= ~HB4_AD;
  
  /* may be no servers available. */
  if (!daemon->servers)
    forward = NULL;
  else if (forward || (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
    {
      /* retry on existing query, send to all available servers  */
      domain = forward->sentto->domain;
      forward->sentto->failed_queries++;
      if (!option_bool(OPT_ORDER))
	{
	  forward->forwardall = 1;
	  daemon->last_server = NULL;
	}
      type = forward->sentto->flags & SERV_TYPE;
      if (!(start = forward->sentto->next))
	start = daemon->servers; /* at end of list, recycle */
      header->id = htons(forward->new_id);
    }
  else 
    {
      if (gotname)
	flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
      
      if (!flags && !(forward = get_new_frec(now, NULL)))
	/* table full - server failure. */
	flags = F_NEG;
      
      if (forward)
	{
	  forward->source = *udpaddr;
	  forward->dest = *dst_addr;
	  forward->iface = dst_iface;
	  forward->orig_id = ntohs(header->id);
	  forward->new_id = get_id(crc);
	  forward->fd = udpfd;
	  forward->crc = crc;
	  forward->forwardall = 0;
	  if (norebind)
	    forward->flags |= FREC_NOREBIND;
	  if (header->hb4 & HB4_CD)
	    forward->flags |= FREC_CHECKING_DISABLED;

	  header->id = htons(forward->new_id);
	  
	  /* In strict_order mode, always try servers in the order 
	     specified in resolv.conf, if a domain is given 
	     always try all the available servers,
	     otherwise, use the one last known to work. */
	  
	  if (type == 0)
	    {
	      if (option_bool(OPT_ORDER))
		start = daemon->servers;
	      else if (!(start = daemon->last_server) ||
		       daemon->forwardcount++ > FORWARD_TEST ||
		       difftime(now, daemon->forwardtime) > FORWARD_TIME)
		{
		  start = daemon->servers;
		  forward->forwardall = 1;
		  daemon->forwardcount = 0;
		  daemon->forwardtime = now;
		}
	    }
	  else
	    {
	      start = daemon->servers;
	      if (!option_bool(OPT_ORDER))
		forward->forwardall = 1;
	    }
	}
    }

  /* check for send errors here (no route to host) 
     if we fail to send to all nameservers, send back an error
     packet straight away (helps modem users when offline)  */
  
  if (!flags && forward)
    {
      struct server *firstsentto = start;
      int forwarded = 0;
      
      if (udpaddr && option_bool(OPT_ADD_MAC))
	plen = add_mac(header, plen, ((char *) header) + PACKETSZ, udpaddr);
      
      while (1)
	{ 
	  /* only send to servers dealing with our domain.
	     domain may be NULL, in which case server->domain 
	     must be NULL also. */
	  
	  if (type == (start->flags & SERV_TYPE) &&
	      (type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
	      !(start->flags & SERV_LITERAL_ADDRESS))
	    {
	      int fd;

	      /* find server socket to use, may need to get random one. */
	      if (start->sfd)
		fd = start->sfd->fd;
	      else 
		{
#ifdef HAVE_IPV6
		  if (start->addr.sa.sa_family == AF_INET6)
		    {
		      if (!forward->rfd6 &&
			  !(forward->rfd6 = allocate_rfd(AF_INET6)))
			break;
		      daemon->rfd_save = forward->rfd6;
		      fd = forward->rfd6->fd;
		    }
		  else
#endif
		    {
		      if (!forward->rfd4 &&
			  !(forward->rfd4 = allocate_rfd(AF_INET)))
			break;
		      daemon->rfd_save = forward->rfd4;
		      fd = forward->rfd4->fd;
		    }

#ifdef HAVE_CONNTRACK
		  /* Copy connection mark of incoming query to outgoing connection. */
		  if (option_bool(OPT_CONNTRACK))
		    {
		      unsigned int mark;
		      if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
			setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
		    }
#endif
		}
	      
	      if (sendto(fd, (char *)header, plen, 0,
			 &start->addr.sa,
			 sa_len(&start->addr)) == -1)
		{
		  if (retry_send())
		    continue;
		}
	      else
		{
		  /* Keep info in case we want to re-send this packet */
		  daemon->srv_save = start;
		  daemon->packet_len = plen;
		  
		  if (!gotname)
		    strcpy(daemon->namebuff, "query");
		  if (start->addr.sa.sa_family == AF_INET)
		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&start->addr.in.sin_addr, NULL); 
#ifdef HAVE_IPV6
		  else
		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&start->addr.in6.sin6_addr, NULL);
#endif 
		  start->queries++;
		  forwarded = 1;
		  forward->sentto = start;
		  if (!forward->forwardall) 
		    break;
		  forward->forwardall++;
		}
	    } 
	  
	  if (!(start = start->next))
 	    start = daemon->servers;
	  
	  if (start == firstsentto)
	    break;
	}
      
      if (forwarded)
	return 1;
      
      /* could not send on, prepare to return */ 
      header->id = htons(forward->orig_id);
      free_frec(forward); /* cancel */
    }	  
  
  /* could not send on, return empty answer or address if known for whole domain */
  if (udpfd != -1)
    {
      plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
      send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface);
    }

  return 0;
}
Exemplo n.º 4
0
/* returns new last_server */
struct server *forward_query(int udpfd, int peerfd, int peerfd6,
                             union mysockaddr *udpaddr, HEADER *header,
                             int plen, int strict_order, char *dnamebuff,
                             struct server *servers, struct server *last_server)
{
    time_t now = time(NULL);
    struct frec *forward;
    char *domain = NULL;
    struct server *serv, *tmp_server = NULL;
    int gotname = extract_request(header, (unsigned int)plen, dnamebuff);
    /* may be  recursion not speced or no servers available. */
    if (!header->rd || !servers)
        forward = NULL;
    else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr)))
    {
        /* retry on existing query, send to next server */
        domain = forward->sentto->domain;
        if (!(forward->sentto = forward->sentto->next))
            forward->sentto = servers; /* at end of list, recycle */
        header->id = htons(forward->new_id);
    }
    else
    {
        /* new query, pick nameserver and send */
        forward = get_new_frec(now);

        /* If the query ends in the domain in one of our servers, set
        domain to point to that name. We find the largest match to allow both
         domain.org and sub.domain.org to exist. */

        if (gotname)
        {
            unsigned int namelen = strlen(dnamebuff);
            unsigned int matchlen = 0;
            for (serv=servers; serv; serv=serv->next)
                if (serv->domain)
                {
                    unsigned int domainlen = strlen(serv->domain);
                    //cprintf("tallest:=====( domainlen=%d, namelen=%d, dnamebuff=%s, serv->domain=%s, servip=%s, sa=%x )=====\n"
                    //	,domainlen, namelen, dnamebuff, serv->domain, inet_ntoa(serv->addr.in.sin_addr), serv->addr.sa.sa_data);
                    if (namelen >= domainlen &&
                            strcmp(dnamebuff + namelen - domainlen, serv->domain) == 0 &&
                            domainlen > matchlen)
                    {
                        //cprintf("tallest:=====( Match it!! dnamebuff=%s, serv->domain=%s, Using DNS=%s )=====\n", dnamebuff, serv->domain, inet_ntoa(serv->addr.in.sin_addr));
                        domain = serv->domain;
                        matchlen = domainlen;
                    }
                }
        }

        /* In strict_order mode, or when using domain specific servers
        always try servers in the order specified in resolv.conf,
         otherwise, use the one last known to work. */

        if (domain || strict_order)
            forward->sentto = servers;
        else
            forward->sentto = last_server;

        forward->source = *udpaddr;
        forward->new_id = get_id();
        forward->fd = udpfd;
        forward->orig_id = ntohs(header->id);
        header->id = htons(forward->new_id);
    }

    /* check for send errors here (no route to host)
       if we fail to send to all nameservers, send back an error
       packet straight away (helps modem users when offline)  */

    if (forward)
    {
        struct server *firstsentto = forward->sentto;
        int sendnotfail = 0;// add by zg 2006.10.23 to fix cdrouter3.3 item 129(cdrouter_app_25) bug
        while (1)
        {
            int af = forward->sentto->addr.sa.sa_family;
            int fd = af == AF_INET ? peerfd : peerfd6;

            /* only send to servers dealing with our domain.
               domain may be NULL, in which case server->domain
               must be NULL also. */

            if ((!domain && !forward->sentto->domain) ||
                    (domain && forward->sentto->domain && strcmp(domain, forward->sentto->domain) == 0))
            {
#ifdef DNS_SUPPORT
                int ret;
                char *ping_argv[] = { "ping",
                                      "-c", "1",
                                      inet_ntoa(forward->sentto->addr.in.sin_addr),
                                      NULL
                                    };
                ret = _eval(ping_argv, NULL, 10, NULL);
                if (ret != 0) {
                    syslog(LOG_WARNING,
                           "Fail to connect to nameserver(%s) !!\n",inet_ntoa(forward->sentto->addr.in.sin_addr));

                    cprintf("Fail to connect to nameserver(%s) !!\n",inet_ntoa(forward->sentto->addr.in.sin_addr));
                }
#endif
                if (sendto(fd, (char *)header, plen, 0,
                           &forward->sentto->addr.sa,
                           sa_len(&forward->sentto->addr)) != -1)
                {
                    sendnotfail = 1;// add by zg 2006.10.23 to fix cdrouter3.3 item 129(cdrouter_app_25) bug

                    /* ******* 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)
                    {
                        forward->dnsMsgBufPtr = get_dns_msg_buf();
                        if(forward->dnsMsgBufPtr != NULL)
                        {
                            struct DNS_MSG_BUF * dnsMsgBufPtr;
                            //DBG_printf("send query ok and backup it\n");
                            dnsMsgBufPtr = forward->dnsMsgBufPtr;
                            dnsMsgBufPtr->udpfd = udpfd;
                            dnsMsgBufPtr->plen = plen;
                            dnsMsgBufPtr->firstsentto = firstsentto;
                            if (!(dnsMsgBufPtr->nextsentto = forward->sentto->next))
                            {
                                dnsMsgBufPtr->nextsentto = servers;
                            }
                            dnsMsgBufPtr->servers = servers;
                            memcpy(&dnsMsgBufPtr->udpaddr, udpaddr, sizeof(union mysockaddr));
                            memcpy(dnsMsgBufPtr->header, header, plen);
                            ((HEADER *)(&dnsMsgBufPtr->header))->id = forward->orig_id;
                        }
                    }
                    if (af == AF_INET)
                        log_query(F_SERVER | F_IPV4 | F_FORWARD, gotname ? dnamebuff : "query",
                                  (struct all_addr *)&forward->sentto->addr.in.sin_addr);
#ifdef HAVE_IPV6
                    else
                        log_query(F_SERVER | F_IPV6 | F_FORWARD, gotname ? dnamebuff : "query",
                                  (struct all_addr *)&forward->sentto->addr.in6.sin6_addr);
#endif
                    break;
                    /* *******end by zg porting DWG814I Source code on 2006.11.06 ******* */

                    /* for no-domain, dont't update last_server */
                    // modify by zg 2006.10.23 to fix cdrouter3.3 item 129(cdrouter_app_25) bug
                    //return domain ? last_server : (forward->sentto->next ? forward->sentto->next : servers);
#if 0
                    if (af == AF_INET)
                        log_query(F_SERVER | F_IPV4 | F_FORWARD, gotname ? dnamebuff : "query",
                                  (struct all_addr *)&forward->sentto->addr.in.sin_addr);
#ifdef HAVE_IPV6
                    else
                        log_query(F_SERVER | F_IPV6 | F_FORWARD, gotname ? dnamebuff : "query",
                                  (struct all_addr *)&forward->sentto->addr.in6.sin6_addr);
#endif
                    /* for no-domain, dont't update last_server */
                    //return domain ? last_server : (forward->sentto->next ? forward->sentto->next : servers);
                    tmp_server = domain ? last_server : (forward->sentto->next ? forward->sentto->next : servers);	// For cdrouter_app_25
#endif
                }
            }

            if (!(forward->sentto = forward->sentto->next))
                forward->sentto = servers;

            /* check if we tried all without success */
            if (forward->sentto == firstsentto) {
#if 0
                if (tmp_server != NULL)
                    return tmp_server;
                else
#endif
                    break;
            }
        }

        /* could not send on, prepare to return */
        /******** add by zg 2006.10.23 to fix cdrouter3.3 item 129(cdrouter_app_25) bug ********/
        if(!sendnotfail)
        {
            header->id = htons(forward->orig_id);
            forward->new_id = 0; /* cancel */
        }
        else
            return last_server;
        /**************** end by zg 2006.10.23 ***************/

    }

    /* could not send on, return empty answer */
    header->qr = 1; /* response */
    header->aa = 0; /* authoritive - never */
    header->ra = 1; /* recursion if available */
    header->tc = 0; /* not truncated */
    header->rcode = NOERROR; /* no error */
    header->ancount = htons(0); /* no answers */
    header->nscount = htons(0);
    header->arcount = htons(0);
    sendto(udpfd, (char *)header, plen, 0, &udpaddr->sa, sa_len(udpaddr));

    return last_server;
}