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 + -
显示快捷键?