/*
This file is part of GNUnet.
- (C) 2011-2013 Christian Grothoff (and other contributing authors)
+ Copyright (C) 2011-2013 GNUnet e.V.
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
You should have received a copy of the GNU General Public License
along with GNUnet; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
*/
/**
/**
* Default timeout for DNS lookups.
*/
-#define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+#define DNS_LOOKUP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
/**
* Default timeout for VPN redirections.
/**
* Expiration time for the DNS record, 0 if we didn't
- * get anything useful (i.e. 'gethostbyname' was used).
+ * get anything useful (i.e. 'gethostbyname()' was used).
*/
uint64_t expiration_time;
/**
* ID of a task associated with the resolution process.
*/
- GNUNET_SCHEDULER_TaskIdentifier task_id;
+ struct GNUNET_SCHEDULER_Task * task_id;
/**
* The name to resolve
*/
enum GNUNET_GNS_LocalOptions options;
+ /**
+ * For SRV and TLSA records, the number of the
+ * protocol specified in the name. 0 if no protocol was given.
+ */
+ int protocol;
+
+ /**
+ * For SRV and TLSA records, the number of the
+ * service specified in the name. 0 if no service was given.
+ */
+ int service;
+
/**
* Desired type for the resolution.
*/
*/
static const struct GNUNET_CONFIGURATION_Handle *cfg;
-#if 0
-/**
- * Check if name is in srv format (_x._y.xxx)
- *
- * @param name
- * @return #GNUNET_YES if true
- */
-static int
-is_srv (const char *name)
-{
- char *ndup;
- int ret;
-
- if (*name != '_')
- return GNUNET_NO;
- if (NULL == strstr (name, "._"))
- return GNUNET_NO;
- ret = GNUNET_YES;
- ndup = GNUNET_strdup (name);
- strtok (ndup, ".");
- if (NULL == strtok (NULL, "."))
- ret = GNUNET_NO;
- if (NULL == strtok (NULL, "."))
- ret = GNUNET_NO;
- if (NULL != strtok (NULL, "."))
- ret = GNUNET_NO;
- GNUNET_free (ndup);
- return ret;
-}
-#endif
-
/**
* Determine if this name is canonical (is a legal name in a zone, without delegation);
* Task scheduled to asynchronously fail a resolution.
*
* @param cls the 'struct GNS_ResolverHandle' of the resolution to fail
- * @param tc task context
*/
static void
-fail_resolution (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+fail_resolution (void *cls)
{
struct GNS_ResolverHandle *rh = cls;
- rh->task_id = GNUNET_SCHEDULER_NO_TASK;
+ rh->task_id = NULL;
rh->proc (rh->proc_cls, 0, NULL);
GNS_resolver_lookup_cancel (rh);
}
#if (defined WINDOWS) || (defined DARWIN)
/* Don't have this on W32, here's a naive implementation
* Was somehow removed on OS X ... */
-void *
+static void *
memrchr (const void *s,
int c,
size_t n)
const char *rp;
const char *dot;
size_t len;
+ char *ret;
+ char *srv_name;
+ char *proto_name;
+ struct protoent *pe;
+ struct servent *se;
if (0 == rh->name_resolution_pos)
return NULL;
rp = dot + 1;
rh->name_resolution_pos = dot - rh->name;
}
- /* merge labels starting with underscore with label on the right (SRV/DANE case) */
- while ( (NULL != (dot = memrchr (rh->name,
- (int) '.',
- rh->name_resolution_pos))) &&
- ('_' == dot[1]) )
+ rh->protocol = 0;
+ rh->service = 0;
+ ret = GNUNET_strndup (rp, len);
+ /* If we have labels starting with underscore with label on
+ * the right (SRV/DANE/BOX case), determine port/protocol;
+ * The format of `rh->name` must be "_PORT._PROTOCOL".
+ */
+ if ( ('_' == rh->name[0]) &&
+ (NULL != (dot = memrchr (rh->name,
+ (int) '.',
+ rh->name_resolution_pos))) &&
+ ('_' == dot[1]) &&
+ (NULL == memrchr (rh->name,
+ (int) '.',
+ dot - rh->name)) )
{
- len += rh->name_resolution_pos - (dot - rh->name) - 1;
- rp = dot + 1;
- rh->name_resolution_pos = dot - rh->name;
+ srv_name = GNUNET_strndup (&rh->name[1],
+ (dot - rh->name) - 1);
+ proto_name = GNUNET_strndup (&dot[2],
+ rh->name_resolution_pos - (dot - rh->name) - 1);
+ rh->name_resolution_pos = 0;
+ pe = getprotobyname (proto_name);
+ if (NULL == pe)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Protocol `%s' unknown, skipping labels.\n"),
+ proto_name);
+ GNUNET_free (proto_name);
+ GNUNET_free (srv_name);
+ return ret;
+ }
+ se = getservbyname (srv_name,
+ proto_name);
+ if (NULL == se)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Service `%s' unknown for protocol `%s', skipping labels.\n"),
+ srv_name,
+ proto_name);
+ GNUNET_free (proto_name);
+ GNUNET_free (srv_name);
+ return ret;
+ }
+ rh->protocol = pe->p_proto;
+ rh->service = se->s_port;
}
- return GNUNET_strndup (rp, len);
+ return ret;
}
const struct sockaddr_in *sa4;
const struct sockaddr_in6 *sa6;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received %u bytes of DNS IP data\n",
- addrlen);
if (NULL == addr)
{
rh->std_resolve = NULL;
transmit_lookup_dns_result (rh);
return;
}
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received %u bytes of DNS IP data\n",
+ addrlen);
switch (addr->sa_family)
{
case AF_INET:
* @param tc task context
*/
static void
-recursive_resolution (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc);
+recursive_resolution (void *cls);
/**
rh->dns_request = NULL;
GNUNET_SCHEDULER_cancel (rh->task_id);
- rh->task_id = GNUNET_SCHEDULER_NO_TASK;
+ rh->task_id = NULL;
p = GNUNET_DNSPARSER_parse ((const char *) dns,
dns_len);
if (NULL == p)
GNUNET_DNSPARSER_free_packet (p);
return;
}
- /* FIXME: add DNAME support */
/* convert from (parsed) DNS to (binary) GNS format! */
rd_count = p->num_answers + p->num_authority_records + p->num_additional_records;
else if (i < p->num_answers + p->num_authority_records)
rec = &p->authority_records[i - p->num_answers];
else
- rec = &p->authority_records[i - p->num_answers - p->num_authority_records];
+ rec = &p->additional_records[i - p->num_answers - p->num_authority_records];
/* As we copied the full DNS name to 'rh->ac_tail->label', this
should be the correct check to see if this record is actually
a record for our label... */
shorten_ac = rh->ac_tail;
for (i=0;i<rd_count;i++)
{
+ if ( (0 != rh->protocol) &&
+ (0 != rh->service) &&
+ (GNUNET_GNSRECORD_TYPE_BOX != rd[i].record_type) )
+ continue; /* we _only_ care about boxed records */
+
rd_new[rd_off] = rd[i];
/* Check if the embedded name(s) end in "+", and if so,
replace the "+" with the zone at "ac_tail", changing the name
struct GNUNET_DNSPARSER_SrvRecord *srv;
off = 0;
- srv = GNUNET_DNSPARSER_parse_srv (rh->name,
- rd[i].data,
+ srv = GNUNET_DNSPARSER_parse_srv (rd[i].data,
rd[i].data_size,
&off);
if ( (NULL == srv) ||
}
else
{
- srv->domain_name = translate_dot_plus (rh, srv->domain_name);
srv->target = translate_dot_plus (rh, srv->target);
scratch_start = scratch_off;
if (GNUNET_OK !=
case GNUNET_GNSRECORD_TYPE_NICK:
{
const char *nick;
+
nick = rd[i].data;
if ((rd[i].data_size > 0) &&
(nick[rd[i].data_size -1] != '\0'))
case GNUNET_GNSRECORD_TYPE_GNS2DNS:
{
/* delegation to DNS */
+ if (GNUNET_GNSRECORD_TYPE_GNS2DNS == rh->record_type)
+ {
+ rd_off++;
+ break; /* do not follow to DNS, we wanted the GNS2DNS record! */
+ }
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Found GNS2DNS record, delegating to DNS!\n");
goto do_recurse;
}
+ case GNUNET_GNSRECORD_TYPE_BOX:
+ {
+ /* unbox SRV/TLSA records if a specific one was requested */
+ if ( (0 != rh->protocol) &&
+ (0 != rh->service) &&
+ (rd[i].data_size >= sizeof (struct GNUNET_GNSRECORD_BoxRecord)) )
+ {
+ const struct GNUNET_GNSRECORD_BoxRecord *box;
+
+ box = rd[i].data;
+ if ( (ntohs (box->protocol) == rh->protocol) &&
+ (ntohs (box->service) == rh->service) )
+ {
+ /* Box matches, unbox! */
+ rd_new[rd_off].record_type = ntohl (box->record_type);
+ rd_new[rd_off].data_size -= sizeof (struct GNUNET_GNSRECORD_BoxRecord);
+ rd_new[rd_off].data = &box[1];
+ rd_off++;
+ }
+ }
+ else
+ {
+ /* no specific protocol/service specified, preserve all BOX
+ records (for modern, GNS-enabled applications) */
+ rd_off++;
+ }
+ }
default:
rd_off++;
break;
resolver to use */
g2dc = GNUNET_new (struct Gns2DnsContext);
g2dc->ns = ns;
+
g2dc->rh = GNUNET_new (struct GNS_ResolverHandle);
g2dc->rh->authority_zone = rh->ac_tail->authority_info.gns_authority;
ip = translate_dot_plus (rh, ip);
* Task scheduled to continue with the resolution process.
*
* @param cls the `struct GNS_ResolverHandle` of the resolution
- * @param tc task context
*/
static void
-recursive_resolution (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+recursive_resolution (void *cls)
{
struct GNS_ResolverHandle *rh = cls;
- rh->task_id = GNUNET_SCHEDULER_NO_TASK;
+ rh->task_id = NULL;
if (MAX_RECURSION < rh->loop_limiter++)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
GNUNET_free (rh->g2dc);
rh->g2dc = NULL;
}
- if (GNUNET_SCHEDULER_NO_TASK != rh->task_id)
+ if (NULL != rh->task_id)
{
GNUNET_SCHEDULER_cancel (rh->task_id);
- rh->task_id = GNUNET_SCHEDULER_NO_TASK;
+ rh->task_id = NULL;
}
if (NULL != rh->get_handle)
{
dht_lookup_heap =
GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
max_allowed_background_queries = max_bg_queries;
- if (GNUNET_SYSERR == (use_cache = GNUNET_CONFIGURATION_get_value_yesno (c,
- "gns",
- "USE_CACHE")))
+ if (GNUNET_SYSERR == (use_cache =
+ GNUNET_CONFIGURATION_get_value_yesno (c,
+ "gns",
+ "USE_CACHE")))
use_cache = GNUNET_YES;
if (GNUNET_NO == use_cache)
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Namecache disabled\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Namecache disabled\n");
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (c,