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
udp/dns/dnshdr.c
- Committer:
- andrewboyson
- Date:
- 2019-03-11
- Revision:
- 128:79052cb4a41c
- Parent:
- 121:bc048b65a630
- Child:
- 136:8a65abb0dc63
File content as of revision 128:79052cb4a41c:
#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" #include "dnslabel.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++) LogChar(*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(); }