/*
 *  assert_ptr_in_answer asserts that a PTR record was
 *  returned in the answer sections.
 */
void assert_ptr_in_answer(struct extracted_response *ex_response)
{
  uint32_t ancount;
  size_t length;
  struct getdns_dict *rr_dict;
  uint32_t type;
  uint32_t ptr_records = 0;
  size_t i;

  ASSERT_RC(getdns_dict_get_int(ex_response->header, "ancount", &ancount),
    GETDNS_RETURN_GOOD, "Failed to extract \"nscount\"");
  ck_assert_msg(ancount >= 1, "Expected ancount >= 1, got %d", ancount);

  ASSERT_RC(getdns_list_get_length(ex_response->answer, &length),
    GETDNS_RETURN_GOOD, "Failed to extract \"answer\" length");
  ck_assert_msg(length == ancount, "Expected \"answer\" length == ancount: %d, got %d", ancount, length);

  for(i = 0; i < length; i++)
  {
    ASSERT_RC(getdns_list_get_dict(ex_response->answer, i, &rr_dict),
      GETDNS_RETURN_GOOD, "Failed to extract \"answer\" record");
    ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type),
      GETDNS_RETURN_GOOD, "Failed to extract \"type\" from answer record");
    if(type == GETDNS_RRTYPE_PTR)
      ptr_records++;
  }

  ck_assert_msg(ptr_records == 1, "Expected to find one PTR record in answer section, got %d", ptr_records);
}
/*
 *  assert_soa_in_authority asserts that a SOA record was
 *  returned in the authority sections.
 */
void assert_soa_in_authority(struct extracted_response *ex_response)
{
  uint32_t nscount;
  size_t length;
  struct getdns_dict *rr_dict;
  uint32_t type;
  uint32_t soa_records = 0;
  size_t i;

  ASSERT_RC(getdns_dict_get_int(ex_response->header, "nscount", &nscount),
    GETDNS_RETURN_GOOD, "Failed to extract \"nscount\"");
  ck_assert_msg(nscount >= 1, "Expected nscount >= 1, got %d", nscount);

  ASSERT_RC(getdns_list_get_length(ex_response->authority, &length),
    GETDNS_RETURN_GOOD, "Failed to extract \"authority\" length");
  ck_assert_msg(length == nscount, "Expected \"authority\" length == nscount: %d, got %d", nscount, length);

  for(i = 0; i < length; i++)
  {
    ASSERT_RC(getdns_list_get_dict(ex_response->authority, i, &rr_dict),
      GETDNS_RETURN_GOOD, "Failed to extract \"authority\" record");
    ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type),
      GETDNS_RETURN_GOOD, "Failed to extract \"type\" from authority record");
    if(type == GETDNS_RRTYPE_SOA)
      soa_records++;
  }

  ck_assert_msg(soa_records == 1, "Expected to find one SOA record in authority section, got %d", soa_records);
}
/*
 *  extract_response extracts all of the various information
 *  a test may want to look at from the response.
 */
