コード例 #1
0
ファイル: example-matcher.c プロジェクト: 3rf/mongo-c-driver
static void
example (void)
{
   bson_t *query;
   bson_t *doc;

   doc = BCON_NEW ("hello", "[", "{", "foo", BCON_UTF8 ("bar"), "}", "]");
   query = BCON_NEW ("hello.0.foo", BCON_UTF8 ("bar"));

   log_query (doc, query);
   check_match (doc, query);

   bson_destroy (doc);
   bson_destroy (query);

   /* i is > 1 or i < -1. */
   query = BCON_NEW ("$or", "[",
                     "{", "i", "{", "$gt", BCON_INT32 (1), "}", "}",
                     "{", "i", "{", "$lt", BCON_INT32 (-1), "}", "}", "]");

   doc = BCON_NEW ("i", BCON_INT32 (2));
   log_query (doc, query);
   check_match (doc, query);

   bson_destroy (doc);

   doc = BCON_NEW ("i", BCON_INT32 (0));
   log_query (doc, query);
   check_match (doc, query);

   bson_destroy (doc);
   bson_destroy (query);
}
コード例 #2
0
char* _std log_gettext(u32t flags) {
   getloginfo li = {flags, 0};
   while (log_query(getlog,&li)==EBUSY) mt_yield();
   // change block context to current process
   if ((flags&LOGTF_SHARED)==0) mem_localblock(li.rc);
   return li.rc;
}
コード例 #3
0
ファイル: dnscache.c プロジェクト: rahulsundaram/ndjbdns
void
u_new (void)
{
    int i = 0, j = 0, len = 0;
    struct udpclient *x = NULL;

    static char *q = 0;
    char qtype[2], qclass[2];

    for (j = 0; j < MAXUDP; j++)
        if (!u[j].active)
            break;

    if (j >= MAXUDP)
    {
        j = 0;
        for (i = 1; i < MAXUDP; i++)
            if (taia_less (&u[i].start, &u[j].start))
                j = i;
        errno = error_timeout;
        u_drop (j);
    }

    x = u + j;
    taia_now (&x->start);

    len = socket_recv4 (udp53, buf, sizeof (buf), x->ip, &x->port, &odst);
    if (len == -1)
        return;
    if ((unsigned)len >= sizeof buf)
        return;
    if (x->port < 1024 && x->port != 53)
        return;
    if (!okclient (x->ip))
        return;
    if (!packetquery (buf, len, &q, qtype, qclass, x->id))
        return;

    x->active = ++numqueries;
    ++uactive;

    if (debug_level)
        log_query (x->active, x->ip, x->port, x->id, q, qtype);

    switch (query_start (&x->q, q, qtype, qclass, myipoutgoing))
    {
    case -1:
        u_drop (j);
        return;

    case 1:
        u_respond (j);
    }
}
コード例 #4
0
ファイル: dnscache.c プロジェクト: qrmn/tinydnssec
void u_new(void)
{
  int j;
  int i;
  struct udpclient *x;
  int len;
  static char *q = 0;
  char qtype[2];
  char qclass[2];

  for (j = 0;j < MAXUDP;++j)
    if (!u[j].active)
      break;

  if (j >= MAXUDP) {
    j = 0;
    for (i = 1;i < MAXUDP;++i)
      if (taia_less(&u[i].start,&u[j].start))
	j = i;
    errno = error_timeout;
    u_drop(j);
  }

  x = u + j;
  taia_now(&x->start);

  len = socket_recv6(udp53,buf,sizeof buf,x->ip,&x->port,&x->scope_id);
  if (len == -1) return;
  if (len >= sizeof buf) return;
  if (x->port < 1024) if (x->port != 53) return;
  if (!okclient(x->ip)) return;

  if (!packetquery(buf,len,&q,qtype,qclass,x->id)) return;

  x->active = ++numqueries; ++uactive;
  log_query(&x->active,x->ip,x->port,x->id,q,qtype);
  switch(query_start(&x->q,q,qtype,qclass,myipoutgoing,interface)) {
    case -1:
      u_drop(j);
      return;
    case 1:
      u_respond(j);
  }
}
コード例 #5
0
ファイル: forward.c プロジェクト: MIPS/external-dnsmasq
static unsigned short search_servers(time_t now, struct all_addr **addrpp, 
				     unsigned short qtype, char *qdomain, int *type, char **domain)
			      
