gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r18996 - in gnunet/src: dns include


From: gnunet
Subject: [GNUnet-SVN] r18996 - in gnunet/src: dns include
Date: Thu, 5 Jan 2012 13:17:51 +0100

Author: grothoff
Date: 2012-01-05 13:17:50 +0100 (Thu, 05 Jan 2012)
New Revision: 18996

Modified:
   gnunet/src/dns/dnsparser.c
   gnunet/src/dns/gnunet-dns-monitor.c
   gnunet/src/include/gnunet_dnsparser_lib.h
Log:
-dns API improvements, towards serialization

Modified: gnunet/src/dns/dnsparser.c
===================================================================
--- gnunet/src/dns/dnsparser.c  2012-01-05 11:16:52 UTC (rev 18995)
+++ gnunet/src/dns/dnsparser.c  2012-01-05 12:17:50 UTC (rev 18996)
@@ -212,6 +212,7 @@
   size_t old_off;
   struct soa_data soa;
   uint16_t mxpref;
+  uint16_t data_len;
 
   name = parse_name (udp_payload, 
                     udp_payload_length,
@@ -227,11 +228,9 @@
   r->class = ntohs (rl.class);
   r->expiration_time = GNUNET_TIME_relative_to_absolute 
(GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
                                                                                
        ntohl (rl.ttl)));
-  r->data_len = ntohs (rl.data_len);
-  if (*off + r->data_len > udp_payload_length)
+  data_len = ntohs (rl.data_len);
+  if (*off + data_len > udp_payload_length)
     return GNUNET_SYSERR;
-  if (0 == r->data_len)
-    return GNUNET_OK;
   switch (r->type)
   {
   case GNUNET_DNSPARSER_TYPE_NS:
@@ -242,7 +241,7 @@
                                   udp_payload_length,
                                   off, 0);    
     if ( (NULL == r->data.hostname) ||
-        (old_off + r->data_len != *off) )
+        (old_off + data_len != *off) )
       return GNUNET_SYSERR;
     return GNUNET_OK;
   case GNUNET_DNSPARSER_TYPE_SOA:
@@ -265,7 +264,7 @@
     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) 
+    if (old_off + data_len != *off) 
       return GNUNET_SYSERR;
     return GNUNET_OK;
   case GNUNET_DNSPARSER_TYPE_MX:
@@ -279,15 +278,16 @@
     r->data.mx->mxhost = parse_name (udp_payload,
                                     udp_payload_length,
                                     off, 0);
-    if (old_off + r->data_len != *off) 
+    if (old_off + 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);
+    r->data.raw.data = GNUNET_malloc (data_len);
+    r->data.raw.data_len = data_len;
+    memcpy (r->data.raw.data, &udp_payload[*off], data_len);
     break;
   }
-  (*off) += r->data_len;
+  (*off) += data_len;
   return GNUNET_OK;  
 }
 
@@ -425,7 +425,7 @@
     GNUNET_free_non_null (r->data.hostname);
     break;
   default:
-    GNUNET_free_non_null (r->data.raw);
+    GNUNET_free_non_null (r->data.raw.data);
     break;
   }
 }
@@ -457,10 +457,208 @@
 }
 
 