void extract_response(struct getdns_dict *response, struct extracted_response *ex_response)
{
  ck_assert_msg(response != NULL, "Response should not be NULL");

  ASSERT_RC(getdns_dict_get_int(response, "answer_type", &ex_response->top_answer_type),
    GETDNS_RETURN_GOOD, "Failed to extract \"top answer_type\"");

  ASSERT_RC(getdns_dict_get_bindata(response, "canonical_name", &ex_response->top_canonical_name),
    GETDNS_RETURN_GOOD, "Failed to extract \"top canonical_name\"");

  ASSERT_RC(getdns_dict_get_list(response, "just_address_answers", &ex_response->just_address_answers),
    GETDNS_RETURN_GOOD, "Failed to extract \"just_address_answers\"");
  ck_assert_msg(ex_response->just_address_answers != NULL, "just_address_answers should not be NULL");

  ASSERT_RC(getdns_dict_get_list(response, "replies_full", &ex_response->replies_full),
    GETDNS_RETURN_GOOD, "Failed to extract \"replies_full\"");
  ck_assert_msg(ex_response->replies_full != NULL, "replies_full should not be NULL");

  ASSERT_RC(getdns_dict_get_list(response, "replies_tree", &ex_response->replies_tree),
    GETDNS_RETURN_GOOD, "Failed to extract \"replies_tree\"");
  ck_assert_msg(ex_response->replies_tree != NULL, "replies_tree should not be NULL");

  ASSERT_RC(getdns_list_get_dict(ex_response->replies_tree, 0, &ex_response->replies_tree_sub_dict),
    GETDNS_RETURN_GOOD, "Failed to extract \"replies_tree[0]\"");
  ck_assert_msg(ex_response->replies_tree_sub_dict != NULL, "replies_tree[0] dict should not be NULL");

  ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "additional", &ex_response->additional),
    GETDNS_RETURN_GOOD, "Failed to extract \"additional\"");
  ck_assert_msg(ex_response->additional != NULL, "additional should not be NULL");

  ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "answer", &ex_response->answer),
    GETDNS_RETURN_GOOD, "Failed to extract \"answer\"");
  ck_assert_msg(ex_response->answer != NULL, "answer should not be NULL");

  ASSERT_RC(getdns_dict_get_int(ex_response->replies_tree_sub_dict, "answer_type", &ex_response->answer_type),
    GETDNS_RETURN_GOOD, "Failed to extract \"answer_type\"");

  ASSERT_RC(getdns_dict_get_list(ex_response->replies_tree_sub_dict, "authority", &ex_response->authority),
    GETDNS_RETURN_GOOD, "Failed to extract \"authority\"");
  ck_assert_msg(ex_response->authority != NULL, "authority should not be NULL");

  ASSERT_RC(getdns_dict_get_bindata(ex_response->replies_tree_sub_dict, "canonical_name", &ex_response->canonical_name),
    GETDNS_RETURN_GOOD, "Failed to extract \"canonical_name\"");

  ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "header", &ex_response->header),
    GETDNS_RETURN_GOOD, "Failed to extract \"header\"");
  ck_assert_msg(ex_response->header != NULL, "header should not be NULL");

  ASSERT_RC(getdns_dict_get_dict(ex_response->replies_tree_sub_dict, "question", &ex_response->question),
    GETDNS_RETURN_GOOD, "Failed to extract \"question\"");
  ck_assert_msg(ex_response->question != NULL, "question should not be NULL");

  ASSERT_RC(getdns_dict_get_int(response, "status", &ex_response->status),
    GETDNS_RETURN_GOOD, "Failed to extract \"status\"");
}
Beispiel #4
0
getdns_return_t
_getdns_get_pubkey_pinset_from_list(const getdns_list *pinset_list,
				    struct mem_funcs *mf,
				    sha256_pin_t **pinset_out)
{
	getdns_return_t r;
	size_t pins, i;
	sha256_pin_t *out = NULL, *onext = NULL;
	getdns_dict * pin;
	getdns_bindata * data = NULL;
	
	if (r = getdns_list_get_length(pinset_list, &pins), r)
		return r;
	for (i = 0; i < pins; i++)
	{
		if (r = getdns_list_get_dict(pinset_list, i, &pin), r)
			goto fail;
		/* does the pin have the right digest type? */
		if (r = getdns_dict_get_bindata(pin, "digest", &data), r)
			goto fail;
		if (data->size != sha256.size ||
		    memcmp(data->data, sha256.data, sha256.size)) {
			r = GETDNS_RETURN_INVALID_PARAMETER;
			goto fail;
		}
		/* if it does, is the value the right length? */
		if (r = getdns_dict_get_bindata(pin, "value", &data), r)
			goto fail;
		if (data->size != SHA256_DIGEST_LENGTH) {
			r = GETDNS_RETURN_INVALID_PARAMETER;
			goto fail;
		}
		/* make a new pin */
		onext = GETDNS_MALLOC(*mf, sha256_pin_t);
		if (onext == NULL) {
			r = GETDNS_RETURN_MEMORY_ERROR;
			goto fail;
		}
		onext->next = out;
		memcpy(onext->pin, data->data, SHA256_DIGEST_LENGTH);
		out = onext;
	}
	
	*pinset_out = out;
	return GETDNS_RETURN_GOOD;
 fail:
	while (out) {
		onext = out->next;
		GETDNS_FREE(*mf, out);
		out = onext;
	}
	return r;
}
Beispiel #5
0
getdns_return_t getdns_pubkey_pinset_sanity_check(
	const getdns_list* pinset,
	getdns_list* errorlist)
{
	size_t errorcount = 0, preverrs = 0, pins = 0, i;
	getdns_bindata err;
	getdns_dict * pin;
	getdns_bindata * data;

	if (errorlist)
		if (getdns_list_get_length(errorlist, &preverrs))
			return GETDNS_RETURN_INVALID_PARAMETER;
	
	if (getdns_list_get_length(pinset, &pins))
		PKP_SC_HARDERR("Can't get length of pinset",
			       GETDNS_RETURN_INVALID_PARAMETER);
	if (pins < 2)
		PKP_SC_ERR("This pinset has fewer than 2 pins");
	for (i = 0; i < pins; i++)
	{
		/* is it a dict? */
		if (getdns_list_get_dict(pinset, i, &pin)) {
			PKP_SC_ERR("Could not retrieve a pin");
		} else {
		/* does the pin have the right digest type? */
			if (getdns_dict_get_bindata(pin, "digest", &data)) {
				PKP_SC_ERR("Pin has no 'digest' entry");
			} else {
				if (data->size != sha256.size ||
				    memcmp(data->data, sha256.data, sha256.size))
					PKP_SC_ERR("Pin has 'digest' other than sha256");
			}
			/* if it does, is the value the right length? */
			if (getdns_dict_get_bindata(pin, "value", &data)) {
				PKP_SC_ERR("Pin has no 'value' entry");
			} else {
				if (data->size != SHA256_DIGEST_LENGTH)
					PKP_SC_ERR("Pin has the wrong size 'value' (should be 32 octets for sha256)");
			}
			
		/* should we choke if it has some other key? for
		 * extensibility, we will not treat this as an
		 * error.*/
		}
	}
	
	if (errorcount > 0)
		return GETDNS_RETURN_GENERIC_ERROR;
	return GETDNS_RETURN_GOOD;
}
Beispiel #6
0
Local<Value> GNUtil::convertToJSArray(struct getdns_list* list) {
    if (!list) {
        return Nan::Null();
    }
    size_t len;
    getdns_list_get_length(list, &len);
    Local<Array> array = Nan::New<Array>();
    for (size_t i = 0; i < len; ++i) {
        getdns_data_type type;
        getdns_list_get_data_type(list, i, &type);
        switch (type) {
            case t_bindata:
            {
                getdns_bindata* data = NULL;
                getdns_list_get_bindata(list, i, &data);
                array->Set(i, convertBinData(data, NULL));
                break;
            }
            case t_int:
            {
                uint32_t res = 0;
                getdns_list_get_int(list, i, &res);
                array->Set(i, Nan::New<Integer>(res));
                break;
            }
            case t_dict:
            {
                getdns_dict* dict = NULL;
                getdns_list_get_dict(list, i, &dict);
                array->Set(i, GNUtil::convertToJSObj(dict));
                break;
            }
            case t_list:
            {
                getdns_list* sublist = NULL;
                getdns_list_get_list(list, i, &sublist);
                array->Set(i, GNUtil::convertToJSArray(sublist));
                break;
            }
            default:
                break;
        }
    }
    return array;
}
/*
 *  assert_address_records_in_answer asserts that ancount in the header
 *  is >= 1, ancount is equal to the length of "answer", and that all of
 *  the records in the answer section are A and/or AAAA resource records
 *  based on the value of the a/aaaa arguments.
 */