{
  /* 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. */
  
  unsigned int namelen = strlen(qdomain);
  unsigned int matchlen = 0;
  struct server *serv;
  unsigned short flags = 0;
  
  for (serv = daemon->servers; serv; serv=serv->next)
    /* domain matches take priority over NODOTS matches */
    if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
      {
	unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6; 
	*type = SERV_FOR_NODOTS;
	if (serv->flags & SERV_NO_ADDR)
	  flags = F_NXDOMAIN;
	else if (serv->flags & SERV_LITERAL_ADDRESS) 
	  { 
	    if (sflag & qtype)
	      {
		flags = sflag;
		if (serv->addr.sa.sa_family == AF_INET) 
		  *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
		else
		  *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif 
	      }
	    else if (!flags || (flags & F_NXDOMAIN))
	      flags = F_NOERR;
	  } 
      }
    else if (serv->flags & SERV_HAS_DOMAIN)
      {
	unsigned int domainlen = strlen(serv->domain);
	char *matchstart = qdomain + namelen - domainlen;
	if (namelen >= domainlen &&
	    hostname_isequal(matchstart, serv->domain) &&
	    domainlen >= matchlen &&
	    (domainlen == 0 || namelen == domainlen || *(serv->domain) == '.' || *(matchstart-1) == '.' ))
	  {
	    unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
	    *type = SERV_HAS_DOMAIN;
	    *domain = serv->domain;
	    matchlen = domainlen;
	    if (serv->flags & SERV_NO_ADDR)
	      flags = F_NXDOMAIN;
	    else if (serv->flags & SERV_LITERAL_ADDRESS)
	      {
		if (sflag & qtype)
		  {
		    flags = sflag;
		    if (serv->addr.sa.sa_family == AF_INET) 
		      *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
		    else
		      *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif
		  }
		else if (!flags || (flags & F_NXDOMAIN))
		  flags = F_NOERR;
	      }
	  } 
      }

  if (flags == 0 && !(qtype & F_BIGNAME) && 
      (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
    /* don't forward simple names, make exception for NS queries and empty name. */
    flags = F_NXDOMAIN;
    
  if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
    flags = F_NOERR;

  if (flags)
    {
      int logflags = 0;
      
      if (flags == F_NXDOMAIN || flags == F_NOERR)
	logflags = F_NEG | qtype;
  
      log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
    }

  return  flags;
}
コード例 #6
0
ファイル: server.c プロジェクト: pillarsdotnet/ndjbdns
static int
doit (void)
{
    char qtype[2];
    char qclass[2];
    char header[12];
    unsigned int pos = 0;

    if ((unsigned)len >= sizeof buf)
        goto NOQ;
    if (!(pos = dns_packet_copy (buf, len, 0, header, 12)))
        goto NOQ;
    if (header[2] & 128)
        goto NOQ;
    if (header[4])
        goto NOQ;
    if (header[5] != 1)
        goto NOQ;

    if (!(pos = dns_packet_getname (buf, len, pos, &q)))
        goto NOQ;
    if (!(pos = dns_packet_copy (buf, len, pos, qtype, 2)))
        goto NOQ;
    if (!(pos = dns_packet_copy (buf, len, pos, qclass, 2)))
        goto NOQ;

    if (!response_query (q, qtype, qclass))
        goto NOQ;
    response_id (header);

    qnum++;
    if (byte_equal (qclass, 2, DNS_C_IN))
        response[2] |= 4;
    else if (byte_diff (qclass, 2, DNS_C_ANY))
            goto WEIRDCLASS;
    response[3] &= ~128;
    if (!(header[2] & 1))
        response[2] &= ~1;

    if (header[2] & 126)
        goto NOTIMP;
    if (byte_equal (qtype, 2, DNS_T_AXFR))
        goto NOTIMP;

    case_lowerb (q, dns_domain_length (q));
    if (!respond (q, qtype, ip))
    {
        log_query (qnum, ip, port, header, q, qtype);
        return 0;
    }
    log_query (qnum, ip, port, header, q, qtype);

    return 1;

NOTIMP:
    response[3] &= ~15;
    response[3] |= 4;
    log_query (qnum, ip, port, header, q, qtype);

    return 1;

WEIRDCLASS:
    response[3] &= ~15;
    response[3] |= 1;
    log_query (qnum, ip, port, header, q, qtype);

    return 1;

NOQ:
    log_query (qnum, ip, port, "\0\0", "", "\0\0");

    return 0;
}
コード例 #7
0
ファイル: dnscache.c プロジェクト: rahulsundaram/ndjbdns
void
t_rw (int j)
{
    int r;
    char ch;
    static char *q = 0;
    char qtype[2], qclass[2];
    struct tcpclient *x = NULL;

    x = t + j;
    if (x->state == -1)
    {
        r = write (x->tcp, x->buf + x->pos, x->len - x->pos);
        if (r <= 0)
        {
            t_close (j);
            return;
        }
        x->pos += r;
        if (x->pos == x->len)
        {
            t_free (j);
            x->state = 1; /* could drop connection immediately */
        }
        return;
    }

    r = read (x->tcp, &ch, 1);
    if (r == 0)
    {
        errno = error_pipe;
        t_close (j);
        return;
    }
    if (r < 0)
    {
        t_close (j);
        return;
    }

    if (x->state == 1)
    {
        x->len = (unsigned char)ch;
        x->len <<= 8;
        x->state = 2;
        return;
    }
    if (x->state == 2)
    {
        x->len += (unsigned char)ch;
        if (!x->len)
        {
            errno = error_proto;
            t_close (j);
            return;
        }
        x->buf = alloc (x->len);
        if (!x->buf)
        {
            t_close(j);
            return;
        }
        x->pos = 0;
        x->state = 3;

        return;
    }

    if (x->state != 3)
        return; /* impossible */

    x->buf[x->pos++] = ch;
    if (x->pos < x->len)
        return;

    if (!packetquery (x->buf, x->len, &q, qtype, qclass, x->id))
    {
        t_close(j);
        return;
    }

    x->active = ++numqueries;

    if (debug_level)
        log_query (x->active, x->ip, x->port, x->id, q, qtype);

    switch (query_start (&x->q, q, qtype, qclass, myipoutgoing))
    {
    case -1:
        t_drop (j);
        return;
    case 1:
        t_respond (j);
        return;
    }
    t_free (j);
    x->state = 0;
}
コード例 #8
0
ファイル: forward.c プロジェクト: a33g-dev/platform_samsung
void receive_query(struct listener *listen, time_t now)
{
  struct dns_header *header = (struct dns_header *)daemon->packet;
  union mysockaddr source_addr;
  unsigned short type;
  struct all_addr dst_addr;
  struct in_addr netmask, dst_addr_4;
  size_t m;
  ssize_t n;
  int if_index = 0;
  struct iovec iov[1];
  struct msghdr msg;
  struct cmsghdr *cmptr;
  union {
    struct cmsghdr align; /* this ensures alignment */
#ifdef HAVE_IPV6
    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
#endif
#if defined(HAVE_LINUX_NETWORK)
    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(IP_RECVDSTADDR) && defined(HAVE_SOLARIS_NETWORK)
    char control[CMSG_SPACE(sizeof(struct in_addr)) +
		 CMSG_SPACE(sizeof(unsigned int))];
#elif defined(IP_RECVDSTADDR)
    char control[CMSG_SPACE(sizeof(struct in_addr)) +
		 CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif
  } control_u;
  
  /* packet buffer overwritten */
  daemon->srv_save = NULL;
  
  if (listen->iface && listen->family == AF_INET && option_bool(OPT_NOWILD))
    {
      dst_addr_4 = listen->iface->addr.in.sin_addr;
      netmask = listen->iface->netmask;
    }
  else
    {
      dst_addr_4.s_addr = 0;
      netmask.s_addr = 0;
    }

  iov[0].iov_base = daemon->packet;
  iov[0].iov_len = daemon->edns_pktsz;
    
  msg.msg_control = control_u.control;
  msg.msg_controllen = sizeof(control_u);
  msg.msg_flags = 0;
  msg.msg_name = &source_addr;
  msg.msg_namelen = sizeof(source_addr);
  msg.msg_iov = iov;
  msg.msg_iovlen = 1;
  
  if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
    return;
  
  if (n < (int)sizeof(struct dns_header) || 
      (msg.msg_flags & MSG_TRUNC) ||
      (header->hb3 & HB3_QR))
    return;
  
  source_addr.sa.sa_family = listen->family;
#ifdef HAVE_IPV6
  if (listen->family == AF_INET6)
    source_addr.in6.sin6_flowinfo = 0;
#endif

  if (!option_bool(OPT_NOWILD))
    {
      struct ifreq ifr;

      if (msg.msg_controllen < sizeof(struct cmsghdr))
	return;

#if defined(HAVE_LINUX_NETWORK)
      if (listen->family == AF_INET)
	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
	  if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
	    {
	      union {
		unsigned char *c;
		struct in_pktinfo *p;
	      } p;
	      p.c = CMSG_DATA(cmptr);
	      dst_addr_4 = dst_addr.addr.addr4 = p.p->ipi_spec_dst;
	      if_index = p.p->ipi_ifindex;
	    }
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
      if (listen->family == AF_INET)
	{
	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
	    {
	      union {
		unsigned char *c;
		unsigned int *i;
		struct in_addr *a;
#ifndef HAVE_SOLARIS_NETWORK
		struct sockaddr_dl *s;
#endif
	      } p;
	       p.c = CMSG_DATA(cmptr);
	       if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
		 dst_addr_4 = dst_addr.addr.addr4 = *(p.a);
	       else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
#ifdef HAVE_SOLARIS_NETWORK
		 if_index = *(p.i);
#else
  	         if_index = p.s->sdl_index;
#endif
	    }
	}
#endif
      
#ifdef HAVE_IPV6
      if (listen->family == AF_INET6)
	{
	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
	    if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
	      {
		union {
		  unsigned char *c;
		  struct in6_pktinfo *p;
		} p;
		p.c = CMSG_DATA(cmptr);
		  
		dst_addr.addr.addr6 = p.p->ipi6_addr;
		if_index = p.p->ipi6_ifindex;
	      }
	}
#endif
      
      /* enforce available interface configuration */
      
      if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
	  !iface_check(listen->family, &dst_addr, ifr.ifr_name))
	return;
      
      if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
	{
	  struct irec *iface;
	  
	  /* get the netmask of the interface whch has the address we were sent to.
	     This is no neccessarily the interface we arrived on. */
	  
	  for (iface = daemon->interfaces; iface; iface = iface->next)
	    if (iface->addr.sa.sa_family == AF_INET &&
		iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
	      break;
	  
	  /* interface may be new */
	  if (!iface)
	    enumerate_interfaces(); 
	  
	  for (iface = daemon->interfaces; iface; iface = iface->next)
	    if (iface->addr.sa.sa_family == AF_INET &&
		iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
	      break;
	  
	  /* If we failed, abandon localisation */
	  if (iface)
	    netmask = iface->netmask;
	  else
	    dst_addr_4.s_addr = 0;
	}
    }
  
  if (extract_request(header, (size_t)n, daemon->namebuff, &type))
    {
      char types[20];

      querystr(types, type);

      if (listen->family == AF_INET) 
	log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, 
		  (struct all_addr *)&source_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
      else
	log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, 
		  (struct all_addr *)&source_addr.in6.sin6_addr, types);
#endif
    }

  m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n, 
		      dst_addr_4, netmask, now);
  if (m >= 1)
    {
      send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header, 
		m, &source_addr, &dst_addr, if_index);
      daemon->local_answer++;
    }
  else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
			 header, (size_t)n, now, NULL))
    daemon->queries_forwarded++;
  else
    daemon->local_answer++;
}
コード例 #9
0
ファイル: axfrdns.c プロジェクト: carriercomm/ndjbdns
int
main (int argc, char *argv[])
{
    int n = 0;
    time_t t = 0;
    struct sigaction sa;

    char qtype[2];
    char qclass[2];
    char header[12];
    const char *x = NULL;
    unsigned int pos = 0;
    unsigned long long qnum = 0;

    sa.sa_handler = handle_term;
    sigaction (SIGINT, &sa, NULL);
    sigaction (SIGTERM, &sa, NULL);

    sa.sa_handler = SIG_IGN;
    sigaction (SIGPIPE, &sa, NULL);

    prog = strdup ((x = strrchr (argv[0], '/')) != NULL ?  x + 1 : argv[0]);
    n = check_option (argc, argv);
    argc -= n;
    argv += n;

    if (mode & DAEMON)
        /* redirect stderr to a log file */
        redirect_to_log (logfile, STDERR_FILENO);

    time (&t);
    memset (seed, 0, sizeof (seed));
    strftime (seed, sizeof (seed), "%b-%d %Y %T %Z", localtime (&t));
    warnx ("version %s: starting %s\n", VERSION, seed);

    set_timezone ();
    if (debug_level)
        warnx ("TIMEZONE: %s", env_get ("TZ"));

    read_conf (cfgfile);
    if (!debug_level)
        if ((x = env_get ("DEBUG_LEVEL")))
            debug_level = atol (x);
    warnx ("DEBUG_LEVEL set to `%d'", debug_level);

    dns_random_init (seed);

    axfr = env_get ("AXFR");
    if (debug_level)
        warnx ("AXFR set to `%s'", axfr);
    x = env_get ("TCPREMOTEIP");
    if (debug_level)
        warnx ("TCPREMOTEIP set to `%s'", x);
    if (x)
        ip4_scan (x, ip);
    else
        byte_zero (ip, 4);

    x = env_get ("TCPREMOTEPORT");
    if (debug_level)
        warnx ("TCPREMOTEPORT set to `%s'", x);
    if (!x)
        x = "0";
    scan_ulong (x, &port);

    droproot ();
    for (;;)
    {
        netread (tcpheader, 2);
        uint16_unpack_big (tcpheader, &len);
        if (len > 512)
            errx (-1, "excessively large request");
        netread (buf, len);

        pos = dns_packet_copy (buf, len, 0, header, 12);
        if (!pos)
            errx (-1, "truncated request");
        if (header[2] & 254)
            errx (-1, "bogus query");
        if (header[4] || (header[5] != 1))
            errx (-1, "bogus query");

        pos = dns_packet_getname (buf, len, pos, &zone);
        if (!pos)
            errx (-1, "truncated request");
        zonelen = dns_domain_length (zone);
        pos = dns_packet_copy (buf, len, pos, qtype, 2);
        if (!pos)
            errx (-1, "truncated request");
        pos = dns_packet_copy (buf, len, pos, qclass, 2);
        if (!pos)
            errx (-1, "truncated request");

        if (byte_diff(qclass, 2, DNS_C_IN) && byte_diff(qclass, 2, DNS_C_ANY))
            errx (-1, "bogus query: bad class");

        log_query (++qnum, ip, port, header, zone, qtype);
        if (byte_equal(qtype,2,DNS_T_AXFR))
        {
            case_lowerb (zone, zonelen);
            fdcdb = open_read ("data.cdb");
            if (fdcdb == -1)
                errx (-1, "could not read from file `data.cdb'");
            doaxfr (header);
            close (fdcdb);
        }
        else
        {
            if (!response_query (zone, qtype, qclass))
                err (-1, "could not allocate enough memory");
            response[2] |= 4;
            case_lowerb (zone, zonelen);
            response_id (header);
            response[3] &= ~128;
            if (!(header[2] & 1))
                response[2] &= ~1;
            if (!respond (zone, qtype, ip))
                errx (-1, "could not find information in file `data.cdb'");
            print (response, response_len);
        }
    }
}
コード例 #10
0
ファイル: forward.c プロジェクト: MIPS/external-dnsmasq
/* The daemon forks before calling this: it should deal with one connection,
   blocking as neccessary, and then return. Note, need to be a bit careful
   about resources for debug mode, when the fork is suppressed: that's
   done by the caller. */
