/* Copy an RDATA, using compression pointers where RFC1035 permits. */ static int rdcpy(ns_newmsg *handle, ns_type type, const u_char *rdata, size_t rdlen) { ns_msg *msg = &handle->msg; u_char *p = (u_char *) (unsigned long) msg->_msg_ptr; u_char *t = p + NS_INT16SZ; u_char *s = t; int n; switch (type) { case ns_t_soa: /* MNAME. */ n = ns_name_pack(rdata, t, msg->_eom - t, handle->dnptrs, handle->lastdnptr); if (n < 0) return (-1); t += n; if (ns_name_skip(&rdata, msg->_eom) < 0) return (-1); /* ANAME. */ n = ns_name_pack(rdata, t, msg->_eom - t, handle->dnptrs, handle->lastdnptr); if (n < 0) return (-1); t += n; if (ns_name_skip(&rdata, msg->_eom) < 0) return (-1); /* Serial, Refresh, Retry, Expiry, and Minimum. */ if ((msg->_eom - t) < (NS_INT32SZ * 5)) { errno = EMSGSIZE; return (-1); } memcpy(t, rdata, NS_INT32SZ * 5); t += (NS_INT32SZ * 5); break; case ns_t_ptr: case ns_t_cname: case ns_t_ns: /* PTRDNAME, CNAME, or NSDNAME. */ n = ns_name_pack(rdata, t, msg->_eom - t, handle->dnptrs, handle->lastdnptr); if (n < 0) return (-1); t += n; break; default: memcpy(t, rdata, rdlen); t += rdlen; } NS_PUT16(t - s, p); msg->_msg_ptr = t; return (0); }
/* Add a question (or zone, if it's an update) to a "newmsg" object. */ int ns_newmsg_q(ns_newmsg *handle, ns_nname_ct qname, ns_type qtype, ns_class qclass) { ns_msg *msg = &handle->msg; u_char *t; int n; if (msg->_sect != ns_s_qd) { errno = ENODEV; return (-1); } t = (u_char *) (unsigned long) msg->_msg_ptr; if (msg->_rrnum == 0) msg->_sections[ns_s_qd] = t; n = ns_name_pack(qname, t, msg->_eom - t, handle->dnptrs, handle->lastdnptr); if (n < 0) return (-1); t += n; if (t + QFIXEDSZ >= msg->_eom) { errno = EMSGSIZE; return (-1); } NS_PUT16(qtype, t); NS_PUT16(qclass, t); msg->_msg_ptr = t; msg->_counts[ns_s_qd] = ++msg->_rrnum; return (0); }
/* Add an RR to a "newmsg" object. */ int ns_newmsg_rr(ns_newmsg *handle, ns_sect sect, ns_nname_ct name, ns_type type, ns_class rr_class, u_int32_t ttl, u_int16_t rdlen, const u_char *rdata) { ns_msg *msg = &handle->msg; u_char *t; int n; if (sect < msg->_sect) { errno = ENODEV; return (-1); } t = (u_char *) (unsigned long) msg->_msg_ptr; if (sect > msg->_sect) { msg->_sect = sect; msg->_sections[sect] = t; msg->_rrnum = 0; } n = ns_name_pack(name, t, msg->_eom - t, handle->dnptrs, handle->lastdnptr); if (n < 0) return (-1); t += n; if (t + RRFIXEDSZ + rdlen >= msg->_eom) { errno = EMSGSIZE; return (-1); } NS_PUT16(type, t); NS_PUT16(rr_class, t); NS_PUT32(ttl, t); msg->_msg_ptr = t; if (rdcpy(handle, type, rdata, rdlen) < 0) return (-1); msg->_counts[sect] = ++msg->_rrnum; return (0); }
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); }