Exemple #1
0
/**
 * Method called to inform about the egos of this peer.
 *
 * When used with #GNUNET_IDENTITY_connect, this function is
 * initially called for all egos and then again whenever a
 * ego's name changes or if it is deleted.  At the end of
 * the initial pass over all egos, the function is once called
 * with 'NULL' for @a ego. That does NOT mean that the callback won't
 * be invoked in the future or that there was an error.
 *
 * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
 * this function is only called ONCE, and 'NULL' being passed in
 * @a ego does indicate an error (i.e. name is taken or no default
 * value is known).  If @a ego is non-NULL and if '*ctx'
 * is set in those callbacks, the value WILL be passed to a subsequent
 * call to the identity callback of #GNUNET_IDENTITY_connect (if
 * that one was not NULL).
 *
 * When an identity is renamed, this function is called with the
 * (known) @a ego but the NEW @a name.
 *
 * When an identity is deleted, this function is called with the
 * (known) ego and "NULL" for the @a name.  In this case,
 * the @a ego is henceforth invalid (and the @a ctx should also be
 * cleaned up).
 *
 * @param cls closure
 * @param ego ego handle
 * @param ctx context for application to store data for this ego
 *                 (during the lifetime of this process, initially NULL)
 * @param name name assigned by the user for this ego,
 *                   NULL if the user just deleted the ego and it
 *                   must thus no longer be used
 */
static void
identity_cb (void *cls,
             struct GNUNET_IDENTITY_Ego *ego,
             void **ctx,
             const char *name)
{
    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key;
    struct GNUNET_GNSRECORD_Data rd;
    char *rd_string;
    char *peername;

    if (NULL == name)
        return;
    if (NULL == ego)
    {
        if (NULL == qe)
        {
            fprintf (stderr,
                     "Failed to find master-zone ego\n");
            GNUNET_SCHEDULER_shutdown ();
            return;
        }
        GNUNET_IDENTITY_disconnect (identity);
        identity = NULL;
        return;
    }
    GNUNET_assert (NULL != name);
    if (0 != strcmp (name,
                     "master-zone"))
    {
        fprintf (stderr,
                 "Unexpected name %s\n",
                 name);
        return;
    }
    zone_key = GNUNET_IDENTITY_ego_get_private_key (ego);
    rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
    peername = GNUNET_strdup (GNUNET_i2s_full (&id));
    GNUNET_asprintf (&rd_string,
                     "6 %s %s",
                     peername,
                     "www");
    GNUNET_free (peername);
    GNUNET_assert (GNUNET_OK ==
                   GNUNET_GNSRECORD_string_to_value (GNUNET_GNSRECORD_TYPE_VPN,
                           rd_string,
                           (void**) &rd.data,
                           &rd.data_size));
    rd.record_type = GNUNET_GNSRECORD_TYPE_VPN;

    qe = GNUNET_NAMESTORE_records_store (namestore,
                                         zone_key,
                                         "www",
                                         1, &rd,
                                         &commence_testing,
                                         NULL);
    GNUNET_free ((void**)rd.data);
    GNUNET_free (rd_string);
}
Exemple #2
0
static void
run (void *cls,
     const struct GNUNET_CONFIGURATION_Handle *cfg,
     struct GNUNET_TESTING_Peer *peer)
{
  enum MHD_FLAG flags;
  struct GNUNET_CRYPTO_EcdsaPrivateKey *host_key;
  struct GNUNET_GNSRECORD_Data rd;
  char *zone_keyfile;

  namestore = GNUNET_NAMESTORE_connect (cfg);
  GNUNET_assert (NULL != namestore);
  flags = MHD_USE_DEBUG;
  mhd = MHD_start_daemon (flags,
			  PORT,
			  NULL, NULL,
			  &mhd_ahc, NULL,
			  MHD_OPTION_END);
  GNUNET_assert (NULL != mhd);
  mhd_main ();

