File: response.c

package info (click to toggle)
dq 20250201-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,408 kB
  • sloc: ansic: 13,644; python: 651; makefile: 382; sh: 336
file content (117 lines) | stat: -rw-r--r-- 3,085 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "dns.h"
#include "byte.h"
#include "crypto_uint16.h"
#include "crypto_uint32.h"
#include "response.h"

unsigned char response[65535];
long long response_len = 0; /* <= 65535 */
static long long tctarget;

#define NAMES 100
static unsigned char name[NAMES][255];
static long long name_ptr[NAMES]; /* each < 16384 */
static long long name_num;

int response_addbytes(const unsigned char *buf, long long len) {

    if (len < 0) return 0;
    if (len > 65535 - response_len) return 0;
    byte_copy(response + response_len, len, buf);
    response_len += len;
    return 1;
}

int response_addname(const unsigned char *d) {

    long long dlen;
    long long i;
    unsigned char buf[2];

    dlen = dns_domain_length(d);

    while (*d) {
        for (i = 0; i < name_num; ++i)
            if (dns_domain_equal(d, name[i])) {
                crypto_uint16_store_bigendian(buf, 49152 + name_ptr[i]);
                return response_addbytes(buf, 2);
            }
        if ((dlen <= 255) && (response_len < 16384))
            if (name_num < NAMES) {
	        byte_copy(name[name_num], dlen, d);
	        name_ptr[name_num] = response_len;
	        ++name_num;
            }
        i = *d;
        ++i;
        if (!response_addbytes(d, i)) return 0;
        d += i;
        dlen -= i;
    }
    return response_addbytes(d, 1);
}

int response_query(const unsigned char *q, const unsigned char qtype[2], const unsigned char qclass[2]) {

    response_len = 0;
    name_num = 0;
    if (!response_addbytes((unsigned char *)"\0\0\201\200\0\1\0\0\0\0\0\0", 12)) return 0;
    if (!response_addname(q)) return 0;
    if (!response_addbytes(qtype, 2)) return 0;
    if (!response_addbytes(qclass, 2)) return 0;
    tctarget = response_len;
    return 1;
}

static long long dpos;

static int flaghidettl = 0;

void response_hidettl(void) {
    flaghidettl = 1;
}

int response_rstart(const unsigned char *d, const unsigned char type[2], crypto_uint32 ttl) {

    unsigned char ttlstr[4];
    if (!response_addname(d)) return 0;
    if (!response_addbytes(type, 2)) return 0;
    if (!response_addbytes(DNS_C_IN, 2)) return 0;
    if (flaghidettl) ttl = 0;
    crypto_uint32_store_bigendian(ttlstr, ttl);
    if (!response_addbytes(ttlstr, 4)) return 0;
    if (!response_addbytes((unsigned char *)"\0\0", 2)) return 0;
    dpos = response_len;
    return 1;
}

void response_rfinish(int x) {
    crypto_uint16_store_bigendian(response + dpos - 2, response_len - dpos);
    if (!++response[x + 1]) ++response[x];
}

int response_cname(const unsigned char *c, const unsigned char *d, crypto_uint32 ttl) {
    if (!response_rstart(c, DNS_T_CNAME, ttl)) return 0;
    if (!response_addname(d)) return 0;
    response_rfinish(RESPONSE_ANSWER);
    return 1;
}

void response_nxdomain(void) {
    response[3] |= 3;
    response[2] |= 4;
}

void response_servfail(void) {
    response[3] |= 2;
}

void response_id(const unsigned char id[2]) {
    byte_copy(response, 2, id);
}

void response_tc(void) {
    response[2] |= 2;
    response_len = tctarget;
    byte_zero(response + 6, 6);
}