Esempio n. 1
0
/**
 * Parse a DNS MX record.
 *
 * @param udp_payload reference to UDP packet
 * @param udp_payload_length length of @a udp_payload
 * @param off pointer to the offset of the query to parse in the MX record (to be
 *                    incremented by the size of the record), unchanged on error
 * @return the parsed MX record, NULL on error
 */
struct GNUNET_DNSPARSER_MxRecord *
GNUNET_DNSPARSER_parse_mx (const char *udp_payload,
			   size_t udp_payload_length,
			   size_t *off)
{
  struct GNUNET_DNSPARSER_MxRecord *mx;
  uint16_t mxpref;
  size_t old_off;

  old_off = *off;
  if (*off + sizeof (uint16_t) > udp_payload_length)
  {
    GNUNET_break_op (0);
    return NULL;
  }
  GNUNET_memcpy (&mxpref, &udp_payload[*off], sizeof (uint16_t));
  (*off) += sizeof (uint16_t);
  mx = GNUNET_new (struct GNUNET_DNSPARSER_MxRecord);
  mx->preference = ntohs (mxpref);
  mx->mxhost = GNUNET_DNSPARSER_parse_name (udp_payload,
					    udp_payload_length,
					    off);
  if (NULL == mx->mxhost)
  {
    GNUNET_break_op (0);
    GNUNET_DNSPARSER_free_mx (mx);
    *off = old_off;
    return NULL;
  }
  return mx;
}
Esempio n. 2
0
/**
 * Parse a DNS SRV record.
 *
 * @param udp_payload reference to UDP packet
 * @param udp_payload_length length of @a udp_payload
 * @param off pointer to the offset of the query to parse in the SRV record (to be
 *                    incremented by the size of the record), unchanged on error
 * @return the parsed SRV record, NULL on error
 */
struct GNUNET_DNSPARSER_SrvRecord *
GNUNET_DNSPARSER_parse_srv (const char *udp_payload,
			    size_t udp_payload_length,
			    size_t *off)
{
  struct GNUNET_DNSPARSER_SrvRecord *srv;
  struct GNUNET_TUN_DnsSrvRecord srv_bin;
  size_t old_off;

  old_off = *off;
  if (*off + sizeof (struct GNUNET_TUN_DnsSrvRecord) > udp_payload_length)
    return NULL;
  GNUNET_memcpy (&srv_bin,
	  &udp_payload[*off],
	  sizeof (struct GNUNET_TUN_DnsSrvRecord));
  (*off) += sizeof (struct GNUNET_TUN_DnsSrvRecord);
  srv = GNUNET_new (struct GNUNET_DNSPARSER_SrvRecord);
  srv->priority = ntohs (srv_bin.prio);
  srv->weight = ntohs (srv_bin.weight);
  srv->port = ntohs (srv_bin.port);
  srv->target = GNUNET_DNSPARSER_parse_name (udp_payload,
					     udp_payload_length,
					     off);
  if (NULL == srv->target)
  {
    GNUNET_DNSPARSER_free_srv (srv);
    *off = old_off;
    return NULL;
  }
  return srv;
}
Esempio n. 3
0
/**
 * Parse a DNS query entry.
 *
 * @param udp_payload entire UDP payload
 * @param udp_payload_length length of @a udp_payload
 * @param off pointer to the offset of the query to parse in the udp_payload (to be
 *                    incremented by the size of the query)
 * @param q where to write the query information
 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the query is malformed
 */
int
GNUNET_DNSPARSER_parse_query (const char *udp_payload,
			      size_t udp_payload_length,
			      size_t *off,
			      struct GNUNET_DNSPARSER_Query *q)
{
  char *name;
  struct GNUNET_TUN_DnsQueryLine ql;