  tmp_cfgfile = GNUNET_DISK_mktemp ("test_gns_proxy_tmp.conf");
  if (NULL == tmp_cfgfile)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Failed to create tmp cfg!\n");
    do_shutdown ();
    return;
  }

  if (GNUNET_OK != GNUNET_CONFIGURATION_write ((struct GNUNET_CONFIGURATION_Handle *)cfg,
                              tmp_cfgfile))
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Failed to write tmp cfg\n");
    do_shutdown ();
    return;
  }

  proxy_proc = GNUNET_OS_start_process (GNUNET_NO,
                                        GNUNET_OS_INHERIT_STD_ALL,
                                        NULL,
                                        NULL,
                                        NULL,
                                        "gnunet-gns-proxy",
                                        "gnunet-gns-proxy",
                                        "-c", tmp_cfgfile, NULL);

  if (NULL == proxy_proc)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Unable to start proxy\n");
    do_shutdown ();
    return;
  }

  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
                                                            "ZONEKEY",
                                                            &zone_keyfile))
  {
    GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Failed to get key from cfg\n");
    return;
  }

  host_key = GNUNET_CRYPTO_ecdsa_key_create_from_file (zone_keyfile);
  rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
  GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_string_to_value (GNUNET_DNSPARSER_TYPE_A,
                                                               "127.0.0.1",
                                                               (void**)&rd.data,
                                                               &rd.data_size));
  rd.record_type = GNUNET_DNSPARSER_TYPE_A;

  GNUNET_NAMESTORE_record_create (namestore,
                                  host_key,
                                  "www",
                                  &rd,
                                  &commence_testing,
                                  NULL);

  GNUNET_free ((void**)rd.data);
  GNUNET_free (zone_keyfile);
  GNUNET_free (host_key);
}
Exemple #3
0
/**
 * Convert human-readable version of a 'value' of a record to the binary
 * representation.
 *
 * @param cls closure, unused
 * @param type type of the record
 * @param s human-readable string
 * @param data set to value in binary encoding (will be allocated)
 * @param data_size set to number of bytes in @a data
 * @return #GNUNET_OK on success
 */
static int
gns_string_to_value (void *cls,
                     uint32_t type,
                     const char *s,
                     void **data,
                     size_t *data_size)
{
  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;

  if (NULL == s)
    return GNUNET_SYSERR;
  switch (type)
  {

  case GNUNET_GNSRECORD_TYPE_PKEY:
    if (GNUNET_OK !=
	GNUNET_CRYPTO_ecdsa_public_key_from_string (s, strlen (s), &pkey))
    {
      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
           _("Unable to parse PKEY record `%s'\n"),
           s);
      return GNUNET_SYSERR;
    }
    *data = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
    memcpy (*data, &pkey, sizeof (pkey));
    *data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
    return GNUNET_OK;

  case GNUNET_GNSRECORD_TYPE_NICK:
    *data = GNUNET_strdup (s);
    *data_size = strlen (s);
    return GNUNET_OK;
  case GNUNET_GNSRECORD_TYPE_LEHO:
    *data = GNUNET_strdup (s);
    *data_size = strlen (s);
    return GNUNET_OK;
  case GNUNET_GNSRECORD_TYPE_GNS2DNS:
    {
      char nsbuf[514];
      char *cpy;
      char *at;
      size_t off;

      cpy = GNUNET_strdup (s);
      at = strchr (cpy, '@');
      if (NULL == at)
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Unable to parse GNS2DNS record `%s'\n"),
                    s);
        GNUNET_free (cpy);
        return GNUNET_SYSERR;
      }
      *at = '\0';
      at++;

      off = 0;
      if ( (GNUNET_OK !=
            GNUNET_DNSPARSER_builder_add_name (nsbuf,
                                               sizeof (nsbuf),
                                               &off,
                                               cpy)) ||
           (GNUNET_OK !=
            GNUNET_DNSPARSER_builder_add_name (nsbuf,
                                               sizeof (nsbuf),
                                               &off,
                                               at)) )
      {
	GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Failed to serialize GNS2DNS record with value `%s'\n"),
                    s);
        GNUNET_free (cpy);
	return GNUNET_SYSERR;
      }
      GNUNET_free (cpy);
      *data_size = off;
      *data = GNUNET_malloc (off);
      memcpy (*data, nsbuf, off);
      return GNUNET_OK;
    }
  case GNUNET_GNSRECORD_TYPE_VPN:
    {
      struct GNUNET_TUN_GnsVpnRecord *vpn;
      char s_peer[103 + 1];
      char s_serv[253 + 1];
      unsigned int proto;

      if (3 != SSCANF (s,
                       "%u %103s %253s",
                       &proto, s_peer, s_serv))
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Unable to parse VPN record string `%s'\n"),
                    s);
        return GNUNET_SYSERR;
      }
      *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
      *data = vpn = GNUNET_malloc (*data_size);
      if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
                                                                   strlen (s_peer),
                                                                   &vpn->peer.public_key))
      {
        GNUNET_free (vpn);
        *data_size = 0;
        return GNUNET_SYSERR;
      }
      vpn->proto = htons ((uint16_t) proto);
      strcpy ((char*)&vpn[1], s_serv);
      return GNUNET_OK;
    }
  case GNUNET_GNSRECORD_TYPE_BOX:
    {
      struct GNUNET_GNSRECORD_BoxRecord *box;
      size_t rest;
      unsigned int protocol;
      unsigned int service;
      unsigned int record_type;
      void *bval;
      size_t bval_size;

      if (3 != SSCANF (s,
                       "%u %u %u ",
                       &protocol,
                       &service,
                       &record_type))
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Unable to parse BOX record string `%s'\n"),
                    s);
        return GNUNET_SYSERR;
      }
      rest = snprintf (NULL, 0,
                       "%u %u %u ",
                       protocol,
                       service,
                       record_type);
      if (GNUNET_OK !=
          GNUNET_GNSRECORD_string_to_value (record_type,
                                            &s[rest],
                                            &bval,
                                            &bval_size))
        return GNUNET_SYSERR;
      *data_size = sizeof (struct GNUNET_GNSRECORD_BoxRecord) + bval_size;
      *data = box = GNUNET_malloc (*data_size);
      box->protocol = htons (protocol);
      box->service = htons (service);
      box->record_type = htonl (record_type);
      memcpy (&box[1],
              bval,
              bval_size);
      GNUNET_free (bval);
      return GNUNET_OK;
    }
  default:
    return GNUNET_SYSERR;
  }
}
Exemple #4
0
/**
 * Function called with the result from the check if the namestore
 * service is actually running.  If it is, we start the actual
 * operation.
 *
 * @param cls closure with our configuration
 * @param result #GNUNET_YES if the namestore service is running
 */
