1 #include "dns.h"
2 #include "byte.h"
3 #include "uint16_pack_big.h"
4 #include "uint32_pack_big.h"
5 #include "response.h"
6 
7 unsigned char response[65535];
8 long long response_len = 0; /* <= 65535 */
9 static long long tctarget;
10 
11 #define NAMES 100
12 static unsigned char name[NAMES][255];
13 static long long name_ptr[NAMES]; /* each < 16384 */
14 static long long name_num;
15 
response_addbytes(const unsigned char * buf,long long len)16 int response_addbytes(const unsigned char *buf, long long len) {
17 
18     if (len < 0) return 0;
19     if (len > 65535 - response_len) return 0;
20     byte_copy(response + response_len, len, buf);
21     response_len += len;
22     return 1;
23 }
24 
response_addname(const unsigned char * d)25 int response_addname(const unsigned char *d) {
26 
27     long long dlen;
28     long long i;
29     unsigned char buf[2];
30 
31     dlen = dns_domain_length(d);
32 
33     while (*d) {
34         for (i = 0; i < name_num; ++i)
35             if (dns_domain_equal(d, name[i])) {
36                 uint16_pack_big(buf, 49152 + name_ptr[i]);
37                 return response_addbytes(buf, 2);
38             }
39         if ((dlen <= 255) && (response_len < 16384))
40             if (name_num < NAMES) {
41 	        byte_copy(name[name_num], dlen, d);
42 	        name_ptr[name_num] = response_len;
43 	        ++name_num;
44             }
45         i = *d;
46         ++i;
47         if (!response_addbytes(d, i)) return 0;
48         d += i;
49         dlen -= i;
50     }
51     return response_addbytes(d, 1);
52 }
53 
response_query(const unsigned char * q,const unsigned char qtype[2],const unsigned char qclass[2])54 int response_query(const unsigned char *q, const unsigned char qtype[2], const unsigned char qclass[2]) {
55 
56     response_len = 0;
57     name_num = 0;
58     if (!response_addbytes((unsigned char *)"\0\0\201\200\0\1\0\0\0\0\0\0", 12)) return 0;
59     if (!response_addname(q)) return 0;
60     if (!response_addbytes(qtype, 2)) return 0;
61     if (!response_addbytes(qclass, 2)) return 0;
62     tctarget = response_len;
63     return 1;
64 }
65 
66 static long long dpos;
67 
68 static int flaghidettl = 0;
69 
response_hidettl(void)70 void response_hidettl(void) {
71     flaghidettl = 1;
72 }
73 
response_rstart(const unsigned char * d,const unsigned char type[2],crypto_uint32 ttl)74 int response_rstart(const unsigned char *d, const unsigned char type[2], crypto_uint32 ttl) {
75 
76     unsigned char ttlstr[4];
77     if (!response_addname(d)) return 0;
78     if (!response_addbytes(type, 2)) return 0;
79     if (!response_addbytes(DNS_C_IN, 2)) return 0;
80     if (flaghidettl) ttl = 0;
81     uint32_pack_big(ttlstr, ttl);
82     if (!response_addbytes(ttlstr, 4)) return 0;
83     if (!response_addbytes((unsigned char *)"\0\0", 2)) return 0;
84     dpos = response_len;
85     return 1;
86 }
87 
response_rfinish(int x)88 void response_rfinish(int x) {
89     uint16_pack_big(response + dpos - 2, response_len - dpos);
90     if (!++response[x + 1]) ++response[x];
91 }
92 
response_cname(const unsigned char * c,const unsigned char * d,crypto_uint32 ttl)93 int response_cname(const unsigned char *c, const unsigned char *d, crypto_uint32 ttl) {
94     if (!response_rstart(c, DNS_T_CNAME, ttl)) return 0;
95     if (!response_addname(d)) return 0;
96     response_rfinish(RESPONSE_ANSWER);
97     return 1;
98 }
99 
response_nxdomain(void)100 void response_nxdomain(void) {
101     response[3] |= 3;
102     response[2] |= 4;
103 }
104 
response_servfail(void)105 void response_servfail(void) {
106     response[3] |= 2;
107 }
108 
response_id(const unsigned char id[2])109 void response_id(const unsigned char id[2]) {
110     byte_copy(response, 2, id);
111 }
112 
response_tc(void)113 void response_tc(void) {
114     response[2] |= 2;
115     response_len = tctarget;
116     byte_zero(response + 6, 6);
117 }
118