djbdnscurve6 53
djbdnscurve6
Loading...
Searching...
No Matches
curvedns.c
Go to the documentation of this file.
1/* cns_transmit_start returns DNS_COM */
2
3#include <stdio.h>
4#include "alloc.h"
5#include "byte.h"
6#include "uint_t.h"
7#include "case.h"
8#include "log.h"
9#include "base32.h"
10#include "socket_if.h"
11#include "ip.h"
12#include "error.h"
13#include "curvedns.h"
14#include "serverok.h"
15#include "log.h"
16#include "dns.h"
17#include "query.h"
18
19int flagedserver; // $FLAGEDSERVER
20int flagusetxtformat = 0; // $USETXTFORMAT
21unsigned int fallback = 0; // $UZ5FALLBACK; typically 2
22
23extern unsigned int flagedns0; // $FLAGDNSOPTRR 1 or 2
24extern unsigned int msgsize; // DNS message size for UDP
25
26char optrr[11] = { '\0', // root = 0
27 '\0','\51', // DNS_T_OPT
28 '\5', '\0', // max payload size (1280)
29 '\0', '\0', '\0', '\0', // without D0 flag
30 '\0', '\0' };
31
32char optdo[11] = { '\0', // root = 0
33 '\0','\51', // DNS_T_OPT
34 '\5', '\0', // max payload size (1280)
35 '\0', '\0','\200','\0', // with D0 flag
36 '\0', '\0' };
37
38unsigned int udp_msgsize(void) { return msgsize; }
39
40void cns_nonce(char nonce[12])
41{
42 int i;
43
44 for (i = 0; i < 12; i++)
45 nonce[i] = dns_random(256);
46}
47
48/* Generate standard DNS query message with EDNS(0) */
49
50void dns_basequery(struct dns_transmit *d,char *query)
51{
52 unsigned int len;
53
54 len = dns_domain_length(d->name);
55
56 byte_copy(query,2,d->nonce + 8); /* 2 byte Identification */
57 /* Parameter Mapping: 1: Query; 1: #Queries; 1: #AddSec = 1*/
58 if (d->flagedns)
59 byte_copy(query + 2,10,d->flagrecursive ? "\1\0\0\1\0\0\0\0\0\1" : \
60 "\0\0\0\1\0\0\0\0\0\1");
61 else
62 byte_copy(query + 2,10,d->flagrecursive ? "\1\0\0\1\0\0\0\0\0\0" : \
63 "\0\0\0\1\0\0\0\0\0\0");
64 byte_copy(query + 12,len,d->name);
65 byte_copy(query + 12 + len,2,d->qtype);
66 byte_copy(query + 14 + len,2,DNS_C_IN);
67
68 /* EDNS(0) Pseudo RR: name(1) + type(2) + class(2) + ttl(4) + rdlen(2) => +11 octetts*/
69
70 if (d->flagedns) {
71 byte_copy(query + 16 + len,3,optrr); // name = 0 + DNS_OPT header
72 uint16_pack_big(query + 19 + len,udp_msgsize()); // msg size
73 if (d->flagedns == 2)
74 byte_copy(query + 21 + len,6,optdo + 5); // DO + rest 0
75 else
76 byte_copy(query + 21 + len,6,optrr + 5); // rest 0
77 }
78}
79
80/* Generate DNSCurve format query message */
81
82void cns_query(struct dns_transmit *d)
83{
84 unsigned int len;
85 char nonce[24];
86 const char *key;
87 unsigned int m;
88 unsigned int suffixlen;
89
90 cns_nonce(d->nonce);
91
92 if (!d->keys) {
93 byte_copy(d->query + 2,2,d->nonce + 8);
94 return;
95 }
96
97 len = dns_domain_length(d->name);
98
99 byte_copy(nonce,12,d->nonce);
100 byte_zero(nonce + 12,12);
101 key = d->keys + KEY_LEN * d->curserver;
102
103 byte_zero(d->query,KEY_LEN);
104 dns_basequery(d,d->query + KEY_LEN); // no EDNS(0) for DNSCurve
105
106 crypto_box_afternm((unsigned char *) d->query,(const unsigned char *) d->query,len + 48, \
107 (const unsigned char *) nonce,(const unsigned char *) key);
108
109 if (!d->suffix) {
110 byte_copyr(d->query + 54,len + KEY_LEN,d->query + 16);
111 uint16_pack_big(d->query,len + 84);
112 byte_copy(d->query + 2,8,"Q6fnvWj8");
113 byte_copy(d->query + 10,KEY_LEN,d->pubkey);
114 byte_copy(d->query + 42,12,nonce);
115 return;
116 }
117
118 byte_copyr(d->query + d->querylen - len - KEY_LEN,len + KEY_LEN,d->query + 16);
119 byte_copy(d->query + d->querylen - len - 44,12,nonce);
120
121 suffixlen = dns_domain_length(d->suffix);
122 m = base32_bytessize(len + 44);
123
124 uint16_pack_big(d->query,d->querylen - 2);
125 d->query[2] = dns_random(256);
126 d->query[3] = dns_random(256);
127 byte_copy(d->query + 4,10,"\0\0\0\1\0\0\0\0\0\0");
128 base32_encode(d->query + 14,d->query + d->querylen - len - 44,len + 44);
129 base32_clientkey(d->query + 14 + m,d->pubkey);
130 byte_copy(d->query + 69 + m,suffixlen,d->suffix);
131 byte_copy(d->query + 69 + m + suffixlen,4,DNS_T_TXT DNS_C_IN);
132}
133
134int cns_uncurve(const struct dns_transmit *d,char *buf,unsigned int *lenp)
135{
136 const char *key;
137 char nonce[24];
138 unsigned int len;
139 char out[16];
140 unsigned int pos;
141 uint16 datalen;
142 unsigned int i;
143 unsigned int j;
144 char ch;
145 unsigned int txtlen;
146 unsigned int namelen;
147
148 if (!d->keys) return 0;
149
150 key = d->keys + KEY_LEN * d->curserver;
151 len = *lenp;
152
153 if (!d->suffix) {
154 if (len < 48) return 1;
155 if (byte_diff(buf,8,"R6fnvWJ8")) return 1;
156 if (byte_diff(buf + 8,12,d->nonce)) return 1;
157 byte_copy(nonce,24,buf + 8);
158 byte_zero(buf + 16,16);
159
160 if (crypto_box_open_afternm((uint8 *) buf + 16,(const uint8 *) buf + 16,len - 16, \
161 (const uint8 *) nonce,(const uint8 *) key)) return 1;
162 byte_copy(buf,len - 48,buf + 48);
163 *lenp = len - 48;
164 return 0;
165 }
166
167 /* XXX: be more leniant? */
168
169 pos = dns_packet_copy(buf,len,0,out,12); if (!pos) return 1;
170 if (byte_diff(out,2,d->query + 2)) return 1;
171 if (byte_diff(out + 2,10,"\204\0\0\1\0\1\0\0\0\0")) return 1;
172
173 /* query name might be >255 bytes, so can't use dns_packet_getname */
174 namelen = dns_domain_length(d->query + 14);
175 pos += namelen;
176
177 pos = dns_packet_copy(buf,len,pos,out,16); if (!pos) return 1;
178 if (byte_diff(out,14,"\0\20\0\1\300\14\0\20\0\1\0\0\0\0")) return 1;
179 uint16_unpack_big(out + 14,&datalen);
180 if (datalen > len - pos) return 1;
181
182 j = 4;
183 txtlen = 0;
184 for (i = 0; i < datalen; ++i) {
185 ch = buf[pos + i];
186 if (!txtlen)
187 txtlen = (unsigned char) ch;
188 else {
189 --txtlen;
190 buf[j++] = ch;
191 }
192 }
193 if (txtlen) return 1;
194
195 if (j < KEY_LEN) return 1;
196 byte_copy(nonce,12,d->nonce);
197 byte_copy(nonce + 12,12,buf + 4);
198 byte_zero(buf,16);
199
200 if (crypto_box_open_afternm((unsigned char *) buf,(const unsigned char *) buf,j, \
201 (const unsigned char *) nonce,(const unsigned char *) key)) return 1;
202 byte_copy(buf,j - KEY_LEN,buf + KEY_LEN);
203 *lenp = j - KEY_LEN;
204
205 return 0;
206}
207
208int cns_pubkey(const char *dn,char *key)
209{
210 unsigned char c;
211
212 while ((c = *dn++)) {
213 if (c == 54)
214 if (!case_diffb(dn,3,"uz5"))
215 if (base32_decode(key,dn + 3,51,1) == KEY_LEN)
216 return 1;
217 dn += (unsigned int) c;
218 }
219 return 0;
220}
221
222void cns_sortns(char *s,char *t,unsigned int n)
223{
224 unsigned int i;
225 char tmp[KEY_LEN];
226
227 /* s = ipaddress, t = pubkey, n = #NS */
228
229 while (n > 1) {
230 i = dns_random(n);
231 --n;
232 byte_copy(tmp,16,s + (i << 4));
233 byte_copy(s + (i << 4),16,s + (n << 4));
234 byte_copy(s + (n << 4),16,tmp);
235 byte_copy(tmp,KEY_LEN,t + (i << 5));
236 byte_copy(t + (i << 5),KEY_LEN,t + (n << 5));
237 byte_copy(t + (n << 5),KEY_LEN,tmp);
238 }
239}
240
241int cns_addns(struct query *z,const char *addr,int flagnskey,const char *key)
242{
243 int k, n;
244 int flagns = 0;
245 int flagcurvetxt = 0;
246 int flagedns = flagedns0;
247
248 if (flagusetxtformat) flagcurvetxt = 1;
249
250 if (flagedserver) {
251 flagns = serverok(addr);
252 if (flagns == 1) return 1;
253 if (flagns == 2) flagedns = flagedns0 ? 0 : flagedns0; /* toggle */
254 if (flagns == -1) flagnskey = 0;
255 if (flagns == -2) flagcurvetxt = flagusetxtformat ? 0 : 1; /* toggle */
256 }
257
258 if (z->flagnskeys[z->level - 1]) {
259 if (!flagnskey) goto IPONLY;
260 } else if (flagnskey) {
261 byte_zero(z->servers[z->level - 1],QUERY_MAXIPLEN);
262 byte_zero(z->keys[z->level - 1],QUERY_MAXNS * KEY_LEN);
263 z->flagnskeys[z->level - 1] = 1;
264 }
265
266 IPONLY:
267 for (k = 0, n = 0; k < QUERY_MAXIPLEN; k += 16, ++n) {
268 z->ctx[z->level - 1][n] = 'd'; /* std q */
269 if (flagedns == 1) z->ctx[z->level - 1][n] = 'e'; /* edns0 q */
270 if (flagedns == 2) z->ctx[z->level - 1][n] = 's'; /* edns0 +do q */
271 if (flagnskey) z->ctx[z->level - 1][n] = 'c'; /* curve q */
272 if (flagnskey && flagcurvetxt) z->ctx[z->level - 1][n] = 't'; /* alt c q */
273
274 if (byte_equal(z->servers[z->level - 1] + k,16,addr)) return flagns;
275
276 if (byte_equal(z->servers[z->level - 1] + k,16,V6localnet)) {
277 byte_copy(z->servers[z->level - 1] + k,16,addr); /* new ns */
278 if (flagnskey) byte_copy(z->keys[z->level - 1] + 2 * k,KEY_LEN,key);
279 break;
280 }
281 }
282
283 return flagns;
284}
285
287 char qflags[2],const char *q,const char qtype[2],const char localip[16],\
288 const char keys[QUERY_MAXNS * KEY_LEN],const char pubkey[KEY_LEN],const char *suffix)
289{
290 unsigned int len;
291 unsigned int suffixlen;
292 unsigned int m;
293 int flagrecursive = qflags[0];
294 int flagedns = qflags[1];
295
297 errno = EIO;
299
300 if (!keys) {
301 d->querylen = len + 18;
302 if (flagedns) d->querylen += 11; // +OPT-RR
303 } else if (!suffix)
304 d->querylen = len + 86;
305 else {
306 suffixlen = dns_domain_length(suffix);
307 m = base32_bytessize(len + 44);
308 d->querylen = m + suffixlen + 73;
309 }
310
311 d->query = alloc(d->querylen);
312 if (!d->query) return DNS_MEM;
313
314 d->name = q;
315 byte_copy(d->qtype,2,qtype);
316 d->servers = servers;
317 byte_copy(d->localip,16,localip);
318 d->flagrecursive = flagrecursive;
319 d->flagedns = flagedns;
320 d->keys = keys;
321 d->pubkey = pubkey;
322 d->suffix = suffix;
323
324 if (!d->keys) {
325 uint16_pack_big(d->query,len + 16);
326 dns_basequery(d,d->query + 2);
327 d->name = d->query + 14; /* keeps dns_transmit_start backwards compatible */
328 }
329 d->udploop = flagrecursive ? 1 : 0;
330
331 if (len > udp_msgsize() - 16) return firsttcp(d);
332
333 return firstudp(d);
334}
uint16 len
Definition: axfrdns.c:322
char buf[MSGSIZE]
Definition: axfrdns.c:321
unsigned int base32_bytessize(unsigned int len)
Definition: base32.c:40
void base32_clientkey(uint8 *out, const char *key)
Definition: base32.c:106
unsigned int base32_decode(uint8 *out, const char *in, unsigned int len, int mode)
Definition: base32.c:46
void base32_encode(uint8 *out, const char *in, unsigned int len)
Definition: base32.c:77
#define crypto_box_afternm
Definition: curve.h:14
#define crypto_box_open_afternm
Definition: curve.h:15
#define KEY_LEN
int cns_transmit_start(struct dns_transmit *d, const char servers[QUERY_MAXIPLEN], char qflags[2], const char *q, const char qtype[2], const char localip[16], const char keys[QUERY_MAXNS *KEY_LEN], const char pubkey[KEY_LEN], const char *suffix)
Definition: curvedns.c:286
void dns_basequery(struct dns_transmit *d, char *query)
Definition: curvedns.c:50
void cns_sortns(char *s, char *t, unsigned int n)
Definition: curvedns.c:222
void cns_query(struct dns_transmit *d)
Definition: curvedns.c:82
void cns_nonce(char nonce[12])
Definition: curvedns.c:40
char optdo[11]
Definition: curvedns.c:32
unsigned int udp_msgsize(void)
Definition: curvedns.c:38
int cns_uncurve(const struct dns_transmit *d, char *buf, unsigned int *lenp)
Definition: curvedns.c:134
int cns_pubkey(const char *dn, char *key)
Definition: curvedns.c:208
unsigned int flagedns0
Definition: axfrdns.c:28
int flagedserver
Definition: curvedns.c:19
int cns_addns(struct query *z, const char *addr, int flagnskey, const char *key)
Definition: curvedns.c:241
int flagusetxtformat
Definition: curvedns.c:20
unsigned int fallback
Definition: curvedns.c:21
unsigned int msgsize
Definition: axfrdns.c:29
char optrr[11]
Definition: curvedns.c:26
#define QUERY_MAXIPLEN
Definition: dns.h:55
#define DNS_C_IN
Definition: dns.h:62
#define DNS_T_TXT
Definition: dns.h:72
#define QUERY_MAXNS
Definition: dns.h:54
#define DNS_MEM
Definition: dns.h:40
unsigned int dns_domain_length(const char *dn)
Definition: dns_domain.c:6
unsigned int dns_packet_copy(const char *buf, unsigned int len, unsigned int pos, char *out, unsigned int outlen)
Definition: dns_packet.c:8
unsigned int dns_random(unsigned int n)
Definition: dns_random.c:55
void dns_transmit_free(struct dns_transmit *d)
Definition: dns_transmit.c:95
int firstudp(struct dns_transmit *d)
Definition: dns_transmit.c:193
int firsttcp(struct dns_transmit *d)
Definition: dns_transmit.c:250
struct tcpclient t[QUERY_MAXTCP]
char servers[QUERY_MAXIPLEN]
Definition: dnsfilter.c:54
struct line tmp
Definition: dnsfilter.c:38
void out(const char *s, unsigned int len)
Definition: generic-conf.c:54
void c(const char *home, const char *subdir, const char *file, int uid, int gid, int mode)
void d(const char *home, const char *subdir, int uid, int gid, int mode)
void z(char *home, char *subdir, char *file, int len, int uid, int gid, int mode)
Definition: install.c:88
int serverok(char[16])
Definition: serverok.c:22
Definition: query.h:60