dnskey.c

来自「ipsec vpn」· C语言 代码 · 共 2,021 行 · 第 1/4 页

C
2,021
字号
    TRY(unpack_txt_rdata(str, sizeof(str), rdata, rdlen));    return process_txt_rr_body(str, doit, dns_auth_level, cr);}static err_tprocess_answer_section(pb_stream *pbs, bool doit	/* should we capture information? */, enum dns_auth_level *dns_auth_level, u_int16_t ancount	/* number of RRs in the answer section */, struct adns_continuation *const cr){    const int type = cr->query.type;	/* type of RR of interest */    unsigned c;    DBG(DBG_DNS, DBG_log("*Answer Section:"));    for (c = 0; c != ancount; c++)    {	struct rr_fixed rrf;	size_t tail;	/* ??? do we need to match the name? */	TRY(eat_name_helpfully(pbs, "Answer Section"));	if (!in_struct(&rrf, &rr_fixed_desc, pbs, NULL))	    return "failed to get fixed part of Answer Section Resource Record";	if (rrf.rdlength > pbs_left(pbs))	    return "RD Length extends beyond end of message";	/* ??? should we care about ttl? */	tail = rrf.rdlength;	if (rrf.type == type && rrf.class == C_IN)	{	    err_t ugh;	    switch (type)	    {#ifdef USE_KEYRR	    case T_KEY:		ugh = process_key_rr(pbs->cur, tail, doit, *dns_auth_level, cr);		break;#endif /* USE_KEYRR */	    case T_TXT:		ugh = process_txt_rr(pbs->cur, tail, doit, *dns_auth_level, cr);		break;	    case T_SIG:		/* Check if SIG RR authenticates what we are learning.		 * The RRset covered by a SIG must have the same owner,		 * class, and type.		 * For us, the class is always C_IN, so that matches.		 * We decode the SIG RR's fixed part to check		 * that the type_covered field matches our query type		 * (this may be redundant).		 * We don't check the owner (apparently this is the		 * name on the record) -- we assume that it matches		 * or we would not have been given this SIG in the		 * Answer Section.		 *		 * We only look on first pass, and only if we've something		 * to learn.  This cuts down on useless decoding.		 */		if (!doit && *dns_auth_level == DAL_UNSIGNED)		{		    struct sig_rdata sr;		    if (!in_struct(&sr, &sig_rdata_desc, pbs, NULL))			ugh = "failed to get fixed part of SIG Resource Record RDATA";		    else if (sr.type_covered == type)			*dns_auth_level = DAL_SIGNED;		}		break;	    default:		ugh = builddiag("unexpected RR type %d", type);		break;	    }	    if (ugh != NULL)		return ugh;	}	in_raw(NULL, tail, pbs, "RR RDATA");    }    return doit	&& cr->gateways_from_dns == NULL#ifdef USE_KEYRR	&& cr->keys_from_dns == NULL#endif /* USE_KEYRR */	? builddiag("no suitable %s record found in DNS", rr_typename(type))	: NULL;}/* process DNS answer -- TXT or KEY query */static err_tprocess_dns_answer(struct adns_continuation *const cr, u_char ans[], int anslen){    const int type = cr->query.type;	/* type of record being sought */    int r;	/* all-purpose return value holder */    u_int16_t c;	/* number of current RR in current answer section */    pb_stream pbs;    u_int8_t *ans_start;	/* saved position of answer section */    struct qr_header qr_header;    enum dns_auth_level dns_auth_level;    init_pbs(&pbs, ans, anslen, "Query Response Message");    /* decode and check header */    if (!in_struct(&qr_header, &qr_header_desc, &pbs, NULL))	return "malformed header";    /* ID: nothing to do with us */    /* stuff -- lots of things */    if ((qr_header.stuff & QRS_QR) == 0)	return "not a response?!?";    if (((qr_header.stuff >> QRS_OPCODE_SHIFT) & QRS_OPCODE_MASK) != QRSO_QUERY)	return "unexpected opcode";    /* I don't think we care about AA */    if (qr_header.stuff & QRS_TC)	return "response truncated";    /* I don't think we care about RD, RA, or CD */    /* AD means "authentic data" */    dns_auth_level = qr_header.stuff & QRS_AD? DAL_UNSIGNED : DAL_NOTSEC;    if (qr_header.stuff & QRS_Z)	return "Z bit is not zero";    r = (qr_header.stuff >> QRS_RCODE_SHIFT) & QRS_RCODE_MASK;    if (r != 0)	return r < (int)elemsof(rcode_text)? rcode_text[r] : "unknown rcode";    if (qr_header.ancount == 0)	return builddiag("no %s RR found by DNS", rr_typename(type));    /* end of header checking */    /* Question Section processing */    /* 4.1.2. Question section format:     *                                 1  1  1  1  1  1     *   0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5     * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     * |                                               |     * /                     QNAME                     /     * /                                               /     * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     * |                     QTYPE                     |     * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     * |                     QCLASS                    |     * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+     */    DBG(DBG_DNS, DBG_log("*Question Section:"));    for (c = 0; c != qr_header.qdcount; c++)    {	struct qs_fixed qsf;	TRY(eat_name_helpfully(&pbs, "Question Section"));	if (!in_struct(&qsf, &qs_fixed_desc, &pbs, NULL))	    return "failed to get fixed part of Question Section";	if (qsf.qtype != type)	    return "unexpected QTYPE in Question Section";	if (qsf.qclass != C_IN)	    return "unexpected QCLASS in Question Section";    }    /* rest of sections are made up of Resource Records */    /* Answer Section processing -- error checking, noting T_SIG */    ans_start = pbs.cur;	/* remember start of answer section */    TRY(process_answer_section(&pbs, FALSE, &dns_auth_level	, qr_header.ancount, cr));    /* Authority Section processing (just sanity checking) */    DBG(DBG_DNS, DBG_log("*Authority Section:"));    for (c = 0; c != qr_header.nscount; c++)    {	struct rr_fixed rrf;	size_t tail;	TRY(eat_name_helpfully(&pbs, "Authority Section"));	if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL))	    return "failed to get fixed part of Authority Section Resource Record";	if (rrf.rdlength > pbs_left(&pbs))	    return "RD Length extends beyond end of message";	/* ??? should we care about ttl? */	tail = rrf.rdlength;	in_raw(NULL, tail, &pbs, "RR RDATA");    }    /* Additional Section processing (just sanity checking) */    DBG(DBG_DNS, DBG_log("*Additional Section:"));    for (c = 0; c != qr_header.arcount; c++)    {	struct rr_fixed rrf;	size_t tail;	TRY(eat_name_helpfully(&pbs, "Additional Section"));	if (!in_struct(&rrf, &rr_fixed_desc, &pbs, NULL))	    return "failed to get fixed part of Additional Section Resource Record";	if (rrf.rdlength > pbs_left(&pbs))	    return "RD Length extends beyond end of message";	/* ??? should we care about ttl? */	tail = rrf.rdlength;	in_raw(NULL, tail, &pbs, "RR RDATA");    }    /* done all sections */    /* ??? is padding legal, or can we complain if more left in record? */    /* process Answer Section again -- accept contents */    pbs.cur = ans_start;	/* go back to start of answer section */    return process_answer_section(&pbs, TRUE, &dns_auth_level	, qr_header.ancount, cr);}#endif /* ! USE_LWRES *//****************************************************************/static err_tbuild_dns_name(u_char name_buf[NS_MAXDNAME + 2], unsigned long serial USED_BY_DEBUG, const struct id *id, const char *typename USED_BY_DEBUG, const char *gwname   USED_BY_DEBUG){    /* note: all end in "." to suppress relative searches */    id = resolve_myid(id);    switch (id->kind)    {    case ID_IPV4_ADDR:    {	/* XXX: this is really ugly and only temporary until addrtot can	 *      generate the correct format	 */	const unsigned char *b;	size_t bl USED_BY_DEBUG = addrbytesptr(&id->ip_addr, &b);	passert(bl == 4);	snprintf(name_buf, NS_MAXDNAME + 2, "%d.%d.%d.%d.in-addr.arpa."	    , b[3], b[2], b[1], b[0]);	break;    }    case ID_IPV6_ADDR:    {	/* ??? is this correct? */	const unsigned char *b;	size_t bl;	u_char *op = name_buf;	static const char suffix[] = "IP6.INT.";	for (bl = addrbytesptr(&id->ip_addr, &b); bl-- != 0; )	{	    if (op + 4 + sizeof(suffix) >= name_buf + NS_MAXDNAME + 1)		return "IPv6 reverse name too long";	    op += sprintf(op, "%x.%x.", b[bl] & 0xF, b[bl] >> 4);	}	strcpy(op, suffix);	break;    }    case ID_FQDN:	/* strip trailing "." characters, then add one */	{	    size_t il = id->name.len;	    while (il > 0 && id->name.ptr[il - 1] == '.')		il--;	    if (il > NS_MAXDNAME)		return "FQDN too long for domain name";	    memcpy(name_buf, id->name.ptr, il);	    strcpy(name_buf + il, ".");	}	break;    default:	return "can only query DNS for key for ID that is a FQDN, IPV4_ADDR, or IPV6_ADDR";    }    DBG(DBG_CONTROL | DBG_DNS, DBG_log("DNS query %lu for %s for %s (gw: %s)"	, serial, typename, name_buf, gwname));    return NULL;}voidgw_addref(struct gw_info *gw){    if (gw != NULL)    {	DBG(DBG_DNS, DBG_log("gw_addref: %p refcnt: %d++", gw, gw->refcnt))	gw->refcnt++;    }}voidgw_delref(struct gw_info **gwp){    struct gw_info *gw = *gwp;    if (gw != NULL)    {	DBG(DBG_DNS, DBG_log("gw_delref: %p refcnt: %d--", gw, gw->refcnt));	passert(gw->refcnt != 0);	gw->refcnt--;	if (gw->refcnt == 0)	{	    free_id_content(&gw->client_id);	    free_id_content(&gw->gw_id);	    if (gw->gw_key_present)		unreference_key(&gw->key);	    gw_delref(&gw->next);	    pfree(gw);	/* trickery could make this a tail-call */	}	*gwp = NULL;    }}/* Start an asynchronous DNS query. * * For KEY record, the result will be a list in cr->keys_from_dns. * For TXT records, the result will be a list in cr->gateways_from_dns. * * If sgw_id is null, only consider TXT records that specify an * IP address for the gatway: we need this in the initiation case. * * If sgw_id is non-null, only consider TXT records that specify * this id as the security gatway; this is useful to the Responder * for confirming claims of gateways. * * Continuation cr gives information for continuing when the result shows up. * * Two kinds of errors must be handled: synchronous (immediate) * and asynchronous.  Synchronous errors are indicated by the returned * value of start_adns_query; in this case, the continuation will * have been freed and the continuation routine will not be called. * Asynchronous errors are indicated by the ugh parameter passed to the * continuation routine. * * After the continuation routine has completed, handle_adns_answer * will free the continuation.  The continuation routine should have * freed any axiliary resources. * * Note: in the synchronous error case, start_adns_query will have * freed the continuation; this means that the caller will have to * be very careful to release any auxiliary resources that were in * the continuation record without using the continuation record. * * Either there will be an error result passed to the continuation routine, * or the results will be in cr->keys_from_dns or cr->gateways_from_dns. * The result variables must by left NULL by the continutation routine. * The continuation routine is responsible for establishing and * disestablishing any logging context (whack_log_fd, cur_*). */static struct adns_continuation *continuations = NULL;	/* newest of queue */static struct adns_continuation *next_query = NULL;	/* oldest not sent */static struct adns_continuation *continuation_for_qtid(unsigned long qtid){    struct adns_continuation *cr = NULL;    if (qtid != 0)	for (cr = continuations; cr != NULL && cr->qtid != qtid; cr = cr->previous)	    ;    return cr;}static voidrelease_adns_continuation(struct adns_continuation *cr){    gw_delref(&cr->gateways_from_dns);#ifdef USE_KEYRR    free_public_keys(&cr->keys_from_dns);#endif /* USE_KEYRR */    unreference_key(&cr->last_info);    unshare_id_content(&cr->id);    unshare_id_content(&cr->sgw_id);    /* unlink from doubly-linked list */    if (cr->next == NULL)    {	passert(continuations == cr);	continuations = cr->previous;    }    else    {	passert(cr->next->previous == cr);	cr->next->previous = cr->previous;    }    if (cr->previous != NULL)    {	passert(cr->previous->next == cr);	cr->previous->next = cr->next;    }    pfree(cr);}static voidrelease_all_continuations(){    struct adns_continuation *cr = NULL;    struct adns_continuation *crnext;    for(cr = continuations; cr != NULL; cr = crnext) {	crnext = cr->previous;	cr->cont_fn(cr, "no results returned by lwdnsq");#ifdef USE_LWRES	cr->used = TRUE;#endif	release_adns_continuation(cr);	adns_in_flight--;    }}err_tstart_adns_query(const struct id *id	/* domain to query */, const struct id *sgw_id	/* if non-null, any accepted gw_info must match */, int type	/* T_TXT or T_KEY, selecting rr type of interest */, cont_fn_t cont_fn, struct adns_continuation *cr){    static unsigned long qtid = 1;	/* query transaction id; NOTE: static */    const char *typename = rr_typename(type);    char gwidb[IDTOA_BUF];    if(adns_pid == 0    && adns_restart_count < ADNS_RESTART_MAX)    {	openswan_log("ADNS helper was not running. Restarting attempt %d",adns_restart_count);	init_adns();    }    /* Splice this in at head of doubly-linked list of continuations.     * Note: this must be done before any release_adns_continuation().     */    cr->next = NULL;    cr->previous = continuations;    if (continuations != NULL)    {	passert(continuations->next == NULL);	continuations->next = cr;    }    continuations = cr;    cr->qtid = qtid++;    cr->type = type;    cr->cont_fn = cont_fn;    cr->id = *id;    unshare_id_content(&cr->id);    cr->sgw_specified = sgw_id != NULL;    cr->sgw_id = cr->sgw_specified? *sgw_id : empty_id;    unshare_id_content(&cr->sgw_id);    cr->gateways_from_dns = NULL;#ifdef USE_KEYRR    cr->keys_from_dns = NULL;#endif /* USE_KEYRR */#ifdef DEBUG    cr->debugging = cur_debugging;#else    cr->debugging = LEMPTY;#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?