static inline unsigned long srv_ruli(char *host, int *port, char *srv) { int srv_code; int ruli_opts = RULI_RES_OPT_SEARCH | RULI_RES_OPT_SRV_NOINET6 | RULI_RES_OPT_SRV_NOSORT6 | RULI_RES_OPT_SRV_NOFALL; #ifdef RULI_RES_OPT_SRV_CNAME ruli_opts |= RULI_RES_OPT_SRV_CNAME; #endif ruli_sync_t *sync_query = ruli_sync_query(srv, host, *port, ruli_opts); /* sync query failure? */ if (!sync_query) { printf("DNS SRV lookup failed for: %s\n", host); exit_code(2, __PRETTY_FUNCTION__, "DNS SRV lookup failed"); } srv_code = ruli_sync_srv_code(sync_query); /* timeout? */ if (srv_code == RULI_SRV_CODE_ALARM) { printf("Timeout during DNS SRV lookup for: %s\n", host); ruli_sync_delete(sync_query); exit_code(2, __PRETTY_FUNCTION__, "timeout during DNS SRV lookup"); } /* service provided? */ else if (srv_code == RULI_SRV_CODE_UNAVAILABLE) { printf("SRV service not provided for: %s\n", host); ruli_sync_delete(sync_query); exit_code(2, __PRETTY_FUNCTION__, "missing service in DNS SRV reply"); } else if (srv_code) { int rcode = ruli_sync_rcode(sync_query); if (verbose > 1) printf("SRV query failed for: %s, srv_code=%d, rcode=%d\n", host, srv_code, rcode); ruli_sync_delete(sync_query); return 0; } ruli_list_t *srv_list = ruli_sync_srv_list(sync_query); int srv_list_size = ruli_list_size(srv_list); if (srv_list_size < 1) { if (verbose > 1) printf("No SRV record: %s.%s\n", srv, host); return 0; } ruli_srv_entry_t *entry = (ruli_srv_entry_t *) ruli_list_get(srv_list, 0); ruli_list_t *addr_list = &entry->addr_list; int addr_list_size = ruli_list_size(addr_list); if (addr_list_size < 1) { printf("missing addresses in SRV lookup for: %s\n", host); ruli_sync_delete(sync_query); exit_code(2, __PRETTY_FUNCTION__, "missing address in DNS SRV reply"); } *port = entry->port; ruli_addr_t *addr = (ruli_addr_t *) ruli_list_get(addr_list, 0); return addr->addr.ipv4.s_addr; }
static const ruli_uint8_t *parse_section(rr_parser_t rr_parser, ruli_list_t *rr_list, const ruli_uint8_t *msg, const ruli_uint8_t *past_end, int rr_count) { int i; const ruli_uint8_t *m; assert(!ruli_list_size(rr_list)); assert(msg <= past_end); m = msg; /* * Scan msg for resource records */ for (i = 0; i < rr_count; ++i) { const ruli_uint8_t *p; ruli_rr_t *rr; /* Allocate space for RR */ rr = (ruli_rr_t *) ruli_malloc(sizeof(ruli_rr_t)); if (!rr) return 0; /* Effectively parse RR */ p = rr_parser(rr, m, past_end); if (!p) { ruli_free(rr); return 0; } assert(m < p); /* We MUST have found at least one RR */ assert(p <= past_end); /* Save reference for RR */ if (ruli_list_push(rr_list, rr)) { ruli_free(rr); return 0; } m = p; } #ifdef RULI_RES_DEBUG fprintf(stderr, "DEBUG: parse_section(): scanned_octets=%d RRs_found=%d\n", m - msg, ruli_list_size(rr_list)); #endif return m; }
void ruli_srv_query_delete(ruli_srv_t *srv_qry) { #ifdef RULI_SRV_DEBUG fprintf(stderr, "DEBUG: %s: %s(): %d: query_id=%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__, srv_qry->query.query_id); #endif /* RULI_SRV_DEBUG */ /* * Dispose list of srv answers */ { ruli_list_t *list = &srv_qry->answer_srv_list; int list_size = ruli_list_size(list); int i; /* * For each entry, release list of *ruli_addr_t */ for (i = 0; i < list_size; ++i) { ruli_srv_entry_t *srv_entry = (ruli_srv_entry_t *) \ ruli_list_get(list, i); ruli_list_dispose_trivial(&srv_entry->addr_list); } } ruli_list_dispose_trivial(&srv_qry->answer_srv_list); ruli_parse_delete(&srv_qry->parse); ruli_list_dispose_trivial(&srv_qry->rr_srv_list); ruli_list_delete(&srv_qry->pri_srv_list); ruli_list_delete(&srv_qry->wei_srv_list); ruli_free(srv_qry->qdomain); ruli_res_query_delete(&srv_qry->query); }
static void addr_selection(ruli_list_t *srv_list, long options) { int i; int srv_list_size = ruli_list_size(srv_list); /* scan srv entries */ for (i = 0; i < srv_list_size; ++i) { ruli_srv_entry_t *entry = (ruli_srv_entry_t *) ruli_list_get(srv_list, i); ruli_addr_rfc3484_sort(&entry->addr_list, options); } }
static int find_addr(const ruli_list_t *addr_list, long options) { int list_size = ruli_list_size(addr_list); int i; for (i = 0; i < list_size; ++i) { ruli_addr_t *addr = (ruli_addr_t *) ruli_list_get(addr_list, i); switch (ruli_addr_family(addr)) { case PF_INET6: if (!(options & RULI_RES_OPT_SRV_NOINET6)) return -1; break; case PF_INET: if (!(options & RULI_RES_OPT_SRV_NOINET)) return -1; break; } } return 0; }
static void *on_answer(ruli_host_t *qry, void *arg) { char *domain = (char *) arg; const int BUFSZ = 1024; char buf[BUFSZ]; int str_len; int answer_code = ruli_host_answer_code(qry); assert(answer_code != RULI_HOST_CODE_VOID); if (answer_code == RULI_HOST_CODE_ALARM) { str_len = snprintf(buf, BUFSZ, "%s query-timeout\n", domain); assert(str_len < BUFSZ); printf(buf); return clean_query(qry, domain); } if (answer_code) { int rcode = ruli_host_rcode(qry); if (rcode != RULI_RCODE_NOERROR) { printf("%s bad-server-rcode: %d\n", domain, rcode); return clean_query(qry, domain); } str_len = snprintf(buf, BUFSZ, "%s query-failure: %d\n", domain, answer_code); assert(str_len < BUFSZ); printf(buf); return clean_query(qry, domain); } #ifdef RULI_HOST_DEBUG { ruli_msg_header_t msg_hdr; /* debug only, DON'T do this in real programs >:] */ msg_hdr = qry->host_query.answer_header; str_len = snprintf(buf, BUFSZ, "%s: query succeded: domain=%s id=%d " "rcode=%d qd=%d an=%d ns=%d ar=%d " "answer_buf_size=%d answer_msg_len=%d\n", prog_name, domain, msg_hdr.id, msg_hdr.rcode, msg_hdr.qdcount, msg_hdr.ancount, msg_hdr.nscount, msg_hdr.arcount, qry->host_query.answer_buf_size, qry->host_query.answer_msg_len); assert(str_len < BUFSZ); printf(buf); } #endif { ruli_list_t *addr_list = &qry->answer_addr_list; int addr_list_size = ruli_list_size(addr_list); int i; printf("%s", domain); for (i = 0; i < addr_list_size; ++i) { ruli_addr_t *addr = ruli_list_get(addr_list, i); printf(" "); ruli_addr_print(stdout, addr); } printf("\n"); } return clean_query(qry, domain); }
int ruli_parse_message(ruli_parse_t *parse, ruli_msg_header_t *msg_hdr, const ruli_uint8_t *msg, int msg_len) { const ruli_uint8_t *i; const ruli_uint8_t *j; const ruli_uint8_t *past_end; assert(!ruli_list_size(&parse->question_list)); assert(!ruli_list_size(&parse->answer_list)); assert(!ruli_list_size(&parse->authority_list)); assert(!ruli_list_size(&parse->additional_list)); parse->qdcount = msg_hdr->qdcount; parse->ancount = msg_hdr->ancount; parse->nscount = msg_hdr->nscount; parse->arcount = msg_hdr->arcount; /* Message too short? */ if (msg_len < RULI_LIMIT_MSG_HEADER) return RULI_PARSE_SHORT_MSG; /* Skip message header */ i = msg + RULI_LIMIT_MSG_HEADER; past_end = msg + msg_len; /* * Parse question section */ j = parse_section(parse_question, &parse->question_list, i, past_end, parse->qdcount); if (!j) return RULI_PARSE_QUESTION; assert(i <= j); assert(j <= past_end); assert(ruli_list_size(&parse->question_list) == parse->qdcount); /* * Parse answer section */ i = parse_section(parse_rr, &parse->answer_list, j, past_end, parse->ancount); if (!i) return RULI_PARSE_ANSWER; assert(j <= i); assert(i <= past_end); assert(ruli_list_size(&parse->answer_list) == parse->ancount); /* * Parse authority section */ j = parse_section(parse_rr, &parse->authority_list, i, past_end, parse->nscount); if (!j) return RULI_PARSE_AUTHORITY; assert(i <= j); assert(j <= past_end); assert(ruli_list_size(&parse->authority_list) == parse->nscount); /* * Parse additional section */ i = parse_section(parse_rr, &parse->additional_list, j, past_end, parse->arcount); if (!i) return RULI_PARSE_ADDITIONAL; assert(j <= i); assert(i <= past_end); assert(ruli_list_size(&parse->additional_list) == parse->arcount); if (i < past_end) return RULI_PARSE_LONG_MSG; return RULI_PARSE_OK; }
void show_srv_list(const char *fullname, const ruli_list_t *srv_list) { int srv_list_size = ruli_list_size(srv_list); int i; assert(srv_list_size >= 0); if (srv_list_size < 1) { printf("%s empty\n", fullname); return; } /* * Scan list of SRV records */ for (i = 0; i < srv_list_size; ++i) { ruli_srv_entry_t *entry = (ruli_srv_entry_t *) ruli_list_get(srv_list, i); ruli_list_t *addr_list = &entry->addr_list; int addr_list_size = ruli_list_size(addr_list); int j; /* * Show original full query name */ printf("%s ", fullname); /* * Show target */ { char txt_dname_buf[RULI_LIMIT_DNAME_TEXT_BUFSZ]; int txt_dname_len; if (ruli_dname_decode(txt_dname_buf, RULI_LIMIT_DNAME_TEXT_BUFSZ, &txt_dname_len, entry->target, entry->target_len)) { printf("target-decoding-failed\n"); continue; } printf("target=%s ", txt_dname_buf); } /* * Show port number and addresses */ printf("priority=%d weight=%d port=%d addresses=", entry->priority, entry->weight, entry->port); /* * Scan addresses */ for (j = 0; j < addr_list_size; ++j) { ruli_addr_t *addr = (ruli_addr_t *) ruli_list_get(addr_list, j); switch (ruli_addr_family(addr)) { case PF_INET: printf("IPv4/"); break; case PF_INET6: printf("IPv6/"); break; default: printf("?/"); } ruli_addr_print(stdout, addr); printf(" "); } printf("\n"); } }
static void *on_srv_answer(ruli_res_query_t *qry, void *arg) { ruli_srv_t *srv_qry = (ruli_srv_t *) arg; int result; assert(qry->answer_code != RULI_SRV_CODE_VOID); /* * Underlying query failed? */ if (qry->answer_code == RULI_CODE_TIMEOUT) return query_done(srv_qry, RULI_SRV_CODE_ALARM); if (qry->answer_code) return query_done(srv_qry, RULI_SRV_CODE_QUERY_FAILED); #ifdef RULI_SRV_DEBUG { ruli_msg_header_t msg_hdr; msg_hdr = qry->answer_header; fprintf(stderr, "DEBUG: on_srv_answer(): underlying query succeded: " "id=%d rcode=%d qd=%d an=%d ns=%d ar=%d " "answer_buf_size=%d answer_msg_len=%d\n", msg_hdr.id, msg_hdr.rcode, msg_hdr.qdcount, msg_hdr.ancount, msg_hdr.nscount, msg_hdr.arcount, qry->answer_buf_size, qry->answer_msg_len); } #endif /* * Parse answer for SRV records */ assert(sizeof(ruli_uint8_t) == sizeof(char)); result = ruli_parse_message(&srv_qry->parse, &qry->answer_header, (ruli_uint8_t *) qry->answer_buf, qry->answer_msg_len); if (result) return query_done(srv_qry, RULI_SRV_CODE_PARSE_FAILED); /* * Check reply code and answer count */ if ((qry->answer_header.rcode != RULI_RCODE_NOERROR) || (qry->answer_header.ancount < 1)) { #ifdef RULI_SRV_DEBUG fprintf(stderr, "DEBUG: on_srv_answer(): SRV query failed\n"); #endif /* Fallback query */ return srv_qry->fallback(srv_qry); } /* * NOERROR && (ancount > 0) */ assert(qry->answer_header.rcode == RULI_RCODE_NOERROR); assert(qry->answer_header.ancount > 0); /* * Processing of SRV answer: * * Step 1/6: One SRV RR with target == '.' ? * Step 2/6: Parse rdata portion of all SRV RRs * Step 3/6: Sort SRV RRs by priority * Step 4/6: Select SRV RRs by random weighted order * Step 5/6: Build list of srv answers by inspecting additional section * Step 6/6: Launch queries to fill missing addresses, if any */ /* * Step 1/6: One SRV RR with target == '.' ? */ if (qry->answer_header.ancount == 1) { ruli_list_t *an_list = &srv_qry->parse.answer_list; if (ruli_list_size(an_list) == 1) { ruli_rr_t *rr = (ruli_rr_t *) ruli_list_top(an_list); if (rr->qclass == RULI_RR_CLASS_IN) { if (rr->type == RULI_RR_TYPE_SRV) { ruli_srv_rdata_t srv_rdata; if (ruli_parse_rr_srv(&srv_rdata, rr->rdata, rr->rdlength)) return query_done(srv_qry, RULI_SRV_CODE_PARSE_FAILED); /* target == '.' ? */ if (*srv_rdata.target == '\0') { /* Sanity test */ if (srv_rdata.target_len != 1) return query_done(srv_qry, RULI_SRV_CODE_PARSE_FAILED); /* * ruli_srv.c: target=='.': Owner match? */ assert(sizeof(ruli_uint8_t) == sizeof(char)); #ifdef RULI_SRV_DEBUG show_dname("on_srv_answer(): target=='.': qdomain", (const char *) qry->full_dname, qry->full_dname_len); #endif if (ruli_dname_compare(rr->owner, (ruli_uint8_t *) qry->answer_buf, qry->answer_msg_len, (ruli_uint8_t *) qry->full_dname, qry->full_dname_len)) return query_done(srv_qry, RULI_SRV_CODE_PARSE_FAILED); return query_done(srv_qry, RULI_SRV_CODE_UNAVAILABLE); } } } } } /* One SRV RR with target == '.' ? */ /* * Step 2/6: Parse rdata portion of all SRV RRs */ { ruli_list_t *an_list = &srv_qry->parse.answer_list; int an_list_size = ruli_list_size(an_list); int i; for (i = 0; i < an_list_size; ++i) { ruli_rr_t *rr = (ruli_rr_t *) ruli_list_get(an_list, i); ruli_srv_rdata_t *srv_rdata; if (rr->qclass != RULI_RR_CLASS_IN) continue; if (rr->type != RULI_RR_TYPE_SRV) continue; #ifdef RULI_SRV_DEBUG fprintf(stderr, "DEBUG: on_srv_answer(): considering SRV-RR owner: %d of %d\n", (i + 1), an_list_size); #endif if (ruli_dname_compare(rr->owner, (ruli_uint8_t *) qry->answer_buf, qry->answer_msg_len, (ruli_uint8_t *) qry->full_dname, qry->full_dname_len)) return query_done(srv_qry, RULI_SRV_CODE_PARSE_FAILED); #ifdef RULI_SRV_DEBUG fprintf(stderr, "DEBUG: on_srv_answer(): SRV-RR owner OK: %d of %d\n", (i + 1), an_list_size); #endif srv_rdata = (ruli_srv_rdata_t *) ruli_malloc(sizeof(ruli_srv_rdata_t)); if (!srv_rdata) return query_done(srv_qry, RULI_SRV_CODE_MALLOC); if (ruli_list_push(&srv_qry->rr_srv_list, srv_rdata)) { ruli_free(srv_rdata); return query_done(srv_qry, RULI_SRV_CODE_LIST); } if (ruli_parse_rr_srv(srv_rdata, rr->rdata, rr->rdlength)) return query_done(srv_qry, RULI_SRV_CODE_PARSE_FAILED); } } #ifdef RULI_SRV_DEBUG { int i; ruli_list_t *list = &srv_qry->rr_srv_list; fflush(stdout); for (i = 0; i < ruli_list_size(list); ++i) { ruli_srv_rdata_t *srv_rdata = \ (ruli_srv_rdata_t *) ruli_list_get(list, i); fflush(stderr); fprintf(stderr, "DEBUG: on_srv_answer(): SRV RR: " "priority=%d weight=%d port=%d\n", srv_rdata->priority, srv_rdata->weight, srv_rdata->port); fflush(stderr); } } #endif /* * Step 3/6: Sort SRV RRs by priority */ { ruli_list_t *src_list = &srv_qry->rr_srv_list; int src_list_size = ruli_list_size(src_list); int j; /* * Handle every RR based on priority (higher priority first) */ for (j = 0; j < src_list_size; ++j) { ruli_srv_rdata_t *srv_rdata = \ (ruli_srv_rdata_t *) ruli_list_get(src_list, j); ruli_list_t *dst_list = &srv_qry->pri_srv_list; int dst_list_size = ruli_list_size(dst_list); int i; assert(srv_rdata); /* * Find a lower-or-equal priority */ for (i = 0; i < dst_list_size; ++i) { ruli_srv_rdata_t *rd = (ruli_srv_rdata_t *) ruli_list_get(dst_list, i); if (srv_rdata->priority < rd->priority) continue; /* * For this priority, put 0-weight-elements at tail */ if (srv_rdata->weight == 0) { /* * Find begin of next priority and insert there */ for (; i < dst_list_size; ++i) { ruli_srv_rdata_t *s_rd = \ (ruli_srv_rdata_t *) ruli_list_get(dst_list, i); if (srv_rdata->priority != s_rd->priority) break; } /* for */ if (i == dst_list_size) break; /* Insert at tail (of this priority) */ } if (ruli_list_insert_at(dst_list, i, srv_rdata)) return query_done(srv_qry, RULI_SRV_CODE_LIST); srv_rdata = 0; /* mark as handled */ break; } /* for */ /* If not handled yet, insert at tail */ if (srv_rdata) if (ruli_list_push(dst_list, srv_rdata)) return query_done(srv_qry, RULI_SRV_CODE_LIST); } /* while */ } #ifdef RULI_SRV_DEBUG { int i; ruli_list_t *list = &srv_qry->pri_srv_list; fflush(stdout); for (i = 0; i < ruli_list_size(list); ++i) { ruli_srv_rdata_t *srv_rdata = \ (ruli_srv_rdata_t *) ruli_list_get(list, i); fflush(stderr); fprintf(stderr, "DEBUG: on_srv_answer(): priority SRV RR: " "priority=%d weight=%d port=%d\n", srv_rdata->priority, srv_rdata->weight, srv_rdata->port); fflush(stderr); } } #endif /* * Step 4/6: Select SRV RRs by random weighted order */ { ruli_list_t *src_list = &srv_qry->pri_srv_list; ruli_list_t *dst_list = &srv_qry->wei_srv_list; /* * Iterate over every priority */ for (;;) { int src_list_size = ruli_list_size(src_list); ruli_uint16_t curr_priority; int priority_weight_sum; int curr; int i; int rnd; int run_sum; ruli_srv_rdata_t *srv_rd; if (src_list_size < 1) break; /* * Get current priority */ curr = src_list_size - 1; srv_rd = (ruli_srv_rdata_t *) ruli_list_get(src_list, curr); curr_priority = srv_rd->priority; /* * Accumulate weight sum for priority */ priority_weight_sum = 0; for (i = curr; i >= 0; --i) { ruli_srv_rdata_t *rd = (ruli_srv_rdata_t *) ruli_list_get(src_list, i); if (curr_priority != rd->priority) break; priority_weight_sum += rd->weight; } /* for */ /* * Pick random number: 0..priority_weight_sum */ rnd = ruli_rand_next(&srv_qry->srv_resolver->rand_ctx, 0, priority_weight_sum); /* * Select least running sum */ run_sum = 0; for (i = curr; ; --i) { ruli_srv_rdata_t *rd; assert(i >= 0); rd = (ruli_srv_rdata_t *) ruli_list_get(src_list, i); run_sum += rd->weight; if (run_sum < rnd) continue; /* * Move from src_list to dst_list * (Both lists are only referential) */ ruli_list_shift_at(src_list, i); if (ruli_list_push(dst_list, rd)) return query_done(srv_qry, RULI_SRV_CODE_LIST); break; } /* for */ } /* for */ } #ifdef RULI_SRV_DEBUG { int i; ruli_list_t *list = &srv_qry->wei_srv_list; fflush(stdout); for (i = 0; i < ruli_list_size(list); ++i) { ruli_srv_rdata_t *srv_rdata = \ (ruli_srv_rdata_t *) ruli_list_get(list, i); fflush(stderr); fprintf(stderr, "DEBUG: on_srv_answer(): weight SRV RR: " "priority=%d weight=%d port=%d\n", srv_rdata->priority, srv_rdata->weight, srv_rdata->port); fflush(stderr); } } #endif /* * Step 5/6: Build list of srv answers by inspecting additional section */ { ruli_list_t *src_list = &srv_qry->wei_srv_list; ruli_list_t *dst_list = &srv_qry->answer_srv_list; int src_list_size = ruli_list_size(src_list); int i; assert(ruli_list_size(dst_list) == 0); #ifdef RULI_SRV_DEBUG { fflush(stdout); fprintf(stderr, "DEBUG: %s: %s(): %d: " "BEFORE addit inspection: " "srv_rr_list_size=%d srv_answer_list_size=%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__, src_list_size, ruli_list_size(&srv_qry->answer_srv_list)); fflush(stderr); } #endif /* * Build answer records inspecting additional section */ /* Scan all targets */ for (i = 0; i < src_list_size; ++i) { ruli_srv_rdata_t *rd = (ruli_srv_rdata_t *) ruli_list_get(src_list, i); ruli_srv_entry_t *srv_entry; /* Create SRV entry and append it to list */ srv_entry =_ruli_srv_list_new_entry(dst_list, (const char *) rd->target, rd->target_len, rd->priority, rd->weight, rd->port); if (!srv_entry) return query_done(srv_qry, RULI_SRV_CODE_MALLOC); /* * Look up target address(es) in additional section */ { ruli_list_t *ad_list = &srv_qry->parse.additional_list; int ad_list_size = ruli_list_size(ad_list); int j; /* Scan additional section */ for (j = 0; j < ad_list_size; ++j) { ruli_rr_t *rr = (ruli_rr_t *) ruli_list_get(ad_list, j); ruli_addr_t *addr; if (rr->qclass != RULI_RR_CLASS_IN) continue; if (!ruli_rr_type_is_address(srv_qry->srv_options, rr->type)) continue; /* Compare SRV target against additional record owner */ if (ruli_dname_compare(rr->owner, (ruli_uint8_t *) qry->answer_buf, qry->answer_msg_len, (ruli_uint8_t *) srv_entry->target, srv_entry->target_len)) continue; /* Allocate space for address */ addr = (ruli_addr_t *) ruli_malloc(sizeof(*addr)); if (!addr) return query_done(srv_qry, RULI_SRV_CODE_MALLOC); /* Save space */ if (ruli_list_push(&srv_entry->addr_list, addr)) { ruli_free(addr); return query_done(srv_qry, RULI_SRV_CODE_LIST); } /* Write address into space */ ruli_parse_addr_rr(addr, rr, srv_qry->srv_options); } /* for */ } } /* for */ #ifdef RULI_SRV_DEBUG { fflush(stdout); fprintf(stderr, "DEBUG: %s: %s(): %d: " "AFTER addit inspection: " "srv_rr_list_size=%d srv_answer_list_size=%d\n", __FILE__, __PRETTY_FUNCTION__, __LINE__, src_list_size, ruli_list_size(&srv_qry->answer_srv_list)); fflush(stderr); } #endif assert(ruli_list_size(dst_list) == src_list_size); } /* Build list of srv answers by inspecting additional section */ #ifdef RULI_SRV_DEBUG { int i; ruli_list_t *list = &srv_qry->answer_srv_list; fflush(stdout); for (i = 0; i < ruli_list_size(list); ++i) { ruli_srv_entry_t *srv_entry = \ (ruli_srv_entry_t *) ruli_list_get(list, i); fprintf(stderr, "DEBUG: on_srv_answer(): answer SRV RR: " "priority=%d weight=%d port=%d\n", srv_entry->priority, srv_entry->weight, srv_entry->port); } fflush(stderr); } #endif /* * Step 6/6: Launch queries to fill missing addresses, if any */ assert(srv_qry->under.walk_index == -1); srv_qry->under.walk_index = 0; return _ruli_srv_answer_walk(srv_qry); }
static void *on_fallback_answer(ruli_host_t *qry, void *qry_arg) { ruli_srv_t *srv_qry = (ruli_srv_t *) qry_arg; int prev_srv_list_size = ruli_list_size(&srv_qry->answer_srv_list); int answer_code; assert(prev_srv_list_size == 0); assert(qry->answer_code != RULI_SRV_CODE_VOID); /* * Query failed? */ answer_code = ruli_host_answer_code(qry); if (answer_code) { srv_qry->last_rcode = RULI_RCODE_VOID; switch(answer_code) { case RULI_HOST_CODE_ALARM: return fall_query_done(srv_qry, RULI_SRV_CODE_FALL_ALARM, qry); case RULI_HOST_CODE_EMPTY: return fall_query_done(srv_qry, RULI_SRV_CODE_FALL_EMPTY, qry); case RULI_HOST_CODE_RCODE: assert(ruli_host_rcode(qry) != RULI_RCODE_VOID); assert(ruli_host_rcode(qry) != RULI_RCODE_NOERROR); srv_qry->last_rcode = ruli_host_rcode(qry); return fall_query_done(srv_qry, RULI_SRV_CODE_FALL_RCODE, qry); default: return fall_query_done(srv_qry, RULI_SRV_CODE_FALL_QUERY, qry); } assert(0); } assert(ruli_host_rcode(qry) == RULI_RCODE_NOERROR); srv_qry->last_rcode = RULI_RCODE_NOERROR; /* * Move addresses into SRV record */ { ruli_srv_entry_t *srv_entry; ruli_list_t *addr_list = &qry->answer_addr_list; int addr_list_size = ruli_list_size(addr_list); int i; /* Create SRV entry and append it to list */ srv_entry =_ruli_srv_list_new_entry(&srv_qry->answer_srv_list, srv_qry->srv_domain, srv_qry->srv_domain_len, -1, -1, srv_qry->srv_fallback_port); if (!srv_entry) return fall_query_done(srv_qry, RULI_SRV_CODE_FALL_OTHER, qry); /* Move addresses from addr query to SRV entry */ for (i = 0; i < addr_list_size; ++i) { ruli_addr_t *addr = (ruli_addr_t *) ruli_list_get(addr_list, i); if (ruli_list_push(&srv_entry->addr_list, addr)) { ruli_list_prune(&srv_entry->addr_list, 0); return fall_query_done(srv_qry, RULI_SRV_CODE_FALL_OTHER, qry); } } } /* * Detaches addresses from addr-query ruli_list_t container * So that next ruli_host_query_delete does not dispose them */ ruli_host_query_detach(qry); return fall_query_done(srv_qry, RULI_SRV_CODE_OK, qry); }
/* Search missing addresses for targets. We make serialized queries so we don't need to keep more than one query reference (walk_query). */ void *_ruli_srv_answer_walk(ruli_srv_t *srv_qry) { ruli_list_t *srv_list = &srv_qry->answer_srv_list; int srv_list_size = ruli_list_size(srv_list); /* Have the user disabled walk query? */ if (srv_qry->srv_options & RULI_RES_OPT_SRV_NOWALK) return query_done(srv_qry, RULI_SRV_CODE_OK); /* * Scan SRV answer targets, considering address lists */ for (; srv_qry->under.walk_index < srv_list_size; ++srv_qry->under.walk_index) { ruli_srv_entry_t *entry = \ (ruli_srv_entry_t *) ruli_list_get(srv_list, srv_qry->under.walk_index); ruli_list_t *addr_list = &entry->addr_list; walk_t *walk_qry; /* If this target already has address(es), skip it */ if (find_addr(addr_list, srv_qry->srv_options)) continue; #ifdef RULI_SRV_DEBUG { char target_txt[RULI_LIMIT_DNAME_TEXT_BUFSZ]; int target_txt_len; int result; result = ruli_dname_decode(target_txt, RULI_LIMIT_DNAME_TEXT_BUFSZ, &target_txt_len, entry->target, entry->target_len); assert(!result); fprintf(stderr, "DEBUG: _ruli_srv_answer_walk(): " "missing target=%s walk_index=%d\n", target_txt, srv_qry->under.walk_index); } #endif /* * Allocate space for auxiliary walk query */ walk_qry = \ (walk_t *) ruli_malloc(sizeof(*walk_qry)); if (!walk_qry) return query_done(srv_qry, RULI_SRV_CODE_WALK_OTHER); walk_qry->srv_query = srv_qry; /* * Initialize walk query arguments */ walk_qry->walk_query.host_resolver = srv_qry->srv_resolver; walk_qry->walk_query.host_on_answer = on_walk_answer; walk_qry->walk_query.host_on_answer_arg = walk_qry; walk_qry->walk_query.host_domain = entry->target; walk_qry->walk_query.host_domain_len = entry->target_len; walk_qry->walk_query.host_options = srv_qry->srv_options; /* RFC 2782 states CNAME aren't valid SRV targets */ walk_qry->walk_query.host_max_cname_depth = (srv_qry->srv_options & RULI_RES_OPT_SRV_CNAME) ? RULI_LIMIT_CNAME_DEPTH : 0; /* * Submit walk query */ if (ruli_host_query_submit(&walk_qry->walk_query)) { ruli_free(walk_qry); return query_done(srv_qry, RULI_SRV_CODE_WALK_QUERY); } /* Wait answer */ return OOP_CONTINUE; } /* for */ /* * All targets scanned, we're done */ return query_done(srv_qry, RULI_SRV_CODE_OK); }
static void *on_walk_answer(ruli_host_t *host_qry, void *qry_arg) { walk_t *walk_qry = (walk_t *) qry_arg; ruli_srv_t *srv_qry = walk_qry->srv_query; ruli_srv_entry_t *srv_entry; assert(ruli_host_answer_code(host_qry) != RULI_SRV_CODE_VOID); srv_entry = (ruli_srv_entry_t *) ruli_list_get(&srv_qry->answer_srv_list, srv_qry->under.walk_index); #ifdef RULI_SRV_DEBUG { char target_txt[RULI_LIMIT_DNAME_TEXT_BUFSZ]; int target_txt_len; int result; result = ruli_dname_decode(target_txt, RULI_LIMIT_DNAME_TEXT_BUFSZ, &target_txt_len, (const char *) walk_qry->walk_query.host_query.full_dname, walk_qry->walk_query.host_query.full_dname_len); assert(!result); fprintf(stderr, "DEBUG: on_walk_answer(): query target=%s target_len=%d\n", target_txt, target_txt_len); } #endif /* * Query failed? */ { int answer_code = ruli_host_answer_code(host_qry); if (answer_code) { srv_qry->last_rcode = RULI_RCODE_VOID; switch(answer_code) { case RULI_HOST_CODE_ALARM: return walk_query_done(walk_qry, RULI_SRV_CODE_WALK_ALARM); case RULI_HOST_CODE_EMPTY: return walk_query_done(walk_qry, RULI_SRV_CODE_WALK_EMPTY); case RULI_HOST_CODE_RCODE: assert(ruli_host_rcode(host_qry) != RULI_RCODE_VOID); assert(ruli_host_rcode(host_qry) != RULI_RCODE_NOERROR); srv_qry->last_rcode = ruli_host_rcode(host_qry); return walk_query_done(walk_qry, RULI_SRV_CODE_WALK_RCODE); default: return walk_query_done(walk_qry, RULI_SRV_CODE_WALK_QUERY); } assert(0); } } assert(ruli_host_rcode(host_qry) == RULI_RCODE_NOERROR); srv_qry->last_rcode = RULI_RCODE_NOERROR; /* * Move addresses into SRV record */ { ruli_list_t *addr_list = &host_qry->answer_addr_list; int addr_list_size = ruli_list_size(addr_list); int i; /* Move addresses from addr query to SRV entry */ for (i = 0; i < addr_list_size; ++i) { ruli_addr_t *addr = (ruli_addr_t *) ruli_list_get(addr_list, i); if (ruli_list_push(&srv_entry->addr_list, addr)) { ruli_list_prune(&srv_entry->addr_list, 0); return walk_query_done(walk_qry, RULI_SRV_CODE_FALL_OTHER); } } } /* * Detaches addresses from addr-query ruli_list_t container * So that next ruli_host_query_delete does not dispose them */ ruli_host_query_detach(host_qry); /* Dispose auxiliary query as it will be re-created by next walk query */ w_query_done(walk_qry); /* In future walk query, consider next answer target */ ++srv_qry->under.walk_index; return _ruli_srv_answer_walk(srv_qry); }