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
resolve/nr4.c
- Committer:
- andrewboyson
- Date:
- 2020-04-02
- Revision:
- 167:3ba4e3c49631
- Parent:
- 159:3ebef2d02f7f
- Child:
- 170:96c637dc3f52
File content as of revision 167:3ba4e3c49631:
#include <stdint.h> #include <stdbool.h> #include <string.h> #include "log.h" #include "mstimer.h" #include "net.h" #include "mac.h" #include "ip4addr.h" #include "dhcp.h" #include "dns.h" #include "dnsquery.h" #include "dnslabel.h" #include "http.h" bool Nr4Trace = false; #define NAME_MAX_LENGTH 20 #define CACHE_TIMEOUT_MS 3600 * 1000 #define FREEZE_TIMEOUT_MS 1800 * 1000 #define REPLY_TIMEOUT_MS 1 * 1000 #define RECORDS_COUNT 20 #define STATE_EMPTY 0 #define STATE_WANT 1 #define STATE_SENT 2 #define STATE_VALID 3 #define TODO_NONE 0 #define TODO_NAME_FROM_IP 1 #define TODO_IP_FROM_NAME 2 struct record { uint32_t elapsed; uint32_t ip; uint8_t todo; uint8_t state; uint8_t protocol; char name[NAME_MAX_LENGTH]; }; static struct record records[RECORDS_COUNT]; static int getExistingIp(uint32_t ip) { for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state == STATE_EMPTY) continue; if (records[i].ip == ip) return i; } return -1; } static int getExistingName(char* name) { for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state == STATE_EMPTY) continue; if (DnsLabelIsSame(records[i].name, name)) return i; } return -1; } static int getNameOnly(char* name) { for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state == STATE_EMPTY) continue; if (records[i].ip) continue; if (DnsLabelIsSame(records[i].name, name)) return i; } return -1; } static int getOldest() { int iOldest = 0; uint32_t ageOldest = 0; for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state == STATE_EMPTY) return i; //Found an empty slot so just return it uint32_t age = MsTimerCount - records[i].elapsed; if (age >= ageOldest) { ageOldest = age; iOldest = i; } } return iOldest; //Otherwise return the oldest } void Nr4MakeRequestForNameFromIp(uint32_t ip) { //Don't treat non ips if (!ip) return; int i; //If a record already exists then request an update i = getExistingIp(ip); if (i > -1) { if (!MsTimerRelative(records[i].elapsed, FREEZE_TIMEOUT_MS)) return; if (Nr4Trace) { LogTimeF("NR - renew name of "); Ip4AddressLog(ip); Log("\r\n"); } records[i].todo = TODO_NAME_FROM_IP; records[i].state = STATE_WANT; records[i].protocol = DnsGetNextProtocol4(DNS_PROTOCOL_NONE); records[i].elapsed = MsTimerCount; return; } //If a record does not exist then find the first empty slot and add the IP and date if (Nr4Trace) { LogTimeF("NR - request name of "); Ip4AddressLog(ip); Log("\r\n"); } i = getOldest(); records[i].ip = ip; records[i].todo = TODO_NAME_FROM_IP; records[i].state = STATE_WANT; records[i].protocol = DnsGetNextProtocol4(DNS_PROTOCOL_NONE); records[i].elapsed = MsTimerCount; records[i].name[0] = 0; } void Nr4MakeRequestForIpFromName(char* name) { //Don't treat non names if (!name[0]) return; int i; //If a record already exists then request an update i = getExistingName(name); if (i > -1) { if (!MsTimerRelative(records[i].elapsed, FREEZE_TIMEOUT_MS)) return; if (Nr4Trace) { LogTimeF("NR - renew IPv4 of %s\r\n", name); } records[i].todo = TODO_IP_FROM_NAME; records[i].state = STATE_WANT; records[i].protocol = DnsGetNextProtocol4(DNS_PROTOCOL_NONE); records[i].elapsed = MsTimerCount; return; } //If a record does not exist then find the first empty slot and add the name and date if (Nr4Trace) { LogTimeF("NR - request IPv4 of %s\r\n", name); } i = getOldest(); records[i].ip = 0; records[i].todo = TODO_IP_FROM_NAME; records[i].state = STATE_WANT; records[i].protocol = DnsGetNextProtocol4(DNS_PROTOCOL_NONE); records[i].elapsed = MsTimerCount; strncpy(records[i].name, name, NAME_MAX_LENGTH); records[i].name[NAME_MAX_LENGTH - 1] = 0; } static void addIpRecord(int i, uint32_t ip, char* name, int protocol) { records[i].todo = TODO_NONE; records[i].elapsed = MsTimerCount; records[i].ip = ip; records[i].protocol = protocol; records[i].state = STATE_VALID; strncpy(records[i].name, name, NAME_MAX_LENGTH); records[i].name[NAME_MAX_LENGTH - 1] = 0; } void Nr4AddIpRecord(uint32_t ip, char* name, int protocol) { int i; //Get existing ip and, if found, add it then clear any name only entries i = getExistingIp(ip); if (i >= 0) { if (Nr4Trace) { if (DnsLabelIsSame(name, records[i].name)) LogTimeF("NR - confirm existing "); else LogTimeF("NR - replace name for existing ip "); Ip4AddressLog(ip); Log(" == '"); Log(name); Log("'\r\n"); } addIpRecord(i, ip, name, protocol); i = getNameOnly(name); if (i >= 0) { if (Nr4Trace) LogTimeF("NR - clear name '%s' with no ip\r\n", name); records[i].state = STATE_EMPTY; } return; } //Get name only entry and, if found, add it i = getNameOnly(name); if (i >= 0) { if (Nr4Trace) { LogTimeF("NR - add ip for name "); Ip4AddressLog(ip); Log(" == '"); Log(name); Log("'\r\n"); } addIpRecord(i, ip, name, protocol); return; } //No other entry exists so just add it to the next available space i = getOldest(); if (Nr4Trace) { LogTimeF("NR - add ip for name "); Ip4AddressLog(ip); Log(" == '"); Log(name); Log("'\r\n"); } addIpRecord(i, ip, name, protocol); } void Nr4IpToName(uint32_t ip, char* name) { for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state == STATE_EMPTY) continue; if (records[i].ip == ip) { strcpy(name, records[i].name); return; } } name[0] = 0; } void Nr4NameToIp(char* name, uint32_t* pIp) { uint32_t newest = 0xFFFFFFFF; *pIp = 0; for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state == STATE_EMPTY) continue; if (!records[i].ip) continue; if (!DnsLabelIsSame(records[i].name, name)) continue; uint32_t age = MsTimerCount - records[i].elapsed; if (age <= newest) { newest = age; *pIp = records[i].ip; } } } bool Nr4HaveIpForName(char* name) { for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state == STATE_EMPTY) continue; if (!records[i].ip) continue; if (!DnsLabelIsSame(records[i].name, name)) return true; } return false; } static char letterFromStateAndProtocol(uint8_t dnsState, uint8_t protocol) { switch (dnsState) { case STATE_SENT: case STATE_WANT: return '>'; case STATE_VALID: switch (protocol) { case DNS_PROTOCOL_UDNS: return 'd'; case DNS_PROTOCOL_MDNS: return 'm'; case DNS_PROTOCOL_LLMNR: return 'l'; case DNS_PROTOCOL_NONE: return '-'; default: return '?'; } default: return '~'; } } void Nr4SendHttp() { for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state == STATE_EMPTY) continue; if (records[i].ip || records[i].name[0]) { HttpAddF("%4u ", (MsTimerCount - records[i].elapsed) / 1000 / 60); int ipLen = Ip4AddressHttp(records[i].ip); HttpAddFillChar(' ', 40 - ipLen); HttpAddChar(letterFromStateAndProtocol(records[i].state, records[i].protocol)); HttpAddChar(' '); HttpAddText(records[i].name); HttpAddChar('\r'); HttpAddChar('\n'); } } } void Nr4SendAjax() { for (int i = 0; i < RECORDS_COUNT; i++) { if (records[i].state == STATE_EMPTY) continue; if (records[i].ip || records[i].name[0]) { HttpAddByteAsHex(i); HttpAddChar('\t'); HttpAddInt32AsHex(MsTimerCount - records[i].elapsed); HttpAddChar('\t'); HttpAddInt32AsHex(records[i].ip); HttpAddChar('\t'); HttpAddChar(letterFromStateAndProtocol(records[i].state, records[i].protocol)); HttpAddChar('\t'); HttpAddText(records[i].name); HttpAddChar('\n'); } } } static void clearCache(struct record* pr) { if (MsTimerRelative(pr->elapsed, CACHE_TIMEOUT_MS)) pr->state = STATE_EMPTY; } static void nextProtocol(struct record* pr) { if (pr->state == STATE_SENT && MsTimerRelative(pr->elapsed, REPLY_TIMEOUT_MS) && pr->protocol) { pr->protocol = DnsGetNextProtocol4(pr->protocol); if (pr->protocol) { pr->state = STATE_WANT; } else { if (pr->todo == TODO_NAME_FROM_IP) pr->name[0] = 0; if (pr->todo == TODO_IP_FROM_NAME) pr->ip = 0; pr->state = STATE_VALID; } pr->elapsed = MsTimerCount; } } static void queryNameFromIp(struct record* pr) { if (Nr4Trace) { LogTime("NR - send "); DnsProtocolLog(pr->protocol); Log(" request for name from IP4 "); Ip4AddressLog(pr->ip); Log("\r\n"); } DnsQueryNameFromIp4(pr->ip, pr->protocol); } static void queryIpFromName(struct record* pr) { if (Nr4Trace) { LogTime("NR - send "); DnsProtocolLog(pr->protocol); Log(" request for IP4 from name '"); Log(pr->name); Log("'\r\n"); } DnsQueryIp4FromName(pr->name, pr->protocol); } static void sendRequest(struct record* pr) { if ( DnsQueryIsBusy ) return; if ( pr->state != STATE_WANT) return; if (!pr->protocol ) return; if (pr->todo == TODO_NAME_FROM_IP) queryNameFromIp(pr); if (pr->todo == TODO_IP_FROM_NAME) queryIpFromName(pr); pr->state = STATE_SENT; pr->elapsed = MsTimerCount; } void Nr4Main() { static int i = -1; i++; if (i >= RECORDS_COUNT) i = 0; struct record* pr = &records[i]; clearCache (pr); nextProtocol(pr); sendRequest (pr); } void Nr4Init() { for (int i = 0; i < RECORDS_COUNT; i++) records[i].state = STATE_EMPTY; }