1/* $NetBSD: res_sendsigned.c,v 1.1.1.1 2009/04/12 15:33:58 christos Exp $ */ 2#include <sys/cdefs.h> 3__RCSID("$NetBSD$"); 4 5#include "port_before.h" 6#include "fd_setsize.h" 7 8#include <sys/types.h> 9#include <sys/param.h> 10 11#include <netinet/in.h> 12#include <arpa/nameser.h> 13#include <arpa/inet.h> 14 15#include <isc/dst.h> 16 17#include <errno.h> 18#include <netdb.h> 19#include <resolv.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <unistd.h> 24 25#include "port_after.h" 26 27#include "res_debug.h" 28 29 30/*% res_nsendsigned */ 31int 32res_nsendsigned(res_state statp, const u_char *msg, int msglen, 33 ns_tsig_key *key, u_char *answer, int anslen) 34{ 35 res_state nstatp; 36 DST_KEY *dstkey; 37 int usingTCP = 0; 38 u_char *newmsg; 39 int newmsglen, bufsize, siglen; 40 u_char sig[64]; 41 HEADER *hp; 42 time_t tsig_time; 43 int ret; 44 int len; 45 46 dst_init(); 47 48 nstatp = (res_state) malloc(sizeof(*statp)); 49 if (nstatp == NULL) { 50 errno = ENOMEM; 51 return (-1); 52 } 53 memcpy(nstatp, statp, sizeof(*statp)); 54 55 bufsize = msglen + 1024; 56 newmsg = (u_char *) malloc(bufsize); 57 if (newmsg == NULL) { 58 free(nstatp); 59 errno = ENOMEM; 60 return (-1); 61 } 62 memcpy(newmsg, msg, msglen); 63 newmsglen = msglen; 64 65 if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1) 66 dstkey = NULL; 67 else 68 dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5, 69 NS_KEY_TYPE_AUTH_ONLY, 70 NS_KEY_PROT_ANY, 71 key->data, key->len); 72 if (dstkey == NULL) { 73 errno = EINVAL; 74 free(nstatp); 75 free(newmsg); 76 return (-1); 77 } 78 79 nstatp->nscount = 1; 80 siglen = sizeof(sig); 81 ret = ns_sign(newmsg, &newmsglen, bufsize, NOERROR, dstkey, NULL, 0, 82 sig, &siglen, 0); 83 if (ret < 0) { 84 free (nstatp); 85 free (newmsg); 86 dst_free_key(dstkey); 87 if (ret == NS_TSIG_ERROR_NO_SPACE) 88 errno = EMSGSIZE; 89 else if (ret == -1) 90 errno = EINVAL; 91 return (ret); 92 } 93 94 if (newmsglen > PACKETSZ || nstatp->options & RES_USEVC) 95 usingTCP = 1; 96 if (usingTCP == 0) 97 nstatp->options |= RES_IGNTC; 98 else 99 nstatp->options |= RES_USEVC; 100 /* 101 * Stop res_send printing the answer. 102 */ 103 nstatp->options &= ~RES_DEBUG; 104 nstatp->pfcode &= ~RES_PRF_REPLY; 105 106retry: 107 108 len = res_nsend(nstatp, newmsg, newmsglen, answer, anslen); 109 if (len < 0) { 110 free (nstatp); 111 free (newmsg); 112 dst_free_key(dstkey); 113 return (len); 114 } 115 116 ret = ns_verify(answer, &len, dstkey, sig, siglen, 117 NULL, NULL, &tsig_time, (nstatp->options & RES_KEEPTSIG) != 0); 118 if (ret != 0) { 119 Dprint((statp->options & RES_DEBUG) || 120 ((statp->pfcode & RES_PRF_REPLY) && 121 (statp->pfcode & RES_PRF_HEAD1)), 122 (stdout, ";; got answer:\n")); 123 124 DprintQ((statp->options & RES_DEBUG) || 125 (statp->pfcode & RES_PRF_REPLY), 126 (stdout, "%s", ""), 127 answer, (anslen > len) ? len : anslen); 128 129 if (ret > 0) { 130 Dprint(statp->pfcode & RES_PRF_REPLY, 131 (stdout, ";; server rejected TSIG (%s)\n", 132 p_rcode(ret))); 133 } else { 134 Dprint(statp->pfcode & RES_PRF_REPLY, 135 (stdout, ";; TSIG invalid (%s)\n", 136 p_rcode(-ret))); 137 } 138 139 free (nstatp); 140 free (newmsg); 141 dst_free_key(dstkey); 142 if (ret == -1) 143 errno = EINVAL; 144 else 145 errno = ENOTTY; 146 return (-1); 147 } 148 149 hp = (HEADER *)(void *)answer; 150 if (hp->tc && !usingTCP && (statp->options & RES_IGNTC) == 0U) { 151 nstatp->options &= ~RES_IGNTC; 152 usingTCP = 1; 153 goto retry; 154 } 155 Dprint((statp->options & RES_DEBUG) || 156 ((statp->pfcode & RES_PRF_REPLY) && 157 (statp->pfcode & RES_PRF_HEAD1)), 158 (stdout, ";; got answer:\n")); 159 160 DprintQ((statp->options & RES_DEBUG) || 161 (statp->pfcode & RES_PRF_REPLY), 162 (stdout, "%s", ""), 163 answer, (anslen > len) ? len : anslen); 164 165 Dprint(statp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n")); 166 167 free (nstatp); 168 free (newmsg); 169 dst_free_key(dstkey); 170 return (len); 171} 172 173/*! \file */ 174