Contiki-NG
ip64-dns64.c
1/*
2 * Copyright (c) 2014, Thingsquare, http://www.thingsquare.com/.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 */
31
32#include "ip64/ip64.h"
33#include "ipv6/ip64-addr.h"
34#include "ip64/ip64-dns64.h"
35
36#include <stdio.h>
37
38#define DEBUG 0
39
40#if DEBUG
41#undef PRINTF
42#define PRINTF(...) printf(__VA_ARGS__)
43#else /* DEBUG */
44#define PRINTF(...)
45#endif /* DEBUG */
46
47struct dns_hdr {
48 uint8_t id[2];
49 uint8_t flags1, flags2;
50#define DNS_FLAG1_RESPONSE 0x80
51#define DNS_FLAG1_OPCODE_STATUS 0x10
52#define DNS_FLAG1_OPCODE_INVERSE 0x08
53#define DNS_FLAG1_OPCODE_STANDARD 0x00
54#define DNS_FLAG1_AUTHORATIVE 0x04
55#define DNS_FLAG1_TRUNC 0x02
56#define DNS_FLAG1_RD 0x01
57#define DNS_FLAG2_RA 0x80
58#define DNS_FLAG2_ERR_MASK 0x0f
59#define DNS_FLAG2_ERR_NONE 0x00
60#define DNS_FLAG2_ERR_NAME 0x03
61 uint8_t numquestions[2];
62 uint8_t numanswers[2];
63 uint8_t numauthrr[2];
64 uint8_t numextrarr[2];
65};
66
67#define DNS_QUESTION_TYPE0 0
68#define DNS_QUESTION_TYPE1 1
69#define DNS_QUESTION_CLASS0 2
70#define DNS_QUESTION_CLASS1 3
71#define DNS_QUESTION_SIZE 4
72
73struct dns_answer {
74 /* DNS answer record starts with either a domain name or a pointer
75 * to a name already present somewhere in the packet. */
76 uint8_t type[2];
77 uint8_t class[2];
78 uint8_t ttl[4];
79 uint8_t len[2];
80 union {
81 uint8_t ip6[16];
82 uint8_t ip4[4];
83 } addr;
84};
85
86#define DNS_TYPE_A 1
87#define DNS_TYPE_AAAA 28
88
89#define DNS_CLASS_IN 1
90#define DNS_CLASS_ANY 255
91
92/*---------------------------------------------------------------------------*/
93void
94ip64_dns64_6to4(const uint8_t *ipv6data, int ipv6datalen,
95 uint8_t *ipv4data, int ipv4datalen)
96{
97 int i, j;
98 int qlen;
99 uint8_t *qdata;
100 uint8_t *q;
101 struct dns_hdr *hdr;
102
103 hdr = (struct dns_hdr *)ipv4data;
104 PRINTF("ip64_dns64_6to4 id: %02x%02x\n", hdr->id[0], hdr->id[1]);
105 PRINTF("ip64_dns64_6to4 flags1: 0x%02x\n", hdr->flags1);
106 PRINTF("ip64_dns64_6to4 flags2: 0x%02x\n", hdr->flags2);
107 PRINTF("ip64_dns64_6to4 numquestions: 0x%02x\n", ((hdr->numquestions[0] << 8) + hdr->numquestions[1]));
108 PRINTF("ip64_dns64_6to4 numanswers: 0x%02x\n", ((hdr->numanswers[0] << 8) + hdr->numanswers[1]));
109 PRINTF("ip64_dns64_6to4 numauthrr: 0x%02x\n", ((hdr->numauthrr[0] << 8) + hdr->numauthrr[1]));
110 PRINTF("ip64_dns64_6to4 numextrarr: 0x%02x\n", ((hdr->numextrarr[0] << 8) + hdr->numextrarr[1]));
111
112 /* Find the DNS question header by scanning through the question
113 labels. */
114 qdata = ipv4data + sizeof(struct dns_hdr);
115 for(i = 0; i < ((hdr->numquestions[0] << 8) + hdr->numquestions[1]); i++) {
116 do {
117 qlen = *qdata;
118 qdata++;
119 for(j = 0; j < qlen; j++) {
120 qdata++;
121 if(qdata > ipv4data + ipv4datalen) {
122 PRINTF("ip64_dns64_6to4: packet ended while parsing\n");
123 return;
124 }
125 }
126 } while(qlen != 0);
127 q = qdata;
128 if(q[DNS_QUESTION_CLASS0] == 0 && q[DNS_QUESTION_CLASS1] == DNS_CLASS_IN &&
129 q[DNS_QUESTION_TYPE0] == 0 && q[DNS_QUESTION_TYPE1] == DNS_TYPE_AAAA) {
130 q[DNS_QUESTION_TYPE1] = DNS_TYPE_A;
131 }
132
133 qdata += DNS_QUESTION_SIZE;
134 }
135}
136/*---------------------------------------------------------------------------*/
137int
138ip64_dns64_4to6(const uint8_t *ipv4data, int ipv4datalen,
139 uint8_t *ipv6data, int ipv6datalen)
140{
141 uint8_t n;
142 int i, j;
143 int qlen, len;
144 const uint8_t *qdata, *adata;
145 uint8_t *qcopy, *acopy, *lenptr;
146 uint8_t *q;
147 struct dns_hdr *hdr;
148
149 hdr = (struct dns_hdr *)ipv4data;
150 PRINTF("ip64_dns64_4to6 id: %02x%02x\n", hdr->id[0], hdr->id[1]);
151 PRINTF("ip64_dns64_4to6 flags1: 0x%02x\n", hdr->flags1);
152 PRINTF("ip64_dns64_4to6 flags2: 0x%02x\n", hdr->flags2);
153 PRINTF("ip64_dns64_4to6 numquestions: 0x%02x\n", ((hdr->numquestions[0] << 8) + hdr->numquestions[1]));
154 PRINTF("ip64_dns64_4to6 numanswers: 0x%02x\n", ((hdr->numanswers[0] << 8) + hdr->numanswers[1]));
155 PRINTF("ip64_dns64_4to6 numauthrr: 0x%02x\n", ((hdr->numauthrr[0] << 8) + hdr->numauthrr[1]));
156 PRINTF("ip64_dns64_4to6 numextrarr: 0x%02x\n", ((hdr->numextrarr[0] << 8) + hdr->numextrarr[1]));
157
158 /* Find the DNS answer header by scanning through the question
159 labels. */
160 qdata = ipv4data + sizeof(struct dns_hdr);
161 qcopy = ipv6data + sizeof(struct dns_hdr);
162 for(i = 0; i < ((hdr->numquestions[0] << 8) + hdr->numquestions[1]); i++) {
163 do {
164 qlen = *qdata;
165 qdata++;
166 qcopy++;
167 for(j = 0; j < qlen; j++) {
168 qdata++;
169 qcopy++;
170 if(qdata > ipv4data + ipv4datalen) {
171 PRINTF("ip64_dns64_4to6: packet ended while parsing\n");
172 return ipv6datalen;
173 }
174 }
175 } while(qlen != 0);
176 q = qcopy;
177 if(q[DNS_QUESTION_CLASS0] == 0 && q[DNS_QUESTION_CLASS1] == DNS_CLASS_IN &&
178 q[DNS_QUESTION_TYPE0] == 0 && q[DNS_QUESTION_TYPE1] == DNS_TYPE_AAAA) {
179 q[DNS_QUESTION_TYPE1] = DNS_TYPE_AAAA;
180 }
181
182 qdata += DNS_QUESTION_SIZE;
183 qcopy += DNS_QUESTION_SIZE;
184 }
185
186 adata = qdata;
187 acopy = qcopy;
188
189 /* Go through the answers section and update the answers. */
190 for(i = 0; i < ((hdr->numanswers[0] << 8) + hdr->numanswers[1]); i++) {
191
192 n = *adata;
193 if(n & 0xc0) {
194 /* Short-hand name format: 2 bytes */
195 *acopy++ = *adata++;
196 *acopy++ = *adata++;
197 } else {
198 /* Name spelled out */
199 do {
200 n = *adata;
201 adata++;
202 acopy++;
203 for(j = 0; j < n; j++) {
204 *acopy++ = *adata++;
205 }
206 } while(n != 0);
207 }
208
209 if(adata[0] == 0 && adata[1] == DNS_TYPE_A) {
210 /* Update the type field from A to AAAA */
211 *acopy = *adata;
212 acopy++;
213 adata++;
214 *acopy = DNS_TYPE_AAAA;
215 acopy++;
216 adata++;
217
218 /* Get the length of the address record. Should be 4. */
219 lenptr = &acopy[6];
220 len = (adata[6] << 8) + adata[7];
221
222 /* Copy the class, the TTL, and the data length */
223 memcpy(acopy, adata, 2 + 4 + 2);
224 acopy += 8;
225 adata += 8;
226
227 if(len == 4) {
229 uip_ipaddr(&addr, adata[0], adata[1], adata[2], adata[3]);
230 ip64_addr_4to6(&addr, (uip_ip6addr_t *)acopy);
231
232 adata += len;
233 acopy += 16;
234 lenptr[0] = 0;
235 lenptr[1] = 16;
236 ipv6datalen += 12;
237
238 } else {
239 memcpy(acopy, adata, len);
240 acopy += len;
241 adata += len;
242 }
243 } else {
244 len = (adata[8] << 8) + adata[9];
245
246 /* Copy the type, class, the TTL, and the data length */
247 memcpy(acopy, adata, 2 + 2 + 4 + 2);
248 acopy += 10;
249 adata += 10;
250
251 /* Copy the data */
252 memcpy(acopy, adata, len);
253 acopy += len;
254 adata += len;
255 }
256 }
257 return ipv6datalen;
258}
259/*---------------------------------------------------------------------------*/
#define uip_ipaddr(addr, addr0, addr1, addr2, addr3)
Construct an IP address from four bytes.
Definition: uip.h:898
static uip_ds6_addr_t * addr
Pointer to a nbr cache entry.
Definition: uip-nd6.c:107
Representation of an IP address.
Definition: uip.h:95