  name = GNUNET_DNSPARSER_parse_name (udp_payload,
				      udp_payload_length,
				      off);
  if (NULL == name)
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  q->name = name;
  if (*off + sizeof (struct GNUNET_TUN_DnsQueryLine) > udp_payload_length)
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  GNUNET_memcpy (&ql, &udp_payload[*off], sizeof (ql));
  *off += sizeof (ql);
  q->type = ntohs (ql.type);
  q->dns_traffic_class = ntohs (ql.dns_traffic_class);
  return GNUNET_OK;
}
Esempio n. 4
0
/**
 * Parse a DNS SOA record.
 *
 * @param udp_payload reference to UDP packet
 * @param udp_payload_length length of @a udp_payload
 * @param off pointer to the offset of the query to parse in the SOA record (to be
 *                    incremented by the size of the record), unchanged on error
 * @return the parsed SOA record, NULL on error
 */
struct GNUNET_DNSPARSER_SoaRecord *
GNUNET_DNSPARSER_parse_soa (const char *udp_payload,
			    size_t udp_payload_length,
			    size_t *off)
{
  struct GNUNET_DNSPARSER_SoaRecord *soa;
  struct GNUNET_TUN_DnsSoaRecord soa_bin;
  size_t old_off;

  old_off = *off;
  soa = GNUNET_new (struct GNUNET_DNSPARSER_SoaRecord);
  soa->mname = GNUNET_DNSPARSER_parse_name (udp_payload,
					    udp_payload_length,
					    off);
  soa->rname = GNUNET_DNSPARSER_parse_name (udp_payload,
					    udp_payload_length,
					    off);
  if ( (NULL == soa->mname) ||
       (NULL == soa->rname) ||
       (*off + sizeof (struct GNUNET_TUN_DnsSoaRecord) > udp_payload_length) )
  {
    GNUNET_break_op (0);
    GNUNET_DNSPARSER_free_soa (soa);
    *off = old_off;
    return NULL;
  }
  GNUNET_memcpy (&soa_bin,
	  &udp_payload[*off],
	  sizeof (struct GNUNET_TUN_DnsSoaRecord));
  soa->serial = ntohl (soa_bin.serial);
  soa->refresh = ntohl (soa_bin.refresh);
  soa->retry = ntohl (soa_bin.retry);
  soa->expire = ntohl (soa_bin.expire);
  soa->minimum_ttl = ntohl (soa_bin.minimum);
  (*off) += sizeof (struct GNUNET_TUN_DnsSoaRecord);
  return soa;
}
Esempio n. 5
0
/**
 * Parse a DNS record entry.
 *
 * @param udp_payload entire UDP payload
 * @param udp_payload_length length of @a udp_payload
 * @param off pointer to the offset of the record to parse in the udp_payload (to be
 *                    incremented by the size of the record)
 * @param r where to write the record information
 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the record is malformed
 */
int
GNUNET_DNSPARSER_parse_record (const char *udp_payload,
			       size_t udp_payload_length,
			       size_t *off,
			       struct GNUNET_DNSPARSER_Record *r)
{
  char *name;
  struct GNUNET_TUN_DnsRecordLine rl;
  size_t old_off;
  uint16_t data_len;

