/* $NetBSD: res_sendsigned.c,v 1.1 2012/11/15 18:48:49 christos Exp $ */ #include __RCSID("$NetBSD: res_sendsigned.c,v 1.1 2012/11/15 18:48:49 christos Exp $"); #include "port_before.h" #include "fd_setsize.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "port_after.h" #include "res_debug.h" /*% res_nsendsigned */ int res_nsendsigned(res_state statp, const u_char *msg, int msglen, ns_tsig_key *key, u_char *answer, int anslen) { res_state nstatp; DST_KEY *dstkey; int usingTCP = 0; u_char *newmsg; int newmsglen, bufsize, siglen; u_char sig[64]; HEADER *hp; time_t tsig_time; int ret; int len; dst_init(); nstatp = (res_state) malloc(sizeof(*statp)); if (nstatp == NULL) { errno = ENOMEM; return (-1); } memcpy(nstatp, statp, sizeof(*statp)); bufsize = msglen + 1024; newmsg = (u_char *) malloc(bufsize); if (newmsg == NULL) { free(nstatp); errno = ENOMEM; return (-1); } memcpy(newmsg, msg, msglen); newmsglen = msglen; if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1) dstkey = NULL; else dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5, NS_KEY_TYPE_AUTH_ONLY, NS_KEY_PROT_ANY, key->data, key->len); if (dstkey == NULL) { errno = EINVAL; free(nstatp); free(newmsg); return (-1); } nstatp->nscount = 1; siglen = sizeof(sig); ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0, sig, &siglen, 0); if (ret < 0) { free (nstatp); free (newmsg); dst_free_key(dstkey); if (ret == NS_TSIG_ERROR_NO_SPACE) errno = EMSGSIZE; else if (ret == -1) errno = EINVAL; return (ret); } if (newmsglen > PACKETSZ || nstatp->options & RES_USEVC) usingTCP = 1; if (usingTCP == 0) nstatp->options |= RES_IGNTC; else nstatp->options |= RES_USEVC; /* * Stop res_send printing the answer. */ nstatp->options &= ~RES_DEBUG; nstatp->pfcode &= ~RES_PRF_REPLY; retry: len = res_nsend(nstatp, newmsg, newmsglen, answer, anslen); if (len < 0) { free (nstatp); free (newmsg); dst_free_key(dstkey); return (len); } ret = ns_verify(answer, &len, dstkey, sig, siglen, NULL, NULL, &tsig_time, (nstatp->options & RES_KEEPTSIG) != 0); if (ret != 0) { Dprint((statp->options & RES_DEBUG) || ((statp->pfcode & RES_PRF_REPLY) && (statp->pfcode & RES_PRF_HEAD1)), (stdout, ";; got answer:\n")); DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, "%s", ""), answer, (anslen > len) ? len : anslen); if (ret > 0) { Dprint(statp->pfcode & RES_PRF_REPLY, (stdout, ";; server rejected TSIG (%s)\n", p_rcode(ret))); } else { Dprint(statp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG invalid (%s)\n", p_rcode(-ret))); } free (nstatp); free (newmsg); dst_free_key(dstkey); if (ret == -1) errno = EINVAL; else errno = ENOTTY; return (-1); } hp = (HEADER *)(void *)answer; if (hp->tc && !usingTCP && (statp->options & RES_IGNTC) == 0U) { nstatp->options &= ~RES_IGNTC; usingTCP = 1; goto retry; } Dprint((statp->options & RES_DEBUG) || ((statp->pfcode & RES_PRF_REPLY) && (statp->pfcode & RES_PRF_HEAD1)), (stdout, ";; got answer:\n")); DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, "%s", ""), answer, (anslen > len) ? len : anslen); Dprint(statp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n")); free (nstatp); free (newmsg); dst_free_key(dstkey); return (len); } /*! \file */