void assert_address_in_answer(struct extracted_response *ex_response, int a, int aaaa)
{
  uint32_t ancount;
  size_t length;
  struct getdns_dict *rr_dict;
  uint32_t type;
  uint32_t address_records = 0;
  size_t i;

  ASSERT_RC(getdns_dict_get_int(ex_response->header, "ancount", &ancount),
    GETDNS_RETURN_GOOD, "Failed to extract \"ancount\"");
  ck_assert_msg(ancount >= 1, "Expected ancount >= 1, got %d", ancount);

  ASSERT_RC(getdns_list_get_length(ex_response->answer, &length),
    GETDNS_RETURN_GOOD, "Failed to extract \"answer\" length");
  ck_assert_msg(length == ancount, "Expected \"answer\" length == ancount: %d, got %d", ancount, length);

  for(i = 0; i < length; i++)
  {
    ASSERT_RC(getdns_list_get_dict(ex_response->answer, i, &rr_dict),
      GETDNS_RETURN_GOOD, "Failed to extract \"answer\" record");
    ASSERT_RC(getdns_dict_get_int(rr_dict, "type", &type),
      GETDNS_RETURN_GOOD, "Failed to extract \"type\" from answer record");
    switch (type)
    {
      case GETDNS_RRTYPE_A:
        if(a && type == GETDNS_RRTYPE_A)
          address_records++;
      case GETDNS_RRTYPE_AAAA:
        if(aaaa && type == GETDNS_RRTYPE_AAAA)
          address_records++;
    }
  }
  ck_assert_msg(ancount == address_records, "ancount: %d address records mismatch: %d",
    ancount, address_records);
}
Beispiel #8
0
/* Set up the callback function, which will also do the processing of the results */
void callback(getdns_context        *context,
              getdns_callback_type_t callback_type,
              getdns_dict           *response, 
              void                  *userarg,
              getdns_transaction_t   transaction_id)
{
	getdns_return_t r;  /* Holder for all function returns */
	getdns_list    *replies_tree;
	size_t          n_replies, i;

	(void) context; (void) userarg; /* unused parameters */

	switch(callback_type) {
	case GETDNS_CALLBACK_CANCEL:
		printf("Transaction with ID %"PRIu64" was cancelled.\n", transaction_id);
		return;
	case GETDNS_CALLBACK_TIMEOUT:
		printf("Transaction with ID %"PRIu64" timed out.\n", transaction_id);
		return;
	case GETDNS_CALLBACK_ERROR:
		printf("An error occurred for transaction ID %"PRIu64".\n", transaction_id);
		return;
	default: break;
	}
	assert( callback_type == GETDNS_CALLBACK_COMPLETE );

	if ((r = getdns_dict_get_list(response, "replies_tree", &replies_tree)))
		fprintf(stderr, "Could not get \"replies_tree\" from response");

	else if ((r = getdns_list_get_length(replies_tree, &n_replies)))
		fprintf(stderr, "Could not get replies_tree\'s length");

	else for (i = 0; i < n_replies && r == GETDNS_RETURN_GOOD; i++) {
		getdns_dict *reply;
		getdns_list *answer;
		size_t       n_answers, j;

		if ((r = getdns_list_get_dict(replies_tree, i, &reply)))
			fprintf(stderr, "Could not get address %zu from just_address_answers", i);

		else if ((r = getdns_dict_get_list(reply, "answer", &answer)))
			fprintf(stderr, "Could not get \"address_data\" from address");

		else if ((r = getdns_list_get_length(answer, &n_answers)))
			fprintf(stderr, "Could not get answer section\'s length");

		else for (j = 0; j < n_answers && r == GETDNS_RETURN_GOOD; j++) {
			getdns_dict    *rr;
			getdns_bindata *address = NULL;

			if ((r = getdns_list_get_dict(answer, j, &rr)))
				fprintf(stderr, "Could net get rr %zu from answer section", j);

			else if (getdns_dict_get_bindata(rr, "/rdata/ipv4_address", &address) == GETDNS_RETURN_GOOD)
				printf("The IPv4 address is ");

			else if (getdns_dict_get_bindata(rr, "/rdata/ipv6_address", &address) == GETDNS_RETURN_GOOD)
				printf("The IPv6 address is ");

			if (address) {
				char *address_str;
				if (!(address_str = getdns_display_ip_address(address))) {
					fprintf(stderr, "Could not convert second address to string");
					r = GETDNS_RETURN_MEMORY_ERROR;
					break;
				}
				printf("%s\n", address_str);
				free(address_str);
			}
		}
	}
	if (r) {
		assert( r != GETDNS_RETURN_GOOD );
		fprintf(stderr, ": %d\n", r);
	}
	getdns_dict_destroy(response); 
}
Beispiel #9
0
static getdns_return_t validate_chain(getdns_dict *response)
{
	getdns_return_t r;
	getdns_list *validation_chain;
	getdns_list *replies_tree;
	getdns_dict *reply;
	getdns_list *to_validate;
	getdns_list *trust_anchor;
	size_t i;
	int s;
	
	if (!(to_validate = getdns_list_create()))
		return GETDNS_RETURN_MEMORY_ERROR;

	trust_anchor = getdns_root_trust_anchor(NULL);

	if ((r = getdns_dict_get_list(
	    response, "validation_chain", &validation_chain)))
		goto error;

	if ((r = getdns_dict_get_list(
	    response, "replies_tree", &replies_tree)))
		goto error;

	fprintf(stdout, "replies_tree dnssec_status: ");
	switch ((s = getdns_validate_dnssec(
	    replies_tree, validation_chain, trust_anchor))) {

	case GETDNS_DNSSEC_SECURE:
		fprintf(stdout, "GETDNS_DNSSEC_SECURE\n");
		break;
	case GETDNS_DNSSEC_BOGUS:
		fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n");
		break;
	case GETDNS_DNSSEC_INDETERMINATE:
		fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n");
		break;
	case GETDNS_DNSSEC_INSECURE:
		fprintf(stdout, "GETDNS_DNSSEC_INSECURE\n");
		break;
	case GETDNS_DNSSEC_NOT_PERFORMED:
		fprintf(stdout, "GETDNS_DNSSEC_NOT_PERFORMED\n");
		break;
	default:
		fprintf(stdout, "%d\n", (int)s);
	}

	i = 0;
	while (!(r = getdns_list_get_dict(replies_tree, i++, &reply))) {

		if ((r = getdns_list_set_dict(to_validate, 0, reply)))
			goto error;

		fprintf( stdout
		       , "reply %zu, dnssec_status: ", i);
		switch ((s = getdns_validate_dnssec(
		    to_validate, validation_chain, trust_anchor))) {

		case GETDNS_DNSSEC_SECURE:
			fprintf(stdout, "GETDNS_DNSSEC_SECURE\n");
			break;
		case GETDNS_DNSSEC_BOGUS:
			fprintf(stdout, "GETDNS_DNSSEC_BOGUS\n");
			break;
		case GETDNS_DNSSEC_INDETERMINATE:
			fprintf(stdout, "GETDNS_DNSSEC_INDETERMINATE\n");
			break;
		case GETDNS_DNSSEC_INSECURE:
			fprintf(stdout, "GETDNS_DNSSEC_INSECURE\n");
			break;
		case GETDNS_DNSSEC_NOT_PERFORMED:
			fprintf(stdout, "GETDNS_DNSSEC_NOT_PERFORMED\n");
			break;
		default:
			fprintf(stdout, "%d\n", (int)s);
		}
	}
	if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM)
		r = GETDNS_RETURN_GOOD;
