Пример #1
0
/**************************************************************************************************
	FIND_ALIAS
	Find an ALIAS or A record for the alias.
	Returns the RR or NULL if not found.
**************************************************************************************************/
MYDNS_RR *
find_alias(TASK *t, char *fqdn)
{
	register MYDNS_SOA *soa;
	register MYDNS_RR *rr;
	register char *label;
	char name[DNS_MAXNAMELEN+1];
	
	/* Load the SOA for the alias name. */
	memset(name, 0, sizeof(name));
	if (!(soa = find_soa(t, fqdn, name)))
		return (NULL);

	/* Examine each label in the name, one at a time; look for relevant records */
	for (label = name; ; label++)
	{
		if (label == name || *label == '.')
		{
			if (label[0] == '.' && label[1]) label++;		/* Advance past leading dot */
#if DEBUG_ENABLED && DEBUG_ALIAS
			Debug("%s: label=`%s'", desctask(t), label);
#endif

			/* Do an exact match if the label is the first in the list */
			if (label == name)
			{
#if DEBUG_ENABLED && DEBUG_ALIAS
				Debug("%s: trying exact match `%s'", desctask(t), label);
#endif
				if ((rr = find_rr(t, soa, DNS_QTYPE_A, label)))
					return (rr);
			}

			/* No exact match. If the label isn't empty, replace the first part
				of the label with `*' and check for wildcard matches. */
			if (*label)
			{
				uchar wclabel[DNS_MAXNAMELEN+1], *c;

				/* Generate wildcarded label, i.e. `*.example' or maybe just `*'. */
				if (!(c = strchr(label, '.')))
					wclabel[0] = '*', wclabel[1] = '\0';
				else
					wclabel[0] = '*', strncpy(wclabel+1, c, sizeof(wclabel)-2);

#if DEBUG_ENABLED && DEBUG_ALIAS
				Debug("%s: trying wildcard `%s'", desctask(t), wclabel);
#endif
				if ((rr = find_rr(t, soa, DNS_QTYPE_A, wclabel)))
					return (rr);
			}
		}
		if (!*label)
			break;
	}
	return (NULL);
}
Пример #2
0
/**************************************************************************************************
	CHECK_XFER
	If the "xfer" column exists in the soa table, it should contain a list of wildcards separated
	by commas.  In order for this zone transfer to continue, one of the wildcards must match
	the client's IP address.
**************************************************************************************************/
static void
check_xfer(TASK *t, MYDNS_SOA *soa) {
  SQL_RES	*res = NULL;
  SQL_ROW	row = NULL;
  char		ip[256];
  char		*query = NULL;
  size_t	querylen = 0;
  int		ok = 0;

  memset(&ip, 0, sizeof(ip));

  if (!mydns_soa_use_xfer)
    return;

  strncpy(ip, clientaddr(t), sizeof(ip)-1);

  querylen = sql_build_query(&query, "SELECT xfer FROM %s WHERE id=%u%s%s%s;",
			     mydns_soa_table_name, soa->id,
			     (mydns_rr_use_active)? " AND active='" : "",
			     (mydns_rr_use_active)? mydns_rr_active_types[0] : "",
			     (mydns_rr_use_active)? "'" : "");

  res = sql_query(sql, query, querylen);
  RELEASE(query);
  if (!res) {
    ErrSQL(sql, "%s: %s", desctask(t), _("error loading zone transfer access rules"));
  }

  if ((row = sql_getrow(res, NULL))) {
    char *wild = NULL, *r = NULL;

    for (r = row[0]; !ok && (wild = strsep(&r, ",")); )	{
      if (strchr(wild, '/')) {
	if (t->family == AF_INET)
	  ok = in_cidr(wild, t->addr4.sin_addr);
      }	else if (wildcard_match(wild, ip))
	ok = 1;
    }
  }
  sql_free(res);

  if (!ok) {
    dnserror(t, DNS_RCODE_REFUSED, ERR_NO_AXFR);
    axfr_reply(t);
    axfr_error(t, _("access denied"));
  }
}
Пример #3
0
/**************************************************************************************************
	LOAD_BALANCE
	Use the 'aux' value to weight multiple A nodes.
**************************************************************************************************/
static inline void
load_balance(TASK *t, RRLIST *rrlist, datasection_t section, int sort_level)
{
	register RR	*node;											/* Current node */
	register int order = 1;										/* Current order */

#if DEBUG_ENABLED && DEBUG_SORT
	Debug("%s: Load balancing A records in %s section", desctask(t), datasection_str[section]);
#endif

	/* Hosts with 'aux' values > 50000 are always listed last */
	for (node = rrlist->head; node; node = node->next)
		if (RR_IS_ADDR(node) && node->sort_level == sort_level && !node->sort1)
			if (((MYDNS_RR *)node->rr)->aux >= 50000)
				node->sort1 = 50000;

	for (;;)
	{
		register int found = 0;									/* Number of records with this aux */
		uint64_t	weights = 0;									/* Sum of aux */
		register uint32_t rweight = 0;						/* Random aux */

		/* Compute the sum of the weights for all nodes where 'sort1' == 0 */
		for (node = rrlist->head; node; node = node->next)
			if (RR_IS_ADDR(node) && node->sort_level == sort_level && !node->sort1)
			{
				found++;
				weights += ((MYDNS_RR *)node->rr)->aux;
			}
		if (!found)
			break;

		/* Set 'sort1' to 'order' for the first node found where the running sum
			value is greater than or equal to 'rweight' */
		rweight = RAND(weights);
		for (weights = 0, node = rrlist->head; node; node = node->next)
			if (RR_IS_ADDR(node) && node->sort_level == sort_level && !node->sort1)
			{
				weights += ((MYDNS_RR *)node->rr)->aux;
				if (weights >= rweight)
				{
					node->sort1 = 65535 - order++;
					break;
				}
			}
	}
}
Пример #4
0
/**************************************************************************************************
	_SORT_SRV_RECS
	Sorts SRV records at the specified sort level.
	1. Sort by priority, lowest to highest.
	2. Sort by weight; 0 means "almost never choose me", higher-than-zero yields
		increased likelihood of being first.
**************************************************************************************************/
static inline void
_sort_srv_recs(TASK *t, RRLIST *rrlist, datasection_t section, int sort_level)
{
	register RR	*node;											/* Current node */
	register int count;											/* Number of SRV nodes on this level */

#if DEBUG_ENABLED && DEBUG_SORT
	Debug("%s: Sorting SRV records in %s section", desctask(t), datasection_str[section]);
#endif

	/* Assign 'sort1' to the priority (aux) and 'sort2' to 0 if there's a zero weight, else random */
	for (count = 0, node = rrlist->head; node; node = node->next)
		if (RR_IS_SRV(node) && node->sort_level == sort_level)
		{
			count++;
			node->sort1 = ((MYDNS_RR *)node->rr)->aux;
			if (((MYDNS_RR *)node->rr)->srv_weight == 0)
				node->sort2 = 0;
			else
	         node->sort2 = RAND(4294967294U);
		}

	if (count < 2)													/* Only one node here, don't bother */
		return;
	t->reply_cache_ok = 0;										/* Don't cache these replies */

	/* Sort a first time, so that the list is ordered by priority/weight */
	sort_rrlist(rrlist, sortcmp);

	/* Reset 'sort2' to zero for each SRV */
	for (node = rrlist->head; node; node = node->next)
		if (RR_IS_SRV(node) && node->sort_level == sort_level)
			node->sort2 = 0;

	/* For each unique priority, sort by weight */
	for (node = rrlist->head; node; node = node->next)
		if (RR_IS_SRV(node) && node->sort_level == sort_level && !node->sort2)
		{
			register int priority = node->sort1;
			register int order = 1;

			while (sort_srv_priority(t, rrlist, section, priority, sort_level, order++))
				/* DONOTHING */;
		}
}
Пример #5
0
/**************************************************************************************************
	AXFR_GET_SOA
	Attempt to find a SOA record.  If SOA id is 0, we made it up.
**************************************************************************************************/
static MYDNS_SOA *
axfr_get_soa(TASK *t) {
  MYDNS_SOA *soa = NULL;

  /* Try to load SOA */
  if (mydns_soa_load(sql, &soa, t->qname) < 0)
    ErrSQL(sql, "%s: %s", desctask(t), _("error loading zone"));
  if (soa) {
    return (soa);
	}

  /* STILL no SOA?  We aren't authoritative */
  dnserror(t, DNS_RCODE_REFUSED, ERR_ZONE_NOT_FOUND);
  axfr_reply(t);
  axfr_error(t, _("unknown zone"));
  /* NOTREACHED */
  return (NULL);
}
Пример #6
0
/**************************************************************************************************
	SORT_MX_RECS
	When there are multiple equal-preference MX records, randomize them to help keep the load
	equal.
**************************************************************************************************/
void
sort_mx_recs(TASK *t, RRLIST *rrlist, datasection_t section)
{
	register RR *node;

#if DEBUG_ENABLED && DEBUG_SORT
	Debug("%s: Sorting MX records in %s section", desctask(t), datasection_str[section]);
#endif

	/* Set 'sort' to a random number */
	for (node = rrlist->head; node; node = node->next)
		if (RR_IS_MX(node))
		{
			node->sort1 = ((MYDNS_RR *)node->rr)->aux;
			node->sort2 = RAND(4294967294U);
		}
	return (sort_rrlist(rrlist, sortcmp));
}
Пример #7
0
/**************************************************************************************************
	AXFR
	DNS-based zone transfer.  Send all resource records for in QNAME's zone to the client.
**************************************************************************************************/
void
axfr(TASK *t) {
#if DEBUG_ENABLED && DEBUG_AXFR
  struct timeval start = { 0, 0}, finish = { 0, 0 };	/* Time AXFR began and ended */
#endif
  MYDNS_SOA *soa = NULL;				/* SOA record for zone (may be bogus!) */

  /* Do generic startup stuff; this is a child process */
  signal(SIGALRM, axfr_timeout);
  alarm(AXFR_TIME_LIMIT);
  sql_close(sql);
  db_connect();

#if DEBUG_ENABLED && DEBUG_AXFR
  gettimeofday(&start, NULL);
  DebugX("axfr", 1,_("%s: Starting AXFR for task ID %u"), desctask(t), t->internal_id);
#endif
  total_records = total_octets = 0;
  t->no_markers = 1;

  /* Get SOA for zone */
  soa = axfr_get_soa(t);

  if (soa){
    /* Transfer that zone */
    axfr_zone(t, soa);
  }

#if DEBUG_ENABLED && DEBUG_AXFR
  /* Report result */
  gettimeofday(&finish, NULL);
  DebugX("axfr", 1,_("AXFR: %u records, %u octets, %.3fs"), 
	 (unsigned int)total_records, (unsigned int)total_octets,
	 ((finish.tv_sec + finish.tv_usec / 1000000.0) - (start.tv_sec + start.tv_usec / 1000000.0)));
#endif
  t->qdcount = 1;
  t->an.size = total_records;
  task_output_info(t, NULL);

  sockclose(t->fd);

  _exit(EXIT_SUCCESS);
}
Пример #8
0
/**************************************************************************************************
	SORT_SRV_PRIORITY
	Sorts one record for a single specified priority.
	After calling this function, 'sort2' should be 'weight' for the node affected.
	Returns the number of nodes processed (0 means "done with this priority").
**************************************************************************************************/
static inline int
sort_srv_priority(TASK *t, RRLIST *rrlist, datasection_t section, uint32_t priority,
						int sort_level, int order)
{
	register RR	*node;											/* Current node */
	register int found = 0;										/* Number of records with this priority */
	uint64_t	weights = 0;										/* Sum of weights */
	register uint32_t rweight = 0;							/* Random weight */

#if DEBUG_ENABLED && DEBUG_SORT
	Debug("%s: Sorting SRV records in %s section with priority %u",
			desctask(t), datasection_str[section], priority);
#endif

	/* Compute the sum of the weights for all nodes with this priority where 'sort2' == 0 */
	for (node = rrlist->head; node; node = node->next)
		if (RR_IS_SRV(node) && node->sort_level == sort_level && node->sort1 == priority && !node->sort2)
		{
			found++;
			weights += ((MYDNS_RR *)node->rr)->srv_weight;
		}
	if (!found)
		return (0);

	/* Set 'sort2' to 'order' for the first node found at this priority where the running sum
		value is greater than or equal to 'rweight' */
	rweight = RAND(weights+1);
	for (weights = 0, node = rrlist->head; node; node = node->next)
		if (RR_IS_SRV(node) && node->sort_level == sort_level
			 && node->sort1 == priority && !node->sort2)
		{
			weights += ((MYDNS_RR *)node->rr)->srv_weight;
			if (weights >= rweight)
			{
				node->sort2 = order;
				return (1);
			}
		}
	return (1);
}
Пример #9
0
/**************************************************************************************************
	_SORT_A_RECS
	If the request is for 'A' or 'AAAA' and there are multiple A or AAAA records, sort them.
	Since this is an A or AAAA record, the answer section contains only addresses.
	If any of the RR's have nonzero "aux" values, do load balancing, else do round robin.
**************************************************************************************************/
static inline void
_sort_a_recs(TASK *t, RRLIST *rrlist, datasection_t section, int sort_level)
{
	register RR *node;
	register int nonzero_aux = 0;
	register int count = 0;										/* Number of nodes at this level */

	/* If any addresses have nonzero 'aux' values, do load balancing */
	for (count = 0, node = rrlist->head; node; node = node->next)
		if (RR_IS_ADDR(node) && node->sort_level == sort_level)
		{
			count++;
			if (((MYDNS_RR *)node->rr)->aux)
				nonzero_aux = 1;
		}

	if (count < 2)													/* Only one node here, don't bother */
		return;
	t->reply_cache_ok = 0;										/* Don't cache load-balanced replies */

	if (nonzero_aux)
	{
		load_balance(t, rrlist, section, sort_level);
	}
	else /* Round robin - for address records, set 'sort' to a random number */
	{
#if DEBUG_ENABLED && DEBUG_SORT
		Debug("%s: Sorting A records in %s section (round robin)", desctask(t), datasection_str[section]);
#endif

		for (node = rrlist->head; node; node = node->next)
			if (RR_IS_ADDR(node) && node->sort_level == sort_level)
				node->sort1 = RAND(4294967294U);
	t->reply_cache_ok = 0;										/* Don't cache load-balanced replies */
	}
}
Пример #10
0
static taskexec_t
ixfr_purge_all_soas(TASK *t, void *data) {

  /*
   * Retrieve all zone id's that have deleted records.
   *
   * For each zone get the expire field and delete any records that have expired.
   *
   */

  SQL_RES	*res = NULL;
  SQL_ROW	row = NULL;

  size_t	querylen;
  const char	*QUERY0 =	"SELECT DISTINCT zone FROM %s WHERE active='%s'";
  const char	*QUERY1 = 	"SELECT origin FROM %s "
				"WHERE id=%u;";
  const char	*QUERY2 =	"DELETE FROM %s WHERE zone=%u AND active='%s' "
				" AND stamp < DATE_SUB(NOW(),INTERVAL %u SECOND);";
  char		*query = NULL;

  /*
   * Reset task timeout clock to some suitable value in the future
   */
  t->timeout = current_time + ixfr_gc_interval;	/* Try again e.g. tomorrow */

  querylen = sql_build_query(&query, QUERY0,
			     mydns_rr_table_name, mydns_rr_active_types[2]);

  if (!(res = sql_query(sql, query, querylen)))
    ErrSQL(sql, "%s: %s", desctask(t),
	   _("error loading zone id's for DELETED records"));

  RELEASE(query);

  while((row = sql_getrow(res, NULL))) {
    unsigned int	id = atou(row[0]);
    char		*origin = NULL;
    MYDNS_SOA		*soa = NULL;
    SQL_RES		*sres = NULL;

    querylen = sql_build_query(&query, QUERY1,
			       mydns_soa_table_name, id);

    if (!(res = sql_query(sql, query, querylen)))
      ErrSQL(sql, "%s: %s", desctask(t),
	     _("error loading zone from DELETED record zone id"));

    RELEASE(query);

    if (!(row = sql_getrow(res, NULL))) {
      Warnx(_("%s: no soa found for soa id %u"), desctask(t),
	    id);
      continue;
    }

    origin = row[0];

    if (mydns_soa_load(sql, &soa, origin) == 0) {
      querylen = sql_build_query(&query, QUERY2,
				 mydns_rr_table_name, soa->id, mydns_rr_active_types[2], soa->expire);

      if (sql_nrquery(sql, query, querylen) != 0)
	WarnSQL(sql, "%s: %s %s", desctask(t),
		_("error deleting expired records for zone "), soa->origin);

      RELEASE(query);

      sql_free(sres);
    }
  }

  sql_free(res);
  RELEASE(query);     

  return (TASK_CONTINUE);
}
Пример #11
0
taskexec_t
ixfr(TASK * t, datasection_t section, dns_qtype_t qtype, char *fqdn, int truncateonly) {
  MYDNS_SOA	*soa = NULL;
  uchar		*query = (uchar*)t->query;
  int		querylen = t->len;
  uchar		*src = query + DNS_HEADERSIZE;
  IQ		*q = NULL;
  task_error_t	errcode = 0;

#if DEBUG_ENABLED && DEBUG_IXFR
  DebugX("ixfr", 1, "%s: ixfr(%s, %s, \"%s\", %d)", desctask(t),
	 resolve_datasection_str[section], mydns_qtype_str(qtype), fqdn, truncateonly);
#endif

  if (!dns_ixfr_enabled) {
    dnserror(t, DNS_RCODE_REFUSED, ERR_IXFR_NOT_ENABLED);
    return (TASK_FAILED);
  }

  /*
   * Authority section contains the SOA record for the client's version of the zone
   * only trust the serial number.
   */

  if (mydns_soa_load(sql, &soa, fqdn) < 0) {
    dnserror(t, DNS_RCODE_SERVFAIL, ERR_DB_ERROR);
    return (TASK_FAILED);
  }

  if (!soa) {
    dnserror(t, DNS_RCODE_REFUSED, ERR_ZONE_NOT_FOUND);
    return (TASK_FAILED);
  }

#if DEBUG_ENABLED && DEBUG_IXFR
  DebugX("ixfr", 1, _("%s: DNS IXFR: SOA id %u"), desctask(t), soa->id);
  DebugX("ixfr", 1, _("%s: DNS IXFR: QDCOUNT=%d (Query)"), desctask(t), t->qdcount);
  DebugX("ixfr", 1, _("%s: DNS IXFR: ANCOUNT=%d (Answer)"), desctask(t), t->ancount);
  DebugX("ixfr", 1, _("%s: DNS IXFR: AUCOUNT=%d (Authority)"), desctask(t), t->nscount);
  DebugX("ixfr", 1, _("%s: DNS IXFR: ADCOUNT=%d (Additional data)"), desctask(t), t->arcount);
#endif
  if (!t->nscount)
    return formerr(t, DNS_RCODE_FORMERR, ERR_NO_AUTHORITY,
		   _("ixfr query contains no authority data"));

  if (t->nscount != 1)
    return formerr(t, DNS_RCODE_FORMERR, ERR_MULTI_AUTHORITY,
		   _("ixfr query contains multiple authority records"));

  if (!t->qdcount)
    return formerr(t, DNS_RCODE_FORMERR, ERR_NO_QUESTION,
		   _("ixfr query does not contain question"));

  if (t->qdcount != 1)
    return formerr(t, DNS_RCODE_FORMERR, ERR_MULTI_QUESTIONS,
		   _("ixfr query contains multiple questions"));

  if (t->ancount || t->arcount)
    return formerr(t, DNS_RCODE_FORMERR, ERR_MALFORMED_REQUEST,
		   _("ixfr query has answer or additional data"));

  q = allocate_iq();

  if (!(IQ_NAME(q) = name_unencode2(query, querylen, &src, &errcode))) {
    free_iq(q);
    return formerr(t, DNS_RCODE_FORMERR, errcode, NULL);
  }

  DNS_GET16(q->type, src);
  DNS_GET16(q->class, src);

  if (!(src = ixfr_gobble_authority_rr(t, query, querylen, src, &q->IR))) {
    free_iq(q);
    return (TASK_FAILED);
  }

  /* Get the serial number from the RR record in the authority section */
#if DEBUG_ENABLED && DEBUG_IXFR
  DebugX("ixfr", 1, _("%s: DNS IXFR Question[zone %s qclass %s qtype %s]"
		      " Authority[zone %s qclass %s qtype %s ttl %u "
		      "mname %s rname %s serial %u refresh %u retry %u expire %u minimum %u]"),
	 desctask(t), q->name, mydns_class_str(q->class), mydns_qtype_str(q->type),
	 q->IR.name, mydns_class_str(q->IR.class), mydns_qtype_str(q->IR.type), q->IR.ttl,
	 q->IR.mname, q->IR.rname, q->IR.serial, q->IR.refresh, q->IR.retry, q->IR.expire, q->IR.minimum);
#endif

  /*
   * As per RFC 1995 we have 3 options for a response if a delta exists.
   *
   * We can send a full zone transfer if it will fit in a UDP packet and is smaller
   * than sending deltas
   *
   * We can send a delta transfer if it will fit into a single UDP packet and we can calculate
   * one for the difference between the client and the current serial
   *
   * We can send a packet with a single SOA record for the latest SOA. This will force the client
   * to initiate an AXFR.
   *
   * We can calculate the size of the response by either building both messages
   * or by an estimation technique. In either case we need to look at the data.
   *
   * I have chosen to check for altered records within the database first.
   *
   * First check is to make sure that the serial held by the client is not the current one
   *
   * Next check to see if out incremental data for the transition from client serial
   * to current serial has not expired.
   *
   * Then retrieve the updated records between the client serial and the latest serial.
   * and retrieve the entire zone ... a record count is the first check.
   *
   * If the number of delta records is larger than the number of zone records then send the zone
   *
   * Calculate the size of the variable parts of the record and compare.
   * We assume that name encoding will have an equal effect on the data.
   * So having chosen to send either the zone or the deltas construct the packet.
   *
   * Check that the packet has not overflowed the UDP limit and send. If it has
   * that abandon the packet and send one containing just the latest SOA.
   *
   */

  if (soa->serial == q->IR.serial) {
    /* Tell the client to do no zone transfer */
    rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
    t->sort_level++;
  } else {
    /* Do we have incremental information in the database */
    if (!truncateonly && mydns_rr_use_active && mydns_rr_use_stamp && mydns_rr_use_serial) {
      /* We can do incrementals */
      /* Need to send an IXFR if available */
      /*
       * Work out when the client SOA came into being
       */
      MYDNS_RR	*ThisRR = NULL, *rr = NULL;
      char	*deltafilter = NULL;
      int	deletecount, activecount, zonesize;
      size_t	deltasize, fullsize;
       
      /* For very large zones we do not want to load all of the records just to give up */
      sql_build_query(&deltafilter, "serial > %u", q->IR.serial);

      /*
       * Compare counts of changes from full zone data
       * ... assumes records are about the same size
       * approximate zone size by 2 * deleted count === actual number of delta records
       */
      deletecount = mydns_rr_count_deleted_filtered(sql,
							soa->id, DNS_QTYPE_ANY, NULL,
							soa->origin, deltafilter);
      activecount = mydns_rr_count_active_filtered(sql,
						       soa->id, DNS_QTYPE_ANY, NULL,
						       soa->origin, deltafilter);
      zonesize = mydns_rr_count_active(sql,
					   soa->id, DNS_QTYPE_ANY, NULL,
					   soa->origin);
      deltasize = deletecount + activecount + 4;
      fullsize = zonesize + 2;

      if ((deletecount < 0) || (activecount < 0) || (zonesize < 0)) {
	RELEASE(deltafilter);
	dnserror(t, DNS_RCODE_SERVFAIL, ERR_DB_ERROR);
	return (TASK_FAILED);
      }
      if (deletecount || activecount) {
	if (deltasize >= fullsize) {
	  /* Send a full zone transfer */
	  /* Current Serial first */
	  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	  t->sort_level++;
	  if (mydns_rr_load_active(sql, &ThisRR, soa->id, DNS_QTYPE_ANY, NULL, soa->origin) == 0) {
	    for (rr = ThisRR; rr; rr = rr->next) {
	      char *name = mydns_rr_append_origin(MYDNS_RR_NAME(rr), soa->origin);
	      rrlist_add(t, ANSWER, DNS_RRTYPE_RR, (void *)rr, name);
	      if (name != MYDNS_RR_NAME(rr)) RELEASE(name);
	    }
	    t->sort_level++;
	    mydns_rr_free(ThisRR);
	    rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	    t->sort_level++;
	  }
	} else {
	  int latest_serial = soa->serial;

	  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	  t->sort_level++;
	  soa->serial = q->IR.serial;
	  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	  t->sort_level++;
	  soa->serial = latest_serial;
	  if (mydns_rr_load_deleted_filtered(sql, &ThisRR, soa->id, DNS_QTYPE_ANY, NULL, soa->origin,
					     deltafilter) == 0) {
	    for (rr = ThisRR; rr; rr = rr->next) {
	      char *name = mydns_rr_append_origin(MYDNS_RR_NAME(rr), soa->origin);
	      rrlist_add(t, ANSWER, DNS_RRTYPE_RR, (void *)rr, name);
	      if (name != MYDNS_RR_NAME(rr)) RELEASE(name);
	    }
	    t->sort_level++;
	    mydns_rr_free(ThisRR);
	  }
	  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	  t->sort_level++;
	  if (mydns_rr_load_active_filtered(sql, &ThisRR, soa->id, DNS_QTYPE_ANY, NULL, soa->origin,
					    deltafilter) == 0) {
	    for (rr = ThisRR; rr; rr = rr->next) {
	      char *name = mydns_rr_append_origin(MYDNS_RR_NAME(rr), soa->origin);
	      rrlist_add(t, ANSWER, DNS_RRTYPE_RR, (void *)rr, name);
	      if (name != MYDNS_RR_NAME(rr)) RELEASE(name);
	    }
	    t->sort_level++;
	    mydns_rr_free(ThisRR);
	    rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
	    t->sort_level++;
	  }
	  RELEASE(deltafilter);
	}
	goto FINISHEDIXFR;
      }
    }
  }

  /* Tell the client to do a full zone transfer or not at all */
  rrlist_add(t, ANSWER, DNS_RRTYPE_SOA, (void *)soa, soa->origin);
  t->sort_level++;

 FINISHEDIXFR:
  mydns_soa_free(soa);

  free_iq(q);

  t->hdr.aa = 1;

  return (TASK_EXECUTED);
}
Пример #12
0
/**************************************************************************************************
	WRITE_UDP_REPLY
**************************************************************************************************/
taskexec_t
write_udp_reply(TASK *t) {
  int			rv = 0;
  struct sockaddr	*addr = NULL;
  int			addrlen = 0;

  if (t->family == AF_INET) {
    addr = (struct sockaddr*)&t->addr4;
    addrlen = sizeof(struct sockaddr_in);
#if HAVE_IPV6
  } else if (t->family == AF_INET6) {
    addr = (struct sockaddr*)&t->addr6;
    addrlen = sizeof(struct sockaddr_in6);
#endif
  }
	
  rv = sendto(t->fd, t->reply, t->replylen, 0, addr, addrlen);

  if (rv < 0) {
    if (
	(errno == EINTR)
#ifdef EAGAIN
	|| (errno == EAGAIN)
#else
#ifdef EWOULDBLOCK
	|| (errno == EWOULDBLOCK)
#endif
#endif
	) {
      return (TASK_CONTINUE); /* Try again */
    }
    if (errno != EPERM && errno != EINVAL)
      Warn("%s: %s", desctask(t), _("sendto (UDP)"));
    return (TASK_FAILED);
  }

  if (rv == 0) {
    /*
     * Should never happen as this implies the "other" end has closed the socket
     * and we do not have another end - this is UDP
     * However, we get this return when a route to the client does not exist
     * this happens over WAN connection and VPN connections that flap
     * so try again and see if the connection returns - this is going to
     * make the process run continuously ....
     */
    return (TASK_EXECUTED);
    /* Err("%s: Send to (UDP) returned 0", desctask(t)); */
  }

  if (rv != (int)t->replylen) {
    /*
     * This should never ever happen as we have sent a partial packet over UDP
     */
    Err(_("%s: Send to (UDP) returned %d when writing %u"), desctask(t), rv, (unsigned int)t->replylen);
  }

#if DEBUG_ENABLED && DEBUG_UDP
  DebugX("udp", 1, _("%s: WRITE %u UDP octets (id %u)"), desctask(t), (unsigned int)t->replylen, t->id);
#endif
  return (TASK_COMPLETED);
}
Пример #13
0
/**************************************************************************************************
	ALIAS_RECURSE
	If the task has a matching ALIAS record, recurse into it.
	Returns the number of records added.
**************************************************************************************************/
int
alias_recurse(TASK *t, datasection_t section, char *fqdn, MYDNS_SOA *soa, char *label, MYDNS_RR *alias)
{
	uint32_t aliases[MAX_ALIAS_LEVEL];
	char name[DNS_MAXNAMELEN+1];
	register MYDNS_RR *rr;
	register int depth, n;

	if (LASTCHAR(alias->data) != '.')
		snprintf(name, sizeof(name), "%s.%s", alias->data, soa->origin);
	else
		strncpy(name, alias->data, sizeof(name)-1);

	for (depth = 0; depth < MAX_ALIAS_LEVEL; depth++)
	{
#if DEBUG_ENABLED && DEBUG_ALIAS
		Debug("%s: ALIAS -> `%s'", desctask(t), name);
#endif
		/* Are there any alias records? */
		if ((rr = find_alias(t, name)))
		{
			/* We need an A record that is not an alias to end the chain. */
			if (rr->alias == 0)
			{
				/* Override the id and name, because rrlist_add() checks for duplicates and we might have several records aliased to one */
				rr->id = alias->id;
				strcpy(rr->name, alias->name);
				rrlist_add(t, section, DNS_RRTYPE_RR, (void *)rr, fqdn);
				t->sort_level++;
				mydns_rr_free(rr);
				return (1);
			}

			/* Append origin if needed */
			int len = strlen(rr->data);
			if (len > 0 && rr->data[len - 1] != '.') {
				strcat(rr->data, ".");
				strncat(rr->data, soa->origin, sizeof(rr->name) - len - 1);
			}

			/* Check aliases list; if we are looping, stop. Otherwise add this to the list. */
			for (n = 0; n < depth; n++)
				if (aliases[n] == rr->id)
				{
					/* ALIAS loop: We aren't going to find an A record, so we're done. */
					Verbose("%s: %s: %s (depth %d)", desctask(t), _("ALIAS loop detected"), fqdn, depth);
					mydns_rr_free(rr);
					return (0);
				}
			aliases[depth] = rr->id;

			/* Continue search with new alias. */
			strncpy(name, rr->data, sizeof(name)-1);
			mydns_rr_free(rr);
		}
		else
		{
			Verbose("%s: %s: %s -> %s", desctask(t), _("ALIAS chain is broken"), fqdn, name);
			return (0);
		}
	}
	Verbose("%s: %s: %s -> %s (depth %d)", desctask(t), _("max ALIAS depth exceeded"), fqdn, alias->data, depth);
	return (0);
}
Пример #14
0
void
axfr_fork(TASK *t) {
  int pfd[2] = { -1, -1 };				/* Parent/child pipe descriptors */
  pid_t pid = -1, parent = -1;

#if DEBUG_ENABLED && DEBUG_AXFR 
  DebugX("axfr", 1,_("%s: axfr_fork called on fd %d"), desctask(t), t->fd);
#endif

  if (pipe(pfd))
    Err(_("pipe"));
  parent = getpid();
  if ((pid = fork()) < 0) {
    close(pfd[0]);
    close(pfd[1]);
    Warn(_("%s: fork"), clientaddr(t));
    return;
  }

  if (!pid) {
    /* Child: reset all signal handlers to default before we dive off elsewhere */
    struct sigaction act;

    memset(&act, 0, sizeof(act));

    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    act.sa_handler = SIG_DFL;

    sigaction(SIGHUP, &act, NULL);
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGUSR2, &act, NULL);
    sigaction(SIGALRM, &act, NULL);
    sigaction(SIGCHLD, &act, NULL);

    sigaction(SIGINT, &act, NULL);
    sigaction(SIGQUIT, &act, NULL);
    sigaction(SIGABRT, &act, NULL);
    sigaction(SIGTERM, &act, NULL);

#if DEBUG_ENABLED && DEBUG_AXFR
    DebugX("axfr", 1,_("%s: axfr_fork is in the child"), desctask(t));
#endif

    /*  Let parent know I have started */
    close(pfd[0]);
    if (write(pfd[1], "OK", 2) != 2)
      Warn(_("error writing startup notification"));
    close(pfd[1]);

#if DEBUG_ENABLED && DEBUG_AXFR
    DebugX("axfr", 1,_("%s: axfr_fork child has told parent I am running"), desctask(t));
#endif

    /* Clean up parents resources */
    free_other_tasks(t, 1);

#if DEBUG_ENABLED && DEBUG_AXFR
    DebugX("axfr", 1,_("%s: AXFR child built"), desctask(t));
#endif
    /* Do AXFR */
    axfr(t);
  } else {	/* Parent */
    char	buf[5] = "\0\0\0\0\0";
    int		errct = 0;

    close(pfd[1]);

    for (errct = 0; errct < 5; errct++) {
      if (read(pfd[0], &buf, 4) != 2)
	Warn(_("%s (%d of 5)"), _("error reading startup notification"), errct+1);
      else
	break;
    }
    close(pfd[0]);

#if DEBUG_ENABLED && DEBUG_AXFR
    DebugX("axfr", 1,_("AXFR: process started on pid %d for TCP fd %d, task ID %u"), pid, t->fd, t->internal_id);
#endif
  }
  /* NOTREACHED*/
}