unsigned char *tcp_request(int confd, time_t now,
			   struct in_addr local_addr, struct in_addr netmask)
{
  int size = 0;
  size_t m;
  unsigned short qtype, gotname;
  unsigned char c1, c2;
  /* Max TCP packet + slop */
  unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
  HEADER *header;
  struct server *last_server;
  
  while (1)
    {
      if (!packet ||
	  !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
	  !(size = c1 << 8 | c2) ||
	  !read_write(confd, packet, size, 1))
       	return packet; 
  
      if (size < (int)sizeof(HEADER))
	continue;
      
      header = (HEADER *)packet;
      
      if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
	{
	  union mysockaddr peer_addr;
	  socklen_t peer_len = sizeof(union mysockaddr);
	  
	  if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
	    {
	      char types[20];

	      querystr(types, qtype);

	      if (peer_addr.sa.sa_family == AF_INET) 
		log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, 
			  (struct all_addr *)&peer_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
	      else
		log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, 
			  (struct all_addr *)&peer_addr.in6.sin6_addr, types);
#endif
	    }
	}
      
      /* m > 0 if answered from cache */
      m = answer_request(header, ((char *) header) + 65536, (unsigned int)size, 
			 local_addr, netmask, now);

      /* Do this by steam now we're not in the select() loop */
      check_log_writer(NULL); 
      
