Home | History | Annotate | Line # | Download | only in libresolv
      1 /*	$NetBSD: res_sendsigned.c,v 1.1 2012/11/15 18:48:49 christos Exp $	*/
      2 #include <sys/cdefs.h>
      3 __RCSID("$NetBSD: res_sendsigned.c,v 1.1 2012/11/15 18:48:49 christos Exp $");
      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 */
     31 int
     32 res_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 
    106 retry:
    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