X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fdns%2Fdnsparser.c;h=4b0c03a773b90282a88f09b9a9cc969646706e8e;hb=56389a7d277b05c9c2968b7ebd529a12f8be15eb;hp=c11ec25d6c438b57dcfec4b646fea168e82569b2;hpb=e2931e9e5cffd9f3dc37b71b2a01ed151c0dd4e5;p=oweals%2Fgnunet.git diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c index c11ec25d6..4b0c03a77 100644 --- a/src/dns/dnsparser.c +++ b/src/dns/dnsparser.c @@ -27,157 +27,9 @@ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_dnsparser_lib.h" +#include "dnsparser.h" -GNUNET_NETWORK_STRUCT_BEGIN - -/* FIXME: replace this one with the one from tcpip_tun.h!? */ -/** - * Head of a any DNS message. - */ -struct GNUNET_TUN_DnsHeader -{ - /** - * Request/response ID. (NBO) - */ - uint16_t id GNUNET_PACKED; - - /** - * Flags for the operation. - */ - struct GNUNET_DNSPARSER_Flags flags; - - /** - * number of questions (NBO) - */ - uint16_t query_count GNUNET_PACKED; - - /** - * number of answers (NBO) - */ - uint16_t answer_rcount GNUNET_PACKED; - - /** - * number of authority-records (NBO) - */ - uint16_t authority_rcount GNUNET_PACKED; - - /** - * number of additional records (NBO) - */ - uint16_t additional_rcount GNUNET_PACKED; -}; - - -/** - * DNS query prefix. - */ -struct query_line -{ - /** - * Desired type (GNUNET_DNSPARSER_TYPE_XXX). (NBO) - */ - uint16_t type GNUNET_PACKED; - - /** - * Desired class (usually GNUNET_DNSPARSER_CLASS_INTERNET). (NBO) - */ - uint16_t class GNUNET_PACKED; -}; - - -/** - * General DNS record prefix. - */ -struct record_line -{ - /** - * Record type (GNUNET_DNSPARSER_TYPE_XXX). (NBO) - */ - uint16_t type GNUNET_PACKED; - - /** - * Record class (usually GNUNET_DNSPARSER_CLASS_INTERNET). (NBO) - */ - uint16_t class GNUNET_PACKED; - - /** - * Expiration for the record (in seconds). (NBO) - */ - uint32_t ttl GNUNET_PACKED; - - /** - * Number of bytes of data that follow. (NBO) - */ - uint16_t data_len GNUNET_PACKED; -}; - - -/** - * Payload of DNS SOA record (header). - */ -struct soa_data -{ - /** - * The version number of the original copy of the zone. (NBO) - */ - uint32_t serial GNUNET_PACKED; - - /** - * Time interval before the zone should be refreshed. (NBO) - */ - uint32_t refresh GNUNET_PACKED; - - /** - * Time interval that should elapse before a failed refresh should - * be retried. (NBO) - */ - uint32_t retry GNUNET_PACKED; - - /** - * Time value that specifies the upper limit on the time interval - * that can elapse before the zone is no longer authoritative. (NBO) - */ - uint32_t expire GNUNET_PACKED; - - /** - * The bit minimum TTL field that should be exported with any RR - * from this zone. (NBO) - */ - uint32_t minimum GNUNET_PACKED; -}; - - -/** - * Payload of DNS SRV record (header). - */ -struct srv_data -{ - - /** - * Preference for this entry (lower value is higher preference). Clients - * will contact hosts from the lowest-priority group first and fall back - * to higher priorities if the low-priority entries are unavailable. (NBO) - */ - uint16_t prio GNUNET_PACKED; - - /** - * Relative weight for records with the same priority. Clients will use - * the hosts of the same (lowest) priority with a probability proportional - * to the weight given. (NBO) - */ - uint16_t weight GNUNET_PACKED; - - /** - * TCP or UDP port of the service. (NBO) - */ - uint16_t port GNUNET_PACKED; - - /* followed by 'target' name */ -}; - -GNUNET_NETWORK_STRUCT_END - /** * Parse name inside of a DNS query or record. @@ -325,6 +177,9 @@ parse_record (const char *udp_payload, struct soa_data soa; uint16_t mxpref; uint16_t data_len; + struct srv_data srv; + char *ndup; + char *tok; name = parse_name (udp_payload, udp_payload_length, @@ -393,6 +248,50 @@ parse_record (const char *udp_payload, if (old_off + data_len != *off) return GNUNET_SYSERR; return GNUNET_OK; + case GNUNET_DNSPARSER_TYPE_SRV: + if ('_' != *r->name) + return GNUNET_SYSERR; /* all valid srv names must start with "_" */ + if (NULL == strstr (r->name, "._")) + return GNUNET_SYSERR; /* necessary string from "._$PROTO" not present */ + old_off = *off; + if (*off + sizeof (struct srv_data) > udp_payload_length) + return GNUNET_SYSERR; + memcpy (&srv, &udp_payload[*off], sizeof (struct srv_data)); + (*off) += sizeof (struct srv_data); + r->data.srv = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_SrvRecord)); + r->data.srv->priority = ntohs (srv.prio); + r->data.srv->weight = ntohs (srv.weight); + r->data.srv->port = ntohs (srv.port); + /* parse 'data.hostname' into components, which are + "_$SERVICE._$PROTO.$DOMAIN_NAME" */ + ndup = GNUNET_strdup (r->name); + tok = strtok (ndup, "."); + GNUNET_assert (NULL != tok); + GNUNET_assert ('_' == *tok); + r->data.srv->service = GNUNET_strdup (&tok[1]); + tok = strtok (NULL, "."); + if ( (NULL == tok) || ('_' != *tok) ) + { + GNUNET_free (r->data.srv); + GNUNET_free (ndup); + return GNUNET_SYSERR; + } + r->data.srv->proto = GNUNET_strdup (&tok[1]); + tok = strtok (NULL, "."); + if (NULL == tok) + { + GNUNET_free (r->data.srv); + GNUNET_free (ndup); + return GNUNET_SYSERR; + } + r->data.srv->domain_name = GNUNET_strdup (tok); + GNUNET_free (ndup); + r->data.srv->target = parse_name (udp_payload, + udp_payload_length, + off, 0); + if (old_off + data_len != *off) + return GNUNET_SYSERR; + return GNUNET_OK; default: r->data.raw.data = GNUNET_malloc (data_len); r->data.raw.data_len = data_len; @@ -504,6 +403,24 @@ free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa) } +/** + * Free SRV information record. + * + * @param srv record to free + */ +static void +free_srv (struct GNUNET_DNSPARSER_SrvRecord *srv) +{ + if (NULL == srv) + return; + GNUNET_free_non_null (srv->target); + GNUNET_free_non_null (srv->domain_name); + GNUNET_free_non_null (srv->proto); + GNUNET_free_non_null (srv->service); + GNUNET_free (srv); +} + + /** * Free MX information record. * @@ -531,6 +448,9 @@ free_record (struct GNUNET_DNSPARSER_Record *r) case GNUNET_DNSPARSER_TYPE_SOA: free_soa (r->data.soa); break; + case GNUNET_DNSPARSER_TYPE_SRV: + free_srv (r->data.srv); + break; case GNUNET_DNSPARSER_TYPE_NS: case GNUNET_DNSPARSER_TYPE_CNAME: case GNUNET_DNSPARSER_TYPE_PTR: @@ -726,6 +646,43 @@ add_soa (char *dst, } +/** + * Add an SRV record to the UDP packet at the given location. + * + * @param dst where to write the SRV record + * @param dst_len number of bytes in dst + * @param off pointer to offset where to write the SRV information (increment by bytes used) + * can also change if there was an error + * @param srv SRV information to write + * @return GNUNET_SYSERR if 'srv' is invalid + * GNUNET_NO if 'srv' did not fit + * GNUNET_OK if 'srv' was added to 'dst' + */ +static int +add_srv (char *dst, + size_t dst_len, + size_t *off, + const struct GNUNET_DNSPARSER_SrvRecord *srv) +{ + struct srv_data sd; + int ret; + + if (*off + sizeof (struct srv_data) > dst_len) + return GNUNET_NO; + sd.prio = htons (srv->priority); + sd.weight = htons (srv->weight); + sd.port = htons (srv->port); + memcpy (&dst[*off], &sd, sizeof (sd)); + (*off) += sizeof (sd); + if (GNUNET_OK != (ret = add_name (dst, + dst_len, + off, + srv->target))) + return ret; + return GNUNET_OK; +} + + /** * Add a DNS record to the UDP packet at the given location. * @@ -748,10 +705,23 @@ add_record (char *dst, size_t start; size_t pos; struct record_line rl; - + char *name; + start = *off; - ret = add_name (dst, dst_len - sizeof (struct record_line), off, record->name); - if (ret != GNUNET_OK) + /* for SRV records, we can create the name from the details + of the record if needed */ + name = record->name; + if ( (GNUNET_DNSPARSER_TYPE_SRV == record->type) && + (NULL == name) ) + GNUNET_asprintf (&name, + "_%s._%s.%s", + record->data.srv->service, + record->data.srv->proto, + record->data.srv->domain_name); + ret = add_name (dst, dst_len - sizeof (struct record_line), off, name); + if (name != record->name) + GNUNET_free (name); + if (GNUNET_OK != ret) return ret; /* '*off' is now the position where we will need to write the record line */ @@ -769,6 +739,9 @@ add_record (char *dst, case GNUNET_DNSPARSER_TYPE_PTR: ret = add_name (dst, dst_len, &pos, record->data.hostname); break; + case GNUNET_DNSPARSER_TYPE_SRV: + ret = add_srv (dst, dst_len, &pos, record->data.srv); + break; default: if (pos + record->data.raw.data_len > dst_len) { @@ -780,7 +753,7 @@ add_record (char *dst, ret = GNUNET_OK; break; } - if (ret != GNUNET_OK) + if (GNUNET_OK != ret) { *off = start; return GNUNET_NO;