示例#1
0
文件: various.c 项目: edwardt/pcp
void
setup_globals(pmOptions *opts)
{
	pmID		pmids[HOST_NMETRICS];
	pmDesc		descs[HOST_NMETRICS];
	pmResult	*result;

	setup_context(opts);
	setup_metrics(hostmetrics, &pmids[0], &descs[0], HOST_NMETRICS);
	fetch_metrics("host", HOST_NMETRICS, pmids, &result);

	if (HOST_NMETRICS != result->numpmid)
	{
		fprintf(stderr,
			"%s: pmFetch failed to fetch initial metric value(s)\n",
			pmProgname);
		cleanstop(1);
	}

	hertz = extract_integer(result, descs, HOST_HERTZ);
	pagesize = extract_integer(result, descs, HOST_PAGESIZE);
	extract_string(result, descs, HOST_RELEASE, sysname.release, sizeof(sysname.release));
	extract_string(result, descs, HOST_VERSION, sysname.version, sizeof(sysname.version));
	extract_string(result, descs, HOST_MACHINE, sysname.machine, sizeof(sysname.machine));
	extract_string(result, descs, HOST_NODENAME, sysname.nodename, sizeof(sysname.nodename));
	nodenamelen = strlen(sysname.nodename);

	pmFreeResult(result);
}
void load_database_contexts(Context_Map* context_map)
{
    int prefix_mask {};
    
    std::ifstream buf;
    buf.open(DBCONFIG_FILE);
    assert(buf.is_open());

    std::string line {};
    
    while (!buf.eof())
    {
        getline(buf,line);
        if (ignore_line(line)) continue;
        else if (str_contains(line,'@'))
        {
            int port {};
            std::string host {};
            int db_num {};
            
            // Complete at 00000111 (7)
            // One bit is set each time one of the above is found.
            // This allows for any number of newlines or comments.
            uint8_t completion {};
            Prefix p {match_prefix(prefix_mask, line)};
            while ((completion != 7) && !buf.eof())
            {
                getline(buf,line);
                if (ignore_line(line)) continue;
                else if (str_contains(line,"port"))
                {
                    port = extract_integer(line);
                    completion |= 1;
                }
                else if (str_contains(line, "number"))
                {
                    db_num = extract_integer(line);
                    completion |= 2;
                }
                else if (str_contains(line, "host"))
                {
                    host = extract_host(line);
                    completion |= 4;
                }
            }
            assert(completion==7);
            Redis::Context* c = new Redis::Context();
            c->port = port;
            c->host = host;
            c->db_num = db_num;
            context_map->set(p,c);
            assert(context_map->get(p));
        }
    }
    buf.close();
    assert(prefix_mask >= max_prefix_mask);
    assert(context_map);
}
示例#3
0
文件: dlv.c 项目: jelu/validns
static struct rr* dlv_parse(char *name, long ttl, int type, char *s)
{
    struct rr_dlv *rr = getmem(sizeof(*rr));
    int key_tag, algorithm, digest_type;

    key_tag = extract_integer(&s, "key tag", NULL);
    if (key_tag < 0)    return NULL;
    rr->key_tag = key_tag;

    algorithm = extract_algorithm(&s, "algorithm");
    if (algorithm == ALG_UNSUPPORTED)   return NULL;
    rr->algorithm = algorithm;

    digest_type = extract_integer(&s, "digest type", NULL);
    if (digest_type < 0)    return NULL;
    rr->digest_type = digest_type;

    rr->digest = extract_hex_binary_data(&s, "digest", EXTRACT_EAT_WHITESPACE);
    if (rr->digest.length < 0)  return NULL;

