uint16_t data_len GNUNET_PACKED;
};
+struct soa_data
+{
+ uint32_t serial GNUNET_PACKED;
+ uint32_t refresh GNUNET_PACKED;
+ uint32_t retry GNUNET_PACKED;
+ uint32_t expire GNUNET_PACKED;
+ uint32_t minimum GNUNET_PACKED;
+};
+
GNUNET_NETWORK_STRUCT_END
{
char *name;
struct record_line rl;
+ size_t old_off;
+ struct soa_data soa;
+ uint16_t mxpref;
name = parse_name (udp_payload,
udp_payload_length,
if (*off + sizeof (struct record_line) > udp_payload_length)
return GNUNET_SYSERR;
memcpy (&rl, &udp_payload[*off], sizeof (rl));
- *off += sizeof (rl);
+ (*off) += sizeof (rl);
r->type = ntohs (rl.type);
r->class = ntohs (rl.class);
r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
return GNUNET_SYSERR;
if (0 == r->data_len)
return GNUNET_OK;
- r->data = GNUNET_malloc (r->data_len);
- memcpy (r->data, &udp_payload[*off], r->data_len);
- *off += r->data_len;
+ switch (r->type)
+ {
+ case GNUNET_DNSPARSER_TYPE_NS:
+ case GNUNET_DNSPARSER_TYPE_CNAME:
+ case GNUNET_DNSPARSER_TYPE_PTR:
+ old_off = *off;
+ r->data.hostname = parse_name (udp_payload,
+ udp_payload_length,
+ off);
+ if ( (NULL == r->data.hostname) ||
+ (old_off + r->data_len != *off) )
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+ case GNUNET_DNSPARSER_TYPE_SOA:
+ old_off = *off;
+ r->data.soa = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_SoaRecord));
+ r->data.soa->mname = parse_name (udp_payload,
+ udp_payload_length,
+ off);
+ r->data.soa->rname = parse_name (udp_payload,
+ udp_payload_length,
+ off);
+ if ( (NULL == r->data.soa->mname) ||
+ (NULL == r->data.soa->rname) ||
+ (*off + sizeof (soa) > udp_payload_length) )
+ return GNUNET_SYSERR;
+ memcpy (&soa, &udp_payload[*off], sizeof (soa));
+ r->data.soa->serial = ntohl (soa.serial);
+ r->data.soa->refresh = ntohl (soa.refresh);
+ r->data.soa->retry = ntohl (soa.retry);
+ r->data.soa->expire = ntohl (soa.expire);
+ r->data.soa->minimum_ttl = ntohl (soa.minimum);
+ (*off) += sizeof (soa);
+ if (old_off + r->data_len != *off)
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+ case GNUNET_DNSPARSER_TYPE_MX:
+ old_off = *off;
+ if (*off + sizeof (uint16_t) > udp_payload_length)
+ return GNUNET_SYSERR;
+ memcpy (&mxpref, &udp_payload[*off], sizeof (uint16_t));
+ (*off) += sizeof (uint16_t);
+ r->data.mx = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_MxRecord));
+ r->data.mx->preference = ntohs (mxpref);
+ r->data.mx->mxhost = parse_name (udp_payload,
+ udp_payload_length,
+ off);
+ if (old_off + r->data_len != *off)
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+ default:
+ r->data.raw = GNUNET_malloc (r->data_len);
+ memcpy (r->data.raw, &udp_payload[*off], r->data_len);
+ break;
+ }
+ (*off) += r->data_len;
return GNUNET_OK;
}
}
+/**
+ * Free SOA information record.
+ *
+ * @param soa record to free
+ */
+static void
+free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa)
+{
+ if (NULL == soa)
+ return;
+ GNUNET_free_non_null (soa->mname);
+ GNUNET_free_non_null (soa->rname);
+ GNUNET_free (soa);
+}
+
+
+/**
+ * Free MX information record.
+ *
+ * @param mx record to free
+ */
+static void
+free_mx (struct GNUNET_DNSPARSER_MxRecord *mx)
+{
+ if (NULL == mx)
+ return;
+ GNUNET_free_non_null (mx->mxhost);
+ GNUNET_free (mx);
+}
+
+
+static void
+free_record (struct GNUNET_DNSPARSER_Record *r)
+{
+ GNUNET_free_non_null (r->name);
+ switch (r->type)
+ {
+ case GNUNET_DNSPARSER_TYPE_MX:
+ free_mx (r->data.mx);
+ break;
+ case GNUNET_DNSPARSER_TYPE_SOA:
+ free_soa (r->data.soa);
+ break;
+ case GNUNET_DNSPARSER_TYPE_NS:
+ case GNUNET_DNSPARSER_TYPE_CNAME:
+ case GNUNET_DNSPARSER_TYPE_PTR:
+ GNUNET_free_non_null (r->data.hostname);
+ break;
+ default:
+ GNUNET_free_non_null (r->data.raw);
+ break;
+ }
+}
+
+
/**
* Free memory taken by a packet.
*
GNUNET_free_non_null (p->queries[i].name);
GNUNET_free_non_null (p->queries);
for (i=0;i<p->num_answers;i++)
- {
- GNUNET_free_non_null (p->answers[i].name);
- GNUNET_free_non_null (p->answers[i].data);
- }
+ free_record (&p->answers[i]);
GNUNET_free_non_null (p->answers);
for (i=0;i<p->num_authority_records;i++)
- {
- GNUNET_free_non_null (p->authority_records[i].name);
- GNUNET_free_non_null (p->authority_records[i].data);
- }
+ free_record (&p->authority_records[i]);
GNUNET_free_non_null (p->authority_records);
for (i=0;i<p->num_additional_records;i++)
- {
- GNUNET_free_non_null (p->additional_records[i].name);
- GNUNET_free_non_null (p->additional_records[i].data);
- }
+ free_record (&p->additional_records[i]);
GNUNET_free_non_null (p->additional_records);
GNUNET_free (p);
}
case GNUNET_DNSPARSER_TYPE_MX: return "MX";
case GNUNET_DNSPARSER_TYPE_TXT: return "TXT";
case GNUNET_DNSPARSER_TYPE_AAAA: return "AAAA";
- case GNUNET_DNSPARSER_TYPE_IXFR: return "IXFR";
- case GNUNET_DNSPARSER_TYPE_AXFR: return "AXFR";
}
GNUNET_snprintf (buf, sizeof (buf), "%u", (unsigned int) type);
return buf;
if (record->data_len != sizeof (struct in_addr))
format = "<invalid>";
else
- format = inet_ntop (AF_INET, record->data, buf, sizeof (buf));
+ format = inet_ntop (AF_INET, record->data.raw, buf, sizeof (buf));
break;
case GNUNET_DNSPARSER_TYPE_AAAA:
if (record->data_len != sizeof (struct in6_addr))
format = "<invalid>";
else
- format = inet_ntop (AF_INET6, record->data, buf, sizeof (buf));
+ format = inet_ntop (AF_INET6, record->data.raw, buf, sizeof (buf));
break;
+ case GNUNET_DNSPARSER_TYPE_NS:
case GNUNET_DNSPARSER_TYPE_CNAME:
- tmp = GNUNET_strdup ("FIXME");
+ case GNUNET_DNSPARSER_TYPE_PTR:
+ format = record->data.hostname;
+ break;
+ case GNUNET_DNSPARSER_TYPE_SOA:
+ if (record->data.soa == NULL)
+ format = "<invalid>";
+ else
+ {
+ GNUNET_asprintf (&tmp,
+ "origin: %s, mail: %s, serial = %u, refresh = %u s, retry = %u s, expire = %u s, minimum = %u s",
+ record->data.soa->mname,
+ record->data.soa->rname,
+ (unsigned int) record->data.soa->serial,
+ (unsigned int) record->data.soa->refresh,
+ (unsigned int) record->data.soa->retry,
+ (unsigned int) record->data.soa->expire,
+ (unsigned int) record->data.soa->minimum_ttl);
+ format = tmp;
+ }
+ break;
+ case GNUNET_DNSPARSER_TYPE_MX:
+ if (record->data.mx == NULL)
+ format = "<invalid>";
+ else
+ {
+ GNUNET_asprintf (&tmp,
+ "%u: %s",
+ record->data.mx->preference,
+ record->data.mx->mxhost);
+ format = tmp;
+ }
+ break;
+ case GNUNET_DNSPARSER_TYPE_TXT:
+ GNUNET_asprintf (&tmp,
+ "%.*s",
+ (unsigned int) record->data_len,
+ record->data.raw);
+ format = tmp;
+ break;
default:
format = "<payload>";
break;
return;
}
fprintf (stdout,
- "%s with ID: %5u Flags: %s%s%s%s%s%s Return Code: %s Opcode: %s\n",
+ "%s with ID: %5u Flags: %s%s%s%s%s%s, Return Code: %s, Opcode: %s\n",
p->flags.query_or_response ? "Response" : "Query",
p->id,
p->flags.recursion_desired ? "RD " : "",
* be dropped). There is no guarantee that other POST-RESOLUTION
* client's won't modify (or drop) the answer afterwards.
*/
- GNUNET_DNS_FLAG_POST_RESOLUTION = 4
+ GNUNET_DNS_FLAG_POST_RESOLUTION = 4,
+
+ /**
+ * Set this flag to see all requests just before they are
+ * returned to the network. Clients that set this flag must then
+ * call "GNUNET_DNS_request_forward" when they process a request
+ * for the last time. Caling "GNUNET_DNS_request_answer" is
+ * not allowed for MONITOR peers.
+ */
+ GNUNET_DNS_FLAG_RESPONSE_MONITOR = 8
};
#define GNUNET_DNSPARSER_TYPE_MX 15
#define GNUNET_DNSPARSER_TYPE_TXT 16
#define GNUNET_DNSPARSER_TYPE_AAAA 28
-#define GNUNET_DNSPARSER_TYPE_IXFR 251
-#define GNUNET_DNSPARSER_TYPE_AXFR 252
/**
* A few common DNS classes (ok, only one is common, but I list a
};
+/**
+ * Information from MX records (RFC 1035).
+ */
+struct GNUNET_DNSPARSER_MxRecord
+{
+
+ /**
+ * Preference for this entry (lower value is higher preference).
+ */
+ uint16_t preference;
+
+ /**
+ * Name of the mail server.
+ */
+ char *mxhost;
+
+};
+
+
+/**
+ * Information from SOA records (RFC 1035).
+ */
+struct GNUNET_DNSPARSER_SoaRecord
+{
+
+ /**
+ *The domainname of the name server that was the
+ * original or primary source of data for this zone.
+ */
+ char *mname;
+
+ /**
+ * A domainname which specifies the mailbox of the
+ * person responsible for this zone.
+ */
+ char *rname;
+
+ /**
+ * The version number of the original copy of the zone.
+ */
+ uint32_t serial;
+
+ /**
+ * Time interval before the zone should be refreshed.
+ */
+ uint32_t refresh;
+
+ /**
+ * Time interval that should elapse before a failed refresh should
+ * be retried.
+ */
+ uint32_t retry;
+
+ /**
+ * Time value that specifies the upper limit on the time interval
+ * that can elapse before the zone is no longer authoritative.
+ */
+ uint32_t expire;
+
+ /**
+ * The bit minimum TTL field that should be exported with any RR
+ * from this zone.
+ */
+ uint32_t minimum_ttl;
+
+};
+
+
/**
* A DNS response record.
*/
*/
char *name;
- /**
- * Raw data, NOT a 0-terminated string (at least not always).
- */
- char *data;
+ union
+ {
+
+ /**
+ * For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname.
+ */
+ char *hostname;
+
+ /**
+ * SOA data for SOA records.
+ */
+ struct GNUNET_DNSPARSER_SoaRecord *soa;
+
+ /**
+ * MX data for MX records.
+ */
+ struct GNUNET_DNSPARSER_MxRecord *mx;
+
+ /**
+ * Raw data for all other types.
+ */
+ char *raw;
+
+ } data;
/**
* Number of bytes in data.
/*
This file is part of GNUnet.
- (C) 2009 Christian Grothoff (and other contributing authors)
+ (C) 2011 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published