From c217aa8750bebf75b4a4a0d020cc516e8efad7be Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 4 Jan 2012 15:17:53 +0000 Subject: -dns parser works now well-enough --- src/dns/dnsparser.c | 143 +++++++++++++++++++++++++++++++---- src/dns/gnunet-dns-monitor.c | 49 ++++++++++-- src/include/gnunet_dns_service-new.h | 11 ++- src/include/gnunet_dnsparser_lib.h | 98 ++++++++++++++++++++++-- src/transport/gnunet-transport.c | 2 +- 5 files changed, 273 insertions(+), 30 deletions(-) diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c index 468c984aa..e02ce73fb 100644 --- a/src/dns/dnsparser.c +++ b/src/dns/dnsparser.c @@ -55,6 +55,15 @@ struct record_line 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 @@ -191,6 +200,9 @@ parse_record (const char *udp_payload, { 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, @@ -201,7 +213,7 @@ parse_record (const char *udp_payload, 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, @@ -211,9 +223,62 @@ parse_record (const char *udp_payload, 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; } @@ -302,6 +367,61 @@ GNUNET_DNSPARSER_parse (const char *udp_payload, } +/** + * 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. * @@ -316,22 +436,13 @@ GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p) GNUNET_free_non_null (p->queries[i].name); GNUNET_free_non_null (p->queries); for (i=0;inum_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;inum_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;inum_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); } diff --git a/src/dns/gnunet-dns-monitor.c b/src/dns/gnunet-dns-monitor.c index c8fb646e5..96d2a4959 100644 --- a/src/dns/gnunet-dns-monitor.c +++ b/src/dns/gnunet-dns-monitor.c @@ -70,8 +70,6 @@ get_type (uint16_t type) 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; @@ -134,16 +132,55 @@ display_record (const struct GNUNET_DNSPARSER_Record *record) if (record->data_len != sizeof (struct in_addr)) format = ""; 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 = ""; 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 = ""; + 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 = ""; + 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 = ""; break; @@ -215,7 +252,7 @@ display_request (void *cls, 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 " : "", diff --git a/src/include/gnunet_dns_service-new.h b/src/include/gnunet_dns_service-new.h index bab8a2485..3517a4609 100644 --- a/src/include/gnunet_dns_service-new.h +++ b/src/include/gnunet_dns_service-new.h @@ -78,7 +78,16 @@ enum GNUNET_DNS_Flags * 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 }; diff --git a/src/include/gnunet_dnsparser_lib.h b/src/include/gnunet_dnsparser_lib.h index ef2ec389f..70dc63326 100644 --- a/src/include/gnunet_dnsparser_lib.h +++ b/src/include/gnunet_dnsparser_lib.h @@ -41,8 +41,6 @@ #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 @@ -157,6 +155,74 @@ struct GNUNET_DNSPARSER_Query }; +/** + * 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. */ @@ -168,10 +234,30 @@ struct GNUNET_DNSPARSER_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. diff --git a/src/transport/gnunet-transport.c b/src/transport/gnunet-transport.c index d15b952d4..c78518813 100644 --- a/src/transport/gnunet-transport.c +++ b/src/transport/gnunet-transport.c @@ -1,6 +1,6 @@ /* 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 -- cgit v1.2.3