~samiam/MaraDNS

ref: 3.5.0002 MaraDNS/sqa/aaaatest.c -rw-r--r-- 12.2 KiB View raw
db09084f — Sam Trenholme MaraDNS release 3.5.0002 3 months ago
                                                                                
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
/* Copyright (c) 2002,2003 Sam Trenholme
 *
 * TERMS
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This software is provided 'as is' with no guarantees of correctness or
 * fitness for purpose.
 */

/* This is a version of askmara modified to test a name server by sending an
   AAAA query to the nameserver in question and seeing what we get.
*/

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "../MaraDns.h"
/* All of the labels */
#include "../tools/askmara_labels_en.h"
/* Yes, we use our RNG to make the psudo-random number */
#include "../rng/rng-api-fst.h"

/* Generate a psudo-random query-id based on the hostname we give it.
   This helps us test the server against a large number of query IDs */

u_int16_t gen_id(char *hostname) {
    /* May as well bring out the bug guns (e.g. our rng) */
    MARA_BYTE r_inBlock[17],r_outBlock[17],r_binKey[34];
    MARA_BYTE r_keyMaterial[320];
    keyInstance r_keyInst;
    cipherInstance r_cipherInst;
    unsigned char crypto_key[34];
    int desc, len;

    if(hostname == 0)
        return JS_ERROR;

    /* Initialize the keys, including the "binKey" (is this used?) */
    memset(r_binKey,'0',16);
    memset(crypto_key,'z',17);
    /* Make the first 32 characters of the hostname the key (padded by the
       z character--do you see a z there?) */
    strncpy(crypto_key,hostname,16);
    /* Set the plaintext block to '0000000000000000' */
    memset(r_inBlock,'0',16);

    if(makeKey(&r_keyInst, DIR_ENCRYPT, 128, crypto_key) != 1)
        return JS_ERROR;
    if(cipherInit(&r_cipherInst, MODE_ECB, NULL) != 1)
        return JS_ERROR;
    if(blockEncrypt(&r_cipherInst,&r_keyInst,r_inBlock,128,r_outBlock) != 128)
        return JS_ERROR;

    return ((r_outBlock[0] << 8) & 0xff00) | (r_outBlock[1] & 0x00ff);
    }

int harderror(char *msg) {
    printf("%s%s%s",L_HARD_ERROR,msg,L_NEWLINE);
    exit(1);
    }

