[svn-upgrade] Integrating new upstream version, iodine (0.4.1)
[debian/iodine.git] / src / dns.c
1 /*
2  * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <arpa/inet.h>
18 #include <arpa/nameser.h>
19 #ifdef DARWIN
20 #include <arpa/nameser8_compat.h>
21 #endif
22 #include <time.h>
23 #include <err.h>
24 #include <stdio.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <ctype.h>
30
31 #include "dns.h"
32 #include "encoding.h"
33 #include "read.h"
34
35 int
36 dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen)
37 {
38         HEADER *header;
39         short name;
40         char *p;
41         int len;
42
43         memset(buf, 0, buflen);
44         
45         header = (HEADER*)buf;
46         
47         header->id = htons(q->id);
48         header->qr = (qr == QR_ANSWER);
49         header->opcode = 0;
50         header->aa = (qr == QR_ANSWER);
51         header->tc = 0;
52         header->rd = (qr == QR_QUERY);
53         header->ra = 0;
54
55         p = buf + sizeof(HEADER);
56
57         switch (qr) {
58         case QR_ANSWER:
59                 header->ancount = htons(1);
60                 header->qdcount = htons(1);
61         
62                 name = 0xc000 | ((p - buf) & 0x3fff);
63
64                 putname(&p, sizeof(q->name), q->name);
65
66                 putshort(&p, q->type);
67                 putshort(&p, C_IN);
68
69                 putshort(&p, name);     
70                 putshort(&p, q->type);
71                 putshort(&p, C_IN);
72                 putlong(&p, 0);
73
74                 putshort(&p, datalen);
75                 putdata(&p, data, datalen);
76                 break;
77         case QR_QUERY:
78                 header->qdcount = htons(1);
79                 header->arcount = htons(1);
80         
81                 putname(&p, datalen, data);
82
83                 putshort(&p, q->type);
84                 putshort(&p, C_IN);
85
86                 /* EDNS0 */
87                 putbyte(&p, 0x00);    /* Root */
88                 putshort(&p, 0x0029); /* OPT */
89                 putshort(&p, 0x1000); /* Payload size: 4096 */
90                 putshort(&p, 0x0000); /* Higher bits/edns version */
91                 putshort(&p, 0x8000); /* Z */
92                 putshort(&p, 0x0000); /* Data length */
93                 break;
94         }
95         
96         len = p - buf;
97
98         return len;
99 }
100
101 int
102 dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
103 {
104         char name[QUERY_NAME_SIZE];
105         char rdata[4*1024];
106         HEADER *header;
107         short qdcount;
108         short ancount;
109         uint32_t ttl;
110         short class;
111         short type;
112         char *data;
113         short rlen;
114         int id; 
115         int rv;
116
117         rv = 0;
118         header = (HEADER*)packet;
119
120         /* Reject short packets */
121         if (packetlen < sizeof(HEADER)) 
122                 return 0;
123         
124         if (header->qr != qr) {
125                 warnx("header->qr does not match the requested qr");
126                 return -1;
127         }
128
129         data = packet + sizeof(HEADER);
130         qdcount = ntohs(header->qdcount);
131         ancount = ntohs(header->ancount);
132         
133         id = ntohs(header->id);
134                 
135         rlen = 0;
136
137         switch (qr) {
138         case QR_ANSWER:
139                 if(qdcount != 1 || ancount != 1) {
140                         switch (header->rcode) {
141                         case REFUSED:
142                                 warnx("Got REFUSED as reply");
143                                 break;
144
145                         case NOTIMP:
146                                 warnx("Got NOTIMP as reply");
147                                 break;
148
149                         case NXDOMAIN:
150                                 warnx("Got NXDOMAIN as reply");
151                                 break;
152
153
154                         case SERVFAIL:
155                                 warnx("Got SERVFAIL as reply");
156                                 break;
157
158                         case NOERROR:
159                         default:
160                                 warnx("no query or answer in answer");
161                                 break;
162                         }
163                         return -1;
164                 }
165
166                 if (q != NULL) 
167                         q->id = id;
168
169                 readname(packet, packetlen, &data, name, sizeof(name));
170                 readshort(packet, &data, &type);
171                 readshort(packet, &data, &class);
172                 
173                 readname(packet, packetlen, &data, name, sizeof(name));
174                 readshort(packet, &data, &type);
175                 readshort(packet, &data, &class);
176                 readlong(packet, &data, &ttl);
177                 readshort(packet, &data, &rlen);
178                 rv = MIN(rlen, sizeof(rdata));
179                 rv = readdata(packet, &data, rdata, rv);
180
181                 if(type == T_NULL && rv > 2) {
182                         rv = MIN(rv, buflen);
183                         memcpy(buf, rdata, rv);
184                 }
185                 break;
186         case QR_QUERY:
187                 if (qdcount != 1) {
188                         warnx("no query on query");
189                         return -1;
190                 }
191
192                 readname(packet, packetlen, &data, name, sizeof(name) - 1);
193                 name[sizeof(name)-1] = '\0';
194                 readshort(packet, &data, &type);
195                 readshort(packet, &data, &class);
196
197                 if(type != T_NULL) {
198                         rv = 0;
199                         break;
200                 }
201
202                 strncpy(q->name, name, sizeof(q->name));
203                 q->name[sizeof(q->name) - 1] = '\0';
204                 q->type = type;
205                 q->id = id;
206
207                 rv = strlen(q->name);
208                 break;
209         }
210
211         return rv;
212 }
213