    switch (digest_type) {
    case 1:
        if (rr->digest.length != SHA1_BYTES) {
            return bitch("wrong SHA-1 digest length: %d bytes found, %d bytes expected", rr->digest.length, SHA1_BYTES);
        }
        break;
    case 2:
        if (rr->digest.length != SHA256_BYTES) {
            return bitch("wrong SHA-256 digest length: %d bytes found, %d bytes expected", rr->digest.length, SHA256_BYTES);
        }
        break;
    case 3:
        if (rr->digest.length != GOST_BYTES) {
            return bitch("wrong GOST R 34.11-94 digest length: %d bytes found, %d bytes expected", rr->digest.length, GOST_BYTES);
        }
        break;
    case 4:
        if (rr->digest.length != SHA384_BYTES) {
            return bitch("wrong SHA-384 digest length: %d bytes found, %d bytes expected", rr->digest.length, SHA384_BYTES);
        }
        break;
    default:
        return bitch("bad or unsupported digest type %d", digest_type);
    }

    if (*s) {
        return bitch("garbage after valid DLV data");
    }
    G.dnssec_active = 1;
    return store_record(type, name, ttl, rr);
}
示例#4
0
文件: naptr.c 项目: regnauld/validns
static struct rr *naptr_parse(char *name, long ttl, int type, char *s)
{
	struct rr_naptr *rr = getmem(sizeof(*rr));
	int i;
	struct binary_data text;

	i = extract_integer(&s, "order");
	if (i < 0)
		return NULL;
	if (i >= 65536)
		return bitch("order range is not valid");
	rr->order = i;

	i = extract_integer(&s, "preference");
	if (i < 0)
		return NULL;
	if (i >= 65536)
		return bitch("preference range is not valid");
	rr->preference = i;

	text = extract_text(&s, "flags");
	if (text.length < 0)
		return NULL;
	for (i = 0; i < text.length; i++) {
		if (!isalnum(text.data[i])) {
			return bitch("flags contains illegal characters");
		}
	}
	rr->flags = text;

	text = extract_text(&s, "services");
	if (text.length < 0)
		return NULL;
	rr->services = text;

	text = extract_text(&s, "regexp");
	if (text.length < 0)
		return NULL;
	rr->regexp = text;

	rr->replacement = extract_name(&s, "replacement");
	if (!rr->replacement)
		return NULL;

	if (*s) {
		return bitch("garbage after valid NAPTR data");
	}

	return store_record(type, name, ttl, rr);
}
示例#5
0
文件: soa.c 项目: jelu/validns
static struct rr* soa_parse(char *name, long ttl, int type, char *s)
{
    struct rr_soa *rr = getmem(sizeof(*rr));
    long long i;

    rr->mname = extract_name(&s, "mname", 0);
    if (!rr->mname) return NULL;
    rr->rname = extract_name(&s, "rname", 0);
    if (!rr->rname) return NULL;
    i = extract_integer(&s, "serial", NULL);
    if (i < 0) return NULL;
    if (i > 4294967295UL) return bitch("serial is out of range");
    rr->serial = i;
    rr->refresh = extract_timevalue(&s, "refresh");
    if (rr->refresh < 0) return NULL;
    rr->retry = extract_timevalue(&s, "retry");
    if (rr->retry < 0) return NULL;
    rr->expire = extract_timevalue(&s, "expire");
    if (rr->expire < 0) return NULL;
    rr->minimum = extract_timevalue(&s, "minimum");
    if (rr->minimum < 0) return NULL;
    if (ttl < 0 && G.opt.soa_minttl_as_default_ttl) {
        ttl = rr->minimum;
    }
    if (*s) {
        return bitch("garbage after valid SOA data");
    }
    return store_record(type, name, ttl, rr);
}
示例#6
0
文件: cert.c 项目: MikeAT/validns
static struct rr* cert_parse(char *name, long ttl, int type, char *s)
{
	struct rr_cert *rr = getmem(sizeof(*rr));
	int cert_type, key_tag, alg;

	cert_type = extract_certificate_type(&s, "certificate type");
	if (cert_type < 0)	return NULL;
	rr->type = cert_type;

	key_tag = extract_integer(&s, "key tag");
	if (key_tag < 0)	return NULL;
	if (key_tag > 65535)
		return bitch("bad key tag");
	rr->key_tag = key_tag;

