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 */
30int
31res_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
105retry:
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