+/* ********************** DNS packet assembly code **************** */
+
+
 /**
+ * Add a DNS name to the UDP packet at the given location.
+ *
+ * @param dst where to write the name
+ * @param dst_len number of bytes in dst
+ * @param off pointer to offset where to write the name (increment by bytes 
used)
+ * @param name name to write
+ * @return GNUNET_SYSERR if 'name' is invalid
+ *         GNUNET_NO if 'name' did not fit
+ *         GNUNET_OK if 'name' was added to 'dst'
+ */
+static int
+add_name (char *dst,
+         size_t dst_len,
+         size_t *off,
+         const char *name)
+{
+  const char *dot;
+  size_t start;
+  size_t pos;
+  size_t len;
+
+  if (NULL == name)
+    return GNUNET_SYSERR;
+  start = *off;
+  if (start + strlen (name) + 2 > dst_len)
+    return GNUNET_NO;
+  pos = start;
+  do
+  {
+    dot = strchr (name, '.');
+    if (NULL == dot)
+      len = strlen (name);
+    else
+      len = dot - name;
+    if ( (len >= 64) || (len == 0) )
+      return GNUNET_NO; /* segment too long or empty */
+    dst[pos++] = (char) (uint8_t) len;
+    memcpy (&dst[pos], name, len);
+    pos += len;
+    name += len + 1; /* also skip dot */
+  }
+  while (NULL != dot);
+  dst[pos++] = '\0'; /* terminator */
+  *off = pos;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Add a DNS query to the UDP packet at the given location.
+ *
+ * @param dst where to write the query
+ * @param dst_len number of bytes in dst
+ * @param off pointer to offset where to write the query (increment by bytes 
used)
+ * @param query query to write
+ * @return GNUNET_SYSERR if 'query' is invalid
+ *         GNUNET_NO if 'query' did not fit
+ *         GNUNET_OK if 'query' was added to 'dst'
+ */
+static int
+add_query (char *dst,
+          size_t dst_len,
+          size_t *off,
+          const struct GNUNET_DNSPARSER_Query *query)
+{
+  int ret;
+  struct query_line ql;
+
+  ret = add_name (dst, dst_len - sizeof (struct query_line), off, query->name);
+  if (ret != GNUNET_OK)
+    return ret;
+  ql.type = htons (query->type);
+  ql.class = htons (query->class);
+  memcpy (&dst[*off], &ql, sizeof (ql));
+  (*off) += sizeof (ql);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Add an MX record to the UDP packet at the given location.
+ *
+ * @param dst where to write the mx record
+ * @param dst_len number of bytes in dst
+ * @param off pointer to offset where to write the mx information (increment 
by bytes used)
+ * @param mx mx information to write
+ * @return GNUNET_SYSERR if 'mx' is invalid
+ *         GNUNET_NO if 'mx' did not fit
+ *         GNUNET_OK if 'mx' was added to 'dst'
+ */
+static int
+add_mx (char *dst,
+       size_t dst_len,
+       size_t *off,
+       const struct GNUNET_DNSPARSER_MxRecord *mx)
+{
+  return GNUNET_SYSERR; // not implemented
+}
+
+
+/**
+ * Add an SOA record to the UDP packet at the given location.
+ *
+ * @param dst where to write the SOA record
+ * @param dst_len number of bytes in dst
+ * @param off pointer to offset where to write the SOA information (increment 
by bytes used)
+ * @param soa SOA information to write
+ * @return GNUNET_SYSERR if 'soa' is invalid
+ *         GNUNET_NO if 'soa' did not fit
+ *         GNUNET_OK if 'soa' was added to 'dst'
+ */
+static int
+add_soa (char *dst,
+        size_t dst_len,
+        size_t *off,
+        const struct GNUNET_DNSPARSER_SoaRecord *soa)
+{
+  return GNUNET_SYSERR; // not implemented
+}
+
+
+/**
+ * Add a DNS record to the UDP packet at the given location.
+ *
+ * @param dst where to write the query
+ * @param dst_len number of bytes in dst
+ * @param off pointer to offset where to write the query (increment by bytes 
used)
+ * @param record record to write
+ * @return GNUNET_SYSERR if 'record' is invalid
+ *         GNUNET_NO if 'record' did not fit
+ *         GNUNET_OK if 'record' was added to 'dst'
+ */
+static int
+add_record (char *dst,
+           size_t dst_len,
+           size_t *off,
+           const struct GNUNET_DNSPARSER_Record *record)
+{
+  int ret;
+  size_t start;
+  size_t pos;
+  struct record_line rl;
+
+  start = *off;
+  ret = add_name (dst, dst_len - sizeof (struct record_line), off, 
record->name);
+  if (ret != GNUNET_OK)
+    return ret;
+  /* '*off' is now the position where we will need to write the record line */
+
+  pos = *off + sizeof (struct record_line);
+  switch (record->type)
+  { 
+  case GNUNET_DNSPARSER_TYPE_MX:
+    ret = add_mx (dst, dst_len, &pos, record->data.mx);    
+    break;
+  case GNUNET_DNSPARSER_TYPE_SOA:
+    ret = add_soa (dst, dst_len, &pos, record->data.soa);
+    break;
+  case GNUNET_DNSPARSER_TYPE_NS:
+  case GNUNET_DNSPARSER_TYPE_CNAME:
+  case GNUNET_DNSPARSER_TYPE_PTR:
+    ret = add_name (dst, dst_len, &pos, record->data.hostname);
+    break;
+  default:
+    if (pos + record->data.raw.data_len > dst_len)
+    {
+      ret = GNUNET_NO;
+      break;
+    }
+    memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len);
+    pos += record->data.raw.data_len;
+    break;
+  }
+  if (pos - (*off + sizeof (struct record_line)) > UINT16_MAX)
+  {
+    /* record data too long */
+    *off = start;
+    return GNUNET_NO;
+  }
+  rl.type = htons (record->type);
+  rl.class = htons (record->class);
+  rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining 
(record->expiration_time).rel_value / 1000); /* in seconds */
+  rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct 
record_line))));
+  memcpy (&dst[*off], &rl, sizeof (struct record_line));
+  *off = pos;
+  return GNUNET_OK;  
+}
+
+
+
+/**
  * Given a DNS packet, generate the corresponding UDP payload.
+ * Note that we do not attempt to pack the strings with pointers
+ * as this would complicate the code and this is about being 
+ * simple and secure, not fast, fancy and broken like bind.
  *
  * @param p packet to pack
+ * @param max maximum allowed size for the resulting UDP payload
  * @param buf set to a buffer with the packed message
  * @param buf_length set to the length of buf
  * @return GNUNET_SYSERR if 'p' is invalid
@@ -468,18 +666,119 @@
  *         GNUNET_OK if 'p' was packed completely into '*buf'
  */
 int