	if (isdigit(*s)) {
		alg = extract_integer(&s, "algorithm");
		if (alg < 0)	return NULL;
		if (alg > 255)	return bitch("bad algorithm");
		if (alg != 0) {  /* 0 is just fine */
			if (algorithm_type(alg) == ALG_UNSUPPORTED)
				return bitch("bad algorithm %d", alg);
		}
	} else {
		alg = extract_algorithm(&s, "algorithm");
		if (alg == ALG_UNSUPPORTED)	return NULL;
	}
	rr->algorithm = alg;

	if (alg == 0 && key_tag != 0) {
		/* we might want to bitch here, but RFC says "SHOULD", so we don't */
	}

	rr->certificate = extract_base64_binary_data(&s, "certificate");
	if (rr->certificate.length < 0)	return NULL;
	/* TODO validate cert length based on algorithm */

	if (*s) {
		return bitch("garbage after valid CERT data");
	}
	return store_record(type, name, ttl, rr);
}
示例#7
0
文件: tlsa.c 项目: jelu/validns
static struct rr* tlsa_smimea_parse(char *name, long ttl, int type, char *s)
{
    struct rr_tlsa_smimea *rr = getmem(sizeof(*rr));
    int cert_usage, selector, matching_type;

    cert_usage = extract_integer(&s, "certificate usage field", NULL);
    if (cert_usage < 0) return NULL;
    if (cert_usage > 3)
        return bitch("bad certificate usage field");
    rr->cert_usage = cert_usage;

    selector = extract_integer(&s, "selector field", NULL);
    if (selector < 0)   return NULL;
    if (selector > 1)
        return bitch("bad selector field");
    rr->selector = selector;

    matching_type = extract_integer(&s, "matching type field", NULL);
    if (matching_type < 0)  return NULL;
    if (matching_type > 2)
        return bitch("bad matching type field");
    rr->matching_type = matching_type;

    rr->association_data = extract_hex_binary_data(&s, "certificate association data", EXTRACT_EAT_WHITESPACE);
    if (rr->association_data.length < 0)    return NULL;
    switch (rr->matching_type) {
    case 1:
        if (rr->association_data.length != SHA256_BYTES)
            return bitch("bad SHA-256 hash length");
        break;
    case 2:
        if (rr->association_data.length != SHA512_BYTES)
            return bitch("bad SHA-512 hash length");
        break;
    }

    if (*s) {
        return bitch("garbage after valid %s data", type == T_TLSA ? "TLSA" : "SMIMEA");
    }
    return store_record(type, name, ttl, rr);
}
示例#8
0
文件: srv.c 项目: MikeAT/validns
static struct rr *srv_parse(char *name, long ttl, int type, char *s)
{
	struct rr_srv *rr = getmem(sizeof(*rr));
	int i;

	/* TODO validate `name` (underscores etc) http://tools.ietf.org/html/rfc2782 */

	i = extract_integer(&s, "priority");
	if (i < 0)
		return NULL;
	if (i >= 65536)
		return bitch("priority range is not valid");
	rr->priority = i;

	i = extract_integer(&s, "weight");
	if (i < 0)
		return NULL;
	if (i >= 65536)
		return bitch("weight range is not valid");
	rr->weight = i;

	i = extract_integer(&s, "port");
	if (i < 0)
		return NULL;
	if (i >= 65536)
		return bitch("port range is not valid");
	rr->port = i;

	rr->target = extract_name(&s, "target", 0);
	if (!rr->target)
		return NULL;

	if (*s) {
		return bitch("garbage after valid SRV data");
	}