      if (m == 0)
	{
	  unsigned short flags = 0;
	  struct all_addr *addrp = NULL;
	  int type = 0;
	  char *domain = NULL;
	  
	  if (gotname)
	    flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain);
	  
	  if (type != 0  || (daemon->options & OPT_ORDER) || !daemon->last_server)
	    last_server = daemon->servers;
	  else
	    last_server = daemon->last_server;
      
	  if (!flags && last_server)
	    {
	      struct server *firstsendto = NULL;
	      unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);

	      /* Loop round available servers until we succeed in connecting to one.
	         Note that this code subtley ensures that consecutive queries on this connection
	         which can go to the same server, do so. */
	      while (1) 
		{
		  if (!firstsendto)
		    firstsendto = last_server;
		  else
		    {
		      if (!(last_server = last_server->next))
			last_server = daemon->servers;
		      
		      if (last_server == firstsendto)
			break;
		    }
	      
		  /* server for wrong domain */
		  if (type != (last_server->flags & SERV_TYPE) ||
		      (type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
		    continue;
		  
		  if ((last_server->tcpfd == -1) &&
		      (last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
		      (!local_bind(last_server->tcpfd, &last_server->source_addr,
				   last_server->interface, last_server->mark, 1) ||
		       connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
		    {
		      close(last_server->tcpfd);
		      last_server->tcpfd = -1;
		    }
		  
		  if (last_server->tcpfd == -1)	
		    continue;

		  c1 = size >> 8;
		  c2 = size;
		  
		  if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
		      !read_write(last_server->tcpfd, &c2, 1, 0) ||
		      !read_write(last_server->tcpfd, packet, size, 0) ||
		      !read_write(last_server->tcpfd, &c1, 1, 1) ||
		      !read_write(last_server->tcpfd, &c2, 1, 1))
		    {
		      close(last_server->tcpfd);
		      last_server->tcpfd = -1;
		      continue;
		    } 
		  
		  m = (c1 << 8) | c2;
		  if (!read_write(last_server->tcpfd, packet, m, 1))
		    return packet;
		  
		  if (!gotname)
		    strcpy(daemon->namebuff, "query");
		  if (last_server->addr.sa.sa_family == AF_INET)
		    log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&last_server->addr.in.sin_addr, NULL); 
#ifdef HAVE_IPV6
		  else
		    log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff, 
			      (struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
#endif 
		  
		  /* There's no point in updating the cache, since this process will exit and
		     lose the information after a few queries. We make this call for the alias and 
		     bogus-nxdomain side-effects. */
		  /* If the crc of the question section doesn't match the crc we sent, then
		     someone might be attempting to insert bogus values into the cache by 
		     sending replies containing questions and bogus answers. */
		  if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
		    m = process_reply(header, now, last_server, (unsigned int)m);
		  
		  break;
		}
	    }
	  
	  /* In case of local answer or no connections made. */
	  if (m == 0)
	    m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
	}

      check_log_writer(NULL);
      
      c1 = m>>8;
      c2 = m;
      if (!read_write(confd, &c1, 1, 0) ||
	  !read_write(confd, &c2, 1, 0) || 
	  !read_write(confd, packet, m, 0))
	return packet;
    }
コード例 #11
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;
}
コード例 #12
0
static unsigned short search_servers(struct daemon *daemon, time_t now, struct all_addr **addrpp, 
				     unsigned short qtype, char *qdomain, int *type, char **domain)
			      
{
  /* 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. */
  
  unsigned int namelen = strlen(qdomain);
  unsigned int matchlen = 0;
  struct server *serv;
  unsigned short flags = 0;
  
  for (serv = daemon->servers; serv; serv=serv->next)
    /* domain matches take priority over NODOTS matches */
    if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
      {
	unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6; 
	*type = SERV_FOR_NODOTS;
	if (serv->flags & SERV_NO_ADDR)
	  flags = F_NXDOMAIN;
	else if (serv->flags & SERV_LITERAL_ADDRESS) 
	  { 
	    if (sflag & qtype)
	      {
		flags = sflag;
		if (serv->addr.sa.sa_family == AF_INET) 
		  *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
		else
		  *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif 
	      }
	    else if (!flags)
	      flags = F_NOERR;
	  } 
      }
    else if (serv->flags & SERV_HAS_DOMAIN)
      {
	unsigned int domainlen = strlen(serv->domain);
	char *matchstart = qdomain + namelen - domainlen;
	if (namelen >= domainlen &&
	    hostname_isequal(matchstart, serv->domain) &&
	    domainlen >= matchlen &&
	    (domainlen == 0 || namelen == domainlen || *(serv->domain) == '.' || *(matchstart-1) == '.' ))
	  {
	    unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
	    *type = SERV_HAS_DOMAIN;
	    *domain = serv->domain;
	    matchlen = domainlen;
	    if (serv->flags & SERV_NO_ADDR)
	      flags = F_NXDOMAIN;
	    else if (serv->flags & SERV_LITERAL_ADDRESS)
	      {
		if ((sflag | F_QUERY ) & qtype)
		  {
		    flags = qtype;
		    if (serv->addr.sa.sa_family == AF_INET) 
		      *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
		    else
		      *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif
		  }
		else if (!flags)
		  flags = F_NOERR;
	      }
	  } 
      }

  if (flags & ~(F_NOERR | F_NXDOMAIN)) /* flags set here means a literal found */
    {
      if (flags & F_QUERY)
	log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL, 0, NULL, 0);
      else
	log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0, NULL, 0);
    }
  else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
    flags = F_NXDOMAIN;
    
  if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now, daemon))
    flags = F_NOERR;

  if (flags == F_NXDOMAIN || flags == F_NOERR)
    log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL, 0, NULL, 0);

  return  flags;
}
コード例 #13
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;
}
コード例 #14
0
/* reforward last query */
int reforward_query(struct frec *forward, int peerfd, int peerfd6, int strict_order, char *dnamebuff)
{
    char *domain;
    struct DNS_MSG_BUF * dnsMsgBufPtr;
    HEADER *header;
    int plen;
    if (forward == NULL)
    {
        return -1;
    }
    dnsMsgBufPtr = forward->dnsMsgBufPtr;
    if (dnsMsgBufPtr == NULL)
    {
        return -1;
    }
    if(dnsMsgBufPtr->nextsentto == dnsMsgBufPtr->firstsentto)
    {
        return -1;
    }
    plen = dnsMsgBufPtr->plen;
    header = (HEADER *)&dnsMsgBufPtr->header;

    /* retry on existing query, send to next server */
    domain = dnsMsgBufPtr->firstsentto->domain;
    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)  */
    while (1)
    {
        int af = dnsMsgBufPtr->nextsentto->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 && !dnsMsgBufPtr->nextsentto->domain) ||
                (domain && dnsMsgBufPtr->nextsentto->domain &&
                 strcmp(domain, dnsMsgBufPtr->nextsentto->domain) == 0))
        {
            if (sendto(fd, (char *)header, plen, 0, &dnsMsgBufPtr->nextsentto->addr.sa,
                       sa_len(&dnsMsgBufPtr->nextsentto->addr)) != -1)
            {
                //junzhao 2004.5.31
                if (af == AF_INET)
                {
                    log_query(F_SERVER | F_IPV4 | F_FORWARD, dnsMsgBufPtr->gotname ? dnamebuff :
                              "query",
                              (struct all_addr *)&dnsMsgBufPtr->nextsentto->addr.in.sin_addr);
                }
#ifdef HAVE_IPV6
                else
                {
                    log_query(F_SERVER | F_IPV6 | F_FORWARD, dnsMsgBufPtr->gotname ? dnamebuff :
                              "query",
                              (struct all_addr *)&dnsMsgBufPtr->nextsentto->addr.in6.sin6_addr);
                }
#endif

                if (!(dnsMsgBufPtr->nextsentto = dnsMsgBufPtr->nextsentto->next))
                {
                    dnsMsgBufPtr->nextsentto = dnsMsgBufPtr->servers;
                }
                return 0;
            }
        }

        if (!(dnsMsgBufPtr->nextsentto = dnsMsgBufPtr->nextsentto->next))
        {
            dnsMsgBufPtr->nextsentto = dnsMsgBufPtr->servers;
        }

        /* check if we tried all without success */
        if (dnsMsgBufPtr->nextsentto == dnsMsgBufPtr->firstsentto)
        {
            break;
        }
    }//while 1

    /* could not send on, prepare to return */
    return -1;
}
コード例 #15
0
ファイル: forward.c プロジェクト: MIPS/external-dnsmasq
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;
}
コード例 #16
0
ファイル: forward.c プロジェクト: MIPS/external-dnsmasq
void receive_query(struct listener *listen, time_t now)
{
  HEADER *header = (HEADER *)daemon->packet;
  union mysockaddr source_addr;
  unsigned short type;
  struct all_addr dst_addr;
  struct in_addr netmask, dst_addr_4;
  size_t m;
  ssize_t n;
  int if_index = 0;
  struct iovec iov[1];
  struct msghdr msg;
  struct cmsghdr *cmptr;
  union {
    struct cmsghdr align; /* this ensures alignment */
#ifdef HAVE_IPV6
    char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
#endif
#if defined(HAVE_LINUX_NETWORK)
    char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(IP_RECVDSTADDR)
    char control[CMSG_SPACE(sizeof(struct in_addr)) +
		 CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif
  } control_u;
  
  /* packet buffer overwritten */
  daemon->srv_save = NULL;
  
  if (listen->family == AF_INET && (daemon->options & OPT_NOWILD))
    {
      dst_addr_4 = listen->iface->addr.in.sin_addr;
      netmask = listen->iface->netmask;
    }
  else
    {
      dst_addr_4.s_addr = 0;
      netmask.s_addr = 0;
    }

  iov[0].iov_base = daemon->packet;
  iov[0].iov_len = daemon->edns_pktsz;
    
  msg.msg_control = control_u.control;
  msg.msg_controllen = sizeof(control_u);
  msg.msg_flags = 0;
  msg.msg_name = &source_addr;
  msg.msg_namelen = sizeof(source_addr);
  msg.msg_iov = iov;
  msg.msg_iovlen = 1;
  
  if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
    return;
  
  if (n < (int)sizeof(HEADER) || 
      (msg.msg_flags & MSG_TRUNC) ||
      header->qr)
    return;
  
  source_addr.sa.sa_family = listen->family;
#ifdef HAVE_IPV6
  if (listen->family == AF_INET6)
    source_addr.in6.sin6_flowinfo = 0;
#endif
  
  if (!(daemon->options & OPT_NOWILD))
    {
      struct ifreq ifr;

      if (msg.msg_controllen < sizeof(struct cmsghdr))
	return;

#if defined(HAVE_LINUX_NETWORK)
      if (listen->family == AF_INET)
	for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
	  if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
	    {
	      dst_addr_4 = dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
	      if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
	    }
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
      if (listen->family == AF_INET)
	{
	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
	    if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
	      dst_addr_4 = dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
	    else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
	      if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
	}
#endif
      
#ifdef HAVE_IPV6
      if (listen->family == AF_INET6)
	{
	  for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
	    if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
	      {
		dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
		if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
	      }
	}
#endif
      
      /* enforce available interface configuration */
      
      if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
	  !iface_check(listen->family, &dst_addr, ifr.ifr_name, &if_index))
	return;
      
      if (listen->family == AF_INET &&
	  (daemon->options & OPT_LOCALISE) &&
	  ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
	return;
      
      netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
    }
  
  if (extract_request(header, (size_t)n, daemon->namebuff, &type))
    {
      char types[20];

      querystr(types, type);

      if (listen->family == AF_INET) 
	log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff, 
		  (struct all_addr *)&source_addr.in.sin_addr, types);
#ifdef HAVE_IPV6
      else
	log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff, 
		  (struct all_addr *)&source_addr.in6.sin6_addr, types);
#endif
    }

  m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n, 
		      dst_addr_4, netmask, now);
  if (m >= 1)
    {
      send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header, 
		m, &source_addr, &dst_addr, if_index);
      daemon->local_answer++;
    }
  else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
			 header, (size_t)n, now, NULL))
    daemon->queries_forwarded++;
  else
    daemon->local_answer++;
}
コード例 #17
0
ファイル: forward.c プロジェクト: a33g-dev/platform_samsung
static unsigned int search_servers(time_t now, struct all_addr **addrpp, 
				     unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind)
			      
