kopia lustrzana https://github.com/martin-ger/esp_mqtt
added basic DNS support
rodzic
c71a6d1f07
commit
a07969e954
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
|
@ -1,2 +1,2 @@
|
|||
6d0d78a5dcacc730d09bdaec896fd17ff46c71a5 0x00000.bin
|
||||
22155ab48cdc32157e0750b275cc0ffaf8d54a81 0x10000.bin
|
||||
10e10e08f05ad126cf205ec87f50412f8642841f 0x00000.bin
|
||||
4831e82954d459e4efc2fd470c8e7cb4d28e528a 0x10000.bin
|
||||
|
|
|
@ -0,0 +1,807 @@
|
|||
#include "c_types.h"
|
||||
#include "mem.h"
|
||||
#include "ets_sys.h"
|
||||
#include "osapi.h"
|
||||
#include "gpio.h"
|
||||
#include "os_type.h"
|
||||
#include "lwip/def.h"
|
||||
|
||||
#include "user_interface.h"
|
||||
|
||||
#include "espconn.h"
|
||||
|
||||
#include "dns_responder.h"
|
||||
|
||||
//#define DNS_RESP_DEBUG 1
|
||||
|
||||
/*
|
||||
* This software is licensed under the CC0.
|
||||
*
|
||||
* This is a _basic_ DNS Server for educational use.
|
||||
* It does not prevent invalid packets from crashing
|
||||
* the server.
|
||||
*
|
||||
* Originating from:
|
||||
* https://github.com/mwarning/SimpleDNS
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
LOCAL struct espconn dns_espconn;
|
||||
struct Message msg;
|
||||
LOCAL uint8_t dns_mode;
|
||||
|
||||
/*
|
||||
* Masks and constants.
|
||||
*/
|
||||
|
||||
static const uint32_t QR_MASK = 0x8000;
|
||||
static const uint32_t OPCODE_MASK = 0x7800;
|
||||
static const uint32_t AA_MASK = 0x0400;
|
||||
static const uint32_t TC_MASK = 0x0200;
|
||||
static const uint32_t RD_MASK = 0x0100;
|
||||
static const uint32_t RA_MASK = 0x8000;
|
||||
static const uint32_t RCODE_MASK = 0x000F;
|
||||
|
||||
/* Response Type */
|
||||
enum {
|
||||
Ok_ResponseType = 0,
|
||||
FormatError_ResponseType = 1,
|
||||
ServerFailure_ResponseType = 2,
|
||||
NameError_ResponseType = 3,
|
||||
NotImplemented_ResponseType = 4,
|
||||
Refused_ResponseType = 5
|
||||
};
|
||||
|
||||
/* Resource Record Types */
|
||||
enum {
|
||||
A_Resource_RecordType = 1,
|
||||
NS_Resource_RecordType = 2,
|
||||
CNAME_Resource_RecordType = 5,
|
||||
SOA_Resource_RecordType = 6,
|
||||
PTR_Resource_RecordType = 12,
|
||||
MX_Resource_RecordType = 15,
|
||||
TXT_Resource_RecordType = 16,
|
||||
AAAA_Resource_RecordType = 28,
|
||||
SRV_Resource_RecordType = 33
|
||||
};
|
||||
|
||||
/* Operation Code */
|
||||
enum {
|
||||
QUERY_OperationCode = 0, /* standard query */
|
||||
IQUERY_OperationCode = 1, /* inverse query */
|
||||
STATUS_OperationCode = 2, /* server status request */
|
||||
NOTIFY_OperationCode = 4, /* request zone transfer */
|
||||
UPDATE_OperationCode = 5 /* change resource records */
|
||||
};
|
||||
|
||||
/* Response Code */
|
||||
enum {
|
||||
NoError_ResponseCode = 0,
|
||||
FormatError_ResponseCode = 1,
|
||||
ServerFailure_ResponseCode = 2,
|
||||
NameError_ResponseCode = 3
|
||||
};
|
||||
|
||||
/* Query Type */
|
||||
enum {
|
||||
IXFR_QueryType = 251,
|
||||
AXFR_QueryType = 252,
|
||||
MAILB_QueryType = 253,
|
||||
MAILA_QueryType = 254,
|
||||
STAR_QueryType = 255
|
||||
};
|
||||
|
||||
/*
|
||||
* Types.
|
||||
*/
|
||||
|
||||
/* Question Section */
|
||||
struct Question {
|
||||
char *qName;
|
||||
uint16_t qType;
|
||||
uint16_t qClass;
|
||||
struct Question* next; // for linked list
|
||||
};
|
||||
|
||||
/* Data part of a Resource Record */
|
||||
union ResourceData {
|
||||
struct {
|
||||
char *txt_data;
|
||||
} txt_record;
|
||||
struct {
|
||||
uint8_t addr[4];
|
||||
} a_record;
|
||||
struct {
|
||||
char* MName;
|
||||
char* RName;
|
||||
uint32_t serial;
|
||||
uint32_t refresh;
|
||||
uint32_t retry;
|
||||
uint32_t expire;
|
||||
uint32_t minimum;
|
||||
} soa_record;
|
||||
struct {
|
||||
char *name;
|
||||
} name_server_record;
|
||||
struct {
|
||||
char name;
|
||||
} cname_record;
|
||||
struct {
|
||||
char *name;
|
||||
} ptr_record;
|
||||
struct {
|
||||
uint16_t preference;
|
||||
char *exchange;
|
||||
} mx_record;
|
||||
struct {
|
||||
uint8_t addr[16];
|
||||
} aaaa_record;
|
||||
struct {
|
||||
uint16_t priority;
|
||||
uint16_t weight;
|
||||
uint16_t port;
|
||||
char *target;
|
||||
} srv_record;
|
||||
};
|
||||
|
||||
/* Resource Record Section */
|
||||
struct ResourceRecord {
|
||||
char *name;
|
||||
uint16_t type;
|
||||
uint16_t class;
|
||||
uint16_t ttl;
|
||||
uint16_t rd_length;
|
||||
union ResourceData rd_data;
|
||||
struct ResourceRecord* next; // for linked list
|
||||
};
|
||||
|
||||
struct Message {
|
||||
uint16_t id; /* Identifier */
|
||||
|
||||
/* Flags */
|
||||
uint16_t qr; /* Query/Response Flag */
|
||||
uint16_t opcode; /* Operation Code */
|
||||
uint16_t aa; /* Authoritative Answer Flag */
|
||||
uint16_t tc; /* Truncation Flag */
|
||||
uint16_t rd; /* Recursion Desired */
|
||||
uint16_t ra; /* Recursion Available */
|
||||
uint16_t rcode; /* Response Code */
|
||||
|
||||
uint16_t qdCount; /* Question Count */
|
||||
uint16_t anCount; /* Answer Record Count */
|
||||
uint16_t nsCount; /* Authority Record Count */
|
||||
uint16_t arCount; /* Additional Record Count */
|
||||
|
||||
/* At least one question; questions are copied to the response 1:1 */
|
||||
struct Question* questions;
|
||||
|
||||
/*
|
||||
* Resource records to be send back.
|
||||
* Every resource record can be in any of the following places.
|
||||
* But every place has a different semantic.
|
||||
*/
|
||||
struct ResourceRecord* answers;
|
||||
struct ResourceRecord* authorities;
|
||||
struct ResourceRecord* additionals;
|
||||
};
|
||||
|
||||
/*
|
||||
int ICACHE_FLASH_ATTR get_A_Record(uint8_t addr[4], const char domain_name[])
|
||||
{
|
||||
if (strcmp("foo.bar.com", domain_name) == 0)
|
||||
{
|
||||
addr[0] = 192;
|
||||
addr[1] = 168;
|
||||
addr[2] = 1;
|
||||
addr[3] = 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR get_AAAA_Record(uint8_t addr[16], const char domain_name[])
|
||||
{
|
||||
if (strcmp("foo.bar.com", domain_name) == 0)
|
||||
{
|
||||
addr[0] = 0xfe;
|
||||
addr[1] = 0x80;
|
||||
addr[2] = 0x00;
|
||||
addr[3] = 0x00;
|
||||
addr[4] = 0x00;
|
||||
addr[5] = 0x00;
|
||||
addr[6] = 0x00;
|
||||
addr[7] = 0x00;
|
||||
addr[8] = 0x00;
|
||||
addr[9] = 0x00;
|
||||
addr[10] = 0x00;
|
||||
addr[11] = 0x00;
|
||||
addr[12] = 0x00;
|
||||
addr[13] = 0x00;
|
||||
addr[14] = 0x00;
|
||||
addr[15] = 0x01;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Debugging functions.
|
||||
*/
|
||||
|
||||
#ifdef DNS_RESP_DEBUG
|
||||
void ICACHE_FLASH_ATTR print_hex(uint8_t* buf, size_t len)
|
||||
{
|
||||
int i;
|
||||
os_printf("%zu bytes:\n", len);
|
||||
for(i = 0; i < len; ++i)
|
||||
os_printf("%02x ", buf[i]);
|
||||
os_printf("\n");
|
||||
}
|
||||
|
||||
void print_resource_record(struct ResourceRecord* rr)
|
||||
{
|
||||
int i;
|
||||
while (rr)
|
||||
{
|
||||
os_printf(" ResourceRecord { name '%s', type %u, class %u, ttl %u, rd_length %u, ",
|
||||
rr->name,
|
||||
rr->type,
|
||||
rr->class,
|
||||
rr->ttl,
|
||||
rr->rd_length
|
||||
);
|
||||
|
||||
union ResourceData *rd = &rr->rd_data;
|
||||
switch (rr->type)
|
||||
{
|
||||
case A_Resource_RecordType:
|
||||
os_printf("Address Resource Record { address ");
|
||||
|
||||
for(i = 0; i < 4; ++i)
|
||||
os_printf("%s%u", (i ? "." : ""), rd->a_record.addr[i]);
|
||||
|
||||
os_printf(" }");
|
||||
break;
|
||||
case NS_Resource_RecordType:
|
||||
os_printf("Name Server Resource Record { name %s }",
|
||||
rd->name_server_record.name
|
||||
);
|
||||
break;
|
||||
case CNAME_Resource_RecordType:
|
||||
os_printf("Canonical Name Resource Record { name %u }",
|
||||
rd->cname_record.name
|
||||
);
|
||||
break;
|
||||
case SOA_Resource_RecordType:
|
||||
os_printf("SOA { MName '%s', RName '%s', serial %u, refresh %u, retry %u, expire %u, minimum %u }",
|
||||
rd->soa_record.MName,
|
||||
rd->soa_record.RName,
|
||||
rd->soa_record.serial,
|
||||
rd->soa_record.refresh,
|
||||
rd->soa_record.retry,
|
||||
rd->soa_record.expire,
|
||||
rd->soa_record.minimum
|
||||
);
|
||||
break;
|
||||
case PTR_Resource_RecordType:
|
||||
os_printf("Pointer Resource Record { name '%s' }",
|
||||
rd->ptr_record.name
|
||||
);
|
||||
break;
|
||||
case MX_Resource_RecordType:
|
||||
os_printf("Mail Exchange Record { preference %u, exchange '%s' }",
|
||||
rd->mx_record.preference,
|
||||
rd->mx_record.exchange
|
||||
);
|
||||
break;
|
||||
case TXT_Resource_RecordType:
|
||||
os_printf("Text Resource Record { txt_data '%s' }",
|
||||
rd->txt_record.txt_data
|
||||
);
|
||||
break;
|
||||
case AAAA_Resource_RecordType:
|
||||
os_printf("AAAA Resource Record { address ");
|
||||
|
||||
for(i = 0; i < 16; ++i)
|
||||
os_printf("%s%02x", (i ? ":" : ""), rd->aaaa_record.addr[i]);
|
||||
|
||||
os_printf(" }");
|
||||
break;
|
||||
default:
|
||||
os_printf("Unknown Resource Record { ??? }");
|
||||
}
|
||||
os_printf("}\n");
|
||||
rr = rr->next;
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR print_query(struct Message* msg)
|
||||
{
|
||||
os_printf("QUERY { ID: %02x", msg->id);
|
||||
os_printf(". FIELDS: [ QR: %u, OpCode: %u ]", msg->qr, msg->opcode);
|
||||
os_printf(", QDcount: %u", msg->qdCount);
|
||||
os_printf(", ANcount: %u", msg->anCount);
|
||||
os_printf(", NScount: %u", msg->nsCount);
|
||||
os_printf(", ARcount: %u,\n", msg->arCount);
|
||||
|
||||
struct Question* q = msg->questions;
|
||||
while (q)
|
||||
{
|
||||
os_printf(" Question { qName '%s', qType %u, qClass %u }\n",
|
||||
q->qName,
|
||||
q->qType,
|
||||
q->qClass
|
||||
);
|
||||
q = q->next;
|
||||
}
|
||||
|
||||
print_resource_record(msg->answers);
|
||||
print_resource_record(msg->authorities);
|
||||
print_resource_record(msg->additionals);
|
||||
|
||||
os_printf("}\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Basic memory operations.
|
||||
*/
|
||||
|
||||
size_t ICACHE_FLASH_ATTR get16bits(const uint8_t** buffer)
|
||||
{
|
||||
uint16_t value;
|
||||
|
||||
os_memcpy(&value, *buffer, 2);
|
||||
*buffer += 2;
|
||||
|
||||
return ntohs(value);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR put8bits(uint8_t** buffer, uint8_t value)
|
||||
{
|
||||
os_memcpy(*buffer, &value, 1);
|
||||
*buffer += 1;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR put16bits(uint8_t** buffer, uint16_t value)
|
||||
{
|
||||
value = htons(value);
|
||||
os_memcpy(*buffer, &value, 2);
|
||||
*buffer += 2;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR put32bits(uint8_t** buffer, uint32_t value)
|
||||
{
|
||||
value = htons(value);
|
||||
os_memcpy(*buffer, &value, 4);
|
||||
*buffer += 4;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Deconding/Encoding functions.
|
||||
*/
|
||||
|
||||
// 3foo3bar3com0 => foo.bar.com
|
||||
char* ICACHE_FLASH_ATTR decode_domain_name(const uint8_t** buffer)
|
||||
{
|
||||
char name[256];
|
||||
const uint8_t* buf = *buffer;
|
||||
int j = 0;
|
||||
int i = 0;
|
||||
|
||||
while (buf[i] != 0)
|
||||
{
|
||||
//if (i >= buflen || i > sizeof(name))
|
||||
// return NULL;
|
||||
|
||||
if (i != 0)
|
||||
{
|
||||
name[j] = '.';
|
||||
j += 1;
|
||||
}
|
||||
|
||||
int len = buf[i];
|
||||
i += 1;
|
||||
|
||||
os_memcpy(name+j, buf+i, len);
|
||||
i += len;
|
||||
j += len;
|
||||
}
|
||||
|
||||
name[j] = '\0';
|
||||
|
||||
*buffer += i + 1; //also jump over the last 0
|
||||
|
||||
//return strdup(name);
|
||||
uint8_t *ret = os_malloc(os_strlen(name)+1);
|
||||
os_strcpy(ret, name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char ICACHE_FLASH_ATTR *_strchr(const char *s, int c) {
|
||||
while (*s != (char)c)
|
||||
if (!*s++)
|
||||
return 0;
|
||||
return (char *)s;
|
||||
}
|
||||
|
||||
// foo.bar.com => 3foo3bar3com0
|
||||
void ICACHE_FLASH_ATTR encode_domain_name(uint8_t** buffer, const char* domain)
|
||||
{
|
||||
uint8_t* buf = *buffer;
|
||||
const char* beg = domain;
|
||||
const char* pos;
|
||||
int len = 0;
|
||||
int i = 0;
|
||||
|
||||
while ((pos = _strchr(beg, '.')))
|
||||
{
|
||||
len = pos - beg;
|
||||
buf[i] = len;
|
||||
i += 1;
|
||||
os_memcpy(buf+i, beg, len);
|
||||
i += len;
|
||||
|
||||
beg = pos + 1;
|
||||
}
|
||||
|
||||
len = os_strlen(domain) - (beg - domain);
|
||||
|
||||
buf[i] = len;
|
||||
i += 1;
|
||||
|
||||
os_memcpy(buf + i, beg, len);
|
||||
i += len;
|
||||
|
||||
buf[i] = 0;
|
||||
i += 1;
|
||||
|
||||
*buffer += i;
|
||||
}
|
||||
|
||||
|
||||
void ICACHE_FLASH_ATTR decode_header(struct Message* msg, const uint8_t** buffer)
|
||||
{
|
||||
msg->id = get16bits(buffer);
|
||||
|
||||
uint32_t fields = get16bits(buffer);
|
||||
msg->qr = (fields & QR_MASK) >> 15;
|
||||
msg->opcode = (fields & OPCODE_MASK) >> 11;
|
||||
msg->aa = (fields & AA_MASK) >> 10;
|
||||
msg->tc = (fields & TC_MASK) >> 9;
|
||||
msg->rd = (fields & RD_MASK) >> 8;
|
||||
msg->ra = (fields & RA_MASK) >> 7;
|
||||
msg->rcode = (fields & RCODE_MASK) >> 0;
|
||||
|
||||
msg->qdCount = get16bits(buffer);
|
||||
msg->anCount = get16bits(buffer);
|
||||
msg->nsCount = get16bits(buffer);
|
||||
msg->arCount = get16bits(buffer);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR encode_header(struct Message* msg, uint8_t** buffer)
|
||||
{
|
||||
put16bits(buffer, msg->id);
|
||||
|
||||
int fields = 0;
|
||||
fields |= (msg->qr << 15) & QR_MASK;
|
||||
fields |= (msg->rcode << 0) & RCODE_MASK;
|
||||
// TODO: insert the rest of the fields
|
||||
put16bits(buffer, fields);
|
||||
|
||||
put16bits(buffer, msg->qdCount);
|
||||
put16bits(buffer, msg->anCount);
|
||||
put16bits(buffer, msg->nsCount);
|
||||
put16bits(buffer, msg->arCount);
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR decode_msg(struct Message* msg, const uint8_t* buffer, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
decode_header(msg, &buffer);
|
||||
|
||||
if (msg->anCount != 0 || msg->nsCount != 0)
|
||||
{
|
||||
os_printf("Only questions expected!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// parse questions
|
||||
uint32_t qcount = msg->qdCount;
|
||||
struct Question* qs = msg->questions;
|
||||
for (i = 0; i < qcount; ++i)
|
||||
{
|
||||
struct Question* q = os_malloc(sizeof(struct Question));
|
||||
|
||||
q->qName = decode_domain_name(&buffer);
|
||||
q->qType = get16bits(&buffer);
|
||||
q->qClass = get16bits(&buffer);
|
||||
|
||||
// prepend question to questions list
|
||||
q->next = qs;
|
||||
msg->questions = q;
|
||||
}
|
||||
|
||||
// We do not expect any resource records to parse here.
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// For every question in the message add a appropiate resource record
|
||||
// in either section 'answers', 'authorities' or 'additionals'.
|
||||
void ICACHE_FLASH_ATTR resolver_process(struct Message* msg)
|
||||
{
|
||||
struct ResourceRecord* beg;
|
||||
struct ResourceRecord* rr;
|
||||
struct Question* q;
|
||||
int rc;
|
||||
|
||||
// leave most values intact for response
|
||||
msg->qr = 1; // this is a response
|
||||
msg->aa = 1; // this server is authoritative
|
||||
msg->ra = 0; // no recursion available
|
||||
msg->rcode = Ok_ResponseType;
|
||||
|
||||
// should already be 0
|
||||
msg->anCount = 0;
|
||||
msg->nsCount = 0;
|
||||
msg->arCount = 0;
|
||||
|
||||
// for every question append resource records
|
||||
q = msg->questions;
|
||||
while (q)
|
||||
{
|
||||
rr = os_malloc(sizeof(struct ResourceRecord));
|
||||
os_memset(rr, 0, sizeof(struct ResourceRecord));
|
||||
|
||||
//rr->name = strdup(q->qName);
|
||||
rr->name = os_malloc(os_strlen(q->qName)+1);
|
||||
os_strcpy(rr->name, q->qName);
|
||||
rr->type = q->qType;
|
||||
rr->class = q->qClass;
|
||||
rr->ttl = 60*60; // in seconds; 0 means no caching
|
||||
#ifdef DNS_RESP_DEBUG
|
||||
os_printf("Query for '%s'\n", q->qName);
|
||||
#endif
|
||||
// We only can only answer two question types so far
|
||||
// and the answer (resource records) will be all put
|
||||
// into the answers list.
|
||||
// This behavior is probably non-standard!
|
||||
switch (q->qType)
|
||||
{
|
||||
case A_Resource_RecordType:
|
||||
rr->rd_length = 4;
|
||||
rc = get_A_Record(rr->rd_data.a_record.addr, q->qName);
|
||||
if (rc < 0)
|
||||
{
|
||||
os_free(rr->name);
|
||||
os_free(rr);
|
||||
goto next;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
case AAAA_Resource_RecordType:
|
||||
rr->rd_length = 16;
|
||||
rc = get_AAAA_Record(rr->rd_data.aaaa_record.addr, q->qName);
|
||||
if (rc < 0)
|
||||
{
|
||||
os_free(rr->name);
|
||||
os_free(rr);
|
||||
goto next;
|
||||
}
|
||||
break;
|
||||
*/
|
||||
/*
|
||||
case NS_Resource_RecordType:
|
||||
case CNAME_Resource_RecordType:
|
||||
case SOA_Resource_RecordType:
|
||||
case PTR_Resource_RecordType:
|
||||
case MX_Resource_RecordType:
|
||||
case TXT_Resource_RecordType:
|
||||
*/
|
||||
default:
|
||||
os_free(rr);
|
||||
msg->rcode = NotImplemented_ResponseType;
|
||||
#ifdef DNS_RESP_DEBUG
|
||||
os_printf("Cannot answer question of type %d.\n", q->qType);
|
||||
#endif
|
||||
goto next;
|
||||
}
|
||||
|
||||
msg->anCount++;
|
||||
|
||||
// prepend resource record to answers list
|
||||
beg = msg->answers;
|
||||
msg->answers = rr;
|
||||
rr->next = beg;
|
||||
|
||||
// jump here to omit question
|
||||
next:
|
||||
|
||||
// process next question
|
||||
q = q->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* @return 0 upon failure, 1 upon success */
|
||||
int ICACHE_FLASH_ATTR encode_resource_records(struct ResourceRecord* rr, uint8_t** buffer)
|
||||
{
|
||||
int i;
|
||||
while (rr)
|
||||
{
|
||||
// Answer questions by attaching resource sections.
|
||||
encode_domain_name(buffer, rr->name);
|
||||
put16bits(buffer, rr->type);
|
||||
put16bits(buffer, rr->class);
|
||||
put32bits(buffer, rr->ttl);
|
||||
put16bits(buffer, rr->rd_length);
|
||||
|
||||
switch (rr->type)
|
||||
{
|
||||
case A_Resource_RecordType:
|
||||
for(i = 0; i < 4; ++i)
|
||||
put8bits(buffer, rr->rd_data.a_record.addr[i]);
|
||||
break;
|
||||
/*
|
||||
case AAAA_Resource_RecordType:
|
||||
for(i = 0; i < 16; ++i)
|
||||
put8bits(buffer, rr->rd_data.aaaa_record.addr[i]);
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
os_printf("Unknown type %u. => Ignore resource record.\n", rr->type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rr = rr->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @return 0 upon failure, 1 upon success */
|
||||
int ICACHE_FLASH_ATTR encode_msg(struct Message* msg, uint8_t** buffer)
|
||||
{
|
||||
struct Question* q;
|
||||
int rc;
|
||||
|
||||
encode_header(msg, buffer);
|
||||
|
||||
q = msg->questions;
|
||||
while (q)
|
||||
{
|
||||
encode_domain_name(buffer, q->qName);
|
||||
put16bits(buffer, q->qType);
|
||||
put16bits(buffer, q->qClass);
|
||||
|
||||
q = q->next;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
rc |= encode_resource_records(msg->answers, buffer);
|
||||
rc |= encode_resource_records(msg->authorities, buffer);
|
||||
rc |= encode_resource_records(msg->additionals, buffer);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR free_resource_records(struct ResourceRecord* rr)
|
||||
{
|
||||
struct ResourceRecord* next;
|
||||
|
||||
while (rr) {
|
||||
os_free(rr->name);
|
||||
next = rr->next;
|
||||
os_free(rr);
|
||||
rr = next;
|
||||
}
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR free_questions(struct Question* qq)
|
||||
{
|
||||
struct Question* next;
|
||||
|
||||
while (qq) {
|
||||
os_free(qq->qName);
|
||||
next = qq->next;
|
||||
os_free(qq);
|
||||
qq = next;
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL void ICACHE_FLASH_ATTR
|
||||
user_udp_recv(void *arg, char *pusrdata, unsigned short length)
|
||||
{
|
||||
uint8_t hwaddr[6];
|
||||
uint8_t buffer[1024];
|
||||
|
||||
struct ip_info ipconfig;
|
||||
struct espconn *pespconn = (struct espconn *)arg;
|
||||
remot_info *premot = NULL;
|
||||
|
||||
if (espconn_get_connection_info(pespconn,&premot,0) == ESPCONN_OK){
|
||||
pespconn->proto.udp->remote_port = premot->remote_port;
|
||||
pespconn->proto.udp->remote_ip[0] = premot->remote_ip[0];
|
||||
pespconn->proto.udp->remote_ip[1] = premot->remote_ip[1];
|
||||
pespconn->proto.udp->remote_ip[2] = premot->remote_ip[2];
|
||||
pespconn->proto.udp->remote_ip[3] = premot->remote_ip[3];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wifi_get_opmode() == STATION_MODE) {
|
||||
//udp packet is received from ESP8266 station
|
||||
if (!(dns_mode & DNS_MODE_STA))
|
||||
return;
|
||||
|
||||
} else {
|
||||
|
||||
wifi_get_ip_info(SOFTAP_IF, &ipconfig);
|
||||
wifi_get_macaddr(SOFTAP_IF, hwaddr);
|
||||
|
||||
if (!ip_addr_netcmp((struct ip_addr *)pespconn->proto.udp->remote_ip, &ipconfig.ip, &ipconfig.netmask)) {
|
||||
//udp packet is received from ESP8266 station
|
||||
|
||||
if (!(dns_mode & DNS_MODE_STA))
|
||||
return;
|
||||
} else {
|
||||
//udp packet is received from ESP8266 softAP
|
||||
|
||||
if (!(dns_mode & DNS_MODE_AP))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pusrdata == NULL)
|
||||
return;
|
||||
|
||||
free_questions(msg.questions);
|
||||
free_resource_records(msg.answers);
|
||||
free_resource_records(msg.authorities);
|
||||
free_resource_records(msg.additionals);
|
||||
os_memset(&msg, 0, sizeof(struct Message));
|
||||
|
||||
if (decode_msg(&msg, pusrdata, length) != 0) {
|
||||
return;
|
||||
}
|
||||
#ifdef DNS_RESP_DEBUG
|
||||
/* Print query */
|
||||
print_query(&msg);
|
||||
#endif
|
||||
|
||||
resolver_process(&msg);
|
||||
|
||||
#ifdef DNS_RESP_DEBUG
|
||||
/* Print response */
|
||||
print_query(&msg);
|
||||
#endif
|
||||
|
||||
uint8_t *p = buffer;
|
||||
if (encode_msg(&msg, &p) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
espconn_sent(pespconn, buffer, p - buffer);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
dns_resp_init(uint8_t mode)
|
||||
{
|
||||
dns_mode = mode;
|
||||
dns_espconn.type = ESPCONN_UDP;
|
||||
dns_espconn.proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp));
|
||||
dns_espconn.proto.udp->local_port = 53; // DNS udp port
|
||||
espconn_regist_recvcb(&dns_espconn, user_udp_recv); // register a udp packet receiving callback
|
||||
espconn_create(&dns_espconn); // create udp
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#define DNS_MODE_STA 0x01
|
||||
#define DNS_MODE_AP 0x02
|
||||
#define DNS_MODE_STATIONAP 0x03
|
||||
|
||||
void dns_resp_init(uint8_t mode);
|
||||
|
||||
int get_A_Record(uint8_t addr[4], const char domain_name[]);
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _USER_CONFIG_
|
||||
#define _USER_CONFIG_
|
||||
|
||||
#define ESP_UBROKER_VERSION "V2.0.3"
|
||||
#define ESP_UBROKER_VERSION "V2.0.4"
|
||||
|
||||
#define WIFI_SSID "ssid"
|
||||
#define WIFI_PASSWORD "password"
|
||||
|
@ -92,7 +92,7 @@
|
|||
// Define this if you want to have access the DNS responder.
|
||||
// Experimental feature - not yet tested
|
||||
//
|
||||
//#define DNS_RESP 1
|
||||
#define DNS_RESP 1
|
||||
|
||||
//
|
||||
// Define this to support the "scan" command for AP search
|
||||
|
|
|
@ -766,11 +766,6 @@ int ICACHE_FLASH_ATTR get_A_Record(uint8_t addr[4], const char domain_name[])
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR get_AAAA_Record(uint8_t addr[16], const char domain_name[])
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue