static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs) { // Build FQDN char fqdn_buf[256]; gethostname(fqdn_buf, sizeof(fqdn_buf)); struct { uint16_t type; uint16_t len; uint8_t flags; uint8_t data[256]; } fqdn; size_t fqdn_len = 5 + dn_comp(fqdn_buf, fqdn.data, sizeof(fqdn.data), NULL, NULL); fqdn.type = htons(DHCPV6_OPT_FQDN); fqdn.len = htons(fqdn_len - 4); fqdn.flags = 0; // Build Client ID size_t cl_id_len; void *cl_id = odhcp6c_get_state(STATE_CLIENT_ID, &cl_id_len); // Get Server ID size_t srv_id_len; void *srv_id = odhcp6c_get_state(STATE_SERVER_ID, &srv_id_len); // Build IA_PDs size_t ia_pd_entries = 0, ia_pd_len = 0; uint8_t *ia_pd; if (type == DHCPV6_MSG_SOLICIT) { odhcp6c_clear_state(STATE_IA_PD); size_t n_prefixes; struct odhcp6c_request_prefix *request_prefixes = odhcp6c_get_state(STATE_IA_PD_INIT, &n_prefixes); n_prefixes /= sizeof(struct odhcp6c_request_prefix); ia_pd = alloca(n_prefixes * (sizeof(struct dhcpv6_ia_hdr) + sizeof(struct dhcpv6_ia_prefix))); for (size_t i = 0; i < n_prefixes; i++) { struct dhcpv6_ia_hdr hdr_ia_pd = { htons(DHCPV6_OPT_IA_PD), htons(sizeof(hdr_ia_pd) - 4 + sizeof(struct dhcpv6_ia_prefix) * !!request_prefixes[i].length), request_prefixes[i].iaid, 0, 0 }; struct dhcpv6_ia_prefix pref = { .type = htons(DHCPV6_OPT_IA_PREFIX), .len = htons(sizeof(pref) - 4), .prefix = request_prefixes[i].length }; memcpy(ia_pd + ia_pd_len, &hdr_ia_pd, sizeof(hdr_ia_pd)); ia_pd_len += sizeof(hdr_ia_pd); if (request_prefixes[i].length) { memcpy(ia_pd + ia_pd_len, &pref, sizeof(pref)); ia_pd_len += sizeof(pref); } } } else {
int ns_sign2(u_char *msg, int *msglen, int msgsize, int error, void *k, const u_char *querysig, int querysiglen, u_char *sig, int *siglen, time_t in_timesigned, u_char **dnptrs, u_char **lastdnptr) { HEADER *hp = (HEADER *)msg; DST_KEY *key = (DST_KEY *)k; u_char *cp, *eob; u_char *lenp; u_char *alg; int n; time_t timesigned; u_char name[NS_MAXCDNAME]; dst_init(); if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL) return (-1); cp = msg + *msglen; eob = msg + msgsize; /* Name. */ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { n = ns_name_pton(key->dk_key_name, name, sizeof name); if (n != -1) n = ns_name_pack(name, cp, eob - cp, (const u_char **)dnptrs, (const u_char **)lastdnptr); } else { n = ns_name_pton("", name, sizeof name); if (n != -1) n = ns_name_pack(name, cp, eob - cp, NULL, NULL); } if (n < 0) return (NS_TSIG_ERROR_NO_SPACE); cp += n; /* Type, class, ttl, length (not filled in yet). */ BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); PUTSHORT(ns_t_tsig, cp); PUTSHORT(ns_c_any, cp); PUTLONG(0, cp); /*%< TTL */ lenp = cp; cp += 2; /* Alg. */ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { if (key->dk_alg != KEY_HMAC_MD5) return (-ns_r_badkey); n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL); } else n = dn_comp("", cp, eob - cp, NULL, NULL); if (n < 0) return (NS_TSIG_ERROR_NO_SPACE); alg = cp; cp += n; /* Time. */ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); PUTSHORT(0, cp); timesigned = time(NULL); if (error != ns_r_badtime) PUTLONG(timesigned, cp); else PUTLONG(in_timesigned, cp); PUTSHORT(NS_TSIG_FUDGE, cp); /* Compute the signature. */ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { void *ctx; u_char buf[NS_MAXCDNAME], *cp2; int n; dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); /* Digest the query signature, if this is a response. */ if (querysiglen > 0 && querysig != NULL) { u_int16_t len_n = htons(querysiglen); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, (u_char *)&len_n, INT16SZ, NULL, 0); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, querysig, querysiglen, NULL, 0); } /* Digest the message. */ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen, NULL, 0); /* Digest the key name. */ n = ns_name_ntol(name, buf, sizeof(buf)); INSIST(n > 0); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); /* Digest the class and TTL. */ cp2 = buf; PUTSHORT(ns_c_any, cp2); PUTLONG(0, cp2); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf, NULL, 0); /* Digest the algorithm. */ n = ns_name_ntol(alg, buf, sizeof(buf)); INSIST(n > 0); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); /* Digest the time signed, fudge, error, and other data */ cp2 = buf; PUTSHORT(0, cp2); /*%< Top 16 bits of time */ if (error != ns_r_badtime) PUTLONG(timesigned, cp2); else PUTLONG(in_timesigned, cp2); PUTSHORT(NS_TSIG_FUDGE, cp2); PUTSHORT(error, cp2); /*%< Error */ if (error != ns_r_badtime) PUTSHORT(0, cp2); /*%< Other data length */ else { PUTSHORT(INT16SZ+INT32SZ, cp2); /*%< Other data length */ PUTSHORT(0, cp2); /*%< Top 16 bits of time */ PUTLONG(timesigned, cp2); } dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf, NULL, 0); n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, sig, *siglen); if (n < 0) return (-ns_r_badkey); *siglen = n; } else *siglen = 0; /* Add the signature. */ BOUNDS_CHECK(cp, INT16SZ + (*siglen)); PUTSHORT(*siglen, cp); memcpy(cp, sig, *siglen); cp += (*siglen); /* The original message ID & error. */ BOUNDS_CHECK(cp, INT16SZ + INT16SZ); PUTSHORT(ntohs(hp->id), cp); /*%< already in network order */ PUTSHORT(error, cp); /* Other data. */ BOUNDS_CHECK(cp, INT16SZ); if (error != ns_r_badtime) PUTSHORT(0, cp); /*%< Other data length */ else { PUTSHORT(INT16SZ+INT32SZ, cp); /*%< Other data length */ BOUNDS_CHECK(cp, INT32SZ+INT16SZ); PUTSHORT(0, cp); /*%< Top 16 bits of time */ PUTLONG(timesigned, cp); } /* Go back and fill in the length. */ PUTSHORT(cp - lenp - INT16SZ, lenp); hp->arcount = htons(ntohs(hp->arcount) + 1); *msglen = (cp - msg); return (0); }
int ns_sign_tcp2(u_char *msg, int *msglen, int msgsize, int error, ns_tcp_tsig_state *state, int done, u_char **dnptrs, u_char **lastdnptr) { u_char *cp, *eob, *lenp; u_char buf[MAXDNAME], *cp2; HEADER *hp = (HEADER *)msg; time_t timesigned; int n; if (msg == NULL || msglen == NULL || state == NULL) return (-1); state->counter++; if (state->counter == 0) return (ns_sign2(msg, msglen, msgsize, error, state->key, state->sig, state->siglen, state->sig, &state->siglen, 0, dnptrs, lastdnptr)); if (state->siglen > 0) { u_int16_t siglen_n = htons(state->siglen); dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx, NULL, 0, NULL, 0); dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, (u_char *)&siglen_n, INT16SZ, NULL, 0); dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, state->sig, state->siglen, NULL, 0); state->siglen = 0; } dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen, NULL, 0); if (done == 0 && (state->counter % 100 != 0)) return (0); cp = msg + *msglen; eob = msg + msgsize; /* Name. */ n = dn_comp(state->key->dk_key_name, cp, eob - cp, dnptrs, lastdnptr); if (n < 0) return (NS_TSIG_ERROR_NO_SPACE); cp += n; /* Type, class, ttl, length (not filled in yet). */ BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); PUTSHORT(ns_t_tsig, cp); PUTSHORT(ns_c_any, cp); PUTLONG(0, cp); /*%< TTL */ lenp = cp; cp += 2; /* Alg. */ n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL); if (n < 0) return (NS_TSIG_ERROR_NO_SPACE); cp += n; /* Time. */ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); PUTSHORT(0, cp); timesigned = time(NULL); PUTLONG(timesigned, cp); PUTSHORT(NS_TSIG_FUDGE, cp); /* * Compute the signature. */ /* Digest the time signed and fudge. */ cp2 = buf; PUTSHORT(0, cp2); /*%< Top 16 bits of time */ PUTLONG(timesigned, cp2); PUTSHORT(NS_TSIG_FUDGE, cp2); dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, buf, cp2 - buf, NULL, 0); n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, state->sig, sizeof(state->sig)); if (n < 0) return (-ns_r_badkey); state->siglen = n; /* Add the signature. */ BOUNDS_CHECK(cp, INT16SZ + state->siglen); PUTSHORT(state->siglen, cp); memcpy(cp, state->sig, state->siglen); cp += state->siglen; /* The original message ID & error. */ BOUNDS_CHECK(cp, INT16SZ + INT16SZ); PUTSHORT(ntohs(hp->id), cp); /*%< already in network order */ PUTSHORT(error, cp); /* Other data. */ BOUNDS_CHECK(cp, INT16SZ); PUTSHORT(0, cp); /* Go back and fill in the length. */ PUTSHORT(cp - lenp - INT16SZ, lenp); hp->arcount = htons(ntohs(hp->arcount) + 1); *msglen = (cp - msg); return (0); }
/* ns_sign * Parameters: * msg message to be sent * msglen input - length of message * output - length of signed message * msgsize length of buffer containing message * error value to put in the error field * key tsig key used for signing * querysig (response), the signature in the query * querysiglen (response), the length of the signature in the query * sig a buffer to hold the generated signature * siglen input - length of signature buffer * output - length of signature * * Errors: * - bad input data (-1) * - bad key / sign failed (-BADKEY) * - not enough space (NS_TSIG_ERROR_NO_SPACE) */ isc_result_t ns_sign(u_char *msg, unsigned *msglen, unsigned msgsize, int error, void *k, const u_char *querysig, unsigned querysiglen, u_char *sig, unsigned *siglen, time_t in_timesigned) { HEADER *hp = (HEADER *)msg; DST_KEY *key = (DST_KEY *)k; if(msglen == NULL){ return ISC_R_INVALIDARG; } u_char *cp = msg + *msglen, *eob = msg + msgsize; u_char *lenp; u_char *name, *alg; unsigned n; time_t timesigned; dst_init(); if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL) return ISC_R_INVALIDARG; /* Name. */ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) n = dn_comp(key->dk_key_name, cp, (unsigned)(eob - cp), NULL, NULL); else n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL); name = cp; cp += n; /* Type, class, ttl, length (not filled in yet). */ BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); PUTSHORT(ns_t_tsig, cp); PUTSHORT(ns_c_any, cp); PUTLONG(0, cp); /* TTL */ lenp = cp; cp += 2; /* Alg. */ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { if (key->dk_alg != KEY_HMAC_MD5) return ISC_R_BADKEY; n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, (unsigned)(eob - cp), NULL, NULL); } else n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL); if (n < 0) return ISC_R_NOSPACE; alg = cp; cp += n; /* Time. */ BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); PUTSHORT(0, cp); timesigned = time(NULL); if (error != ns_r_badtime) PUTLONG(timesigned, cp); else PUTLONG(in_timesigned, cp); PUTSHORT(NS_TSIG_FUDGE, cp); /* Compute the signature. */ if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { void *ctx; u_char buf[MAXDNAME], *cp2; unsigned n; dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); /* Digest the query signature, if this is a response. */ if (querysiglen > 0 && querysig != NULL) { u_int16_t len_n = htons(querysiglen); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, (u_char *)&len_n, INT16SZ, NULL, 0); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, querysig, querysiglen, NULL, 0); } /* Digest the message. */ dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen, NULL, 0); /* Digest the key name. */ n = ns_name_ntol(name, buf, sizeof(buf)); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); /* Digest the class and TTL. */ cp2 = buf; PUTSHORT(ns_c_any, cp2); PUTLONG(0, cp2); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, (unsigned)(cp2-buf), NULL, 0); /* Digest the algorithm. */ n = ns_name_ntol(alg, buf, sizeof(buf)); dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); /* Digest the time signed, fudge, error, and other data */ cp2 = buf; PUTSHORT(0, cp2); /* Top 16 bits of time */ if (error != ns_r_badtime) PUTLONG(timesigned, cp2); else PUTLONG(in_timesigned, cp2); PUTSHORT(NS_TSIG_FUDGE, cp2); PUTSHORT(error, cp2); /* Error */ if (error != ns_r_badtime) PUTSHORT(0, cp2); /* Other data length */ else { PUTSHORT(INT16SZ+INT32SZ, cp2); /* Other data length */ PUTSHORT(0, cp2); /* Top 16 bits of time */ PUTLONG(timesigned, cp2); } dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, (unsigned)(cp2-buf), NULL, 0); n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, sig, *siglen); if (n < 0) return ISC_R_BADKEY; *siglen = n; } else *siglen = 0; /* Add the signature. */ BOUNDS_CHECK(cp, INT16SZ + (*siglen)); PUTSHORT(*siglen, cp); if(*siglen>=0){ memcpy(cp, sig, *siglen); cp += (*siglen); } /* The original message ID & error. */ BOUNDS_CHECK(cp, INT16SZ + INT16SZ); PUTSHORT(ntohs(hp->id), cp); /* already in network order */ PUTSHORT(error, cp); /* Other data. */ BOUNDS_CHECK(cp, INT16SZ); if (error != ns_r_badtime) PUTSHORT(0, cp); /* Other data length */ else { PUTSHORT(INT16SZ+INT32SZ, cp); /* Other data length */ BOUNDS_CHECK(cp, INT32SZ+INT16SZ); PUTSHORT(0, cp); /* Top 16 bits of time */ PUTLONG(timesigned, cp); } /* Go back and fill in the length. */ PUTSHORT(cp - lenp - INT16SZ, lenp); hp->arcount = htons(ntohs(hp->arcount) + 1); *msglen = (cp - msg); return ISC_R_SUCCESS; }
/* * Form update packets. * Returns the size of the resulting packet if no error * On error, * returns -1 if error in reading a word/number in rdata * portion for update packets * -2 if length of buffer passed is insufficient * -3 if zone section is not the first section in * the linked list, or section order has a problem * -4 on a number overflow * -5 unknown operation or no records */ int res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) { ns_updrec *rrecp_start = rrecp_in; HEADER *hp; u_char *cp, *sp1, *sp2, *startp, *endp; int n, i, soanum, multiline; ns_updrec *rrecp; struct in_addr ina; char buf2[MAXDNAME]; int section, numrrs = 0, counts[ns_s_max]; u_int16_t rtype, rclass; u_int32_t n1, rttl; u_char *dnptrs[20], **dpp, **lastdnptr; if ((_res.options & RES_INIT) == 0 && res_init() == -1) { h_errno = NETDB_INTERNAL; return (-1); } /* * Initialize header fields. */ if ((buf == NULL) || (buflen < HFIXEDSZ)) return (-1); memset(buf, 0, HFIXEDSZ); hp = (HEADER *) buf; hp->id = htons(++_res.id); hp->opcode = ns_o_update; hp->rcode = NOERROR; sp1 = buf + 2*INT16SZ; /* save pointer to zocount */ cp = buf + HFIXEDSZ; buflen -= HFIXEDSZ; dpp = dnptrs; *dpp++ = buf; *dpp++ = NULL; lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; if (rrecp_start == NULL) return (-5); else if (rrecp_start->r_section != S_ZONE) return (-3); memset(counts, 0, sizeof counts); for (rrecp = rrecp_start; rrecp; rrecp = rrecp->r_grpnext) { numrrs++; section = rrecp->r_section; if (section < 0 || section >= ns_s_max) return (-1); counts[section]++; for (i = section + 1; i < ns_s_max; i++) if (counts[i]) return (-3); rtype = rrecp->r_type; rclass = rrecp->r_class; rttl = rrecp->r_ttl; /* overload class and type */ if (section == S_PREREQ) { rttl = 0; switch (rrecp->r_opcode) { case YXDOMAIN: rclass = C_ANY; rtype = T_ANY; rrecp->r_size = 0; break; case NXDOMAIN: rclass = C_NONE; rtype = T_ANY; rrecp->r_size = 0; break; case NXRRSET: rclass = C_NONE; rrecp->r_size = 0; break; case YXRRSET: if (rrecp->r_size == 0) rclass = C_ANY; break; default: fprintf(stderr, "res_mkupdate: incorrect opcode: %d\n", rrecp->r_opcode); fflush(stderr); return (-1); } } else if (section == S_UPDATE) { switch (rrecp->r_opcode) { case DELETE: rclass = rrecp->r_size == 0 ? C_ANY : C_NONE; break; case ADD: break; default: fprintf(stderr, "res_mkupdate: incorrect opcode: %d\n", rrecp->r_opcode); fflush(stderr); return (-1); } } /* * XXX appending default domain to owner name is omitted, * fqdn must be provided */ if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs, lastdnptr)) < 0) return (-1); cp += n; ShrinkBuffer(n + 2*INT16SZ); PUTSHORT(rtype, cp); PUTSHORT(rclass, cp); if (section == S_ZONE) { if (numrrs != 1 || rrecp->r_type != T_SOA) return (-3); continue; } ShrinkBuffer(INT32SZ + INT16SZ); PUTLONG(rttl, cp); sp2 = cp; /* save pointer to length byte */ cp += INT16SZ; if (rrecp->r_size == 0) { if (section == S_UPDATE && rclass != C_ANY) return (-1); else { PUTSHORT(0, sp2); continue; } } startp = rrecp->r_data; endp = startp + rrecp->r_size - 1; /* XXX this should be done centrally. */ switch (rrecp->r_type) { case T_A: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (!inet_aton(buf2, &ina)) return (-1); n1 = ntohl(ina.s_addr); ShrinkBuffer(INT32SZ); PUTLONG(n1, cp); break; case T_CNAME: case T_MB: case T_MG: case T_MR: case T_NS: case T_PTR: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case T_MINFO: case T_SOA: case T_RP: for (i = 0; i < 2; i++) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); } if (rrecp->r_type == T_SOA) { ShrinkBuffer(5 * INT32SZ); while (isspace(*startp) || !*startp) startp++; if (*startp == '(') { multiline = 1; startp++; } else multiline = 0; /* serial, refresh, retry, expire, minimum */ for (i = 0; i < 5; i++) { soanum = getnum_str(&startp, endp); if (soanum < 0) return (-1); PUTLONG(soanum, cp); } if (multiline) { while (isspace(*startp) || !*startp) startp++; if (*startp != ')') return (-1); } } break; case T_MX: case T_AFSDB: case T_RT: n = getnum_str(&startp, endp); if (n < 0) return (-1); PUTSHORT(n, cp); ShrinkBuffer(INT16SZ); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case T_PX: n = getnum_str(&startp, endp); if (n < 0) return (-1); PUTSHORT(n, cp); ShrinkBuffer(INT16SZ); for (i = 0; i < 2; i++) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); } break; case T_WKS: case T_HINFO: case T_TXT: case T_X25: case T_ISDN: case T_NSAP: case T_LOC: /* XXX - more fine tuning needed here */ ShrinkBuffer(rrecp->r_size); memcpy(cp, rrecp->r_data, rrecp->r_size); cp += rrecp->r_size; break; default: return (-1); } /*switch*/ n = (u_int16_t)((cp - sp2) - INT16SZ); PUTSHORT(n, sp2); } /*for*/ hp->qdcount = htons(counts[0]); hp->ancount = htons(counts[1]); hp->nscount = htons(counts[2]); hp->arcount = htons(counts[3]); return (cp - buf); }
/*********************************************************************** * cygwin_query: implements res_nquery by calling DnsQuery ***********************************************************************/ static int cygwin_query(res_state statp, const char * DomName, int Class, int Type, unsigned char * AnsPtr, int AnsLength) { DNS_STATUS res; PDNS_RECORD pQueryResultsSet, rr; int section, len, counts[4] = {0, 0, 0, 0}, debug = statp->options & RES_DEBUG; unsigned char * dnptrs[256], * ptr; dnptrs[0] = AnsPtr; dnptrs[1] = NULL; if (Class != ns_c_in) { errno = ENOSYS; statp->res_h_errno = NETDB_INTERNAL; return -1; } res = DnsQuery_A(DomName, Type, DNS_QUERY_TREAT_AS_FQDN, NULL, &pQueryResultsSet, NULL); #if 0 #define NETDB_INTERNAL -1 /* see errno */ #define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ #define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */ #define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ #define NO_DATA 4 /* Valid name, no data record of requested type */ #endif DPRINTF(debug, "DnsQuery: %lu (Windows)\n", res); if (res) { switch (res) { case ERROR_INVALID_NAME: errno = EINVAL; statp->res_h_errno = NETDB_INTERNAL;; break; case ERROR_TIMEOUT: statp->res_h_errno = TRY_AGAIN; break; case DNS_ERROR_RCODE_NAME_ERROR: statp->res_h_errno = HOST_NOT_FOUND; break; case DNS_ERROR_RCODE_SERVER_FAILURE: statp->res_h_errno = TRY_AGAIN; break; case DNS_ERROR_NO_DNS_SERVERS: case DNS_ERROR_RCODE_FORMAT_ERROR: case DNS_ERROR_RCODE_NOT_IMPLEMENTED: case DNS_ERROR_RCODE_REFUSED: statp->res_h_errno = NO_RECOVERY; break; case DNS_INFO_NO_RECORDS: /* May be returned even if the host doesn't exist */ statp->res_h_errno = NO_DATA; break; default: DPRINTF(debug, "Unknown code %lu for %s %d\n", res, DomName, Type); statp->res_h_errno = NO_RECOVERY; break; } len = -1; goto done; } ptr = AnsPtr + HFIXEDSZ; /* Skip header */ rr = pQueryResultsSet; section = 0; while (rr) { if (!counts[0] && (rr->Flags.DW & 0x3)) { /* No question. Adopt the first name as the name in the question */ if ((len = dn_comp(rr->pName, ptr, AnsLength - 4, dnptrs, &dnptrs[DIM(dnptrs) - 1])) < 0) { ptr = NULL; break; } ptr += len; PUTSHORT(Type, ptr); PUTSHORT(ns_c_in, ptr); counts[0] = 1; } DPRINTF(debug, "%s Section %d Type %u Windows Record Length %u\n", rr->pName, rr->Flags.DW & 0x3, rr->wType, rr->wDataLength); /* Check the records are in correct section order */ if ((rr->Flags.DW & 0x3) < section) { DPRINTF(debug, "Unexpected section order %s %d\n", DomName, Type); continue; } section = rr->Flags.DW & 0x3; ptr = write_record(ptr, rr, AnsPtr + AnsLength, dnptrs, &dnptrs[DIM(dnptrs) - 1], debug); counts[section]++; rr = rr->pNext; } DnsRecordListFree(pQueryResultsSet, DnsFreeRecordList); len = ptr - AnsPtr; done: ptr = AnsPtr; PUTSHORT(0, ptr); /* Id */ PUTSHORT((QR << 8) + RA + RD, ptr); for (section = 0; section < DIM(counts); section++) { PUTSHORT(counts[section], ptr); } return len; }
int main(int argc, char **argv) { short port = htons(NAMESERVER_PORT); short lport; /* Wierd stuff for SPARC alignment, hurts nothing else. */ union { HEADER header_; u_char packet_[PACKETSZ]; } packet_; #define header (packet_.header_) #define packet (packet_.packet_) union { HEADER u; u_char b[NS_MAXMSG]; } answer; int n; char doping[90]; char pingstr[50]; char *afile; char *addrc, *addrend, *addrbegin; time_t exectime; struct timeval tv1, tv2, start_time, end_time, query_time; char *srv; int anyflag = 0; int sticky = 0; int tmp; int qtypeSet; ns_type xfr = ns_t_invalid; int bytes_out, bytes_in; char cmd[512]; char domain[MAXDNAME]; char msg[120], **vtmp; char *args[DIG_MAXARGS]; char **ax; int once = 1, dofile = 0; /* batch -vs- interactive control */ char fileq[384]; int fp; int wait=0, delay; int envset=0, envsave=0; struct __res_state res_x, res_t; int r; struct in6_addr in6; ns_tsig_key key; char *keyfile = NULL, *keyname = NULL; const char *pingfmt = NULL; UNUSED(argc); res_ninit(&res); res.pfcode = PRF_DEF; qtypeSet = 0; memset(domain, 0, sizeof domain); gethostname(myhostname, (sizeof myhostname)); #ifdef HAVE_SA_LEN myaddress.sin_len = sizeof(struct sockaddr_in); #endif myaddress.sin_family = AF_INET; myaddress.sin_addr.s_addr = INADDR_ANY; myaddress.sin_port = 0; /*INPORT_ANY*/; #ifdef HAVE_SA_LEN myaddress6.sin6_len = sizeof(struct sockaddr_in6); #endif myaddress6.sin6_family = AF_INET6; myaddress6.sin6_addr = in6addr_any; myaddress6.sin6_port = 0; /*INPORT_ANY*/; res_x = res; /* * If LOCALDEF in environment, should point to file * containing local favourite defaults. Also look for file * DiG.env (i.e. SAVEENV) in local directory. */ if ((((afile = (char *) getenv("LOCALDEF")) != (char *) NULL) && ((fp = open(afile, O_RDONLY)) > 0)) || ((fp = open(SAVEENV, O_RDONLY)) > 0)) { read(fp, (char *)&res_x, (sizeof res_x)); close(fp); res = res_x; } /* * Check for batch-mode DiG; also pre-scan for 'help'. */ vtmp = argv; ax = args; while (*vtmp != NULL) { if (strcmp(*vtmp, "-h") == 0 || strcmp(*vtmp, "-help") == 0 || strcmp(*vtmp, "-usage") == 0 || strcmp(*vtmp, "help") == 0) { Usage(); exit(0); } if (strcmp(*vtmp, "-f") == 0) { dofile++; once=0; if ((qfp = fopen(*++vtmp, "r")) == NULL) { fflush(stdout); perror("file open"); fflush(stderr); exit(10); } } else { if (ax - args == DIG_MAXARGS) { fprintf(stderr, "dig: too many arguments\n"); exit(10); } *ax++ = *vtmp; } vtmp++; } gettimeofday(&tv1, NULL); /* * Main section: once if cmd-line query * while !EOF if batch mode */ *fileq = '\0'; while ((dofile && fgets(fileq, sizeof fileq, qfp) != NULL) || (!dofile && once--)) { if (*fileq == '\n' || *fileq == '#' || *fileq==';') { printf("%s", fileq); /* echo but otherwise ignore */ continue; /* blank lines and comments */ } /* * "Sticky" requests that before current parsing args * return to current "working" environment (X******). */ if (sticky) { printf(";; (using sticky settings)\n"); res = res_x; } /* * Concat cmd-line and file args. */ stackarg(fileq, ax); /* defaults */ queryType = ns_t_ns; queryClass = ns_c_in; xfr = ns_t_invalid; *pingstr = 0; srv = NULL; sprintf(cmd, "\n; <<>> DiG %s (libbind %d) <<>> ", VSTRING, __RES); argv = args; /* argc = ax - args; */ /* * More cmd-line options than anyone should ever have to * deal with .... */ while (*(++argv) != NULL && **argv != '\0') { if (strlen(cmd) + strlen(*argv) + 2 > sizeof (cmd)) { fprintf(stderr, "Argument too large for input buffer\n"); exit(1); } strcat(cmd, *argv); strcat(cmd, " "); if (**argv == '@') { srv = (*argv+1); continue; } if (**argv == '%') continue; if (**argv == '+') { setopt(*argv+1); continue; } if (**argv == '=') { ixfr_serial = strtoul(*argv+1, NULL, 0); continue; } if (strncmp(*argv, "-nost", 5) == 0) { sticky = 0; continue; } else if (strncmp(*argv, "-st", 3) == 0) { sticky++; continue; } else if (strncmp(*argv, "-envsa", 6) == 0) { envsave++; continue; } else if (strncmp(*argv, "-envse", 6) == 0) { envset++; continue; } if (**argv == '-') { switch (argv[0][1]) { case 'T': if (*++argv == NULL) printf("; no arg for -T?\n"); else wait = atoi(*argv); break; case 'c': if(*++argv == NULL) printf("; no arg for -c?\n"); else if ((tmp = atoi(*argv)) || *argv[0] == '0') { queryClass = tmp; } else if ((tmp = StringToClass(*argv, 0, NULL) ) != 0) { queryClass = tmp; } else { printf( "; invalid class specified\n" ); } break; case 't': if (*++argv == NULL) printf("; no arg for -t?\n"); else if ((tmp = atoi(*argv)) || *argv[0]=='0') { if (ns_t_xfr_p(tmp)) { xfr = tmp; } else { queryType = tmp; qtypeSet++; } } else if ((tmp = StringToType(*argv, 0, NULL) ) != 0) { if (ns_t_xfr_p(tmp)) { xfr = tmp; } else { queryType = tmp; qtypeSet++; } } else { printf( "; invalid type specified\n" ); } break; case 'x': if (!qtypeSet) { queryType = T_ANY; qtypeSet++; } if ((addrc = *++argv) == NULL) { printf("; no arg for -x?\n"); break; } r = inet_pton(AF_INET6, addrc, &in6); if (r > 0) { reverse6(domain, &in6); break; } addrend = addrc + strlen(addrc); if (*addrend == '.') *addrend = '\0'; *domain = '\0'; while ((addrbegin = strrchr(addrc,'.'))) { strcat(domain, addrbegin+1); strcat(domain, "."); *addrbegin = '\0'; } strcat(domain, addrc); strcat(domain, ".in-addr.arpa."); break; case 'p': if (argv[0][2] != '\0') port = htons(atoi(argv[0]+2)); else if (*++argv == NULL) printf("; no arg for -p?\n"); else port = htons(atoi(*argv)); break; case 'P': if (argv[0][2] != '\0') { strcpy(pingstr, argv[0]+2); pingfmt = "%s %s 56 3 | %s -3"; } else { strcpy(pingstr, DIG_PING); pingfmt = DIG_PINGFMT; } break; case 'n': if (argv[0][2] != '\0') res.ndots = atoi(argv[0]+2); else if (*++argv == NULL) printf("; no arg for -n?\n"); else res.ndots = atoi(*argv); break; case 'b': { char *a, *p; if (argv[0][2] != '\0') a = argv[0]+2; else if (*++argv == NULL) { printf("; no arg for -b?\n"); break; } else a = *argv; if ((p = strchr(a, ':')) != NULL) { *p++ = '\0'; lport = htons(atoi(p)); } else lport = htons(0); if (inet_pton(AF_INET6, a, &myaddress6.sin6_addr) == 1) { myaddress6.sin6_port = lport; } else if (!inet_aton(a, &myaddress.sin_addr)) { fprintf(stderr, ";; bad -b addr\n"); exit(1); } else myaddress.sin_port = lport; } break; case 'k': /* -k keydir:keyname */ if (argv[0][2] != '\0') keyfile = argv[0]+2; else if (*++argv == NULL) { printf("; no arg for -k?\n"); break; } else keyfile = *argv; keyname = strchr(keyfile, ':'); if (keyname == NULL) { fprintf(stderr, "key option argument should be keydir:keyname\n"); exit(1); } *keyname++='\0'; break; } /* switch - */ continue; } /* if '-' */ if ((tmp = StringToType(*argv, -1, NULL)) != -1) { if ((T_ANY == tmp) && anyflag++) { queryClass = C_ANY; continue; } if (ns_t_xfr_p(tmp) && (tmp == ns_t_axfr || (res.options & RES_USEVC) != 0) ) { res.pfcode = PRF_ZONE; xfr = (ns_type)tmp; } else { queryType = tmp; qtypeSet++; } } else if ((tmp = StringToClass(*argv, -1, NULL)) != -1) { queryClass = tmp; } else { memset(domain, 0, sizeof domain); sprintf(domain,"%s",*argv); } } /* while argv remains */ /* process key options */ if (keyfile) { #ifdef PARSE_KEYFILE int i, n1; char buf[BUFSIZ], *p; FILE *fp = NULL; int file_major, file_minor, alg; fp = fopen(keyfile, "r"); if (fp == NULL) { perror(keyfile); exit(1); } /* Now read the header info from the file. */ i = fread(buf, 1, BUFSIZ, fp); if (i < 5) { fclose(fp); exit(1); } fclose(fp); p = buf; n=strlen(p); /* get length of strings */ n1=strlen("Private-key-format: v"); if (n1 > n || strncmp(buf, "Private-key-format: v", n1)) { fprintf(stderr, "Invalid key file format\n"); exit(1); /* not a match */ } p+=n1; /* advance pointer */ sscanf((char *)p, "%d.%d", &file_major, &file_minor); /* should do some error checking with these someday */ while (*p++!='\n'); /* skip to end of line */ n=strlen(p); /* get length of strings */ n1=strlen("Algorithm: "); if (n1 > n || strncmp(p, "Algorithm: ", n1)) { fprintf(stderr, "Invalid key file format\n"); exit(1); /* not a match */ } p+=n1; /* advance pointer */ if (sscanf((char *)p, "%d", &alg)!=1) { fprintf(stderr, "Invalid key file format\n"); exit(1); } while (*p++!='\n'); /* skip to end of line */ n=strlen(p); /* get length of strings */ n1=strlen("Key: "); if (n1 > n || strncmp(p, "Key: ", n1)) { fprintf(stderr, "Invalid key file format\n"); exit(1); /* not a match */ } p+=n1; /* advance pointer */ pp=p; while (*pp++!='\n'); /* skip to end of line, * terminate it */ *--pp='\0'; key.data=malloc(1024*sizeof(char)); key.len=b64_pton(p, key.data, 1024); strcpy(key.name, keyname); strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); #else /* use the dst* routines to parse the key files * * This requires that both the .key and the .private * files exist in your cwd, so the keyfile parmeter * here is assumed to be a path in which the * K*.{key,private} files exist. */ DST_KEY *dst_key; char cwd[PATH_MAX+1]; if (getcwd(cwd, PATH_MAX)==NULL) { perror("unable to get current directory"); exit(1); } if (chdir(keyfile)<0) { fprintf(stderr, "unable to chdir to %s: %s\n", keyfile, strerror(errno)); exit(1); } dst_init(); dst_key = dst_read_key(keyname, 0 /* not used for priv keys */, KEY_HMAC_MD5, DST_PRIVATE); if (!dst_key) { fprintf(stderr, "dst_read_key: error reading key\n"); exit(1); } key.data=malloc(1024*sizeof(char)); dst_key_to_buffer(dst_key, key.data, 1024); key.len=dst_key->dk_key_size; strcpy(key.name, keyname); strcpy(key.alg, "HMAC-MD5.SIG-ALG.REG.INT"); if (chdir(cwd)<0) { fprintf(stderr, "unable to chdir to %s: %s\n", cwd, strerror(errno)); exit(1); } #endif } if (res.pfcode & 0x80000) printf("; pfcode: %08lx, options: %08lx\n", (unsigned long)res.pfcode, (unsigned long)res.options); /* * Current env. (after this parse) is to become the * new "working" environmnet. Used in conj. with sticky. */ if (envset) { res_x = res; envset = 0; } /* * Current env. (after this parse) is to become the * new default saved environmnet. Save in user specified * file if exists else is SAVEENV (== "DiG.env"). */ if (envsave) { afile = (char *) getenv("LOCALDEF"); if ((afile && ((fp = open(afile, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE)) > 0)) || ((fp = open(SAVEENV, O_WRONLY|O_CREAT|O_TRUNC, S_IREAD|S_IWRITE)) > 0)) { write(fp, (char *)&res, (sizeof res)); close(fp); } envsave = 0; } if (res.pfcode & RES_PRF_CMD) printf("%s\n", cmd); anyflag = 0; /* * Find address of server to query. If not dot-notation, then * try to resolve domain-name (if so, save and turn off print * options, this domain-query is not the one we want. Restore * user options when done. * Things get a bit wierd since we need to use resolver to be * able to "put the resolver to work". */ if (srv != NULL) { int nscount = 0; union res_sockaddr_union u[MAXNS]; struct addrinfo *answer = NULL; struct addrinfo *cur = NULL; struct addrinfo hint; memset(u, 0, sizeof(u)); res_t = res; res_ninit(&res); res.pfcode = 0; res.options = RES_DEFAULT; memset(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_DGRAM; if (!getaddrinfo(srv, NULL, &hint, &answer)) { res = res_t; cur = answer; for (cur = answer; cur != NULL; cur = cur->ai_next) { if (nscount == MAXNS) break; switch (cur->ai_addr->sa_family) { case AF_INET6: u[nscount].sin6 = *(struct sockaddr_in6*)cur->ai_addr; u[nscount++].sin6.sin6_port = port; break; case AF_INET: u[nscount].sin = *(struct sockaddr_in*)cur->ai_addr; u[nscount++].sin.sin_port = port; break; } } if (nscount != 0) res_setservers(&res, u, nscount); freeaddrinfo(answer); } else { res = res_t; fflush(stdout); fprintf(stderr, "; Bad server: %s -- using default server and timer opts\n", srv); fflush(stderr); srv = NULL; } printf("; (%d server%s found)\n", res.nscount, (res.nscount==1)?"":"s"); res.id += res.retry; } if (ns_t_xfr_p(xfr)) { int i; int nscount; union res_sockaddr_union u[MAXNS]; nscount = res_getservers(&res, u, MAXNS); for (i = 0; i < nscount; i++) { int x; if (keyfile) x = printZone(xfr, domain, &u[i].sin, &key); else x = printZone(xfr, domain, &u[i].sin, NULL); if (res.pfcode & RES_PRF_STATS) { exectime = time(NULL); printf(";; FROM: %s to SERVER: %s\n", myhostname, p_sockun(u[i], ubuf, sizeof(ubuf))); printf(";; WHEN: %s", ctime(&exectime)); } if (!x) break; /* success */ } fflush(stdout); continue; } if (*domain && !qtypeSet) { queryType = T_A; qtypeSet++; } bytes_out = n = res_nmkquery(&res, QUERY, domain, queryClass, queryType, NULL, 0, NULL, packet, sizeof packet); if (n < 0) { fflush(stderr); printf(";; res_nmkquery: buffer too small\n\n"); fflush(stdout); continue; } if (queryType == T_IXFR) { HEADER *hp = (HEADER *) packet; u_char *cpp = packet + bytes_out; hp->nscount = htons(1+ntohs(hp->nscount)); n = dn_comp(domain, cpp, (sizeof packet) - (cpp - packet), NULL, NULL); cpp += n; PUTSHORT(T_SOA, cpp); /* type */ PUTSHORT(C_IN, cpp); /* class */ PUTLONG(0, cpp); /* ttl */ PUTSHORT(22, cpp); /* dlen */ *cpp++ = 0; /* mname */ *cpp++ = 0; /* rname */ PUTLONG(ixfr_serial, cpp); PUTLONG(0xDEAD, cpp); /* Refresh */ PUTLONG(0xBEEF, cpp); /* Retry */ PUTLONG(0xABCD, cpp); /* Expire */ PUTLONG(0x1776, cpp); /* Min TTL */ bytes_out = n = cpp - packet; }; #if defined(RES_USE_EDNS0) && defined(RES_USE_DNSSEC) if (n > 0 && (res.options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) bytes_out = n = res_nopt(&res, n, packet, sizeof(packet), 4096); #endif eecode = 0; if (res.pfcode & RES_PRF_HEAD1) fp_resstat(&res, stdout); (void) gettimeofday(&start_time, NULL); if (keyfile) n = res_nsendsigned(&res, packet, n, &key, answer.b, sizeof(answer.b)); else n = res_nsend(&res, packet, n, answer.b, sizeof(answer.b)); if ((bytes_in = n) < 0) { fflush(stdout); n = 0 - n; if (keyfile) strcpy(msg, ";; res_nsendsigned"); else strcpy(msg, ";; res_nsend"); perror(msg); fflush(stderr); if (!dofile) { if (eecode) exit(eecode); else exit(9); } } (void) gettimeofday(&end_time, NULL); if (res.pfcode & RES_PRF_STATS) { union res_sockaddr_union u[MAXNS]; (void) res_getservers(&res, u, MAXNS); query_time = difftv(start_time, end_time); printf(";; Total query time: "); prnttime(query_time); putchar('\n'); exectime = time(NULL); printf(";; FROM: %s to SERVER: %s\n", myhostname, p_sockun(u[RES_GETLAST(res)], ubuf, sizeof(ubuf))); printf(";; WHEN: %s", ctime(&exectime)); printf(";; MSG SIZE sent: %d rcvd: %d\n", bytes_out, bytes_in); } fflush(stdout); /* * Argh ... not particularly elegant. Should put in *real* ping code. * Would necessitate root priviledges for icmp port though! */ if (*pingstr && srv != NULL) { sprintf(doping, pingfmt, pingstr, srv, DIG_TAIL); system(doping); } putchar('\n'); /* * Fairly crude method and low overhead method of keeping two * batches started at different sites somewhat synchronized. */ gettimeofday(&tv2, NULL); delay = (int)(tv2.tv_sec - tv1.tv_sec); if (delay < wait) { sleep(wait - delay); } tv1 = tv2; } return (eecode); }
/*% * Form update packets. * Returns the size of the resulting packet if no error * * On error, * returns *\li -1 if error in reading a word/number in rdata * portion for update packets *\li -2 if length of buffer passed is insufficient *\li -3 if zone section is not the first section in * the linked list, or section order has a problem *\li -4 on a number overflow *\li -5 unknown operation or no records */ int res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) { ns_updrec *rrecp_start = rrecp_in; HEADER *hp; u_char *cp, *sp2, *startp, *endp; int n, i, soanum, multiline; ns_updrec *rrecp; struct in_addr ina; struct in6_addr in6a; char buf2[MAXDNAME]; u_char buf3[MAXDNAME]; int section, numrrs = 0, counts[ns_s_max]; u_int16_t rtype, rclass; u_int32_t n1, rttl; u_char *dnptrs[20], **dpp, **lastdnptr; int siglen, keylen, certlen; /* * Initialize header fields. */ if ((buf == NULL) || (buflen < HFIXEDSZ)) return (-1); memset(buf, 0, HFIXEDSZ); hp = (HEADER *) buf; hp->id = htons(++statp->id); hp->opcode = ns_o_update; hp->rcode = NOERROR; cp = buf + HFIXEDSZ; buflen -= HFIXEDSZ; dpp = dnptrs; *dpp++ = buf; *dpp++ = NULL; lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; if (rrecp_start == NULL) return (-5); else if (rrecp_start->r_section != S_ZONE) return (-3); memset(counts, 0, sizeof counts); for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) { numrrs++; section = rrecp->r_section; if (section < 0 || section >= ns_s_max) return (-1); counts[section]++; for (i = section + 1; i < ns_s_max; i++) if (counts[i]) return (-3); rtype = rrecp->r_type; rclass = rrecp->r_class; rttl = rrecp->r_ttl; /* overload class and type */ if (section == S_PREREQ) { rttl = 0; switch (rrecp->r_opcode) { case YXDOMAIN: rclass = C_ANY; rtype = T_ANY; rrecp->r_size = 0; break; case NXDOMAIN: rclass = C_NONE; rtype = T_ANY; rrecp->r_size = 0; break; case NXRRSET: rclass = C_NONE; rrecp->r_size = 0; break; case YXRRSET: if (rrecp->r_size == 0) rclass = C_ANY; break; default: fprintf(stderr, "res_mkupdate: incorrect opcode: %d\n", rrecp->r_opcode); fflush(stderr); return (-1); } } else if (section == S_UPDATE) { switch (rrecp->r_opcode) { case DELETE: rclass = rrecp->r_size == 0 ? C_ANY : C_NONE; break; case ADD: break; default: fprintf(stderr, "res_mkupdate: incorrect opcode: %d\n", rrecp->r_opcode); fflush(stderr); return (-1); } } /* * XXX appending default domain to owner name is omitted, * fqdn must be provided */ if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs, lastdnptr)) < 0) return (-1); cp += n; ShrinkBuffer(n + 2*INT16SZ); PUTSHORT(rtype, cp); PUTSHORT(rclass, cp); if (section == S_ZONE) { if (numrrs != 1 || rrecp->r_type != T_SOA) return (-3); continue; } ShrinkBuffer(INT32SZ + INT16SZ); PUTLONG(rttl, cp); sp2 = cp; /*%< save pointer to length byte */ cp += INT16SZ; if (rrecp->r_size == 0) { if (section == S_UPDATE && rclass != C_ANY) return (-1); else { PUTSHORT(0, sp2); continue; } } startp = rrecp->r_data; endp = startp + rrecp->r_size - 1; /* XXX this should be done centrally. */ switch (rrecp->r_type) { case T_A: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (!inet_aton(buf2, &ina)) return (-1); n1 = ntohl(ina.s_addr); ShrinkBuffer(INT32SZ); PUTLONG(n1, cp); break; case T_CNAME: case T_MB: case T_MG: case T_MR: case T_NS: case T_PTR: case ns_t_dname: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case T_MINFO: case T_SOA: case T_RP: for (i = 0; i < 2; i++) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); } if (rrecp->r_type == T_SOA) { ShrinkBuffer(5 * INT32SZ); while (isspace(*startp) || !*startp) startp++; if (*startp == '(') { multiline = 1; startp++; } else multiline = 0; /* serial, refresh, retry, expire, minimum */ for (i = 0; i < 5; i++) { soanum = getnum_str(&startp, endp); if (soanum < 0) return (-1); PUTLONG(soanum, cp); } if (multiline) { while (isspace(*startp) || !*startp) startp++; if (*startp != ')') return (-1); } } break; case T_MX: case T_AFSDB: case T_RT: n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case T_SRV: n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, NULL, NULL); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case T_PX: n = getnum_str(&startp, endp); if (n < 0) return (-1); PUTSHORT(n, cp); ShrinkBuffer(INT16SZ); for (i = 0; i < 2; i++) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); } break; case T_WKS: { char bm[MAXPORT/8]; unsigned int maxbm = 0; if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (!inet_aton(buf2, &ina)) return (-1); n1 = ntohl(ina.s_addr); ShrinkBuffer(INT32SZ); PUTLONG(n1, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if ((i = res_protocolnumber(buf2)) < 0) return (-1); ShrinkBuffer(1); *cp++ = i & 0xff; for (i = 0; i < MAXPORT/8 ; i++) bm[i] = 0; while (getword_str(buf2, sizeof buf2, &startp, endp)) { if ((n = res_servicenumber(buf2)) <= 0) return (-1); if (n < MAXPORT) { bm[n/8] |= (0x80>>(n%8)); if ((unsigned)n > maxbm) maxbm = n; } else return (-1); } maxbm = maxbm/8 + 1; ShrinkBuffer(maxbm); memcpy(cp, bm, maxbm); cp += maxbm; break; } case T_HINFO: for (i = 0; i < 2; i++) { if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; } break; case T_TXT: for (;;) { if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) { if (cp != (sp2 + INT16SZ)) break; return (-1); } if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; } break; case T_X25: /* RFC1183 */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; break; case T_ISDN: /* RFC1183 */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); if ((n > 255) || (n == 0)) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) n = 0; if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; break; case T_NSAP: if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) { ShrinkBuffer(n); memcpy(cp, buf2, n); cp += n; } else { return (-1); } break; case T_LOC: if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) { ShrinkBuffer(n); memcpy(cp, buf2, n); cp += n; } else return (-1); break; case ns_t_sig: { int sig_type, success, dateerror; u_int32_t exptime, timesigned; /* type */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); sig_type = sym_ston(__p_type_syms, buf2, &success); if (!success || sig_type == ns_t_any) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(sig_type, cp); /* alg */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* labels */ n = getnum_str(&startp, endp); if (n <= 0 || n > 255) return (-1); ShrinkBuffer(1); *cp++ = n; /* ottl & expire */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); exptime = ns_datetosecs(buf2, &dateerror); if (!dateerror) { ShrinkBuffer(INT32SZ); PUTLONG(rttl, cp); } else { char *ulendp; u_int32_t ottl; errno = 0; ottl = strtoul(buf2, &ulendp, 10); if (errno != 0 || (ulendp != NULL && *ulendp != '\0')) return (-1); ShrinkBuffer(INT32SZ); PUTLONG(ottl, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); exptime = ns_datetosecs(buf2, &dateerror); if (dateerror) return (-1); } /* expire */ ShrinkBuffer(INT32SZ); PUTLONG(exptime, cp); /* timesigned */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); timesigned = ns_datetosecs(buf2, &dateerror); if (!dateerror) { ShrinkBuffer(INT32SZ); PUTLONG(timesigned, cp); } else return (-1); /* footprint */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* signer name */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); /* sig */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); siglen = b64_pton(buf2, buf3, sizeof(buf3)); if (siglen < 0) return (-1); ShrinkBuffer(siglen); memcpy(cp, buf3, siglen); cp += siglen; break; } case ns_t_key: /* flags */ n = gethexnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* proto */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* alg */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* key */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); keylen = b64_pton(buf2, buf3, sizeof(buf3)); if (keylen < 0) return (-1); ShrinkBuffer(keylen); memcpy(cp, buf3, keylen); cp += keylen; break; case ns_t_nxt: { int success, nxt_type; u_char data[32]; int maxtype; /* next name */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, NULL, NULL); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); maxtype = 0; memset(data, 0, sizeof data); for (;;) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) break; nxt_type = sym_ston(__p_type_syms, buf2, &success); if (!success || !ns_t_rr_p(nxt_type)) return (-1); NS_NXT_BIT_SET(nxt_type, data); if (nxt_type > maxtype) maxtype = nxt_type; } n = maxtype/NS_NXT_BITS+1; ShrinkBuffer(n); memcpy(cp, data, n); cp += n; break; } case ns_t_cert: /* type */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* key tag */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* alg */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* cert */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); certlen = b64_pton(buf2, buf3, sizeof(buf3)); if (certlen < 0) return (-1); ShrinkBuffer(certlen); memcpy(cp, buf3, certlen); cp += certlen; break; case ns_t_aaaa: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (inet_pton(AF_INET6, buf2, &in6a) <= 0) return (-1); ShrinkBuffer(NS_IN6ADDRSZ); memcpy(cp, &in6a, NS_IN6ADDRSZ); cp += NS_IN6ADDRSZ; break; case ns_t_naptr: /* Order Preference Flags Service Replacement Regexp */ /* Order */ n = getnum_str(&startp, endp); if (n < 0 || n > 65535) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* Preference */ n = getnum_str(&startp, endp); if (n < 0 || n > 65535) return (-1); ShrinkBuffer(INT16SZ); PUTSHORT(n, cp); /* Flags */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) { return (-1); } if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; /* Service Classes */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) { return (-1); } if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; /* Pattern */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) { return (-1); } if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; /* Replacement */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, NULL, NULL); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; default: return (-1); } /*switch*/
static int niquery_option_subject_name_handler(int index, const char *arg) { static char nigroup_buf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ]; unsigned char *dnptrs[2], **dpp, **lastdnptr; int n; int i; char *name, *p; char *canonname = NULL, *idn = NULL; unsigned char *buf = NULL; size_t namelen; size_t buflen; int dots, fqdn = niquery_options[index].data; MD5_CTX ctxt; __u8 digest[MD5_DIGEST_LENGTH]; #ifdef USE_IDN int rc; #endif if (niquery_set_subject_type(NI_SUBJ_NAME) < 0) return -1; #ifdef USE_IDN name = stringprep_locale_to_utf8(arg); if (!name) { fprintf(stderr, "ping6: IDN support failed.\n"); exit(2); } #else name = strdup(arg); if (!name) goto oomexit; #endif p = strchr(name, SCOPE_DELIMITER); if (p) { *p = '\0'; if (strlen(p + 1) >= IFNAMSIZ) { fprintf(stderr, "ping6: too long scope name.\n"); exit(1); } } #ifdef USE_IDN rc = idna_to_ascii_8z(name, &idn, 0); if (rc) { fprintf(stderr, "ping6: IDN encoding error: %s\n", idna_strerror(rc)); exit(2); } #else idn = strdup(name); if (!idn) goto oomexit; #endif namelen = strlen(idn); canonname = malloc(namelen + 1); if (!canonname) goto oomexit; dots = 0; for (i = 0; i < namelen + 1; i++) { canonname[i] = isupper(idn[i]) ? tolower(idn[i]) : idn[i]; if (idn[i] == '.') dots++; } if (fqdn == 0) { /* guess if hostname is FQDN */ fqdn = dots ? 1 : -1; } buflen = namelen + 3 + 1; /* dn_comp() requrires strlen() + 3, plus non-fqdn indicator. */ buf = malloc(buflen); if (!buf) { fprintf(stderr, "ping6: out of memory.\n"); goto errexit; } dpp = dnptrs; lastdnptr = &dnptrs[ARRAY_SIZE(dnptrs)]; *dpp++ = (unsigned char *)buf; *dpp++ = NULL; n = dn_comp(canonname, (unsigned char *)buf, buflen, dnptrs, lastdnptr); if (n < 0) { fprintf(stderr, "ping6: Inappropriate subject name: %s\n", canonname); goto errexit; } else if (n >= buflen) { fprintf(stderr, "ping6: dn_comp() returned too long result.\n"); goto errexit; } MD5_Init(&ctxt); MD5_Update(&ctxt, buf, buf[0]); MD5_Final(digest, &ctxt); sprintf(nigroup_buf, "ff02::2:%02x%02x:%02x%02x%s%s", digest[0], digest[1], digest[2], digest[3], p ? "%" : "", p ? p + 1 : ""); if (fqdn < 0) buf[n] = 0; free(ni_subject); ni_group = nigroup_buf; ni_subject = buf; ni_subject_len = n + (fqdn < 0); ni_group = nigroup_buf; free(canonname); free(idn); free(name); return 0; oomexit: fprintf(stderr, "ping6: out of memory.\n"); errexit: free(buf); free(canonname); free(idn); free(name); exit(1); }
/* 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; }
/* * Form update packets. * Returns the size of the resulting packet if no error * On error, * returns -1 if error in reading a word/number in rdata * portion for update packets * -2 if length of buffer passed is insufficient * -3 if zone section is not the first section in * the linked list, or section order has a problem * -4 on a number overflow * -5 unknown operation or no records */ int res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) { ns_updrec *rrecp_start = rrecp_in; HEADER *hp; u_char *cp, *sp1, *sp2, *startp, *endp; int n, i, soanum, multiline; ns_updrec *rrecp; struct in_addr ina; struct in6_addr in6a; char buf2[NS_MAXDNAME]; u_char buf3[NS_MAXDNAME]; int section, numrrs = 0, counts[ns_s_max]; u_int16_t rtype, rclass; u_int32_t n1, rttl; u_char *dnptrs[20], **dpp, **lastdnptr; int siglen, keylen, certlen; /* * Initialize header fields. */ if ((buf == NULL) || (buflen < NS_HFIXEDSZ)) return (-1); memset(buf, 0, NS_HFIXEDSZ); hp = (HEADER *) buf; #ifdef __APPLE__ hp->id = res_randomid(); #else hp->id = htons(++statp->id); #endif hp->opcode = ns_o_update; hp->rcode = ns_r_noerror; sp1 = buf + 2*NS_INT16SZ; /* save pointer to zocount */ cp = buf + NS_HFIXEDSZ; buflen -= NS_HFIXEDSZ; dpp = dnptrs; *dpp++ = buf; *dpp++ = NULL; lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; if (rrecp_start == NULL) return (-5); else if (rrecp_start->r_section != ns_s_zn) return (-3); memset(counts, 0, sizeof counts); for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) { numrrs++; section = rrecp->r_section; if (section < 0 || section >= ns_s_max) return (-1); counts[section]++; for (i = section + 1; i < ns_s_max; i++) if (counts[i]) return (-3); rtype = rrecp->r_type; rclass = rrecp->r_class; rttl = rrecp->r_ttl; /* overload class and type */ if (section == ns_s_pr) { rttl = 0; switch (rrecp->r_opcode) { case ns_r_yxdomain: rclass = ns_c_any; rtype = ns_t_any; rrecp->r_size = 0; break; case ns_r_nxdomain: rclass = ns_c_none; rtype = ns_t_any; rrecp->r_size = 0; break; case ns_r_nxrrset: rclass = ns_c_none; rrecp->r_size = 0; break; case ns_r_yxrrset: if (rrecp->r_size == 0) rclass = ns_c_any; break; default: fprintf(stderr, "res_mkupdate: incorrect opcode: %d\n", rrecp->r_opcode); fflush(stderr); return (-1); } } else if (section == ns_s_ud) { switch (rrecp->r_opcode) { case ns_uop_delete: rclass = rrecp->r_size == 0 ? ns_c_any : ns_c_none; break; case ns_uop_add: break; default: fprintf(stderr, "res_mkupdate: incorrect opcode: %d\n", rrecp->r_opcode); fflush(stderr); return (-1); } } /* * XXX appending default domain to owner name is omitted, * fqdn must be provided */ if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs, lastdnptr)) < 0) return (-1); cp += n; ShrinkBuffer(n + 2*NS_INT16SZ); NS_PUT16(rtype, cp); NS_PUT16(rclass, cp); if (section == ns_s_zn) { if (numrrs != 1 || rrecp->r_type != ns_t_soa) return (-3); continue; } ShrinkBuffer(NS_INT32SZ + NS_INT16SZ); NS_PUT32(rttl, cp); sp2 = cp; /* save pointer to length byte */ cp += NS_INT16SZ; if (rrecp->r_size == 0) { if (section == ns_s_ud && rclass != ns_c_any) return (-1); else { NS_PUT16(0, sp2); continue; } } startp = rrecp->r_data; endp = startp + rrecp->r_size - 1; /* XXX this should be done centrally. */ switch (rrecp->r_type) { case ns_t_a: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (!inet_aton(buf2, &ina)) return (-1); n1 = ntohl(ina.s_addr); ShrinkBuffer(NS_INT32SZ); NS_PUT32(n1, cp); break; case ns_t_cname: case ns_t_mb: case ns_t_mg: case ns_t_mr: case ns_t_ns: case ns_t_ptr: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case ns_t_minfo: case ns_t_soa: case ns_t_rp: for (i = 0; i < 2; i++) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); } if (rrecp->r_type == ns_t_soa) { ShrinkBuffer(5 * NS_INT32SZ); while (isspace(*startp) || !*startp) startp++; if (*startp == '(') { multiline = 1; startp++; } else multiline = 0; /* serial, refresh, retry, expire, minimum */ for (i = 0; i < 5; i++) { soanum = getnum_str(&startp, endp); if (soanum < 0) return (-1); NS_PUT32(soanum, cp); } if (multiline) { while (isspace(*startp) || !*startp) startp++; if (*startp != ')') return (-1); } } break; case ns_t_mx: case ns_t_afsdb: case ns_t_rt: n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(NS_INT16SZ); NS_PUT16(n, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case ns_t_srv: n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(NS_INT16SZ); NS_PUT16(n, cp); n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(NS_INT16SZ); NS_PUT16(n, cp); n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(NS_INT16SZ); NS_PUT16(n, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); break; case ns_t_px: n = getnum_str(&startp, endp); if (n < 0) return (-1); NS_PUT16(n, cp); ShrinkBuffer(NS_INT16SZ); for (i = 0; i < 2; i++) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); } break; case ns_t_wks: { char bm[MAXPORT/8]; unsigned int maxbm = 0; if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (!inet_aton(buf2, &ina)) return (-1); n1 = ntohl(ina.s_addr); ShrinkBuffer(NS_INT32SZ); NS_PUT32(n1, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if ((i = res_protocolnumber(buf2)) < 0) return (-1); ShrinkBuffer(1); *cp++ = i & 0xff; for (i = 0; i < MAXPORT/8 ; i++) bm[i] = 0; while (getword_str(buf2, sizeof buf2, &startp, endp)) { if ((n1 = res_servicenumber(buf2)) <= 0) return (-1); if (n1 < MAXPORT) { bm[n1/8] |= (0x80>>(n1%8)); if (n1 > maxbm) maxbm = n1; } else return (-1); } maxbm = maxbm/8 + 1; ShrinkBuffer(maxbm); memcpy(cp, bm, maxbm); cp += maxbm; break; } case ns_t_hinfo: for (i = 0; i < 2; i++) { if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; } break; case ns_t_txt: while (1) { if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) { if (cp != (sp2 + NS_INT16SZ)) break; return (-1); } if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; } break; case ns_t_x25: /* RFC 1183 */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; break; case ns_t_isdn: /* RFC 1183 */ if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); if ((n > 255) || (n == 0)) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; if ((n = getstr_str(buf2, sizeof buf2, &startp, endp)) < 0) n = 0; if (n > 255) return (-1); ShrinkBuffer(n+1); *cp++ = n; memcpy(cp, buf2, n); cp += n; break; case ns_t_nsap: if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) { ShrinkBuffer(n); memcpy(cp, buf2, n); cp += n; } else { return (-1); } break; case ns_t_loc: if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) { ShrinkBuffer(n); memcpy(cp, buf2, n); cp += n; } else return (-1); break; case ns_t_sig: { int sig_type, success, dateerror; u_int32_t exptime, timesigned; /* type */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); sig_type = sym_ston(__p_type_syms, buf2, &success); if (!success || sig_type == ns_t_any) return (-1); ShrinkBuffer(NS_INT16SZ); NS_PUT16(sig_type, cp); /* alg */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* labels */ n = getnum_str(&startp, endp); if (n <= 0 || n > 255) return (-1); ShrinkBuffer(1); *cp++ = n; /* ottl & expire */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); exptime = ns_datetosecs(buf2, &dateerror); if (!dateerror) { ShrinkBuffer(NS_INT32SZ); NS_PUT32(rttl, cp); } else { char *ulendp; u_int32_t ottl; ottl = strtoul(buf2, &ulendp, 10); if (ulendp != NULL && *ulendp != '\0') return (-1); ShrinkBuffer(NS_INT32SZ); NS_PUT32(ottl, cp); if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); exptime = ns_datetosecs(buf2, &dateerror); if (dateerror) return (-1); } /* expire */ ShrinkBuffer(NS_INT32SZ); NS_PUT32(exptime, cp); /* timesigned */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); timesigned = ns_datetosecs(buf2, &dateerror); if (!dateerror) { ShrinkBuffer(NS_INT32SZ); NS_PUT32(timesigned, cp); } else return (-1); /* footprint */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(NS_INT16SZ); NS_PUT16(n, cp); /* signer name */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); /* sig */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); siglen = b64_pton(buf2, buf3, sizeof(buf3)); if (siglen < 0) return (-1); ShrinkBuffer(siglen); memcpy(cp, buf3, siglen); cp += siglen; break; } case ns_t_key: /* flags */ n = gethexnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(NS_INT16SZ); NS_PUT16(n, cp); /* proto */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* alg */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* key */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); keylen = b64_pton(buf2, buf3, sizeof(buf3)); if (keylen < 0) return (-1); ShrinkBuffer(keylen); memcpy(cp, buf3, keylen); cp += keylen; break; case ns_t_nxt: { int success, nxt_type; u_char data[32]; int maxtype; /* next name */ if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; ShrinkBuffer(n); maxtype = 0; memset(data, 0, sizeof data); while (1) { if (!getword_str(buf2, sizeof buf2, &startp, endp)) break; nxt_type = sym_ston(__p_type_syms, buf2, &success); if (!success || !ns_t_rr_p(nxt_type)) return (-1); NS_NXT_BIT_SET(nxt_type, data); if (nxt_type > maxtype) maxtype = nxt_type; } n = maxtype/NS_NXT_BITS+1; ShrinkBuffer(n); memcpy(cp, data, n); cp += n; break; } case ns_t_cert: /* type */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(NS_INT16SZ); NS_PUT16(n, cp); /* key tag */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(NS_INT16SZ); NS_PUT16(n, cp); /* alg */ n = getnum_str(&startp, endp); if (n < 0) return (-1); ShrinkBuffer(1); *cp++ = n; /* cert */ if ((n = getword_str(buf2, sizeof buf2, &startp, endp)) < 0) return (-1); certlen = b64_pton(buf2, buf3, sizeof(buf3)); if (certlen < 0) return (-1); ShrinkBuffer(certlen); memcpy(cp, buf3, certlen); cp += certlen; break; case ns_t_aaaa: if (!getword_str(buf2, sizeof buf2, &startp, endp)) return (-1); if (inet_pton(AF_INET6, buf2, &in6a) <= 0) return (-1); ShrinkBuffer(NS_IN6ADDRSZ); memcpy(cp, &in6a, NS_IN6ADDRSZ); cp += NS_IN6ADDRSZ; break; default: return (-1); } /*switch*/
/* * Form all types of queries. * Returns the size of the result or -1. */ int res_mkquery ( int op, /* opcode of query */ const char *dname, /* domain name */ int Class, /* class of query */ int type, /* type of query */ const u_char *data, /* resource record data */ int datalen, /* length of data */ const u_char *newrr_in, /* new rr for modify or append */ u_char *buf, /* buffer to put query */ int buflen) /* size of buffer */ { struct rrec *newrr = (struct rrec *) newrr_in; HEADER *hp; u_char *cp; u_char *dnptrs[20]; u_char **dpp, **lastdnptr; int n; if ((_res.options & RES_INIT) == 0 && res_init() == -1) { h_errno = NETDB_INTERNAL; return (-1); } if (_res.options & RES_DEBUG) (*_printf) (";; res_mkquery(%d, %s, %d, %d)\n", op, dname, Class, type); /* Initialize header fields. */ if (!buf || buflen < HFIXEDSZ) return (-1); memset (buf, 0, HFIXEDSZ); hp = (HEADER*) buf; hp->id = htons (++_res.id); hp->opcode = op; hp->rd = (_res.options & RES_RECURSE) != 0; hp->rcode = NOERROR; cp = buf + HFIXEDSZ; buflen -= HFIXEDSZ; dpp = dnptrs; *dpp++ = buf; *dpp++ = NULL; lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; /* perform opcode specific processing */ switch (op) { case STATUS: /** \todo Handle STATUS case */ return (-1); case QUERY: /* fallthrough */ case NS_NOTIFY_OP: /* Notify secondary server of SOA change */ buflen -= QFIXEDSZ; if (buflen < 0) return (-1); if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) return (-1); cp += n; buflen -= n; __putshort (type, cp); cp += INT16SZ; __putshort (Class, cp); cp += INT16SZ; hp->qdcount = htons (1); if (op == QUERY || !data) break; /* * Make an additional record for completion domain. */ buflen -= RRFIXEDSZ; n = dn_comp ((char*)data, cp, buflen, dnptrs, lastdnptr); if (n < 0) return (-1); cp += n; buflen -= n; __putshort (T_NULL, cp); cp += INT16SZ; __putshort (Class, cp); cp += INT16SZ; __putlong (0, cp); cp += INT32SZ; __putshort (0, cp); cp += INT16SZ; hp->arcount = htons (1); break; case IQUERY: /* * Initialize answer section */ if (buflen < 1 + RRFIXEDSZ + datalen) return (-1); *cp++ = '\0'; /* no domain name */ __putshort (type, cp); cp += INT16SZ; __putshort (Class, cp); cp += INT16SZ; __putlong (0, cp); cp += INT32SZ; __putshort (datalen, cp); cp += INT16SZ; if (datalen) { memcpy (cp,data,datalen); cp += datalen; } hp->ancount = htons (1); break; #if ALLOW_UPDATES /* * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA * (Record to be modified is followed by its replacement in msg.) */ case UPDATEM: case UPDATEMA: case UPDATED: /* * The res code for UPDATED and UPDATEDA is the same; user * calls them differently: specifies data for UPDATED; server * ignores data if specified for UPDATEDA. */ case UPDATEDA: buflen -= RRFIXEDSZ + datalen; if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) return (-1); cp += n; __putshort (type, cp); cp += INT16SZ; __putshort (Class, cp); cp += INT16SZ; __putlong (0, cp); cp += INT32SZ; __putshort (datalen, cp); cp += INT16SZ; if (datalen) { memcpy (cp,data,datalen); cp += datalen; } if (op == UPDATED || op == UPDATEDA) { hp->ancount = 0; break; } /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */ case UPDATEA: /* Add new resource record */ buflen -= RRFIXEDSZ + datalen; if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) return (-1); cp += n; __putshort (newrr->r_type, cp); cp += INT16SZ; __putshort (newrr->r_class, cp); cp += INT16SZ; __putlong (0, cp); cp += INT32SZ; __putshort (newrr->r_size, cp); cp += INT16SZ; if (newrr->r_size) { memcpy (cp,newrr->r_data,newrr->r_size); cp += newrr->r_size; } hp->ancount = 0; break; #endif default: return (-1); } #if ALLOW_UPDATES == 0 ARGSUSED (newrr); ARGSUSED (newrr_in); #endif return (cp - buf); }