static void
testservice_task (void *cls,
                  int result)
{
  const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  struct GNUNET_GNSRECORD_Data rd;

  if (GNUNET_YES != result)
  {
    FPRINTF (stderr, _("Service `%s' is not running\n"),
	     "namestore");
    return;
  }
  if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)) )
  {
    /* nothing more to be done */
    fprintf (stderr,
             _("No options given\n"));
    GNUNET_SCHEDULER_shutdown ();
    return;
  }
  GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
                                    &pub);

  ns = GNUNET_NAMESTORE_connect (cfg);
  if (NULL == ns)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Failed to connect to namestore\n"));
    return;
  }
  if (add)
  {
    if (NULL == name)
    {
      fprintf (stderr,
               _("Missing option `%s' for operation `%s'\n"),
               "-n", _("add"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (NULL == typestring)
    {
      fprintf (stderr,
	       _("Missing option `%s' for operation `%s'\n"),
	       "-t", _("add"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    type = GNUNET_GNSRECORD_typename_to_number (typestring);
    if (UINT32_MAX == type)
    {
      fprintf (stderr, _("Unsupported type `%s'\n"), typestring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (NULL == value)
    {
      fprintf (stderr,
	       _("Missing option `%s' for operation `%s'\n"),
	       "-V", _("add"));
      ret = 1;
      GNUNET_SCHEDULER_shutdown ();
      return;
    }
    if (GNUNET_OK !=
	GNUNET_GNSRECORD_string_to_value (type,
					  value,
					  &data,
					  &data_size))
    {
      fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
	       value,
	       typestring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (NULL == expirationstring)
    {
      fprintf (stderr,
	       _("Missing option `%s' for operation `%s'\n"),
	       "-e", _("add"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (0 == strcmp (expirationstring, "never"))
    {
      etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
      etime_is_rel = GNUNET_NO;
    }
    else if (GNUNET_OK ==
             GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
                                                    &etime_rel))
    {
      etime_is_rel = GNUNET_YES;
    }
    else if (GNUNET_OK ==
             GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
                                                    &etime_abs))
    {
      etime_is_rel = GNUNET_NO;
    }
    else
    {
      fprintf (stderr,
               _("Invalid time format `%s'\n"),
               expirationstring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    add_qe = GNUNET_NAMESTORE_records_lookup (ns, &zone_pkey, name,
        &get_existing_record, NULL );
  }
  if (del)
  {
    if (NULL == name)
    {
      fprintf (stderr,
               _("Missing option `%s' for operation `%s'\n"),
               "-n", _("del"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    del_qe = GNUNET_NAMESTORE_records_lookup (ns,
                                              &zone_pkey,
                                              name,
                                              &del_monitor,
                                              NULL);
  }
  if (list)
  {
    list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
                                                     &zone_pkey,
                                                     &display_record,
                                                     NULL);
  }
  if (NULL != reverse_pkey)
  {
    struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;

    if (GNUNET_OK !=
        GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_pkey,
                                                       strlen (reverse_pkey),
                                                       &pubkey))
    {
      fprintf (stderr,
               _("Invalid public key for reverse lookup `%s'\n"),
               reverse_pkey);
      GNUNET_SCHEDULER_shutdown ();
    }
    reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
                                                &zone_pkey,
                                                &pubkey,
                                                &handle_reverse_lookup,
                                                NULL);
  }
  if (NULL != uri)
  {
    char sh[105];
    char sname[64];
    struct GNUNET_CRYPTO_EcdsaPublicKey pkey;

    GNUNET_STRINGS_utf8_tolower (uri, uri);
    if ( (2 != (sscanf (uri,
                        "gnunet://gns/%52s/%63s",
                        sh,
                        sname)) ) ||
         (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (sh, strlen (sh), &pkey)) )
    {
      fprintf (stderr,
               _("Invalid URI `%s'\n"),
               uri);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    memset (&rd, 0, sizeof (rd));
    rd.data = &pkey;
    rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
    rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
    if (GNUNET_YES == etime_is_rel)
    {
      rd.expiration_time = etime_rel.rel_value_us;
      rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
    }
    else if (GNUNET_NO == etime_is_rel)
      rd.expiration_time = etime_abs.abs_value_us;
    else
      rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;

    if (1 == is_shadow)
      rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
    add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
						 &zone_pkey,
						 sname,
						 1,
						 &rd,
						 &add_continuation,
						 &add_qe_uri);
  }
  if (NULL != nickstring)
  {
    if (0 == strlen(nickstring))
    {
      fprintf (stderr,
               _("Invalid nick `%s'\n"),
               nickstring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    add_qe_uri = GNUNET_NAMESTORE_set_nick(ns, &zone_pkey, nickstring,
        &add_continuation, &add_qe_uri);
  }
  if (monitor)
  {
    zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
					      &zone_pkey,
                                              GNUNET_YES,
					      &display_record,
					      &sync_cb,
					      NULL);
  }
}
Exemple #5
0
/**
 * Convert human-readable version of a 'value' of a record to the binary
 * representation.
 *
 * @param cls closure, unused
 * @param type type of the record
 * @param s human-readable string
 * @param data set to value in binary encoding (will be allocated)
 * @param data_size set to number of bytes in @a data
 * @return #GNUNET_OK on success
 */
static int
gns_string_to_value (void *cls,
                     uint32_t type,
                     const char *s,
                     void **data,
                     size_t *data_size)
{
  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;

  if (NULL == s)
    return GNUNET_SYSERR;
  switch (type)
  {

    case GNUNET_GNSRECORD_TYPE_PKEY:
      if (GNUNET_OK !=
          GNUNET_CRYPTO_ecdsa_public_key_from_string (s, strlen (s), &pkey))
      {
        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                    _("Unable to parse PKEY record `%s'\n"),
                    s);
        return GNUNET_SYSERR;
      }
      *data = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey);
      GNUNET_memcpy (*data, &pkey, sizeof (pkey));
      *data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
      return GNUNET_OK;

    case GNUNET_GNSRECORD_TYPE_NICK:
      *data = GNUNET_strdup (s);
      *data_size = strlen (s);
      return GNUNET_OK;
    case GNUNET_GNSRECORD_TYPE_LEHO:
      *data = GNUNET_strdup (s);
      *data_size = strlen (s);
      return GNUNET_OK;
    case GNUNET_GNSRECORD_TYPE_GNS2DNS:
      {
        char nsbuf[514];
        char *cpy;
        char *at;
        size_t off;

        cpy = GNUNET_strdup (s);
        at = strchr (cpy, '@');
        if (NULL == at)
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Unable to parse GNS2DNS record `%s'\n"),
                      s);
          GNUNET_free (cpy);
          return GNUNET_SYSERR;
        }
        *at = '\0';
        at++;

        off = 0;
        if ( (GNUNET_OK !=
              GNUNET_DNSPARSER_builder_add_name (nsbuf,
                                                 sizeof (nsbuf),
                                                 &off,
                                                 cpy)) ||
             (GNUNET_OK !=
              GNUNET_DNSPARSER_builder_add_name (nsbuf,
                                                 sizeof (nsbuf),
                                                 &off,
                                                 at)) )
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Failed to serialize GNS2DNS record with value `%s'\n"),
                      s);
          GNUNET_free (cpy);
          return GNUNET_SYSERR;
        }
        GNUNET_free (cpy);
        *data_size = off;
        *data = GNUNET_malloc (off);
        GNUNET_memcpy (*data, nsbuf, off);
        return GNUNET_OK;
      }
    case GNUNET_GNSRECORD_TYPE_VPN:
      {
        struct GNUNET_TUN_GnsVpnRecord *vpn;
        char s_peer[103 + 1];
        char s_serv[253 + 1];
        unsigned int proto;

        if (3 != SSCANF (s,
                         "%u %103s %253s",
                         &proto, s_peer, s_serv))
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Unable to parse VPN record string `%s'\n"),
                      s);
          return GNUNET_SYSERR;
        }
        *data_size = sizeof (struct GNUNET_TUN_GnsVpnRecord) + strlen (s_serv) + 1;
        *data = vpn = GNUNET_malloc (*data_size);
        if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string ((char*) s_peer,
                                                                     strlen (s_peer),
                                                                     &vpn->peer.public_key))
        {
          GNUNET_free (vpn);
          *data_size = 0;
          return GNUNET_SYSERR;
        }
        vpn->proto = htons ((uint16_t) proto);
        strcpy ((char*)&vpn[1], s_serv);
        return GNUNET_OK;
      }
    case GNUNET_GNSRECORD_TYPE_BOX:
      {
        struct GNUNET_GNSRECORD_BoxRecord *box;
        size_t rest;
        unsigned int protocol;
        unsigned int service;
        unsigned int record_type;
        void *bval;
        size_t bval_size;

        if (3 != SSCANF (s,
                         "%u %u %u ",
                         &protocol,
                         &service,
                         &record_type))
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Unable to parse BOX record string `%s'\n"),
                      s);
          return GNUNET_SYSERR;
        }
        rest = snprintf (NULL, 0,
                         "%u %u %u ",
                         protocol,
                         service,
                         record_type);
        if (GNUNET_OK !=
            GNUNET_GNSRECORD_string_to_value (record_type,
                                              &s[rest],
                                              &bval,
                                              &bval_size))
          return GNUNET_SYSERR;
        *data_size = sizeof (struct GNUNET_GNSRECORD_BoxRecord) + bval_size;
        *data = box = GNUNET_malloc (*data_size);
        box->protocol = htons (protocol);
        box->service = htons (service);
        box->record_type = htonl (record_type);
        GNUNET_memcpy (&box[1],
                       bval,
                       bval_size);
        GNUNET_free (bval);
        return GNUNET_OK;
      }
    case GNUNET_GNSRECORD_TYPE_REVERSE:
      {
        struct GNUNET_GNSRECORD_ReverseRecord *rev;
        char known_by[253 + 1];
        struct GNUNET_TIME_Absolute expiration;

        /* TODO: From crypto_ecc.c
         * Why is this not a constant???
         */
        size_t enclen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
        if (enclen % 5 > 0)
          enclen += 5 - enclen % 5;
        enclen /= 5; /* 260/5 = 52 */
        char pkey_str[enclen + 1];

        if (3 != SSCANF (s,
                         "%253s %52s %"SCNu64,
                         known_by,
                         pkey_str,
                         &expiration.abs_value_us))
        {
          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                      _("Unable to parse REVERSE record string `%s'\n"),
                      s);
          return GNUNET_SYSERR;
        }
        *data_size = sizeof (struct GNUNET_GNSRECORD_ReverseRecord) + strlen (known_by) + 1;
        *data = rev = GNUNET_malloc (*data_size);
        GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey_str,
                                                    strlen (pkey_str),
                                                    &rev->pkey);
        rev->expiration = expiration;
        GNUNET_memcpy (&rev[1],
                       known_by,
                       strlen (known_by));
        return GNUNET_OK;
      }
    default:
      return GNUNET_SYSERR;
  }
}