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