	return store_record(type, name, ttl, rr);
}
示例#9
0
文件: cert.c 项目: MikeAT/validns
static int extract_certificate_type(char **s, char *what)
{
	int type;
	char *str_type;

	if (isdigit(**s)) {
		type = extract_integer(s, what);
		if (type >= 1 && type <= 8)
			return type;
		if (type == 253 || type == 254)
			return type;
		if (type >= 65280 && type <= 65534)
			return type;
		if (type < 0 || type > 65535) {
			bitch("bad certificate type %d", type);
			return -1;
		}
		if (type == 0 || type == 255 || type == 65535) {
			bitch("certificate type %d is reserved by IANA", type);
			return -1;
		}
		bitch("certificate type %d is unassigned", type);
		return -1;
	} else {
		str_type = extract_label(s, what, "temporary");
		if (!str_type) return -1;
		if (strcmp(str_type, "pkix") == 0)
			return 1;
		if (strcmp(str_type, "spki") == 0)
			return 2;
		if (strcmp(str_type, "pgp") == 0)
			return 3;
		if (strcmp(str_type, "ipkix") == 0)
			return 4;
		if (strcmp(str_type, "ispki") == 0)
			return 5;
		if (strcmp(str_type, "ipgp") == 0)
			return 6;
		if (strcmp(str_type, "acpkix") == 0)
			return 7;
		if (strcmp(str_type, "iacpkix") == 0)
			return 8;
		if (strcmp(str_type, "uri") == 0)
			return 253;
		if (strcmp(str_type, "oid") == 0)
			return 254;
		bitch("bad certificate type %s", str_type);
		return -1;
	}
}
示例#10
0
文件: rt.c 项目: jelu/validns
static struct rr *rt_parse(char *name, long ttl, int type, char *s)
{
    struct rr_rt *rr = getmem(sizeof(*rr));

    rr->preference = extract_integer(&s, "RT preference", NULL);
    if (rr->preference < 0)
        return NULL;

    rr->intermediate_host = extract_name(&s, "intermediate-host", 0);
    if (!rr->intermediate_host)
        return NULL;
    if (*s) {
        return bitch("garbage after valid RT data");
    }

    return store_record(type, name, ttl, rr);
}
示例#11
0
文件: mx.c 项目: umq/validns
static struct rr *mx_parse(char *name, long ttl, int type, char *s)
{
	struct rr_mx *rr = getmem(sizeof(*rr));

	rr->preference = extract_integer(&s, "MX preference");
	if (rr->preference < 0)
		return NULL;
	/* XXX preference range check */
	rr->exchange = extract_name(&s, "MX exchange", 0);
	if (!rr->exchange)
		return NULL;
	if (*s) {
		return bitch("garbage after valid MX data");
	}

	return store_record(type, name, ttl, rr);
}
示例#12
0
文件: l64.c 项目: MikeAT/validns
static struct rr *l64_parse(char *name, long ttl, int type, char *s)
{
	struct rr_l64 *rr = getmem(sizeof(*rr));
	int preference;

	rr->preference = preference = extract_integer(&s, "L64 preference");
	if (preference < 0)
		return NULL;
	if (extract_u64(&s, "Locator64", &rr->locator64) < 0)
		return NULL;

	if (*s) {
		return bitch("garbage after valid L64 data");
	}

	return store_record(type, name, ttl, rr);
}
示例#13
0
文件: nid.c 项目: pieterlexis/validns
static struct rr *nid_parse(char *name, long ttl, int type, char *s)
{
	struct rr_nid *rr = getmem(sizeof(*rr));
	int preference;

	rr->preference = preference = extract_integer(&s, "NID preference", NULL);
	if (preference < 0)
		return NULL;
	if (extract_u64(&s, "NodeID", &rr->node_id) < 0)
		return NULL;

	if (*s) {
		return bitch("garbage after valid NID data");
	}

	return store_record(type, name, ttl, rr);
}
示例#14
0
文件: kx.c 项目: jelu/validns
static struct rr *kx_parse(char *name, long ttl, int type, char *s)
{
    struct rr_kx *rr = getmem(sizeof(*rr));

    rr->preference = extract_integer(&s, "KX preference", NULL);
    if (rr->preference < 0)
        return NULL;

