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.cpp

Committer:
andrewboyson
Date:
2017-12-07
Revision:
58:d48c899e482f
Parent:
49:1a6336f2b3f9
Child:
59:e0e556c8bd46

File content as of revision 58:d48c899e482f:

#include    "mbed.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;

void DnsHdrSetup(void* pPacket)
{
    DnsHdrPacket = (char*)pPacket;
    DnsHdrData = DnsHdrPacket + HEADER_LENGTH;
}

void DnsHdrRead()
{
    struct header* pHeader = (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 = (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 + 500)
        {
            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 + 500) { 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();
}