115 if(len < DNS_HDR_SIZE) {
119 qdcount = RD16(&data[DNS_HDR_QDCOUNT]);
120 p = data + DNS_HDR_SIZE;
123 LOG_DBG(
"DNS64 6to4: id=0x%04x, %u questions\n",
124 RD16(&data[DNS_HDR_ID]), qdcount);
128 for(uint16_t i = 0; i < qdcount; i++) {
129 const uint8_t *after_name = skip_dns_name(p, end);
130 if(after_name == NULL || after_name + DNS_QTAIL_SIZE > end) {
131 LOG_WARN(
"DNS64 6to4: malformed question section\n");
135 uint8_t *qtail = (uint8_t *)after_name;
136 if(RD16(&qtail[DNS_QTAIL_QTYPE]) == DNS_TYPE_AAAA &&
137 RD16(&qtail[DNS_QTAIL_QCLASS]) == DNS_CLASS_IN) {
138 WR16(&qtail[DNS_QTAIL_QTYPE], DNS_TYPE_A);
140 p = qtail + DNS_QTAIL_SIZE;
146 uint8_t *ipv6data, uint16_t ipv6len,
149 uint16_t qdcount, ancount;
152 const uint8_t *src_end;
153 const uint8_t *dst_end = ipv6data + ipv6bufsiz;
155 if(ipv4len < DNS_HDR_SIZE) {
159 qdcount = RD16(&ipv4data[DNS_HDR_QDCOUNT]);
160 ancount = RD16(&ipv4data[DNS_HDR_ANCOUNT]);
161 src = ipv4data + DNS_HDR_SIZE;
162 dst = ipv6data + DNS_HDR_SIZE;
163 src_end = ipv4data + ipv4len;
165 LOG_DBG(
"DNS64 4to6: id=0x%04x, %u answers\n",
166 RD16(&ipv4data[DNS_HDR_ID]), ancount);
170 for(uint16_t i = 0; i < qdcount; i++) {
171 const uint8_t *after_name = skip_dns_name(src, src_end);
172 if(after_name == NULL || after_name + DNS_QTAIL_SIZE > src_end) {
176 dst = ipv6data + (after_name - ipv4data);
177 if(RD16(&dst[DNS_QTAIL_QTYPE]) == DNS_TYPE_A &&
178 RD16(&dst[DNS_QTAIL_QCLASS]) == DNS_CLASS_IN) {
179 WR16(&dst[DNS_QTAIL_QTYPE], DNS_TYPE_AAAA);
181 src = after_name + DNS_QTAIL_SIZE;
182 dst = ipv6data + (src - ipv4data);
188 uint16_t emitted_ancount = 0;
192 uint8_t *rr_start = dst;
193 for(uint16_t i = 0; i < ancount; i++) {
196 const uint8_t *name_end = skip_dns_name(src, src_end);
197 if(name_end == NULL) {
200 size_t name_len = name_end - src;
201 if(dst + name_len > dst_end) {
202 LOG_WARN(
"DNS64 4to6: output buffer full at name copy\n");
205 memcpy(dst, src, name_len);
209 if(src + 10 > src_end) {
213 uint16_t rr_type = RD16(&src[0]);
214 uint16_t rdlength = RD16(&src[8]);
216 if(rr_type == DNS_TYPE_A && rdlength == 4 && src + 10 + 4 <= src_end) {
219 if(dst + 10 + 16 > dst_end) {
220 LOG_WARN(
"DNS64 4to6: output buffer full\n");
223 WR16(&dst[0], DNS_TYPE_AAAA);
224 memcpy(&dst[2], &src[2], 2 + 4);
232 ip64_addr_4to6(&a4, (uip_ip6addr_t *)dst);
238 size_t rr_total = 10 + rdlength;
239 if(src + rr_total > src_end) {
242 if(dst + rr_total > dst_end) {
243 LOG_WARN(
"DNS64 4to6: output buffer full\n");
246 memcpy(dst, src, rr_total);
259 WR16(&ipv6data[DNS_HDR_ANCOUNT], emitted_ancount);
262 WR16(&ipv6data[DNS_HDR_NSCOUNT], 0);
263 WR16(&ipv6data[DNS_HDR_ARCOUNT], 0);
264 return (uint16_t)(dst - ipv6data);