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