{
  /* 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. */
  
  unsigned int namelen = strlen(qdomain);
  unsigned int matchlen = 0;
  struct server *serv;
  unsigned int flags = 0;
  
  for (serv = daemon->servers; serv; serv=serv->next)
    /* domain matches take priority over NODOTS matches */
    if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
      {
	unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6; 
	*type = SERV_FOR_NODOTS;
	if (serv->flags & SERV_NO_ADDR)
	  flags = F_NXDOMAIN;
	else if (serv->flags & SERV_LITERAL_ADDRESS) 
	  { 
	    if (sflag & qtype)
	      {
		flags = sflag;
		if (serv->addr.sa.sa_family == AF_INET) 
		  *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
		else
		  *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif 
	      }
	    else if (!flags || (flags & F_NXDOMAIN))
	      flags = F_NOERR;
	  } 
      }
    else if (serv->flags & SERV_HAS_DOMAIN)
      {
	unsigned int domainlen = strlen(serv->domain);
	char *matchstart = qdomain + namelen - domainlen;
	if (namelen >= domainlen &&
	    hostname_isequal(matchstart, serv->domain) &&
	    (domainlen == 0 || namelen == domainlen || *(matchstart-1) == '.' ))
	  {
	    if (serv->flags & SERV_NO_REBIND)	
	      *norebind = 1;
	    else
	      {
		unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
		/* implement priority rules for --address and --server for same domain.
		   --address wins if the address is for the correct AF
		   --server wins otherwise. */
		if (domainlen != 0 && domainlen == matchlen)
		  {
		    if ((serv->flags & SERV_LITERAL_ADDRESS))
		      {
			if (!(sflag & qtype) && flags == 0)
			  continue;
		      }
		    else
		      {
			if (flags & (F_IPV4 | F_IPV6))
			  continue;
		      }
		  }
		
		if (domainlen >= matchlen)
		  {
		    *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
		    *domain = serv->domain;
		    matchlen = domainlen;
		    if (serv->flags & SERV_NO_ADDR)
		      flags = F_NXDOMAIN;
		    else if (serv->flags & SERV_LITERAL_ADDRESS)
		      {
			if (sflag & qtype)
			  {
			    flags = sflag;
			    if (serv->addr.sa.sa_family == AF_INET) 
			      *addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
#ifdef HAVE_IPV6
			    else
			      *addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
#endif
			  }
			else if (!flags || (flags & F_NXDOMAIN))
			  flags = F_NOERR;
		      }
		    else
		      flags = 0;
		  } 
	      }
	  }
      }
  
  if (flags == 0 && !(qtype & F_QUERY) && 
      option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
    /* don't forward A or AAAA queries for simple names, except the empty name */
    flags = F_NOERR;
  
  if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
    flags = F_NOERR;

  if (flags)
    {
      int logflags = 0;
      
      if (flags == F_NXDOMAIN || flags == F_NOERR)
	logflags = F_NEG | qtype;
  
      log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
    }
  else if ((*type) & SERV_USE_RESOLV)
    {
      *type = 0; /* use normal servers for this domain */
      *domain = NULL;
    }
  return  flags;
}
コード例 #18
0
ファイル: dnsmasq.c プロジェクト: gittestusername/uClinux
int main (int argc, char **argv)
{
  char *int_err_string;
  int cachesize = CACHESIZ;
  int port = NAMESERVER_PORT;
  int query_port = 0;
  unsigned long local_ttl = 0;
  int logged_lease = 0, first_loop = 1;
  unsigned int options;
  char *runfile = RUNFILE;
  time_t resolv_changed = 0;
  time_t now, last = 0;
  time_t lease_file_change = 0;
  ino_t lease_file_inode = (ino_t)0;
  struct irec *iface, *interfaces = NULL;
  char *mxname = NULL;
  char *mxtarget = NULL;
  char *lease_file = NULL;
  char *addn_hosts = NULL;
  char *domain_suffix = NULL;
  char *username = CHUSER;
  char *groupname = CHGRP;
  struct iname *if_names = NULL;
  struct iname *if_addrs = NULL;
  struct iname *if_except = NULL;
  struct iname *if_tmp;
  struct server *serv_addrs = NULL;
  char *dnamebuff, *packet;
  struct server *servers, *last_server;
  struct resolvc default_resolv = { NULL, 1, 0, RESOLVFILE };
  struct resolvc *resolv = &default_resolv;
  struct bogus_addr *bogus_addr = NULL;
  struct serverfd *serverfdp, *sfds = NULL;

  sighup = 1; /* init cache the first time through */
  sigusr1 = 0; /* but don't dump */
  sigusr2 = 0; /* or rescan interfaces */
  signal(SIGUSR1, sig_handler);
  signal(SIGUSR2, sig_handler);
  signal(SIGHUP, sig_handler);

  /* These get allocated here to avoid overflowing the small stack
     on embedded systems. dnamebuff is big enough to hold one
     maximal sixed domain name and gets passed into all the processing
     code. We manage to get away with one buffer. */
  dnamebuff = safe_malloc(MAXDNAME);
  /* Size: we check after adding each record, so there must be 
     memory for the largest packet, and the largest record */
  packet = safe_malloc(PACKETSZ+MAXDNAME+RRFIXEDSZ);
  
  options = read_opts(argc, argv, dnamebuff, &resolv, &mxname, &mxtarget, &lease_file,
		      &username, &groupname, &domain_suffix, &runfile, 
		      &if_names, &if_addrs, &if_except, &bogus_addr, 
		      &serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts);
  
  int_err_string = enumerate_interfaces(&interfaces, if_names, if_addrs, if_except, port);
  
  if (int_err_string)
    die(int_err_string, NULL);
  
  for (if_tmp = if_names; if_tmp; if_tmp = if_tmp->next)
    if (if_tmp->name && !if_tmp->found)
      die("unknown interface %s", if_tmp->name);
  
  for (if_tmp = if_addrs; if_tmp; if_tmp = if_tmp->next)
    if (!if_tmp->found)
      {
	char addrbuff[ADDRSTRLEN];
#ifdef HAVE_IPV6
	if (if_tmp->addr.sa.sa_family == AF_INET)
	  inet_ntop(AF_INET, &if_tmp->addr.in.sin_addr,
		    addrbuff, ADDRSTRLEN);
	  else
	    inet_ntop(AF_INET6, &if_tmp->addr.in6.sin6_addr,
		      addrbuff, ADDRSTRLEN);
#else
	strcpy(addrbuff, inet_ntoa(if_tmp->addr.in.sin_addr));
#endif
	die("no interface with address %s", addrbuff);
      }
      
  forward_init(1);

  cache_init(cachesize, options & OPT_LOG);
  
  setbuf(stdout, NULL);

  if (!(options & OPT_DEBUG))
    {
      FILE *pidfile;
      struct passwd *ent_pw;
      int i;
        
      /* The following code "daemonizes" the process. 
	 See Stevens section 12.4 */

#ifndef NO_FORK
      if (fork() != 0 )
	exit(0);
      
      setsid();
      
      if (fork() != 0)
	exit(0);
#endif
      
      chdir("/");
      umask(022); /* make pidfile 0644 */
      
      /* write pidfile _after_ forking ! */
      if (runfile && (pidfile = fopen(runfile, "w")))
      	{
	  fprintf(pidfile, "%d\n", (int) getpid());
	  fclose(pidfile);
	}
      
      umask(0);

      for (i=0; i<64; i++)
	{
	  for (iface = interfaces; iface; iface = iface->next)
	    if (iface->fd == i)
	      break;
	  if (iface)
	    continue;
	  
	  close(i);
	}

      /* Change uid and gid for security */
      if (username && (ent_pw = getpwnam(username)))
	{
	  gid_t dummy;
	  struct group *gp;
	  /* remove all supplimentary groups */
	  setgroups(0, &dummy);
	  /* change group for /etc/ppp/resolv.conf 
	     otherwise get the group for "nobody" */
	  if ((groupname && (gp = getgrnam(groupname))) || 
	      (gp = getgrgid(ent_pw->pw_gid)))
	    setgid(gp->gr_gid); 
	  /* finally drop root */
	  setuid(ent_pw->pw_uid);
	}
    }

  openlog("dnsmasq", 
	  DNSMASQ_LOG_OPT(options & OPT_DEBUG), 
	  DNSMASQ_LOG_FAC(options & OPT_DEBUG));
  
  if (cachesize)
    syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, cachesize);
  else
    syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
  
  if (options & OPT_LOCALMX)
    syslog(LOG_INFO, "serving MX record for local hosts target %s", mxtarget);
  else if (mxname)
    syslog(LOG_INFO, "serving MX record for mailhost %s target %s", 
	   mxname, mxtarget);
  
  if (getuid() == 0 || geteuid() == 0)
    syslog(LOG_WARNING, "failed to drop root privs");
  
  servers = last_server = check_servers(serv_addrs, interfaces, &sfds);
  
  while (1)
    {
      int ready, maxfd = 0;
      fd_set rset;
      HEADER *header;
      struct stat statbuf;
   
      if (first_loop)
	/* do init stuff only first time round. */
	{
	  first_loop = 0;
	  ready = 0;
	}
      else
	{
	  FD_ZERO(&rset);

	  for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
	    {
	      FD_SET(serverfdp->fd, &rset);
	      if (serverfdp->fd > maxfd)
		maxfd = serverfdp->fd;
	    }

	  for (iface = interfaces; iface; iface = iface->next)
	    {
	      FD_SET(iface->fd, &rset);
	      if (iface->fd > maxfd)
		maxfd = iface->fd;
	    }
	  
	  ready = select(maxfd+1, &rset, NULL, NULL, NULL);
	  
	  if (ready == -1)
	    {
	      if (errno == EINTR)
		ready = 0; /* do signal handlers */
	      else
		continue;
	    }
	}
      
      if (sighup)
	{
	  signal(SIGHUP, SIG_IGN);
	  cache_reload(options, dnamebuff, domain_suffix, addn_hosts);
	  if (resolv && (options & OPT_NO_POLL))
	    servers = last_server = 
	      check_servers(reload_servers(resolv->name, dnamebuff, servers, query_port), 
			    interfaces, &sfds);
	  sighup = 0;
	  signal(SIGHUP, sig_handler);
	}
      
      if (sigusr1)
	{
	  signal(SIGUSR1, SIG_IGN);
	  dump_cache(options & (OPT_DEBUG | OPT_LOG), cachesize);
	  sigusr1 = 0;
	  signal(SIGUSR1, sig_handler);
	}
      
      if (sigusr2)
	{
	  signal(SIGUSR2, SIG_IGN);
	  if (getuid() != 0 && port <= 1024)
	    syslog(LOG_ERR, "cannot re-scan interfaces unless --user=root");
	  else
	   {
	     syslog(LOG_INFO, "rescanning network interfaces");
	     int_err_string = enumerate_interfaces(&interfaces, if_names, if_addrs, if_except, port);
	     if (int_err_string)
	       syslog(LOG_ERR, int_err_string, strerror(errno));
	   }
	  sigusr2 = 0;
	  signal(SIGUSR2, sig_handler);
	  /* may be new file descriptors now, so redo select() */
	  ready = 0;
	}
      
      now = time(NULL);

      /* Check for changes to resolv files and DHCP leases file once per second max. */
      if (last == 0 || now > last)
	{
	  last = now;
	  if (!(options & OPT_NO_POLL))
	    {
	      struct resolvc *res = resolv, *latest = NULL;
	      time_t last_change = 0;
	      /* There may be more than one possible file. 
		 Go through and find the one which changed _last_.
		 Warn of any which can't be read. */
	      while (res)
		{
		  if (stat(res->name, &statbuf) == -1)
		    {
		      if (!res->logged)
			syslog(LOG_WARNING, "failed to access %s: %m", res->name);
		      res->logged = 1;
		    }
		  else
		    {
		      res->logged = 0;
		      if (statbuf.st_mtime > last_change)
			{
			  last_change = statbuf.st_mtime;
			  latest = res;
			}
		    }
		  res = res->next;
		}
	  
	      if (latest && last_change > resolv_changed)
		{
		  resolv_changed = last_change;
		  servers = last_server = 
		    check_servers(reload_servers(latest->name, dnamebuff, servers, query_port),
				  interfaces, &sfds);
		}
	    }

	  if (lease_file)
	    {
syslog(LOG_WARNING, "checking lease file %s", lease_file);
	      if (stat(lease_file, &statbuf) == -1)
		{
		  if (!logged_lease)
		    syslog(LOG_WARNING, "failed to access %s: %m", lease_file);
		  logged_lease = 1;
		}
	      else
		{ 
		  logged_lease = 0;
		  if ((statbuf.st_mtime != lease_file_change) ||
		      (statbuf.st_ino != lease_file_inode))
		    {
		      lease_file_change = statbuf.st_mtime;
		      lease_file_inode = statbuf.st_ino;
		      load_dhcp(lease_file, domain_suffix, now, dnamebuff);
		    }
		}
	    }
	}
		
      if (ready == 0)
	continue; /* no sockets ready */
      
       for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
	 if (FD_ISSET(serverfdp->fd, &rset))
	   last_server = reply_query(serverfdp->fd, options, packet, now, 
				     dnamebuff, last_server, bogus_addr);
      
      for (iface = interfaces; iface; iface = iface->next)
	{
	  if (FD_ISSET(iface->fd, &rset))
	    {
	      /* request packet, deal with query */
	      union mysockaddr udpaddr;
	      socklen_t udplen = sizeof(udpaddr);
	      int m, n = recvfrom(iface->fd, packet, PACKETSZ, 0, &udpaddr.sa, &udplen); 
	      udpaddr.sa.sa_family = iface->addr.sa.sa_family;
#ifdef HAVE_IPV6
	      if (udpaddr.sa.sa_family == AF_INET6)
		udpaddr.in6.sin6_flowinfo = htonl(0);
#endif	      
	      header = (HEADER *)packet;
	      if (n >= (int)sizeof(HEADER) && !header->qr)
		{
		  if (extract_request(header, (unsigned int)n, dnamebuff))
		    {
		      if (udpaddr.sa.sa_family == AF_INET) 
			log_query(F_QUERY | F_IPV4 | F_FORWARD, dnamebuff, 
				  (struct all_addr *)&udpaddr.in.sin_addr);
#ifdef HAVE_IPV6
		      else
			log_query(F_QUERY | F_IPV6 | F_FORWARD, dnamebuff, 
				  (struct all_addr *)&udpaddr.in6.sin6_addr);
#endif
		    }
		  
		  m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n, 
				      mxname, mxtarget, options, now, local_ttl, dnamebuff);
		  if (m >= 1)
		    {
		      /* answered from cache, send reply */
		      sendto(iface->fd, (char *)header, m, 0, 
			     &udpaddr.sa, sa_len(&udpaddr));
		    }
		  else 
		    {
		      /* cannot answer from cache, send on to real nameserver */
		      last_server = forward_query(iface->fd, &udpaddr, header, n, 
						  options, dnamebuff, servers, 
						  last_server, now, local_ttl);
		    }
		}
	      
	    }
	}
    }
  
  return 0;
}
コード例 #19
0
ファイル: forward.c プロジェクト: a33g-dev/platform_samsung
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;
}