  name = GNUNET_DNSPARSER_parse_name (udp_payload,
				      udp_payload_length,
				      off);
  if (NULL == name)
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  r->name = name;
  if (*off + sizeof (struct GNUNET_TUN_DnsRecordLine) > udp_payload_length)
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  GNUNET_memcpy (&rl, &udp_payload[*off], sizeof (rl));
  (*off) += sizeof (rl);
  r->type = ntohs (rl.type);
  r->dns_traffic_class = ntohs (rl.dns_traffic_class);
  r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
											ntohl (rl.ttl)));
  data_len = ntohs (rl.data_len);
  if (*off + data_len > udp_payload_length)
  {
    GNUNET_break_op (0);
    return GNUNET_SYSERR;
  }
  old_off = *off;
  switch (r->type)
  {
  case GNUNET_DNSPARSER_TYPE_NS:
  case GNUNET_DNSPARSER_TYPE_CNAME:
  case GNUNET_DNSPARSER_TYPE_PTR:
    r->data.hostname = GNUNET_DNSPARSER_parse_name (udp_payload,
						    udp_payload_length,
						    off);
    if ( (NULL == r->data.hostname) ||
	 (old_off + data_len != *off) )
      return GNUNET_SYSERR;
    return GNUNET_OK;
  case GNUNET_DNSPARSER_TYPE_SOA:
    r->data.soa = GNUNET_DNSPARSER_parse_soa (udp_payload,
					      udp_payload_length,
					      off);
    if ( (NULL == r->data.soa) ||
	 (old_off + data_len != *off) )
    {
      GNUNET_break_op (0);
      return GNUNET_SYSERR;
    }
    return GNUNET_OK;
  case GNUNET_DNSPARSER_TYPE_MX:
    r->data.mx = GNUNET_DNSPARSER_parse_mx (udp_payload,
					    udp_payload_length,
					    off);
    if ( (NULL == r->data.mx) ||
	 (old_off + data_len != *off) )
    {
      GNUNET_break_op (0);
      return GNUNET_SYSERR;
    }
    return GNUNET_OK;
  case GNUNET_DNSPARSER_TYPE_SRV:
    r->data.srv = GNUNET_DNSPARSER_parse_srv (udp_payload,
					      udp_payload_length,
					      off);
    if ( (NULL == r->data.srv) ||
	 (old_off + data_len != *off) )
    {
      GNUNET_break_op (0);
      return GNUNET_SYSERR;
    }
    return GNUNET_OK;
  default:
    r->data.raw.data = GNUNET_malloc (data_len);
    r->data.raw.data_len = data_len;
    GNUNET_memcpy (r->data.raw.data, &udp_payload[*off], data_len);
    break;
  }
  (*off) += data_len;
  return GNUNET_OK;
}
/**
 * Reply to dns request with the result from our lookup.
 *
 * @param cls the closure to the request (an InterceptLookupHandle)
 * @param rd_count the number of records to return
 * @param rd the record data
 */