-GNUNET_DNSPARSER_pack (struct GNUNET_DNSPARSER_Packet *p,
+GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p,
+                      uint16_t max,
                       char **buf,
                       size_t *buf_length)
-{
-  // FIXME: not implemented
-  GNUNET_break (0);
-  return GNUNET_SYSERR;
+{  
+  struct dns_header dns;
+  size_t off;
+  char tmp[max];
+  unsigned int i;
+  int ret;
+  int trc;
+  
+  if ( (p->num_queries > UINT16_MAX) ||
+       (p->num_answers > UINT16_MAX) ||
+       (p->num_authority_records > UINT16_MAX) ||
+       (p->num_additional_records > UINT16_MAX) )
+    return GNUNET_SYSERR;
+  dns.id = p->id;
+  dns.flags = p->flags;
+  dns.query_count = htons (p->num_queries);
+  dns.answer_rcount = htons (p->num_answers);
+  dns.authority_rcount = htons (p->num_authority_records);
+  dns.additional_rcount = htons (p->num_additional_records);
+  off = sizeof (struct dns_header);
+  trc = GNUNET_NO;
+  for (i=0;i<p->num_queries;i++)
+  {
+    ret = add_query (tmp, sizeof (tmp), &off, &p->queries[i]);  
+    if (GNUNET_SYSERR == ret)
+      return GNUNET_SYSERR;
+    if (GNUNET_NO == ret)
+    {
+      dns.query_count = htons ((uint16_t) (i-1));
+      trc = GNUNET_YES;      
+      break;
+    }
+  }
+  for (i=0;i<p->num_answers;i++)
+  {
+    ret = add_record (tmp, sizeof (tmp), &off, &p->answers[i]);  
+    if (GNUNET_SYSERR == ret)
+      return GNUNET_SYSERR;
+    if (GNUNET_NO == ret)
+    {
+      dns.answer_rcount = htons ((uint16_t) (i-1));
+      trc = GNUNET_YES;      
+      break;
+    }
+  }
+  for (i=0;i<p->num_authority_records;i++)
+  {
+    ret = add_record (tmp, sizeof (tmp), &off, &p->authority_records[i]);  
+    if (GNUNET_SYSERR == ret)
+      return GNUNET_SYSERR;
+    if (GNUNET_NO == ret)
+    {
+      dns.authority_rcount = htons ((uint16_t) (i-1));
+      trc = GNUNET_YES;      
+      break;
+    }
+  }
+  for (i=0;i<p->num_additional_records;i++)
+  {
+    ret = add_record (tmp, sizeof (tmp), &off, &p->additional_records[i]);  
+    if (GNUNET_SYSERR == ret)
+      return GNUNET_SYSERR;
+    if (GNUNET_NO == ret)
+    {
+      dns.additional_rcount = htons (i-1);
+      trc = GNUNET_YES;      
+      break;
+    }
+  }
+  if (GNUNET_YES == trc)
+    dns.flags.message_truncated = 1;
+    
+
+  memcpy (tmp, &dns, sizeof (struct dns_header));
+  *buf = GNUNET_malloc (off);
+  *buf_length = off;
+  memcpy (*buf, tmp, off);
+  return trc;
 }
 
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 /* legacy code follows */
 
 /**

Modified: gnunet/src/dns/gnunet-dns-monitor.c
===================================================================
--- gnunet/src/dns/gnunet-dns-monitor.c 2012-01-05 11:16:52 UTC (rev 18995)
+++ gnunet/src/dns/gnunet-dns-monitor.c 2012-01-05 12:17:50 UTC (rev 18996)
@@ -134,16 +134,16 @@
   switch (record->type)
   {
   case GNUNET_DNSPARSER_TYPE_A:
-    if (record->data_len != sizeof (struct in_addr))
+    if (record->data.raw.data_len != sizeof (struct in_addr))
       format = "<invalid>";
     else
-      format = inet_ntop (AF_INET, record->data.raw, buf, sizeof (buf));
+      format = inet_ntop (AF_INET, record->data.raw.data, buf, sizeof (buf));
     break;
   case GNUNET_DNSPARSER_TYPE_AAAA:
-    if (record->data_len != sizeof (struct in6_addr))
+    if (record->data.raw.data_len != sizeof (struct in6_addr))
       format = "<invalid>";
     else
-      format = inet_ntop (AF_INET6, record->data.raw, buf, sizeof (buf));
+      format = inet_ntop (AF_INET6, record->data.raw.data, buf, sizeof (buf));
     break;
   case GNUNET_DNSPARSER_TYPE_NS:
   case GNUNET_DNSPARSER_TYPE_CNAME:
@@ -182,8 +182,8 @@
   case GNUNET_DNSPARSER_TYPE_TXT:
     GNUNET_asprintf (&tmp,
                     "%.*s",
-                    (unsigned int) record->data_len,
-                    record->data.raw);
+                    (unsigned int) record->data.raw.data_len,
+                    record->data.raw.data);
     format = tmp;
     break;
   default:
@@ -191,12 +191,11 @@
     break;
   }
   fprintf (stdout,
-          "\t\t%s %s: %s = %s (%u bytes, %u s)\n",
+          "\t\t%s %s: %s = %s (%u s)\n",
           get_class (record->class),
           get_type (record->type),
           record->name,
           format,
-          (unsigned int) record->data_len,
           (unsigned int) (GNUNET_TIME_absolute_get_remaining 
(record->expiration_time).rel_value / 1000));
   GNUNET_free_non_null (tmp);
 }

Modified: gnunet/src/include/gnunet_dnsparser_lib.h
===================================================================
--- gnunet/src/include/gnunet_dnsparser_lib.h   2012-01-05 11:16:52 UTC (rev 
18995)
+++ gnunet/src/include/gnunet_dnsparser_lib.h   2012-01-05 12:17:50 UTC (rev 
18996)
@@ -224,6 +224,24 @@
 
 
 /**
+ * Binary record information (unparsed).
+ */
+struct GNUNET_DNSPARSER_RawRecord
+{
+
+  /**
+   * Binary record data.
+   */
+  void *data;
+
+  /**
+   * Number of bytes in data.
+   */
+  size_t data_len;
+};
+
+
+/**
  * A DNS response record.
  */
 struct GNUNET_DNSPARSER_Record
@@ -255,14 +273,10 @@
     /**
      * Raw data for all other types.
      */
-    char *raw;
+    struct GNUNET_DNSPARSER_RawRecord raw;
 
   } data;
 
-  /**
-   * Number of bytes in data.
-   */
-  size_t data_len;
 
   /**
    * When does the record expire?
@@ -366,6 +380,7 @@
  * Given a DNS packet, generate the corresponding UDP payload.
  *
  * @param p packet to pack
+ * @param max maximum allowed size for the resulting UDP payload
  * @param buf set to a buffer with the packed message
  * @param buf_length set to the length of buf
  * @return GNUNET_SYSERR if 'p' is invalid
@@ -373,7 +388,8 @@
  *         GNUNET_OK if 'p' was packed completely into '*buf'
  */
 int
-GNUNET_DNSPARSER_pack (struct GNUNET_DNSPARSER_Packet *p,
+GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p,
+                      uint16_t max,
                       char **buf,
                       size_t *buf_length);
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]