main(int argc, char **argv) {
    char *server_address = NULL;
    struct sockaddr_in dns_udp, server;
    int len_inet; /* Length */
    int s; /* Socket */
    int q; /* Used for binding, etc */
    js_string *outdata; /* Outgoing data */
    js_string *indata, *uindata; /* Incoming data (uncompressed version) */
    js_string *qstring; /* String to store the question we ask the server */
    q_header header; /* header data */
    q_question question;
    int counter,place,count,qtype;
    fd_set rx_set; /* Using select() because if its timeout option */
    int maxd;      /* select() */
    int idnum;
    struct timeval tv;  /* select() */
    int n; /* Select() return value */
    int rtype;
    int soa_ns = 0; /* Is this a "not there" or a referral */

    /* Determine what the query string is */
    if(argc < 2 || argc > 3)
        harderror(L_USAGE);

    /* Determine what IP address to bind to */
    if(argc == 3)
        server_address = argv[2];
    else
        server_address = "127.0.0.3";

    if((indata = js_create(512,1)) == 0)
       harderror(L_JS_CREATE_INDATA);
    if((uindata = js_create(2048,1)) == 0)
       harderror(L_JS_CREATE_UINDATA);
    if((outdata = js_create(512,1)) == 0)
       harderror(L_JS_CREATE_OUTDATA);
    if((question.qname = js_create(512,1)) == 0)
       harderror(L_JS_CREATE_QNAME);
    if((qstring = js_create(512,1)) == 0)
       harderror("Can not create qstring string");
    /* Create a UDP client socket */
    if((s = socket(AF_INET,SOCK_DGRAM,0)) == -1)
        harderror(L_SOCKET);

    /* Create a socket address to use with sendto() */
    memset(&dns_udp,0,sizeof(dns_udp));
    dns_udp.sin_family = AF_INET;
    dns_udp.sin_port = htons(53);
    if((dns_udp.sin_addr.s_addr = inet_addr(server_address)) == INADDR_NONE)
        harderror(L_MAL_IP);

    len_inet = sizeof(dns_udp);

    idnum = gen_id(argv[1]); /* Make a psudo-random number based on the
                                first 32 characters of the request to send
                                to the server */

    /* Format a DNS request */
    /* DNS header */
    header.id = idnum; /* Psudo-random number */
    header.qr = 0; /* It is a question */
    header.opcode = 0;
    header.aa = 0;
    header.tc = 0;
    header.rd = 1; /* Recursion desired */
    header.ra = 0;
    header.z = 0;
    header.rcode = 0;
    header.qdcount = 1;
    header.ancount = 0;
    header.nscount = 0;
    header.arcount = 0;

    /* Create a DNS question , and put it in raw UDP format */
    /* DNS question -> looking up an A record... */
    question.qclass = 1; /* ...on the internet */
    if(js_qstr2js(question.qname,argv[1]) == JS_ERROR)
        harderror(L_INVALID_Q); /* Invalid query */

    /* Make 'Aexample.com.' raw UDP data */

    qtype = 28; /* AAAA resource record */
    if(qtype == JS_ERROR)
        harderror(L_INVALID_DQ); /* Invalid form of domain query */
    question.qtype = qtype;

    if(js_copy(question.qname,qstring) == JS_ERROR)
        harderror("Problem copying question.qname to qstring");

    /* Make a string containing the RAW UDP query */
    make_hdr(&header,outdata);
    make_question(&question,outdata);

    /* Send out a DNS request */
    if(sendto(s,outdata->string,outdata->unit_count,0,
       (struct sockaddr *)&dns_udp,len_inet) < 0)
        harderror(L_UDP_NOSEND); /* Unable to send UDP packet */

    /* Wait for a reply from the DNS server */
    FD_ZERO(&rx_set);
    FD_SET(s,&rx_set);
    maxd = s + 1;
    tv.tv_sec = 2;
    tv.tv_usec = 0;
    n = select(maxd,&rx_set,NULL,NULL,&tv);
    if(n == -1)  /* select error */
        harderror("Select() failed");
    if(n == 0) /* Timeout */ {
        printf("Result: timeout\n");
        exit(7);
        }
    if((count = recvfrom(s,indata->string,indata->max_count,0,
                        (struct sockaddr *)&dns_udp,&len_inet)) < 0)
        harderror(L_DNS_R_ERROR); /* Problem getting DNS server response */

    indata->unit_count = count;

    decompress_data(indata,uindata);

    if(read_hdr(uindata,&header) == JS_ERROR) {
        printf("Result: Currupt DNS header\n");
        exit(9);
        }

    /* If the header ID is not the same as what we sent them, this is an
       error */
    if(header.id != idnum) {
        printf("Result: Bad ID (expected %d, got %d)\n",idnum,header.id);
        exit(10);
        }

    /* Make sure the reply is marked as a reply */
    if(header.qr != 1) {
        printf("Result: Reply not marked as reply\n");
        exit(11);
        }

    /* If the response code was not 0, show them the error */
    if(header.rcode != 0) {
        switch(header.rcode) {
            case 1:
                printf("Result: Format error\n");
                exit(1);
            case 2:
                printf("Result: Server failure\n");
                exit(2);
            case 3:
                printf("Result: NXDOMAIN\n");
                exit(0);
            case 4:
                printf("Result: Not implemented\n");
                exit(4);
            case 5:
                printf("Result: Query refused\n");
                exit(5);
            default:
                printf("Result: Unknown rcode %d\n",header.rcode);
                exit(6);
            }
        }

    /* Return error if no reply from server */
    if(header.ancount == 0 && header.nscount == 0 && header.arcount == 0) {
        printf("Result: We have no answers!\n");
        exit(8);
        }

    if(header.qdcount > 1) {
        printf("Result: qdcount is greater than one");
        exit(3);
        }

    /* Make sure that, if we have a question section in the reply,
       the question is the same as what we sent to the server */

    /* Get all of the questions in the reply */
    place = 12;
    for(counter = 0;counter < header.qdcount;counter++) {
        count = read_question(uindata,&question,place);
        if(count < 0) /* Error handling */
            harderror(L_QERROR); /* Error reading question */
        place += count;
        /* Check to make sure the question name is the same */
        if(js_issame(question.qname,qstring) != 1) {
            printf("The question they sent us is not the one we sent them\n");
            exit(12);
            }
        if(question.qtype != qtype) {
            printf("The question type they sent has been changed\n");
            exit(13);
            }
        if(question.qclass != 1) /* Internet class */ {
            printf("The question class they sent has been changed\n");
            exit(14);
            }
        }

    /* Get all of the answers in the reply */
    /* Get all of the an replies */
    for(counter = 0; counter < header.ancount; counter++) {
        if(out_answer(uindata,&place) < 0) {
            printf("Problem reading answer\n");
            exit(15);
            }
        }

    /* Get all of the ns replies */
    for(counter = 0; counter < header.nscount; counter++) {
        rtype = out_answer(uindata,&place);
        if(rtype < 0) {
            printf("Problem reading authority record\n");
            exit(16);
            }
        if(rtype == RR_SOA) {
            soa_ns = 1;
            }
        }

    /* Get all of the ar replies */
    for(counter = 0; counter < header.arcount; counter++) {
        if(out_answer(uindata,&place) < 0) {
            printf("Problem reading additional record\n");
            exit(17);
            }
        }

    if(header.ancount > 0)
        printf("Result: Answer from server\n");
    else {
        if(soa_ns == 0) {
            printf("Result: Referral from server\n");
            }
        else {
            printf("Result: No such host form server\n");
            }
        }
    exit(0);

    }