    rr->exchanger = extract_name(&s, "KX exchanger", 0);
    if (!rr->exchanger)
        return NULL;

    if (*s) {
        return bitch("garbage after valid KX data");
    }

    return store_record(type, name, ttl, rr);
}
示例#15
0
文件: l32.c 项目: jelu/validns
static struct rr *l32_parse(char *name, long ttl, int type, char *s)
{
    struct rr_l32 *rr = getmem(sizeof(*rr));
    struct in_addr ipv4_like;
    int preference;

    rr->preference = preference = extract_integer(&s, "L32 preference", NULL);
    if (preference < 0)
        return NULL;
    if (extract_ipv4(&s, "Locator32", &ipv4_like) <= 0)
        return NULL;
    rr->locator32 = ipv4_like.s_addr;

    if (*s) {
        return bitch("garbage after valid L32 data");
    }

    return store_record(type, name, ttl, rr);
}
示例#16
0
文件: afsdb.c 项目: jelu/validns
static struct rr *afsdb_parse(char *name, long ttl, int type, char *s)
{
    struct rr_afsdb *rr = getmem(sizeof(*rr));

    rr->subtype = extract_integer(&s, "AFSDB subtype", NULL);
    if (rr->subtype < 0)
        return NULL;

    if (rr->subtype != 1 && rr->subtype != 2)
        return bitch("unknown AFSDB subtype");

    rr->hostname = extract_name(&s, "AFSDB hostname", 0);
    if (!rr->hostname)
        return NULL;

    if (*s) {
        return bitch("garbage after valid AFSDB data");
    }

    return store_record(type, name, ttl, rr);
}
示例#17
0
文件: px.c 项目: pieterlexis/validns
static struct rr *px_parse(char *name, long ttl, int type, char *s)
{
	struct rr_px *rr = getmem(sizeof(*rr));

	rr->preference = extract_integer(&s, "PX preference", NULL);
	if (rr->preference < 0)
		return NULL;

	rr->map822 = extract_name(&s, "map822", 0);
	if (!rr->map822)
		return NULL;

	rr->mapx400 = extract_name(&s, "mapx400", 0);
	if (!rr->mapx400)
		return NULL;

	if (*s) {
		return bitch("garbage after valid KX data");
	}

	return store_record(type, name, ttl, rr);
}
示例#18
0
static struct rr* dnskey_parse(char *name, long ttl, int type, char *s)
{
	struct rr_dnskey *rr = getmem(sizeof(*rr));
	struct binary_data key;
	int flags, proto, algorithm;
	unsigned int ac;
	int i;
	static struct rr *result;

	flags = extract_integer(&s, "flags");
	if (flags < 0) return NULL;
	if (flags & 0xfefe)
		return bitch("reserved flags bits are set");
	if (flags & 0x0001 && !(flags & 0x0100))
		return bitch("SEP bit is set but Zone Key bit is unset");
	rr->flags = flags;

	/* TODO validate that `name` is the name of the zone if flags have Zone Key bit set */

	proto = extract_integer(&s, "protocol");
	if (proto < 0) return NULL;
	if (proto != 3)
		return bitch("bad protocol value");
	rr->protocol = proto;

	algorithm = extract_algorithm(&s, "algorithm");
	if (algorithm == ALG_UNSUPPORTED)	return NULL;
	if (algorithm == ALG_PRIVATEDNS || algorithm == ALG_PRIVATEOID) {
		return bitch("private algorithms are not supported in DNSKEY");
	}
	rr->algorithm = algorithm;

	key = extract_base64_binary_data(&s, "public key");
	if (key.length < 0)	return NULL;
	/* TODO validate key length based on algorithm */
	rr->pubkey = key;

	ac = 0;
	ac += rr->flags;
	ac += rr->protocol << 8;
	ac += rr->algorithm;
	for (i = 0; i < rr->pubkey.length; i++) {
		ac += (i & 1) ? (unsigned char)rr->pubkey.data[i] : ((unsigned char)rr->pubkey.data[i]) << 8;
	}
	ac += (ac >> 16) & 0xFFFF;
	rr->key_tag = ac & 0xFFFF;