error:
	getdns_list_destroy(trust_anchor);
	getdns_list_destroy(to_validate);

	return GETDNS_RETURN_GOOD;
}
Beispiel #10
0
/*---------------------------------------- getkeyviadane
  fetch the smime/a key identified by the encoded keyid and host name
  populate *certtxt with the key record, caller must free certtxt
*/
void
getkeyviadane(char *dname, int rrtype, char **certtxt)
{
    int      i;
    uint32_t status;
    size_t   nans;
    size_t   numrrs;
    int      rrnum;
    char     getdnserr[MAX_ERROR_STRING+1];
    uint32_t recrrtype;
    getdns_return_t getdnsret;
    getdns_context  *getdnsctx = NULL;
    getdns_dict     *getdnsrsp = NULL;
    getdns_dict     *dnsrec    = NULL;
    getdns_dict     *rr        = NULL;
    getdns_dict     *rrdata    = NULL;
    getdns_list     *dnsreplytree = NULL;
    getdns_list     *dnsans    = NULL;
    getdns_bindata  *rawrdata  = NULL;

    *certtxt = NULL;

    // create the context for DNS resolution using local OS system settings

    getdnsret = getdns_context_create(&getdnsctx, 1);
    if(getdnsret != GETDNS_RETURN_GOOD)
    {
        getdns_strerror(getdnsret, getdnserr, MAX_ERROR_STRING);
        fprintf(stderr, "error creating getdns context, %d, %s\n"
         , getdnsret, getdnserr);
        return;
    }

    // getdns_context_set_resolution_type(getdnsctx, GETDNS_RESOLUTION_STUB);

    // perform the DNS resolution request

    getdnsret = getdns_general_sync(getdnsctx, dname, rrtype, NULL, &getdnsrsp);
    if(getdnsret != GETDNS_RETURN_GOOD)
    {
        getdns_strerror(getdnsret, getdnserr, MAX_ERROR_STRING);
        fprintf(stderr, "DNS request failed, %d, %s\n", getdnsret, getdnserr);

        getdns_dict_destroy(getdnsrsp);
        getdns_context_destroy(getdnsctx);

        return;
    }

    // sanity check the result of the query

    getdnsret = getdns_dict_get_int(getdnsrsp, (char *) "status", &status);
    if(getdnsret != GETDNS_RETURN_GOOD || status != GETDNS_RESPSTATUS_GOOD)
    {
        fprintf(stderr, "DNS request did not return results\n");

        getdns_dict_destroy(getdnsrsp);
        getdns_context_destroy(getdnsctx);

        return;
    }

    getdnsret = getdns_dict_get_list(getdnsrsp, (char *)"replies_tree", &dnsreplytree);
    if(getdnsret != GETDNS_RETURN_GOOD)
    {
        fprintf(stderr, "DNS reply tree empty\n");

        getdns_dict_destroy(getdnsrsp);
        getdns_context_destroy(getdnsctx);

        return;
    }

    nans = 0;
    getdns_list_get_length(dnsreplytree, &nans); 
    for(i=0; i<nans && *certtxt == NULL; i++)
    {
        // extract a record from the reply tree, extract answer from that record

        getdns_list_get_dict(dnsreplytree, i, &dnsrec);

        getdnsret = getdns_dict_get_list(dnsrec, (char *)"answer", &dnsans);
        if(getdnsret != GETDNS_RETURN_GOOD)
        {
            fprintf(stderr, "answer missing from DNS reply tree, exiting\n");
            exit(1);
        }

        // walk the RRs in the DNS answer

        getdns_list_get_length(dnsans, &numrrs);
        for(rrnum=0; rrnum < numrrs && *certtxt == NULL; rrnum++)
        {
            getdns_list_get_dict(dnsans, rrnum, &rr);
            recrrtype = 0;
            getdns_dict_get_int(rr, (char *)"type", &recrrtype);
            if(recrrtype == rrtype)
            {
                getdns_dict_get_dict(rr, (char *)"rdata", &rrdata);
                getdnsret = getdns_dict_get_bindata(rrdata, (char *)"rdata_raw"
                 , &rawrdata);
                if(getdnsret != GETDNS_RETURN_GOOD)
                {
                    fprintf(stderr, "error, rdata missing address\n");
                }
                else
                {
                    *certtxt = (char *) malloc(rawrdata->size + 1);
                    memcpy(*certtxt, rawrdata->data, rawrdata->size);
                    *certtxt[rawrdata->size] = '\0';
                }
            }
        } // for rrnum
    } // for i in nans

    getdns_dict_destroy(getdnsrsp);
    getdns_context_destroy(getdnsctx);

    return;
} // getkeyviadane
Beispiel #11
0
/**
 * test the dict get and set routines 
 */