/* Parse the answer part of a DNS query.
   input: pointer to js_string with uncompressed UDP data
          pointer to where we are in that string
   output: negative number on error, type of record on success
*/

int out_answer(js_string *uindata,int *place) {

    q_rr rr_hdr;
    rr_soa soa;
    rr_mx mx;
    int count;

    /* Create the needed strings */
    if((rr_hdr.name = js_create(512,1)) == 0)
       harderror(L_HNAME_OA); /* js_create with hname in oa */
    if((soa.mname = js_create(512,1)) == 0)
       harderror(L_C_MNAME); /* js_create with soa.mname in oa */
    if((soa.rname = js_create(512,1)) == 0)
       harderror(L_C_RNAME); /* js_create with soa.rname in oa */
    if((mx.exchange = js_create(512,1)) == 0)
       harderror(L_C_MXEXC); /* js_create with mx.exchange in oa */

    /* Start printing out the data header */
    count = read_rr_h(uindata,&rr_hdr,*place);
    if(count < 0)
        return -2; /* Error reading rr in AN section */
    *place += count;
    if(rr_hdr.type == RR_SOA) {
        if(read_soa(uindata,&soa,*place) == JS_ERROR)
            return -3; /* Problem reading the SOA */
        }
    else if(rr_hdr.type == RR_MX) {
        if(uindata->unit_count < *place + 2)
            return -4; /* Problem reading MX */
        mx.preference = ((*(uindata->string + *place) & 0xff) << 8) |
                          (*(uindata->string + *place + 1) & 0xff);
        if(read_ns(uindata,mx.exchange,*place + 2) < 0)
            return -4; /* Problem reading MX */
        }
    else if(rr_hdr.type == RR_NS || rr_hdr.type == RR_CNAME ||
            rr_hdr.type == RR_PTR) {
        if(read_ns(uindata,mx.exchange,*place) < 0)
            return -6; /* Problem reading NS/CNAME/PTR */
        }
    else if(rr_hdr.type == RR_A) {
        if(uindata->unit_count < *place + 4)
            return -5; /* Problem reading A record */
        }
    else if(rr_hdr.type = RR_TXT) {
        printf("%s",L_TXT); /* Text String */
        if(read_txt(uindata,mx.exchange,*place) < 0)
            return -7; /* Problem reading TXT record */
        }

    *place += rr_hdr.rdlength; /* To do: read the RD data itself for
                                  all MaraDNS supported RRs */

    return rr_hdr.type;
    }