	rr->pkey_built = 0;
	rr->pkey = NULL;
	rr->key_type = KEY_TYPE_UNUSED;

	if (*s) {
		return bitch("garbage after valid DNSKEY data");
	}
	result = store_record(type, name, ttl, rr);
	if (result) {
		rr->next_key = all_dns_keys;
		all_dns_keys = rr;
	}
	return result;
}
示例#19
0
static struct rr *ipseckey_parse(char *name, long ttl, int type, char *s)
{
	struct rr_ipseckey *rr = getmem(sizeof(*rr));
	int i;

	rr->precedence = i = extract_integer(&s, "precedence", NULL);
	if (i < 0)    return NULL;
	if (i >= 256) return bitch("precedence range is not valid");

	rr->gateway_type = i = extract_integer(&s, "gateway type", NULL);
	if (i < 0) return NULL;
	if (i > 3) return bitch("gateway type is not valid");

	rr->algorithm = i = extract_integer(&s, "algorithm", NULL);
	if (i < 0) return NULL;
	if (i > 2) return bitch("algorithm is not valid");

	switch (rr->gateway_type) {
	case 0:
		rr->gateway.gateway_none = extract_name(&s, "gateway/.", KEEP_CAPITALIZATION);
		if (!rr->gateway.gateway_none) return NULL;
		if (strcmp(rr->gateway.gateway_none, ".") != 0)
			return bitch("gateway must be \".\" for gateway type 0");
		break;
	case 1:
		if (extract_ipv4(&s, "gateway/IPv4", &rr->gateway.gateway_ipv4) <= 0)
			return NULL;
		break;
	case 2:
		if (extract_ipv6(&s, "gateway/IPv6", &rr->gateway.gateway_ipv6) <= 0)
			return NULL;
		break;
	case 3:
		rr->gateway.gateway_name = extract_name(&s, "gateway/name", KEEP_CAPITALIZATION);
		if (!rr->gateway.gateway_name) return NULL;
		break;
	default:
		croakx(7, "assertion failed: gateway type %d not within range", rr->gateway_type);
	}

	/* My reading of http://tools.ietf.org/html/rfc4025 is fuzzy on:
	 *
	 * - whether it is possible to have algorithm 0 and non-empty key;
	 * - whether it is possible to have empty key and algorithm != 0.
	 *
	 * Here I assume "not possible" for both.
	 */
	switch (rr->algorithm) {
	case 0:
		break;
	case 1:
		/* DSA key */
		rr->public_key = extract_base64_binary_data(&s, "public key");
		if (rr->public_key.length < 0)     return NULL;
		break;
	case 2:
		/* RSA key */
		rr->public_key = extract_base64_binary_data(&s, "public key");
		if (rr->public_key.length < 0)     return NULL;
		break;
	default:
		croakx(7, "assertion failed: algorithm %d not within range", rr->algorithm);
	}

	if (*s) {
		return bitch("garbage after valid IPSECKEY data");
	}

	return store_record(type, name, ttl, rr);
}
示例#20
0
文件: nsec3.c 项目: regnauld/validns
static struct rr* nsec3_parse(char *name, long ttl, int type, char *s)
{
    struct rr_nsec3 *rr = getmem(sizeof(*rr));
    struct rr *ret_rr;
    struct binary_data bitmap;
    int i;
    int opt_out = 0;
    char *str_type = NULL;
    int ltype;

    i = extract_integer(&s, "hash algorithm");
    if (i < 0)
        return NULL;
    if (i > 255)
        return bitch("bad hash algorithm value");
    if (i != 1)
        return bitch("unrecognized or unsupported hash algorithm");
    rr->hash_algorithm = i;