void
tst_dictsetget(void)
{
	char msg[TSTMSGBUF];
	size_t index = 0;
	uint32_t ans_int;
	getdns_return_t retval;
	struct getdns_list *list = NULL;
	struct getdns_dict *dict = NULL;
	struct getdns_dict *ansdict = NULL;

	tstmsg_case_begin("tst_dictsetget");

	list = getdns_list_create();
	dict = getdns_dict_create();

	/* test dict get function against empty list and with bogus params */

	tstmsg_case_msg("getdns_list_get_dict() empty list");
	retval = getdns_list_get_dict(NULL, index, &dict);
	snprintf(msg, sizeof(msg), "getdns_list_get_dict(NULL, index, &dict),retval = %d",
	    retval);
	tstmsg_case_msg(msg);

	retval = getdns_list_get_dict(list, index, NULL);
	snprintf(msg, sizeof(msg), "getdns_list_get_dict(list, index, NULL),retval = %d",
	    retval);
	tstmsg_case_msg(msg);

	tstmsg_case_msg("getdns_list_get_dict(list, 0, &dict)");
	retval = getdns_list_get_dict(list, 0, &dict);
	snprintf(msg, sizeof(msg), "getdns_list_get_dict,retval = %d", retval);
	tstmsg_case_msg(msg);

	tstmsg_case_msg("getdns_list_get_dict(list, 1, &dict)");
	retval = getdns_list_get_dict(list, 1, &dict);
	snprintf(msg, sizeof(msg), "getdns_list_get_dict,retval = %d", retval);
	tstmsg_case_msg(msg);

	/* test int set function against empty list with bogus params */

	tstmsg_case_msg("getdns_list_set_dict(list, 0, dict)");
	retval = getdns_list_set_dict(list, -1, dict);
	snprintf(msg, sizeof(msg), "getdns_list_set_dict,retval = %d", retval);
	tstmsg_case_msg(msg);

	tstmsg_case_msg("getdns_list_set_dict(list, 1, dict)");
	retval = getdns_list_set_dict(list, 1, dict);
	snprintf(msg, sizeof(msg), "getdns_list_set_dict,retval = %d", retval);
	tstmsg_case_msg(msg);

	/* test set and get legitimate use case */

	getdns_dict_set_int(dict, "foo", 42);
	getdns_list_set_dict(list, index, dict);
	retval = getdns_list_get_dict(list, index, &ansdict);
	getdns_dict_get_int(ansdict, "foo", &ans_int);
	snprintf(msg, sizeof(msg), "getdns_list_set/get_dict,retval=%d, ans=%d", retval,
	    ans_int);
	tstmsg_case_msg(msg);

	getdns_dict_destroy(dict);
	getdns_list_destroy(list);

	tstmsg_case_end();

	return;
}				/* tst_dictsetget */
int main(int argc, char const * const argv[])
{
	getdns_return_t r;
	getdns_dict    *rr_dict;
	getdns_bindata *dns_name;
	getdns_bindata  address = { 4, "\xb9\x31\x8d\x25" };
	getdns_bindata  fourth  = { 11, "last string" };
	size_t          length;
	char           *str;
	uint8_t        *wire, *prev_wire;
	size_t          wire_len;
	getdns_list    *rr_list;
	FILE           *in;
	uint8_t         wire_buf[8200];
	size_t          i;
	size_t          uavailable;
	int             available;
	char            str_buf[10000];
	int             str_len = sizeof(str_buf);

	/* Convert string to rr_dict
	 */
	if ((r = getdns_str2rr_dict(
	    "some.domain.tld. 60 IN TXT \"first string\" second \"and third\"",
	    &rr_dict, NULL, 3600)))
		FAIL_r("getdns_str2rr_dict");


	/* Add a fourth text element.
	 */
	if ((r = getdns_dict_set_bindata(rr_dict, "/rdata/txt_strings/-", &fourth)))
		FAIL_r("getdns_list_set_bindata");

	print_dict(rr_dict);


	/* Convert to wireformat from rdata_raw.
	 * Added fourth list element should NOT show.
	 */
	wire = NULL;
	if ((r = getdns_rr_dict2wire(rr_dict, &wire, &wire_len)))
		FAIL_r("getdns_rr_dict2wire");

	print_wire(wire, wire_len);
	free(wire);


	/* Convert to wireformat from parsing rdata fields.
	 * Added fourth list element should show.
	 */
	if ((r = getdns_dict_remove_name(rr_dict, "/rdata/rdata_raw")))
		FAIL_r("getdns_dict_remove_name");

	printf("\nremoved \"/rdata/rdata_raw\":\n\n");

	if ((r = getdns_rr_dict2wire(rr_dict, &wire, &wire_len)))
		FAIL_r("getdns_rr_dict2wire");

	print_wire(wire, wire_len);
	free(wire);


	/* Remove second and third string elements and show text format.
	 */
	if ((r = getdns_dict_remove_name(rr_dict, "/rdata/txt_strings/1")))
		FAIL_r("getdns_dict_remove_name");
	if ((r = getdns_dict_remove_name(rr_dict, "/rdata/txt_strings/1")))
		FAIL_r("getdns_dict_remove_name");

	if ((r = getdns_rr_dict2str(rr_dict, &str)))
		FAIL_r("getdns_rr_dict2str");

	printf("\n%s", str);
	free(str);


	/* Remove all string elements and show text format.
	 */
	if ((r = getdns_dict_remove_name(rr_dict, "/rdata/txt_strings/0")))
		FAIL_r("getdns_dict_remove_name");
	if ((r = getdns_dict_remove_name(rr_dict, "/rdata/txt_strings/0")))
		FAIL_r("getdns_dict_remove_name");

	if ((r = getdns_rr_dict2str(rr_dict, &str)))
		FAIL_r("getdns_rr_dict2str");

	printf("%s", str);
	free(str);

	getdns_dict_destroy(rr_dict);

	/* Construct rr_dict and convert to string
	 */
	if (!(rr_dict = getdns_dict_create()))
		FAIL("getdns_dict_create returned NULL");

	if ((r = getdns_convert_fqdn_to_dns_name("www.getdnsapi.net", &dns_name)))
		FAIL_r("getdns_convert_fqdn_to_dns_name");

	r = getdns_dict_set_bindata(rr_dict, "name", dns_name);
	free(dns_name->data);
	free(dns_name);
	if (r)
		FAIL_r("getdns_dict_set_bindata");

	if ((r = getdns_dict_set_int(rr_dict, "type", GETDNS_RRTYPE_A)))
		FAIL_r("getdns_dict_set_int");

	if ((r = getdns_dict_set_bindata(rr_dict, "/rdata/ipv4_address", &address)))
		FAIL_r("getdns_dict_set_int");

	if ((r = getdns_rr_dict2str(rr_dict, &str)))
		FAIL_r("getdns_rr_dict2str");

	printf("\n%s\n", str);
	free(str);

	if ((r = getdns_rr_dict2wire(rr_dict, &wire, &wire_len)))
		FAIL_r("getdns_rr_dict2wire");

	getdns_dict_destroy(rr_dict);
	print_wire(wire, wire_len);
	free(wire);


	/* Convert RR with special rdata fields and repeating last element 
	 * from string to rr_dict
	 */
	if ((r = getdns_str2rr_dict(
	    "hip2 IN HIP 2 200100107B1A74DF365639CC39F1D578 AwEAAbdxyhNuSutc5EMzxTs9LBPCIkOFH8cIvM4p9+LrV4e19WzK00+CI6zBCQTdtWsuxKbWIy87UOoJTwkUs7lBu+Upr1gsNrut79ryra+bSRGQb1slImA8YVJyuIDsj7kwzG7jnERNqnWxZ48AWkskmdHaVDP4BcelrTI3rMXdXF5D rvs1.example.com. rvs2.example.com.",
	    &rr_dict, "nlnetlabs.nl", 3600)))
		FAIL_r("getdns_str2rr_dict");

	if ((r = getdns_dict_remove_name(rr_dict, "/rdata/rdata_raw")))
		FAIL_r("getdns_dict_remove_name");

	printf("\n");
	print_dict(rr_dict);

	/* Convert RR with special rdata fields and repeating last element
	 * back to string.
	 */
	if ((r = getdns_rr_dict2str(rr_dict, &str)))
		FAIL_r("getdns_rr_dict2str");

	printf("%s", str);
	free(str);


	/* Convert RR with special rdata fields without repeating last element
	 * to string.
	 */
	if ((r = getdns_dict_remove_name(rr_dict, "/rdata/rendezvous_servers")))
		FAIL_r("getdns_dict_remove_name");

	if ((r = getdns_dict_get_bindata(rr_dict, "name", &dns_name)))
		FAIL_r("getdns_dict_get_bindata");

	dns_name->data[4] = '0';

	if ((r = getdns_rr_dict2str(rr_dict, &str)))
		FAIL_r("getdns_rr_dict2str");

	printf("%s\n", str);
	free(str);
	getdns_dict_destroy(rr_dict);


	/* Convert RR with repeat block from string to rr_dict
	 */
	if ((r = getdns_str2rr_dict(
	    "apl APL 1:192.168.42.0/26 1:192.168.42.64/26 !1:192.168.42.128/25  1:224.0.0.0/4  2:FF00:0:0:0:0:0:0:0/8",
	    &rr_dict, "net-dns.org", 3600)))
		FAIL_r("getdns_str2rr_dict");

	if ((r = getdns_dict_remove_name(rr_dict, "/rdata/rdata_raw")))
		FAIL_r("getdns_dict_remove_name");

	print_dict(rr_dict);


	/* Convert repeat block from rr_dict back to string.
	 */
	if ((r = getdns_rr_dict2str(rr_dict, &str)))
		FAIL_r("getdns_rr_dict2str");

	printf("%s", str);
	free(str);
	getdns_dict_destroy(rr_dict);

	if (!(in = fopen(argv[1], "r")))
		FAIL("Could not fopen %s\n", argv[1]);

	if ((r = getdns_fp2rr_list(in, &rr_list, NULL, 0)))
		FAIL_r("getdns_fp2rr_list");

	fclose(in);

	print_list(rr_list);
	print_json_list(rr_list, 1);


	/* Fill the wire_buf with wireformat RR's in rr_list
	 * wire_buf is too small for last two rr's.
	 */
	wire = wire_buf;
	available = sizeof(wire_buf);

	for (i = 0; !(r = getdns_list_get_dict(rr_list, i, &rr_dict)); i++) {
		prev_wire = wire;
		if ((r = getdns_rr_dict2wire_scan(rr_dict,&wire,&available))) {
			if (r == GETDNS_RETURN_NEED_MORE_SPACE) {
				printf("record %.3zu, available buffer space: "
				       "%d\n", i, available);

				/* The buffer was too small to fit the wire-
				 * format representation.  available now holds
				 * a negative number.  the wire pointer is this
				 * much beyond the end of the buffer space.
				 *
				 * If we would add available to wire, wire
				 * would be positioned at the end of the buffer
				 * but would not be positioned at a clean RR
				 * border.  Therefore we have to remember the
				 * previous position of wire, so we can reset
				 * it at the end of the wireformat representa-
				 * tion of the previously converted rr_dict.
				 */
				wire = prev_wire;
				break;
			}
			else
				FAIL_r("getdns_rr_dict2wire_scan");
		}
		printf("record %3zu, available buffer space: "
		       "%d\n", i, available);
		fflush(stdout);
	}
	if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM)
		r = GETDNS_RETURN_GOOD;

	getdns_list_destroy(rr_list);

	/* Now scan over the wireformat buffer and convert to rr_dicts again.
	 * Then fill a string buffer with those rr_dicts.
	 */
	available = wire - wire_buf;
	if (available < 0) {
		fprintf(stderr, "Negative sized buffer!\n");
		exit(EXIT_FAILURE);
	}
	uavailable = available;
	wire = wire_buf;

	str = str_buf;
	str_len = sizeof(str_buf);

	while (uavailable > 0 && str_len > 0) {
		rr_dict = NULL;
		if ((r = getdns_wire2rr_dict_scan(
		    (const uint8_t **)&wire, &uavailable, &rr_dict)))
			FAIL_r("getdns_wire2rr_dict_scan");
		
		if ((r = getdns_rr_dict2str_scan(rr_dict, &str, &str_len)))
			FAIL_r("getdns_rr_dict2str_scan");

		getdns_dict_destroy(rr_dict);
	}
	*str = 0;

	/* Print the entire buffer */
	printf("%s", str_buf);

	exit(EXIT_SUCCESS);
}