static void
reply_to_dns (void *cls, uint32_t rd_count,
	      const struct GNUNET_GNSRECORD_Data *rd)
{
  struct InterceptLookupHandle *ilh = cls;
  struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
  struct GNUNET_DNSPARSER_Query *query = &packet->queries[0];
  uint32_t i;
  size_t len;
  int ret;
  char *buf;
  unsigned int num_answers;
  unsigned int skip_answers;
  unsigned int skip_additional;
  size_t off;

  /* Put records in the DNS packet */
  num_answers = 0;
  for (i=0; i < rd_count; i++)
    if (rd[i].record_type == query->type)
      num_answers++;
  skip_answers = 0;
  skip_additional = 0;

  {
    struct GNUNET_DNSPARSER_Record answer_records[num_answers];
    struct GNUNET_DNSPARSER_Record additional_records[rd_count - num_answers];

    packet->answers = answer_records;
    packet->additional_records = additional_records;
    /* FIXME: need to handle #GNUNET_GNSRECORD_RF_SHADOW_RECORD option
       (by ignoring records where this flag is set if there is any
       other record of that type in the result set) */
    for (i=0; i < rd_count; i++)
    {
      if (rd[i].record_type == query->type)
      {
	answer_records[i - skip_answers].name = query->name;
	answer_records[i - skip_answers].type = rd[i].record_type;
	switch(rd[i].record_type)
	{
	case GNUNET_DNSPARSER_TYPE_NS:
	case GNUNET_DNSPARSER_TYPE_CNAME:
	case GNUNET_DNSPARSER_TYPE_PTR:
	  answer_records[i - skip_answers].data.hostname
	    = GNUNET_DNSPARSER_parse_name (rd[i].data,
					   rd[i].data_size,
					   &off);
	  if ( (off != rd[i].data_size) ||
	       (NULL == answer_records[i].data.hostname) )
	  {
	    GNUNET_break_op (0);
	    skip_answers++;
	  }
	  break;
	case GNUNET_DNSPARSER_TYPE_SOA:
	  answer_records[i - skip_answers].data.soa
	    = GNUNET_DNSPARSER_parse_soa (rd[i].data,
					  rd[i].data_size,
					  &off);
	  if ( (off != rd[i].data_size) ||
	       (NULL == answer_records[i].data.soa) )
	  {
	    GNUNET_break_op (0);
	    skip_answers++;
	  }
	  break;
	case GNUNET_DNSPARSER_TYPE_SRV:
	  /* FIXME: SRV is not yet supported */
	  skip_answers++;
	  break;
	case GNUNET_DNSPARSER_TYPE_MX:
	  answer_records[i - skip_answers].data.mx
	    = GNUNET_DNSPARSER_parse_mx (rd[i].data,
					 rd[i].data_size,
					 &off);
	  if ( (off != rd[i].data_size) ||
	       (NULL == answer_records[i].data.hostname) )
	  {
	    GNUNET_break_op (0);
	    skip_answers++;
	  }
	  break;
	default:
	  answer_records[i - skip_answers].data.raw.data_len = rd[i].data_size;
	  answer_records[i - skip_answers].data.raw.data = (char*)rd[i].data;
	  break;
	}
	GNUNET_break (0 == (rd[i - skip_answers].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
	answer_records[i - skip_answers].expiration_time.abs_value_us = rd[i].expiration_time;
	answer_records[i - skip_answers].dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
      }
      else
      {
	additional_records[i - skip_additional].name = query->name;
	additional_records[i - skip_additional].type = rd[i].record_type;
	switch(rd[i].record_type)
	{
	case GNUNET_DNSPARSER_TYPE_NS:
	case GNUNET_DNSPARSER_TYPE_CNAME:
	case GNUNET_DNSPARSER_TYPE_PTR:
	  additional_records[i - skip_additional].data.hostname
	    = GNUNET_DNSPARSER_parse_name (rd[i].data,
					   rd[i].data_size,
					   &off);
	  if ( (off != rd[i].data_size) ||
	       (NULL == additional_records[i].data.hostname) )
	  {
	    GNUNET_break_op (0);
	    skip_additional++;
	  }
	  break;
	case GNUNET_DNSPARSER_TYPE_SOA:
	  additional_records[i - skip_additional].data.soa
	    = GNUNET_DNSPARSER_parse_soa (rd[i].data,
					  rd[i].data_size,
					  &off);
	  if ( (off != rd[i].data_size) ||
	       (NULL == additional_records[i].data.hostname) )
	  {
	    GNUNET_break_op (0);
	    skip_additional++;
	  }
	  break;
	case GNUNET_DNSPARSER_TYPE_MX:
	  additional_records[i - skip_additional].data.mx
	    = GNUNET_DNSPARSER_parse_mx (rd[i].data,
					 rd[i].data_size,
					 &off);
	  if ( (off != rd[i].data_size) ||
	       (NULL == additional_records[i].data.hostname) )
	  {
	    GNUNET_break_op (0);
	    skip_additional++;
	  }
	  break;
	case GNUNET_DNSPARSER_TYPE_SRV:
	  /* FIXME: SRV is not yet supported */
	  skip_answers++;
	  break;
	default:
	  additional_records[i - skip_additional].data.raw.data_len = rd[i].data_size;
	  additional_records[i - skip_additional].data.raw.data = (char*)rd[i].data;
	  break;
	}
	GNUNET_break (0 == (rd[i - skip_additional].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
	additional_records[i - skip_additional].expiration_time.abs_value_us = rd[i].expiration_time;
	additional_records[i - skip_additional].dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
      }
    }
    packet->num_answers = num_answers - skip_answers;
    packet->num_additional_records = rd_count - num_answers - skip_additional;
    packet->flags.authoritative_answer = 1;
    if (NULL == rd)
      packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NAME_ERROR;
    else
      packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
    packet->flags.query_or_response = 1;
    ret = GNUNET_DNSPARSER_pack (packet,
				 1024, /* maximum allowed size for DNS reply */
				 &buf,
				 &len);
    if (GNUNET_OK != ret)
    {
      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
		  _("Error converting GNS response to DNS response!\n"));
    }
    else
    {
      GNUNET_DNS_request_answer (ilh->request_handle,
				 len,
				 buf);
      GNUNET_free (buf);
    }
    packet->num_answers = 0;
    packet->answers = NULL;
    packet->num_additional_records = 0;
    packet->additional_records = NULL;
    GNUNET_DNSPARSER_free_packet (packet);
  }
  GNUNET_CONTAINER_DLL_remove (ilh_head, ilh_tail, ilh);
  GNUNET_free (ilh);
}
Esempio n. 7
0
/**
 * Convert the 'value' of a record to a string.
 *
 * @param cls closure, unused
 * @param type type of the record
 * @param data value in binary encoding
 * @param data_size number of bytes in @a data
 * @return NULL on error, otherwise human-readable representation of the value
 */
static char *
gns_value_to_string (void *cls,
                     uint32_t type,
                     const void *data,
                     size_t data_size)
{
  const char *cdata;

  switch (type)
  {
  case GNUNET_GNSRECORD_TYPE_PKEY:
    if (data_size != sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))
      return NULL;
    return GNUNET_CRYPTO_ecdsa_public_key_to_string (data);
  case GNUNET_GNSRECORD_TYPE_NICK:
    return GNUNET_strndup (data, data_size);
  case GNUNET_GNSRECORD_TYPE_LEHO:
    return GNUNET_strndup (data, data_size);
  case GNUNET_GNSRECORD_TYPE_GNS2DNS:
    {
      char *ns;
      char *ip;
      size_t off;
      char *nstr;

      off = 0;
      ns = GNUNET_DNSPARSER_parse_name (data,
					data_size,
					&off);
      ip = GNUNET_DNSPARSER_parse_name (data,
					data_size,
					&off);
      if ( (NULL == ns) ||
           (NULL == ip) ||
	   (off != data_size) )
      {
	GNUNET_break_op (0);
	GNUNET_free_non_null (ns);
	GNUNET_free_non_null (ip);
	return NULL;
      }
      GNUNET_asprintf (&nstr,
                       "%s@%s",
                       ns,
                       ip);
      GNUNET_free_non_null (ns);
      GNUNET_free_non_null (ip);
      return nstr;
    }
  case GNUNET_GNSRECORD_TYPE_VPN:
    {
      const struct GNUNET_TUN_GnsVpnRecord *vpn;
      char* vpn_str;

      cdata = data;
      if ( (data_size <= sizeof (struct GNUNET_TUN_GnsVpnRecord)) ||
	   ('\0' != cdata[data_size - 1]) )
	return NULL; /* malformed */
      vpn = data;
      GNUNET_asprintf (&vpn_str,
                       "%u %s %s",
                       (unsigned int) ntohs (vpn->proto),
                       (const char*) GNUNET_i2s_full (&vpn->peer),
                       (const char*) &vpn[1]);
      return vpn_str;
    }
  case GNUNET_GNSRECORD_TYPE_BOX:
    {
      const struct GNUNET_GNSRECORD_BoxRecord *box;
      uint32_t rt;
      char *box_str;
      char *ival;

      if (data_size < sizeof (struct GNUNET_GNSRECORD_BoxRecord))
	return NULL; /* malformed */
      box = data;
      rt = ntohl (box->record_type);
      ival = GNUNET_GNSRECORD_value_to_string (rt,
                                               &box[1],
                                               data_size - sizeof (struct GNUNET_GNSRECORD_BoxRecord));
      if (NULL == ival)
        return NULL; /* malformed */
      GNUNET_asprintf (&box_str,
                       "%u %u %u %s",
                       (unsigned int) ntohs (box->protocol),
                       (unsigned int) ntohs (box->service),
                       (unsigned int) rt,
                       ival);
      GNUNET_free (ival);
      return box_str;
    }
  default:
    return NULL;
  }
}
Esempio n. 8
0
/**
 * Convert the 'value' of a record to a string.
 *
 * @param cls closure, unused
 * @param type type of the record
 * @param data value in binary encoding
 * @param data_size number of bytes in @a data
 * @return NULL on error, otherwise human-readable representation of the value
 */
static char *
gns_value_to_string (void *cls,
                     uint32_t type,
                     const void *data,
                     size_t data_size)
{
  const char *cdata;

  switch (type)
  {
  case GNUNET_GNSRECORD_TYPE_PKEY:
    if (data_size != sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))
      return NULL;
    return GNUNET_CRYPTO_ecdsa_public_key_to_string (data);
  case GNUNET_GNSRECORD_TYPE_NICK:
    return GNUNET_strndup (data, data_size);
  case GNUNET_GNSRECORD_TYPE_LEHO:
    return GNUNET_strndup (data, data_size);
  case GNUNET_GNSRECORD_TYPE_GNS2DNS:
    {
      char *ns;
      char *ip;
      size_t off;
      char *nstr;

      off = 0;
      ns = GNUNET_DNSPARSER_parse_name (data,
					data_size,
					&off);
      ip = GNUNET_DNSPARSER_parse_name (data,
					data_size,
					&off);
      if ( (NULL == ns) ||
           (NULL == ip) ||
	   (off != data_size) )
      {
	GNUNET_break_op (0);
	GNUNET_free_non_null (ns);
	GNUNET_free_non_null (ip);
	return NULL;
      }
      GNUNET_asprintf (&nstr,
                       "%s@%s",
                       ns,
                       ip);
      GNUNET_free_non_null (ns);
      GNUNET_free_non_null (ip);
      return nstr;
    }
  case GNUNET_GNSRECORD_TYPE_VPN:
    {
      struct GNUNET_TUN_GnsVpnRecord vpn;
      char* vpn_str;

      cdata = data;
      if ( (data_size <= sizeof (vpn)) ||
	   ('\0' != cdata[data_size - 1]) )
	return NULL; /* malformed */
      /* need to memcpy for alignment */
      memcpy (&vpn,
              data,
              sizeof (vpn));
      GNUNET_asprintf (&vpn_str,
                       "%u %s %s",
                       (unsigned int) ntohs (vpn.proto),
                       (const char*) GNUNET_i2s_full (&vpn.peer),
                       (const char*) &cdata[sizeof (vpn)]);
      return vpn_str;
    }
  case GNUNET_GNSRECORD_TYPE_BOX:
    {
      struct GNUNET_GNSRECORD_BoxRecord box;
      uint32_t rt;
      char *box_str;
      char *ival;

      cdata = data;
      if (data_size < sizeof (struct GNUNET_GNSRECORD_BoxRecord))
	return NULL; /* malformed */
      memcpy (&box,
              data,
              sizeof (box));
      rt = ntohl (box.record_type);
      ival = GNUNET_GNSRECORD_value_to_string (rt,
                                               &cdata[sizeof (box)],
                                               data_size - sizeof (box));
      if (NULL == ival)
        return NULL; /* malformed */
      GNUNET_asprintf (&box_str,
                       "%u %u %u %s",
                       (unsigned int) ntohs (box.protocol),
                       (unsigned int) ntohs (box.service),
                       (unsigned int) rt,
                       ival);
      GNUNET_free (ival);
      return box_str;
    }
  case GNUNET_GNSRECORD_TYPE_REVERSE:
    {
      struct GNUNET_GNSRECORD_ReverseRecord rev;
      char *rev_str;
      char *pkey_str;

      if (data_size < sizeof (struct GNUNET_GNSRECORD_ReverseRecord))
        return NULL; /* malformed */

      memcpy (&rev,
              data,
              sizeof (rev));
      cdata = data;
      pkey_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&rev.pkey);

      GNUNET_asprintf (&rev_str,
                       "%s %s %"SCNu64,
                       &cdata[sizeof (rev)],
                       pkey_str,
                       rev.expiration.abs_value_us);
      GNUNET_free (pkey_str);
      return rev_str;

    }
  default:
    return NULL;
  }
}