[svn-upgrade] Integrating new upstream version, iodine (0.4.0)
[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, 256, 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, 256, 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 rdata[4*1024];
105         HEADER *header;
106         short qdcount;
107         short ancount;
108         char name[255];
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                         warnx("no query or answer in answer");
141                         return -1;
142                 }
143
144                 if (q != NULL) 
145                         q->id = id;
146
147                 readname(packet, packetlen, &data, name, sizeof(name));
148                 readshort(packet, &data, &type);
149                 readshort(packet, &data, &class);
150                 
151                 readname(packet, packetlen, &data, name, sizeof(name));
152                 readshort(packet, &data, &type);
153                 readshort(packet, &data, &class);
154                 readlong(packet, &data, &ttl);
155                 readshort(packet, &data, &rlen);
156                 rv = MIN(rlen, sizeof(rdata));
157                 rv = readdata(packet, &data, rdata, rv);
158
159                 if(type == T_NULL && rv > 2) {
160                         rv = MIN(rv, buflen);
161                         memcpy(buf, rdata, rv);
162                 }
163                 break;
164         case QR_QUERY:
165                 if (qdcount != 1) {
166                         warnx("no query on query");
167                         return -1;
168                 }
169
170                 readname(packet, packetlen, &data, name, sizeof(name) -1);
171                 name[256] = 0;
172                 readshort(packet, &data, &type);
173                 readshort(packet, &data, &class);
174
175                 if(type != T_NULL) {
176                         rv = 0;
177                         break;
178                 }
179
180                 strncpy(q->name, name, 257);
181                 q->type = type;
182                 q->id = id;
183
184                 rv = strlen(q->name);
185                 break;
186         }
187
188         return rv;
189 }
190
191 int
192 dns_build_hostname(char *buf, size_t buflen, 
193                                    const char *data, const size_t datalen, 
194                                    const char *topdomain)
195 {
196         int consumed;
197         int avail;
198         char *b;
199
200         avail = MIN(0xFF, buflen) - strlen(topdomain) - 2;
201         memset(buf, 0, buflen);
202         b = buf;
203         
204         consumed = encode_data(data, datalen, avail, b);
205
206         b += strlen(buf);
207         if (*b != '.') 
208                 *b++ = '.';
209
210         strncpy(b, topdomain, strlen(topdomain)+1);
211         
212         return consumed;
213 }
214