1/*
2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1995-2003 by Internet Software Consortium
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 *   Internet Systems Consortium, Inc.
18 *   950 Charter Street
19 *   Redwood City, CA 94063
20 *   <info@isc.org>
21 *   http://www.isc.org/
22 */
23
24#include <sys/types.h>
25#include <sys/param.h>
26
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <sys/socket.h>
30
31#include <errno.h>
32#include <netdb.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37
38#include "minires/minires.h"
39#include "arpa/nameser.h"
40
41#include <isc-dhcp/dst.h>
42
43/* res_nsendsigned */
44isc_result_t
45res_nsendsigned(res_state statp,
46		double *msg, unsigned msglen, ns_tsig_key *key,
47		double *answer, unsigned anslen, unsigned *anssize)
48{
49	res_state nstatp;
50	DST_KEY *dstkey;
51	int usingTCP = 0;
52	double *newmsg;
53	unsigned newmsglen;
54	unsigned bufsize, siglen;
55	u_char sig[64];
56	HEADER *hp;
57	time_t tsig_time;
58	unsigned ret;
59	isc_result_t rcode;
60
61	dst_init();
62
63	nstatp = (res_state) malloc(sizeof(*statp));
64	if (nstatp == NULL)
65		return ISC_R_NOMEMORY;
66	memcpy(nstatp, statp, sizeof(*statp));
67
68	bufsize = msglen + 1024;
69	newmsg = (double *) malloc(bufsize);
70	if (newmsg == NULL)
71		return ISC_R_NOMEMORY;
72	memcpy(newmsg, msg, msglen);
73	newmsglen = msglen;
74
75	if (ns_samename(key->alg, NS_TSIG_ALG_HMAC_MD5) != 1)
76		dstkey = NULL;
77	else
78		dstkey = dst_buffer_to_key(key->name, KEY_HMAC_MD5,
79					   NS_KEY_TYPE_AUTH_ONLY,
80					   NS_KEY_PROT_ANY,
81					   key->data, key->len);
82	if (dstkey == NULL) {
83		free(nstatp);
84		free(newmsg);
85		return ISC_R_BADKEY;
86	}
87
88	nstatp->nscount = 1;
89	siglen = sizeof(sig);
90	rcode = ns_sign((u_char *)newmsg, &newmsglen, bufsize,
91			NOERROR, dstkey, NULL, 0,
92			sig, &siglen, 0);
93	if (rcode != ISC_R_SUCCESS) {
94		free (nstatp);
95		free (newmsg);
96		return rcode;
97	}
98
99	if (newmsglen > PACKETSZ || (nstatp->options & RES_IGNTC))
100		usingTCP = 1;
101	if (usingTCP == 0)
102		nstatp->options |= RES_IGNTC;
103	else
104		nstatp->options |= RES_USEVC;
105
106retry:
107
108	rcode = res_nsend(nstatp, newmsg, newmsglen, answer, anslen, &ret);
109	if (rcode != ISC_R_SUCCESS) {
110		free (nstatp);
111		free (newmsg);
112		return rcode;
113	}
114
115	anslen = ret;
116	rcode = ns_verify((u_char *)answer, &anslen, dstkey, sig, siglen,
117			  NULL, NULL, &tsig_time,
118			  (nstatp->options & RES_KEEPTSIG) ? 1 : 0);
119	if (rcode != ISC_R_SUCCESS) {
120		Dprint(nstatp->pfcode & RES_PRF_REPLY,
121		       (stdout, ";; TSIG invalid (%s)\n", p_rcode(ret)));
122		free (nstatp);
123		free (newmsg);
124		return rcode;
125	}
126	Dprint(nstatp->pfcode & RES_PRF_REPLY, (stdout, ";; TSIG ok\n"));
127
128	hp = (HEADER *) answer;
129	if (hp->tc && usingTCP == 0) {
130		nstatp->options &= ~RES_IGNTC;
131		usingTCP = 1;
132		goto retry;
133	}
134
135	free (nstatp);
136	free (newmsg);
137	*anssize = anslen;
138	return ISC_R_SUCCESS;
139}
140