    i = extract_integer(&s, "flags");
    if (i < 0)
        return NULL;
    if (i > 255)
        return bitch("bad flags value");

    if (!(i == 0 || i == 1))
        return bitch("unsupported flags value");
    if (i == 1)
        opt_out = 1;
    rr->flags = i;

    i = extract_integer(&s, "iterations");
    if (i < 0)
        return NULL;
    if (i > 2500)
        return bitch("bad iterations value");
    rr->iterations = i;
    /* TODO validate iteration count according to key size,
     * as per http://tools.ietf.org/html/rfc5155#section-10.3 */

    if (*s == '-') {
        rr->salt.length = 0;
        rr->salt.data = NULL;
        s++;
        if (*s && !isspace(*s) && *s != ';' && *s != ')')
            return bitch("salt is not valid");
        s = skip_white_space(s);
    } else {
        rr->salt = extract_hex_binary_data(&s, "salt", EXTRACT_DONT_EAT_WHITESPACE);
        if (rr->salt.length <= 0)
            return NULL;
        if (rr->salt.length > 255)
            return bitch("salt is too long");
    }

    rr->next_hashed_owner = extract_base32hex_binary_data(&s, "next hashed owner");

    bitmap = new_set();
    while (s && *s) {
        str_type = extract_label(&s, "type list", "temporary");
        if (!str_type) return NULL;
        ltype = str2rdtype(str_type);
        add_bit_to_set(&bitmap, ltype);
    }
    if (!s)
        return NULL;
    rr->type_bitmap = compressed_set(&bitmap);

    ret_rr = store_record(type, name, ttl, rr);
    if (ret_rr) {
        G.nsec3_present = 1;
        if (opt_out)
            G.nsec3_opt_out_present = 1;
    }
    return ret_rr;
}
示例#21
0
static struct rr* nsec3param_parse(char *name, long ttl, int type, char *s)
{
    struct rr_nsec3param *rr = getmem(sizeof(*rr));
	struct rr *ret_rr;
	int i;

	i = extract_integer(&s, "hash algorithm");
	if (i < 0)
		return NULL;
	if (i > 255)
		return bitch("bad hash algorithm value");
	if (i != 1)
		return bitch("unrecognized or unsupported hash algorithm");
	rr->hash_algorithm = i;

	i = extract_integer(&s, "flags");
	if (i < 0)
		return NULL;
	if (i > 255)
		return bitch("bad flags value");
	if (i != 0)
		return bitch("flags is supposed to be 0 for NSEC3PARAM");
	rr->flags = i;

	i = extract_integer(&s, "iterations");
	if (i < 0)
		return NULL;
	if (i > 2500)
		return bitch("bad iterations value");
	rr->iterations = i;
	/* TODO validate iteration count according to key size,
	 * as per http://tools.ietf.org/html/rfc5155#section-10.3 */

	if (*s == '-') {
		rr->salt.length = 0;
		rr->salt.data = NULL;
		s++;
		if (*s && !isspace(*s) && *s != ';' && *s != ')')
			return bitch("salt is not valid");
		s = skip_white_space(s);
	} else {
		rr->salt = extract_hex_binary_data(&s, "salt", EXTRACT_DONT_EAT_WHITESPACE);
		if (rr->salt.length <= 0)
			return NULL;
		if (rr->salt.length > 255)
			return bitch("salt is too long");
	}
	if (*s) {
		return bitch("garbage after valid NSEC3PARAM data");
	}

	G.dnssec_active = 1;
    ret_rr = store_record(type, name, ttl, rr);
	if (ret_rr && !nsec3param && (ret_rr->rr_set->named_rr->flags & NAME_FLAG_APEX))
		nsec3param = ret_rr;
	if (G.opt.policy_checks[POLICY_NSEC3PARAM_NOT_APEX] &&
		(ret_rr->rr_set->named_rr->flags & NAME_FLAG_APEX) == 0)
	{
		return bitch("NSEC3PARAM found not at zone apex");
	}
	return ret_rr;
}