/* * Copyright (c) 2006 Bjorn Andersson , Erik Ekman * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #ifdef DARWIN #include #endif #include #include #include #include #include #include #include #include #include "dns.h" #include "encoding.h" #include "read.h" int dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen) { HEADER *header; short name; char *p; int len; memset(buf, 0, buflen); header = (HEADER*)buf; header->id = htons(q->id); header->qr = (qr == QR_ANSWER); header->opcode = 0; header->aa = (qr == QR_ANSWER); header->tc = 0; header->rd = (qr == QR_QUERY); header->ra = 0; p = buf + sizeof(HEADER); switch (qr) { case QR_ANSWER: header->ancount = htons(1); header->qdcount = htons(1); name = 0xc000 | ((p - buf) & 0x3fff); putname(&p, 256, q->name); putshort(&p, q->type); putshort(&p, C_IN); putshort(&p, name); putshort(&p, q->type); putshort(&p, C_IN); putlong(&p, 0); putshort(&p, datalen); putdata(&p, data, datalen); break; case QR_QUERY: header->qdcount = htons(1); header->arcount = htons(1); putname(&p, 256, data); putshort(&p, q->type); putshort(&p, C_IN); // EDNS0 putbyte(&p, 0x00); //Root putshort(&p, 0x0029); // OPT putshort(&p, 0x1000); // Payload size: 4096 putshort(&p, 0x0000); // Higher bits/edns version putshort(&p, 0x8000); // Z putshort(&p, 0x0000); // Data length break; } len = p - buf; return len; } int dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen) { char rdata[4*1024]; HEADER *header; short qdcount; short ancount; char name[255]; uint32_t ttl; short class; short type; char *data; short rlen; int id; int rv; rv = 0; header = (HEADER*)packet; // Reject short packets if (packetlen < sizeof(HEADER)) return 0; if (header->qr != qr) { warnx("header->qr does not match the requested qr"); return -1; } data = packet + sizeof(HEADER); qdcount = ntohs(header->qdcount); ancount = ntohs(header->ancount); id = ntohs(header->id); rlen = 0; switch (qr) { case QR_ANSWER: if(qdcount != 1 || ancount != 1) { warnx("no query or answer in answer"); return -1; } if (q != NULL) q->id = id; readname(packet, packetlen, &data, name, sizeof(name)); readshort(packet, &data, &type); readshort(packet, &data, &class); readname(packet, packetlen, &data, name, sizeof(name)); readshort(packet, &data, &type); readshort(packet, &data, &class); readlong(packet, &data, &ttl); readshort(packet, &data, &rlen); rv = MIN(rlen, sizeof(rdata)); rv = readdata(packet, &data, rdata, rv); if(type == T_NULL && rv > 2) { rv = MIN(rv, buflen); memcpy(buf, rdata, rv); } break; case QR_QUERY: if (qdcount != 1) { warnx("no query on query"); return -1; } readname(packet, packetlen, &data, name, sizeof(name) -1); name[256] = 0; readshort(packet, &data, &type); readshort(packet, &data, &class); if(type != T_NULL) { rv = 0; break; } strncpy(q->name, name, 257); q->type = type; q->id = id; rv = strlen(q->name); break; } return rv; } int dns_build_hostname(char *buf, size_t buflen, const char *data, const size_t datalen, const char *topdomain) { int consumed; int avail; char *b; avail = MIN(0xFF, buflen) - strlen(topdomain) - 2; memset(buf, 0, buflen); b = buf; consumed = encode_data(data, datalen, avail, b); b += strlen(buf); if (*b != '.') *b++ = '.'; strncpy(b, topdomain, strlen(topdomain)+1); return consumed; }