static char * target_name(const unsigned char *target) { char buf[NS_MAXDNAME]; if (ns_name_ntop(target, buf, sizeof buf) == -1) { perror("ns_name_ntop"); exit(EXIT_FAILURE); } return (strdup(buf)); }
static void print_flag_qname(const u_char *qname, uint16_t setflags, uint16_t invflag) { char tmp[XT_DNS_MAXSIZE]; if (XT_DNS_FLAG_QNAME & setflags) { if (XT_DNS_FLAG_QNAME & invflag) { printf("! "); } if (ns_name_ntop(qname, tmp, sizeof(tmp)) == -1) xtables_error(PARAMETER_PROBLEM, "Unknown qname %s\n", tmp); printf("--qname %s ", tmp); } }
int mdn_prepend(ns_name_ntop)(const u_char *src, char *dst, size_t dstsiz) { return (ns_name_ntop(src, dst, dstsiz)); }
DNS::HostMap DNS::resolve( const std::string& service, const std::string& proto, const std::string& domain, const LogSink& logInstance ) { buffer srvbuf; bool error = false; const std::string dname = "_" + service + "._" + proto; if( !domain.empty() ) srvbuf.len = res_querydomain( dname.c_str(), const_cast<char*>( domain.c_str() ), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ ); else srvbuf.len = res_query( dname.c_str(), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ ); if( srvbuf.len < 0 ) return defaultHostMap( domain, logInstance ); HEADER* hdr = (HEADER*)srvbuf.buf; unsigned char* here = srvbuf.buf + NS_HFIXEDSZ; if( ( hdr->tc ) || ( srvbuf.len < NS_HFIXEDSZ ) ) error = true; if( hdr->rcode >= 1 && hdr->rcode <= 5 ) error = true; if( ntohs( hdr->ancount ) == 0 ) error = true; if( ntohs( hdr->ancount ) > NS_PACKETSZ ) error = true; int cnt; for( cnt = ntohs( hdr->qdcount ); cnt>0; --cnt ) { int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len ); here += strlen + NS_QFIXEDSZ; } unsigned char* srv[NS_PACKETSZ]; int srvnum = 0; for( cnt = ntohs( hdr->ancount ); cnt>0; --cnt ) { int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len ); here += strlen; srv[srvnum++] = here; here += SRV_FIXEDSZ; here += dn_skipname( here, srvbuf.buf + srvbuf.len ); } if( error ) { return defaultHostMap( domain, logInstance ); } // (q)sort here HostMap servers; for( cnt=0; cnt<srvnum; ++cnt ) { name srvname; if( ns_name_ntop( srv[cnt] + SRV_SERVER, (char*)srvname, NS_MAXDNAME ) < 0 ) printf( "handle this error!\n" ); servers[(char*)srvname] = ns_get16( srv[cnt] + SRV_PORT ); } return servers; }
void verify_next_assertion(val_context_t * ctx, struct val_digested_auth_chain *as, struct val_digested_auth_chain *the_trust, u_int32_t flags) { struct rrset_rec *the_set; struct rrset_rr *the_sig; u_char *signby_name_n; u_int16_t signby_footprint_n; val_dnskey_rdata_t dnskey; int is_a_wildcard; struct rrset_rr *nextrr; struct rrset_rr *keyrr; u_int16_t tag_h; char name_p[NS_MAXDNAME]; if ((as == NULL) || (as->val_ac_rrset.ac_data == NULL) || (the_trust == NULL)) { val_log(ctx, LOG_INFO, "verify_next_assertion(): Cannot verify assertion - no data"); return; } the_set = as->val_ac_rrset.ac_data; dnskey.public_key = NULL; if (-1 == ns_name_ntop(the_set->rrs_name_n, name_p, sizeof(name_p))) snprintf(name_p, sizeof(name_p), "unknown/error"); if (the_set->rrs_sig == NULL) { val_log(ctx, LOG_INFO, "verify_next_assertion(): RRSIG is missing"); as->val_ac_status = VAL_AC_RRSIG_MISSING; return; } if (the_set->rrs_type_h != ns_t_dnskey) { /* * trust path contains the key */ if (the_trust->val_ac_rrset.ac_data == NULL) { val_log(ctx, LOG_INFO, "verify_next_assertion(): Key is empty"); as->val_ac_status = VAL_AC_DNSKEY_MISSING; return; } keyrr = the_trust->val_ac_rrset.ac_data->rrs_data; } else { /* * data itself contains the key */ if (the_set->rrs_data == NULL) { val_log(ctx, LOG_INFO, "verify_next_assertion(): Key is empty"); as->val_ac_status = VAL_AC_DNSKEY_MISSING; return; } keyrr = the_set->rrs_data; } for (the_sig = the_set->rrs_sig; the_sig; the_sig = the_sig->rr_next) { /* * do wildcard processing */ if (!check_label_count(the_set, the_sig, &is_a_wildcard)) { SET_STATUS(as->val_ac_status, the_sig, VAL_AC_WRONG_LABEL_COUNT); val_log(ctx, LOG_INFO, "verify_next_assertion(): Incorrect RRSIG label count"); continue; } /* * for each sig, identify key, */ if (VAL_NO_ERROR != identify_key_from_sig(the_sig, &signby_name_n, &signby_footprint_n)) { SET_STATUS(as->val_ac_status, the_sig, VAL_AC_INVALID_RRSIG); val_log(ctx, LOG_INFO, "verify_next_assertion(): Cannot extract key footprint from RRSIG"); continue; } tag_h = ntohs(signby_footprint_n); for (nextrr = keyrr; nextrr; nextrr = nextrr->rr_next) { int is_verified = 0; if (VAL_NO_ERROR != val_parse_dnskey_rdata(nextrr->rr_rdata, nextrr->rr_rdata_length, &dnskey)) { val_log(ctx, LOG_INFO, "verify_next_assertion(): Cannot parse DNSKEY data"); nextrr->rr_status = VAL_AC_INVALID_KEY; continue; } dnskey.next = NULL; if (dnskey.key_tag != tag_h) { if (dnskey.public_key != NULL) { FREE(dnskey.public_key); dnskey.public_key = NULL; } continue; } val_log(ctx, LOG_DEBUG, "verify_next_assertion(): Found potential matching DNSKEY for RRSIG"); /* * check the signature */ is_verified = do_verify(ctx, signby_name_n, &nextrr->rr_status, &the_sig->rr_status, the_set, the_sig, &dnskey, is_a_wildcard, flags); /* * There might be multiple keys with the same key tag; set this as * the signing key only if we dont have other status for this key */ SET_STATUS(as->val_ac_status, the_sig, the_sig->rr_status); if (nextrr->rr_status == VAL_AC_UNSET) { nextrr->rr_status = VAL_AC_SIGNING_KEY; } if (is_verified) { val_log(ctx, LOG_INFO, "verify_next_assertion(): Verified a RRSIG for %s (%s) using a DNSKEY (%d)", name_p, p_type(the_set->rrs_type_h), dnskey.key_tag); if ( as->val_ac_status == VAL_AC_TRUST || nextrr->rr_status == VAL_AC_TRUST_POINT) { /* we've verified a trust anchor */ as->val_ac_status = VAL_AC_TRUST; val_log(ctx, LOG_INFO, "verify_next_assertion(): verification traces back to trust anchor"); if (dnskey.public_key != NULL) { FREE(dnskey.public_key); dnskey.public_key = NULL; } return; } /* Check if we're trying to verify some key in the authentication chain */ if ( the_set->rrs_type_h == ns_t_dnskey && as != the_trust) { /* Check if we have reached our trust key */ /* * If this record contains a DNSKEY, check if the DS record contains this key * DNSKEYs cannot be wildcard expanded, so VAL_AC_WCARD_VERIFIED does not * count as a good sig * Create the link even if the DNSKEY algorithm is unknown since this * may be the provably insecure case */ /* * follow the trust path */ struct rrset_rr *dsrec = the_trust->val_ac_rrset.ac_data->rrs_data; while (dsrec) { val_ds_rdata_t ds; ds.d_hash = NULL; int retval = val_parse_ds_rdata(dsrec->rr_rdata, dsrec->rr_rdata_length, &ds); if(retval == VAL_NOT_IMPLEMENTED) { val_log(ctx, LOG_INFO, "verify_next_assertion(): DS hash not supported"); dsrec->rr_status = VAL_AC_ALGORITHM_NOT_SUPPORTED; } else if (retval != VAL_NO_ERROR) { val_log(ctx, LOG_INFO, "verify_next_assertion(): DS parse error"); dsrec->rr_status = VAL_AC_INVALID_DS; } else if (DNSKEY_MATCHES_DS(ctx, &dnskey, &ds, the_set->rrs_name_n, nextrr, &dsrec->rr_status)) { val_log(ctx, LOG_DEBUG, "verify_next_assertion(): DNSKEY tag (%d) matches DS tag (%d)", (&dnskey)->key_tag, (&ds)->d_keytag); /* * the first match is enough */ nextrr->rr_status = VAL_AC_VERIFIED_LINK; FREE(ds.d_hash); ds.d_hash = NULL; if (dnskey.public_key) { FREE(dnskey.public_key); dnskey.public_key = NULL; } val_log(ctx, LOG_INFO, "verify_next_assertion(): Key links upward"); return; } else { /* * Didn't find a valid entry in the DS record set * Not necessarily a problem, since there is no requirement that a DS be present * If none match, then we set the status accordingly. See below. */ nextrr->rr_status = VAL_AC_DS_NOMATCH; } if (ds.d_hash != NULL) FREE(ds.d_hash); dsrec = dsrec->rr_next; } } } if (dnskey.public_key != NULL) { FREE(dnskey.public_key); } dnskey.public_key = NULL; } val_log(ctx, LOG_INFO, "verify_next_assertion(): Could not link this RRSIG to a DNSKEY"); SET_STATUS(as->val_ac_status, the_sig, VAL_AC_DNSKEY_NOMATCH); } /* * If we reach here and we're a keyset, we either didn't verify the keyset or * didn't verify the link from the key to the DS */ if (the_set->rrs_type_h == ns_t_dnskey){ as->val_ac_status = VAL_AC_NO_LINK; } }
/* Setup a client socket for the named service over the given protocol under * the given domain name. */ static int insrv_lookup (int (*mksox) (int,const struct sockaddr *,socklen_t), char *service, char *proto, char *domain, char *cnxhost, size_t cnxhlen, int *cnxport) { // 1. convert service/proto to svcnm // 2. construct SRV query for _service._proto.domain // 3. try connecting to all answers in turn // 4. if no SRV records exist, lookup A record to connect to on stdport // 5. return connection socket or error code iobuf query, names; name svcnm; int error=0; int ctr; int rnd; int sox=0; HEADER *nameshdr; unsigned char *here, *srv[MAXNUM_SRV], *ip; int num_srv=0; // Storage for fallback SRV list, constructed when DNS gives no SRV unsigned char fallbacksrv [2*(MAXCDNAME+SRV_FIXEDSZ+MAXCDNAME)]; srv_flags &= ~SRV_GOT_MASK; srv_flags |= SRV_GOT_SRV; strcpy (svcnm, "_"); strcat (svcnm, service); strcat (svcnm, "._"); strcat (svcnm, proto); // Note that SRV records are only defined for class IN if (domain) { names.len=res_querydomain (svcnm, domain, C_IN, T_SRV, names.buf, PACKETSZ); } else { names.len=res_query (svcnm, C_IN, T_SRV, names.buf, PACKETSZ); } if (names.len < 0) { error = -ENOENT; goto fallback; } nameshdr=(HEADER *) names.buf; here=names.buf + HFIXEDSZ; rnd=nameshdr->id; // Heck, gimme one reason why not! if ((names.len < HFIXEDSZ) || nameshdr->tc) { error = -EMSGSIZE; } switch (nameshdr->rcode) { case 1: error = -EFAULT; goto fallback; case 2: error = -EAGAIN; goto fallback; case 3: error = -ENOENT; goto fallback; case 4: error = -ENOSYS; goto fallback; case 5: error = -EPERM; goto fallback; default: break; } if (ntohs (nameshdr->ancount) == 0) { error = -ENOENT; goto fallback; } if (ntohs (nameshdr->ancount) > MAXNUM_SRV) { error = -ERANGE; goto fallback; } for (ctr=ntohs (nameshdr->qdcount); ctr>0; ctr--) { int strlen=dn_skipname (here, names.buf+names.len); here += strlen + QFIXEDSZ; } for (ctr=ntohs (nameshdr->ancount); ctr>0; ctr--) { int strlen=dn_skipname (here, names.buf+names.len); here += strlen; srv [num_srv++] = here; here += SRV_FIXEDSZ; here += dn_skipname (here, names.buf+names.len); } // In case an error occurred, there are no SRV records. // Fallback strategy now is: construct two. One with the domain name, // the other with the /standard/ service name prefixed. // Note: Assuming a domain without the service name prefixed! fallback: if (error) { struct servent *servent = getservbyname (service, proto); srv_flags &= ~SRV_GOT_MASK; srv_flags |= SRV_GOT_A; num_srv = 2; if (!servent) { return error; // First error returned } srv [0] = here = fallbacksrv; // Only few record fields are really needed: *(unsigned short *)(here + SRV_COST) = htons (0); *(unsigned short *)(here + SRV_WEIGHT) = htons (0); *(unsigned short *)(here + SRV_PORT) = servent->s_port; here += SRV_FIXEDSZ; if (domain) { here += dn_comp (domain, here, MAXCDNAME, NULL, NULL); } // Forget about the name whose SRV IN this is, no need for it srv [1] = here; // Only few record fields are really needed: *(unsigned short *)(here + SRV_COST) = htons (1); *(unsigned short *)(here + SRV_WEIGHT) = htons (0); *(unsigned short *)(here + SRV_PORT) = servent->s_port; here += SRV_FIXEDSZ; here += dn_comp (servent->s_name, here, MAXCDNAME, NULL, NULL); here--; // Go back to overwrite final zero byte if (domain) { here += dn_comp (domain, here, MAXCDNAME, NULL, NULL); } rnd = 1; } // End of fallback construction, making sure that variables are defined // srv[] points to the SRV RR, num_srv counts the number of entries. // Every SRV RR has at least cost, weight, port and servername set. #ifdef DEBUG for (ctr=0; ctr<num_srv; ctr++) { name srvname; if (ns_name_ntop (srv [ctr]+SRV_SERVER, srvname, MAXDNAME) < 0) { return -errno; } printf ("Considering SRV server %d %d %d\t%s\n", ns_get16 (srv [ctr]+SRV_COST), ns_get16 (srv [ctr]+SRV_WEIGHT), ns_get16 (srv [ctr]+SRV_PORT), srvname ); } #endif // Overwrite weight with rnd-spread version to divide load over weights for (ctr=0; ctr<num_srv; ctr++) { *(unsigned short *)(srv [ctr]+SRV_WEIGHT) = rnd % (1+ns_get16 (srv [ctr]+SRV_WEIGHT)); } qsort (srv, num_srv, sizeof (*srv), srvcmp); for (ctr=0; ctr<num_srv; ctr++) { name srvname; struct hostent *host; // Open a socket to connect with int sox = socket (PF_INET, (*proto!='u')? SOCK_STREAM: SOCK_DGRAM, 0); if (sox < 0) { return -errno; } if (ns_name_ntop (srv [ctr]+SRV_SERVER, srvname, MAXDNAME) < 0) { return -errno; } #ifdef DEBUG printf ("Trying SRV server %d %d\t%s\n", ns_get16 (srv [ctr]+SRV_COST), *(unsigned short *)(srv [ctr]+SRV_WEIGHT), srvname ); #endif if ((host=gethostbyname (srvname)) && (host->h_addrtype == AF_INET)) { char **ip=host->h_addr_list; while (*ip) { char *ipnr=*ip; struct sockaddr_in sin; memset (&sin, 0, sizeof (sin)); sin.sin_family = AF_INET; memcpy (&sin.sin_addr, ipnr, sizeof (sin.sin_addr)); sin.sin_port = *(unsigned short *) (srv [ctr]+SRV_PORT); #ifdef DEBUG fprintf (stderr, "\tbind_connect (%d, 0x%08lx, %d)\t", sox, ntohl(*(unsigned long *)ipnr), ntohs (sin.sin_port)); #endif #ifdef DEBUG if (mksox == connect) { printf ("mksox == connect\n"); } if (mksox == bind) { printf ("mksox == bind\n"); } { int i; printf ("SIN ="); for (i=0; i<sizeof (sin); i++) printf (" %02x", (int) (((unsigned char *) &sin) [i])); printf ("\n"); } #endif if (mksox (sox, (struct sockaddr *) &sin, sizeof (sin)) == 0) { #ifdef DEBUG fprintf (stderr, "Connected or bound to %s:%d\n", srvname, ntohs (sin.sin_port)); #endif if (cnxhost) { if (strlen (cnxhost) > cnxhlen-1) { *cnxhost = '\0'; } else { strncpy (cnxhost,srvname,cnxhlen); } } if (cnxport) { *cnxport = ntohs (sin.sin_port); } return sox; } else { if (!error) { error = -errno; } } ip++; } } #ifdef DEBUG printf ("Closing socket %d\n", sox); #endif close (sox); } if (!error) { error = -ENOENT; } return error; }
/* * A thread-safe, re-entrant version of val_gethostbyaddr */ int val_gethostbyaddr_r(val_context_t * context, const char *addr, int len, int type, struct hostent *ret, char *buf, int buflen, struct hostent **result, int *h_errnop, val_status_t * val_status) { char domain_string[NS_MAXDNAME]; int ret_status = 0, bufused = 0; struct val_answer_chain *val_res = NULL; struct val_answer_chain *res; int retval; val_context_t *ctx = NULL; /* * check misc parameters exist */ if (!addr || !ret || !buf || (buflen <= 0) || !result || !h_errnop || !val_status) { if (h_errnop) *h_errnop = NO_RECOVERY; return (NO_RECOVERY); } /* * default the input parameters */ *result = NULL; ret->h_name = NULL; ret->h_aliases = NULL; ret->h_addr_list = NULL; *h_errnop = 0; *val_status = VAL_UNTRUSTED_ANSWER; /* * get the address values, only support IPv4 and IPv6 */ if (AF_INET == type && len >= sizeof(struct in_addr)) { ret->h_addrtype = type; ret->h_length = sizeof(struct in_addr); } #ifdef VAL_IPV6 else if (AF_INET6 == type && len >= sizeof(struct in6_addr)) { ret->h_addrtype = type; ret->h_length = sizeof(struct in6_addr); } #endif else { *h_errnop = NO_RECOVERY; return (NO_RECOVERY); } memset(domain_string, 0, sizeof(domain_string)); if (0 != (ret_status = address_to_reverse_domain(addr, type, domain_string, sizeof(domain_string))) ) { *h_errnop = ret_status; return ret_status; } /* * if there is memory, add the address to hostent's address list */ if ((buflen > bufused) && ((buflen - bufused) >= (ret->h_length + (sizeof(char *) * 2)))) { ret->h_addr_list = (char **) (buf + bufused); bufused = bufused + (sizeof(char *) * 2); ret->h_addr_list[0] = buf + bufused; ret->h_addr_list[1] = NULL; bufused = bufused + ret->h_length; memcpy(ret->h_addr_list[0], addr, ret->h_length); } else { /* no memory, fail */ *h_errnop = NO_RECOVERY; return (NO_RECOVERY); } ctx = val_create_or_refresh_context(context); /* does CTX_LOCK_POL_SH */ if (ctx == NULL) { *h_errnop = NO_RECOVERY; return (NO_RECOVERY); } if (VAL_NO_ERROR != (retval = val_get_rrset(ctx, /* val_context_t * */ domain_string, /* domain name */ ns_c_in, /* const u_int16_t q_class */ ns_t_ptr, /* const u_int16_t type */ 0, &val_res))) { /* struct val_answer_chain **results */ val_log(ctx, LOG_ERR, "val_gethostbyaddr_r(): val_get_rrset failed - %s", p_val_err(retval)); CTX_UNLOCK_POL(ctx); *h_errnop = NO_RECOVERY; return NO_RECOVERY; } CTX_UNLOCK_POL(ctx); if (!val_res) { *h_errnop = NO_RECOVERY; return NO_RECOVERY; } for (res = val_res; res; res=res->val_ans_next) { struct rr_rec *rr = res->val_ans; if (rr) { struct rr_rec *rr_it = NULL; int count = 0; int aliases_sz = 0; /* * if the buffer has enough room add the first host address */ if (rr->rr_length < (buflen - bufused - 1)) { /* * setup hostent */ ret->h_name = buf + bufused; ns_name_ntop(rr->rr_data, ret->h_name, (buflen - bufused)); bufused = bufused + strlen(ret->h_name) + 1; rr_it = rr->rr_next; /* * are there other hostnames? */ if (rr_it) { /* * calculate the amount of memory we need for aliases. */ do { count++; aliases_sz = aliases_sz + rr_it->rr_length + 1; } while (NULL != (rr_it = rr_it->rr_next)); /* * check that we have the space in the buffer */ if (buflen >= (bufused + (sizeof(char *) * (count + 1)) + aliases_sz)) { /* * assign the string pointer array */ ret->h_aliases = (char **) (buf + bufused); bufused = bufused + (sizeof(char *) * (count + 1)); /* * assign the strings */ rr_it = rr->rr_next; count = 0; do { ret->h_aliases[count] = buf + bufused; ns_name_ntop(rr_it->rr_data, ret->h_aliases[count], (buflen - bufused)); bufused = bufused + strlen(ret->h_aliases[count]) + 1; count++; } while (NULL != (rr_it = rr_it->rr_next)); /* * mark end of array */ ret->h_aliases[count] = NULL; } /* * else we didn't have enough memory for the aliases. They * will be ignored with only one hostname returned */ } /* else there are no other hostnames/aliases */ } else { /* else there is not enough room for even one host name, fail */ ret->h_name = NULL; *h_errnop = NO_RECOVERY; return NO_RECOVERY; } break; } else if (val_does_not_exist(res->val_ans_status)) { if ((res->val_ans_status == VAL_NONEXISTENT_TYPE) || (res->val_ans_status == VAL_NONEXISTENT_TYPE_NOCHAIN)) { *h_errnop = NO_DATA; } else if ((res->val_ans_status == VAL_NONEXISTENT_NAME) || (res->val_ans_status == VAL_NONEXISTENT_NAME_NOCHAIN)) { *h_errnop = HOST_NOT_FOUND; } *result = ret; return *h_errnop; } } if (!res) { /* no rrset, but a succesful return from the query?, fail */ ret->h_name = NULL; *h_errnop = NO_RECOVERY; return NO_RECOVERY; } /* set the value of merged trusted and validated status values */ if (val_isvalidated(res->val_ans_status)) *val_status = VAL_VALIDATED_ANSWER; else if (val_istrusted(res->val_ans_status)) *val_status = VAL_TRUSTED_ANSWER; /* * no error, set result */ *result = ret; return *h_errnop; } /* val_getthostbyaddr_r */
/* Setup a client socket for the named service over the given protocol under * the given domain name. */ int insrv_lookup (const char *service, const char *proto, const char *domain, list<t_dns_result> &result) { // 1. convert service/proto to svcnm // 2. construct SRV query for _service._proto.domain iobuf names; name svcnm; int ctr; int rnd; HEADER *nameshdr; unsigned char *here, *srv[MAXNUM_SRV]; int num_srv=0; // Storage for fallback SRV list, constructed when DNS gives no SRV //unsigned char fallbacksrv [2*(MAXCDNAME+SRV_FIXEDSZ+MAXCDNAME)]; // srv_flags &= ~SRV_GOT_MASK; // srv_flags |= SRV_GOT_SRV; strcpy (svcnm, "_"); strcat (svcnm, service); strcat (svcnm, "._"); strcat (svcnm, proto); // Note that SRV records are only defined for class IN if (domain) { names.len=res_querydomain (svcnm, domain, C_IN, T_SRV, names.buf, PACKETSZ); } else { names.len=res_query (svcnm, C_IN, T_SRV, names.buf, PACKETSZ); } if (names.len < 0) { return -ENOENT; } nameshdr=(HEADER *) names.buf; here=names.buf + HFIXEDSZ; rnd=nameshdr->id; // Heck, gimme one reason why not! if ((names.len < HFIXEDSZ) || nameshdr->tc) { return -EMSGSIZE; } switch (nameshdr->rcode) { case 1: return -EFAULT; case 2: return -EAGAIN; case 3: return -ENOENT; case 4: return -ENOSYS; case 5: return -EPERM; default: break; } if (ntohs (nameshdr->ancount) == 0) { return -ENOENT; } if (ntohs (nameshdr->ancount) > MAXNUM_SRV) { return -ERANGE; } for (ctr=ntohs (nameshdr->qdcount); ctr>0; ctr--) { int strlen=dn_skipname (here, names.buf+names.len); here += strlen + QFIXEDSZ; } for (ctr=ntohs (nameshdr->ancount); ctr>0; ctr--) { int strlen=dn_skipname (here, names.buf+names.len); here += strlen; srv [num_srv++] = here; here += SRV_FIXEDSZ; here += dn_skipname (here, names.buf+names.len); } // Overwrite weight with rnd-spread version to divide load over weights for (ctr=0; ctr<num_srv; ctr++) { *(unsigned short *) (srv [ctr]+SRV_WEIGHT) = htons(rnd % (1+ns_get16 (srv [ctr]+SRV_WEIGHT))); } qsort (srv, num_srv, sizeof (*srv), srvcmp); result.clear(); for (ctr=0; ctr<num_srv; ctr++) { name srvname; if (ns_name_ntop (srv [ctr]+SRV_SERVER, srvname, MAXDNAME) < 0) { return -errno; } t_dns_result r; r.hostname = srvname; r.port = ns_get16(srv [ctr]+SRV_PORT); result.push_back(r); } return 0; }