A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.
Dependents: oldheating gps motorhome heating
Diff: udp/dns/dnshdr.c
- Revision:
- 61:aad055f1b0d1
- Parent:
- 59:e0e556c8bd46
- Child:
- 121:bc048b65a630
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/udp/dns/dnshdr.c Thu Jan 11 17:38:21 2018 +0000 @@ -0,0 +1,225 @@ +#include <stdint.h> +#include <stdbool.h> + +#include "dns.h" +#include "net.h" +#include "log.h" +#include "net.h" +#include "eth.h" +#include "ip4addr.h" +#include "ip6addr.h" +#include "udp.h" +#include "dnsname.h" + +#define HEADER_LENGTH 12 + +__packed struct header +{ + uint16_t id; + uint8_t uflags; + uint8_t lflags; + + uint16_t qdcount; + uint16_t ancount; + uint16_t nscount; + uint16_t arcount; +}; + +uint16_t DnsHdrId; + +bool DnsHdrIsReply; +bool DnsHdrIsAuthoritative; +bool DnsHdrIsRecursiveQuery; + +uint16_t DnsHdrQdcount; +uint16_t DnsHdrAncount; +uint16_t DnsHdrNscount; +uint16_t DnsHdrArcount; + +char* DnsHdrPacket; +char* DnsHdrData; +int DnsHdrDataLength; + +void DnsHdrSetup(void* pPacket, int lenPacket) +{ + DnsHdrPacket = (char*)pPacket; + DnsHdrData = DnsHdrPacket + sizeof(struct header); + DnsHdrDataLength = lenPacket - sizeof(struct header); +} + +void DnsHdrRead() +{ + struct header* pHeader = (struct header*)DnsHdrPacket; + + DnsHdrId = NetToHost16(pHeader->id); + + uint8_t uflags = pHeader->uflags; + DnsHdrIsReply = uflags & 0x80; + DnsHdrIsAuthoritative = uflags & 0x04; + DnsHdrIsRecursiveQuery = uflags & 0x01; + + DnsHdrQdcount = NetToHost16(pHeader->qdcount); + DnsHdrAncount = NetToHost16(pHeader->ancount); + DnsHdrNscount = NetToHost16(pHeader->nscount); + DnsHdrArcount = NetToHost16(pHeader->arcount); + +} +void DnsHdrWrite() +{ + struct header* pHeader = (struct header*)DnsHdrPacket; + + pHeader->id = NetToHost16(DnsHdrId); + + uint8_t uflags = 0; + uint8_t lflags = 0; + if (DnsHdrIsReply) uflags |= 0x80; + if (DnsHdrIsAuthoritative) uflags |= 0x04; + if (DnsHdrIsRecursiveQuery) uflags |= 0x01; + pHeader->uflags = uflags; + pHeader->lflags = lflags; + + pHeader->qdcount = NetToHost16(DnsHdrQdcount); + pHeader->ancount = NetToHost16(DnsHdrAncount); + pHeader->nscount = NetToHost16(DnsHdrNscount); + pHeader->arcount = NetToHost16(DnsHdrArcount); +} +static uint16_t decodeUint16(char* p) +{ + uint16_t value = *p++; + value <<= 8; value += *p++; + return value; +} +static uint32_t decodeUint32(char* p) +{ + uint32_t value = *p++; + value <<= 8; value += *p++; + value <<= 8; value += *p++; + value <<= 8; value += *p++; + return value; +} +static void logRecordA(int len, char* p) +{ + if (len == 4) Ip4AddressLog(*(uint32_t*)p); + else LogF("expected 4 bytes but had %d", len); +} +static void logRecordAAAA(int len, char* p) +{ + if (len == 16) Ip6AddressLog(p); + else LogF("expected 16 bytes but had %d", len); +} +static void logRecordPTR(int len, char* p) +{ + if (len <= DNS_MAX_LABEL_LENGTH) DnsNameLogPtr(p); + else LogF("length %d is greater than max DNS label length of %d\r\n", len, DNS_MAX_LABEL_LENGTH); +} +static void logRecordSRV(int len, char* p) +{ + LogF("pri=%d " , decodeUint16(p)); p += 2; + LogF("wei=%d " , decodeUint16(p)); p += 2; + LogF("port=%d ", decodeUint16(p)); p += 2; + DnsNameLogPtr(p); +} +static void logRecordTXT(int len, char* p) +{ + char* pEnd = p + len; + while (p < pEnd) + { + Log("\r\n "); + int fieldLen = *p++; + for (int i = 0; i < fieldLen; i++) LogPush(*p++); + } +} +static void logContent() +{ + char* p = DnsHdrData; + + //Get the questions + for (int q = 0; q < DnsHdrQdcount; q++) + { + if (p >= DnsHdrData + DnsHdrDataLength) + { + Log(" Questions have overrun the buffer\r\n"); + return; + } + char* pEncodedName = p; + int nameLength = DnsNameLength(p); + if (!nameLength) { LogTimeF(" Questions namelength is zero\r\n"); return; } + p += nameLength; //Skip past the name + p++ ; //skip the first byte of the type + char recordType = *p++; //read the record type + p += 2; //skip the class + + LogF(" Query "); + DnsRecordTypeLog(recordType); + Log(" type record of "); + DnsNameLogPtr(pEncodedName); + Log("\r\n"); + } + + //Get the answers + for (int a = 0; a < DnsHdrAncount; a++) + { + if (p >= DnsHdrData + DnsHdrDataLength) { Log(" Answers have overrun the buffer\r\n"); return; } + + char* pEncodedName = p; + int nameLength = DnsNameLength(p); + if (!nameLength) { Log(" Answer name length is zero\r\n"); return; } + p += nameLength; //Skip past the name + + p++; //Skip the high byte of the record type + int recordType = *p++; //Record type + + p++; //Skip the high byte of the class type + int classType = *p++; //Class type + + int ttl = decodeUint32(p); p += 4; //32bit TTL + + int len = decodeUint16(p); p += 2; //16bit length + + Log(" Answer "); + DnsRecordTypeLog(recordType); + Log(" type record of "); + DnsNameLogPtr(pEncodedName); + Log(" ==> "); + + switch (recordType) //Log the payload if its type is known + { + case DNS_RECORD_A: logRecordA (len, p); break; + case DNS_RECORD_AAAA: logRecordAAAA(len, p); break; + case DNS_RECORD_PTR: logRecordPTR (len, p); break; + case DNS_RECORD_SRV: logRecordSRV (len, p); break; + case DNS_RECORD_TXT: logRecordTXT (len, p); break; + default: LogF("%d characters", len); break; + } + Log("\r\n"); + p += len; //Adjust the pointer to the next character after the payload + } +} + +void DnsHdrLog(int protocol) +{ + if (NetTraceVerbose) + { + DnsProtocolLog(protocol); + Log(" header\r\n"); + LogF(" Ident %hd\r\n", DnsHdrId); + if (DnsHdrIsReply) + { + if (DnsHdrIsAuthoritative) LogF(" Authoritative reply\r\n"); + else LogF(" Non authoritative reply\r\n"); + } + else + { + if (DnsHdrIsRecursiveQuery) LogF(" Recursive query\r\n"); + else LogF(" Non recursive query\r\n"); + } + LogF(" qd, an, ns, ar %hu, %hu, %hu, %hu\r\n", DnsHdrQdcount, DnsHdrAncount, DnsHdrNscount, DnsHdrArcount); + } + else + { + DnsProtocolLog(protocol); + LogF(" header qd, an, ns, ar %hu, %hu, %hu, %hu\r\n", DnsHdrQdcount, DnsHdrAncount, DnsHdrNscount, DnsHdrArcount); + } + logContent(); +} +