mDNS-responder: ipv6 support and fixes
* Adds ipv6 support. Compiles with ipv6 enabled and then accepts ipv6 connections and answers AAAA questions. * Fixes a few overflows of the reply buffer. Reduce the default reply buffer size, name it MDNS_RESPONDER_REPLY_SIZE, and allow overriding. * Fix mdns_add_TXT. * Prefer malloc to large stack buffers, to control stack sizes, and try to malloc only the buffer size needed where known in advance. * Determine the IP addresses when responding, eliminating the update function and the update task. * Allow use in SoftAP and StationAP mode too. * Fix to compile without the debug output. * Slightly better integration with lwip. * Accept a NULL TXT entry. * Some code style changes, not comprehensive.
This commit is contained in:
parent
61f23d0cf4
commit
85338ee672
2 changed files with 340 additions and 249 deletions
|
@ -1,9 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* Basic multicast DNS responder
|
* Basic multicast DNS responder
|
||||||
*
|
*
|
||||||
* Advertises the IP address, port, and characteristics of a service to other devices using multicast DNS on the same LAN,
|
* Advertises the IP address, port, and characteristics of a service to other
|
||||||
* so they can find devices with addresses dynamically allocated by DHCP. See avahi, Bonjour, etc
|
* devices using multicast DNS on the same LAN, so they can find devices with
|
||||||
* See RFC6762, RFC6763
|
* addresses dynamically allocated by DHCP. See avahi, Bonjour, etc. See
|
||||||
|
* RFC6762, RFC6763
|
||||||
*
|
*
|
||||||
* This sample code is in the public domain.
|
* This sample code is in the public domain.
|
||||||
*
|
*
|
||||||
|
@ -26,22 +27,21 @@
|
||||||
#include <lwip/netdb.h>
|
#include <lwip/netdb.h>
|
||||||
#include <lwip/dns.h>
|
#include <lwip/dns.h>
|
||||||
#include <lwip/prot/dns.h>
|
#include <lwip/prot/dns.h>
|
||||||
|
#include <lwip/prot/iana.h>
|
||||||
#include <lwip/udp.h>
|
#include <lwip/udp.h>
|
||||||
#include <lwip/igmp.h>
|
#include <lwip/igmp.h>
|
||||||
#include <lwip/netif.h>
|
#include <lwip/netif.h>
|
||||||
|
|
||||||
#include "mdnsresponder.h"
|
#include "mdnsresponder.h"
|
||||||
|
|
||||||
|
#if !LWIP_IGMP
|
||||||
|
#error "LWIP_IGMP needs to be defined in lwipopts.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define qDebugLog // Log activity generally
|
#define qDebugLog // Log activity generally
|
||||||
#define qLogIncoming // Log all arriving multicast packets
|
#define qLogIncoming // Log all arriving multicast packets
|
||||||
#define qLogAllTraffic // Log and decode all mDNS packets
|
#define qLogAllTraffic // Log and decode all mDNS packets
|
||||||
|
|
||||||
#define kMDNSStackSize 800
|
|
||||||
|
|
||||||
#define DNS_MULTICAST_ADDRESS "224.0.0.251" // RFC 6762
|
|
||||||
#define DNS_MDNS_PORT 5353 // RFC 6762
|
|
||||||
#define DNS_MSG_SIZE 512
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef PACK_STRUCT_USE_INCLUDES
|
#ifdef PACK_STRUCT_USE_INCLUDES
|
||||||
|
@ -120,13 +120,15 @@ typedef struct mdns_rsrc {
|
||||||
} mdns_rsrc;
|
} mdns_rsrc;
|
||||||
|
|
||||||
static struct udp_pcb* gMDNS_pcb = NULL;
|
static struct udp_pcb* gMDNS_pcb = NULL;
|
||||||
static ip_addr_t gMulticastAddr; // == DNS_MULTICAST_ADDRESS
|
static const ip_addr_t gMulticastV4Addr = DNS_MQUERY_IPV4_GROUP_INIT;
|
||||||
|
#if LWIP_IPV6
|
||||||
|
#include "lwip/mld6.h"
|
||||||
|
static const ip_addr_t gMulticastV6Addr = DNS_MQUERY_IPV6_GROUP_INIT;
|
||||||
|
#endif
|
||||||
static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
|
|
||||||
//---------------------- Debug/logging utilities -------------------------
|
//---------------------- Debug/logging utilities -------------------------
|
||||||
|
|
||||||
#ifdef qDebugLog
|
|
||||||
|
|
||||||
// DNS field TYPE used for "Resource Records", some additions
|
// DNS field TYPE used for "Resource Records", some additions
|
||||||
#define DNS_RRTYPE_AAAA 28 /* IPv6 host address */
|
#define DNS_RRTYPE_AAAA 28 /* IPv6 host address */
|
||||||
#define DNS_RRTYPE_SRV 33 /* Service record */
|
#define DNS_RRTYPE_SRV 33 /* Service record */
|
||||||
|
@ -146,6 +148,7 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
#define DNS_FLAG2_RA 0x80
|
#define DNS_FLAG2_RA 0x80
|
||||||
#define DNS_FLAG2_RESMASK 0x0F
|
#define DNS_FLAG2_RESMASK 0x0F
|
||||||
|
|
||||||
|
#ifdef qDebugLog
|
||||||
static char qstr[12];
|
static char qstr[12];
|
||||||
|
|
||||||
static char* mdns_qrtype(uint16_t typ)
|
static char* mdns_qrtype(uint16_t typ)
|
||||||
|
@ -160,11 +163,11 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
case DNS_RRTYPE_NSEC : return ("NSEC ");
|
case DNS_RRTYPE_NSEC : return ("NSEC ");
|
||||||
case DNS_RRTYPE_ANY : return ("ANY");
|
case DNS_RRTYPE_ANY : return ("ANY");
|
||||||
}
|
}
|
||||||
sprintf(qstr,"type %d",typ);
|
sprintf(qstr, "type %d", typ);
|
||||||
return qstr;
|
return qstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef qLogAllTraffic
|
#ifdef qLogAllTraffic
|
||||||
|
|
||||||
static void mdns_printhex(u8_t* p, int n)
|
static void mdns_printhex(u8_t* p, int n)
|
||||||
{
|
{
|
||||||
|
@ -183,7 +186,9 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
|
|
||||||
n = *p++;
|
n = *p++;
|
||||||
cp = (char*)p;
|
cp = (char*)p;
|
||||||
for (i=0; i<n; i++) putchar(*cp++);
|
for (i = 0; i < n; i++) {
|
||||||
|
putchar(*cp++);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char cstr[16];
|
static char cstr[16];
|
||||||
|
@ -198,9 +203,9 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
return cstr;
|
return cstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8_t* mdns_print_name(u8_t* p, struct mdns_hdr* hp)
|
|
||||||
// Sequence of Pascal strings, terminated by zero-length string
|
// Sequence of Pascal strings, terminated by zero-length string
|
||||||
// Handles compression, returns ptr to next item
|
// Handles compression, returns ptr to next item
|
||||||
|
static u8_t* mdns_print_name(u8_t* p, struct mdns_hdr* hp)
|
||||||
{
|
{
|
||||||
char* cp = (char*)p;
|
char* cp = (char*)p;
|
||||||
int i, n;
|
int i, n;
|
||||||
|
@ -210,17 +215,17 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
if ((n & 0xC0) == 0xC0) {
|
if ((n & 0xC0) == 0xC0) {
|
||||||
n = (n & 0x3F) << 8;
|
n = (n & 0x3F) << 8;
|
||||||
n |= (u8_t)*cp++;
|
n |= (u8_t)*cp++;
|
||||||
mdns_print_name( (u8_t*)hp + n ,hp );
|
mdns_print_name((u8_t*)hp + n, hp);
|
||||||
n = 0;
|
n = 0;
|
||||||
} else if (n & 0xC0) {
|
} else if (n & 0xC0) {
|
||||||
printf("<label $%X?>",n);
|
printf("<label $%X?>",n);
|
||||||
n = 0;
|
n = 0;
|
||||||
} else {
|
} else {
|
||||||
for (i=0; i<n; i++)
|
for (i = 0; i < n; i++)
|
||||||
putchar(*cp++);
|
putchar(*cp++);
|
||||||
if (n!=0) putchar('.');
|
if (n != 0) putchar('.');
|
||||||
}
|
}
|
||||||
} while (n>0);
|
} while (n > 0);
|
||||||
return (u8_t*)cp;
|
return (u8_t*)cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,10 +235,10 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
if (hdr->flags1 & DNS_FLAG1_RESP) {
|
if (hdr->flags1 & DNS_FLAG1_RESP) {
|
||||||
printf("Response, ID $%X %s ", htons(hdr->id), (hdr->flags1 & DNS_FLAG1_AUTH) ? "Auth " : "Non-auth ");
|
printf("Response, ID $%X %s ", htons(hdr->id), (hdr->flags1 & DNS_FLAG1_AUTH) ? "Auth " : "Non-auth ");
|
||||||
if (hdr->flags2 & DNS_FLAG2_RA) printf("RA ");
|
if (hdr->flags2 & DNS_FLAG2_RA) printf("RA ");
|
||||||
if ((hdr->flags2 & DNS_FLAG2_RESMASK)==0) printf("noerr");
|
if ((hdr->flags2 & DNS_FLAG2_RESMASK) == 0) printf("noerr");
|
||||||
else printf("err %d", hdr->flags2 & DNS_FLAG2_RESMASK);
|
else printf("err %d", hdr->flags2 & DNS_FLAG2_RESMASK);
|
||||||
} else {
|
} else {
|
||||||
printf("Query, ID $%X op %d", htons(hdr->id), (hdr->flags1>>4) & 0x7 );
|
printf("Query, ID $%X op %d", htons(hdr->id), (hdr->flags1 >> 4) & 0x7 );
|
||||||
}
|
}
|
||||||
if (hdr->flags1 & DNS_FLAG1_RD) printf("RD ");
|
if (hdr->flags1 & DNS_FLAG1_RD) printf("RD ");
|
||||||
if (hdr->flags1 & DNS_FLAG1_TRUNC) printf("[TRUNC] ");
|
if (hdr->flags1 & DNS_FLAG1_TRUNC) printf("[TRUNC] ");
|
||||||
|
@ -249,13 +254,13 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
return (u8_t*)hdr + SIZEOF_DNS_HDR;
|
return (u8_t*)hdr + SIZEOF_DNS_HDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8_t* mdns_print_query(u8_t* p)
|
|
||||||
// Copy needed because it may be misaligned
|
// Copy needed because it may be misaligned
|
||||||
|
static u8_t* mdns_print_query(u8_t* p)
|
||||||
{
|
{
|
||||||
struct mdns_query q;
|
struct mdns_query q;
|
||||||
uint16_t c;
|
uint16_t c;
|
||||||
|
|
||||||
memcpy(&q,p,SIZEOF_DNS_QUERY);
|
memcpy(&q, p, SIZEOF_DNS_QUERY);
|
||||||
c = htons(q.class);
|
c = htons(q.class);
|
||||||
printf(" %s %s", mdns_qrtype(htons(q.type)), mdns_qclass(c & 0x7FFF) );
|
printf(" %s %s", mdns_qrtype(htons(q.type)), mdns_qclass(c & 0x7FFF) );
|
||||||
if (c & 0x8000) printf(" unicast-req");
|
if (c & 0x8000) printf(" unicast-req");
|
||||||
|
@ -263,8 +268,8 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
return p + SIZEOF_DNS_QUERY;
|
return p + SIZEOF_DNS_QUERY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8_t* mdns_print_answer(u8_t* p, struct mdns_hdr* hp)
|
|
||||||
// Copy needed because it may be misaligned
|
// Copy needed because it may be misaligned
|
||||||
|
static u8_t* mdns_print_answer(u8_t* p, struct mdns_hdr* hp)
|
||||||
{
|
{
|
||||||
struct mdns_answer ans;
|
struct mdns_answer ans;
|
||||||
u16_t rrlen, atype, rrClass;;
|
u16_t rrlen, atype, rrClass;;
|
||||||
|
@ -278,23 +283,23 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
printf("cache-flush ");
|
printf("cache-flush ");
|
||||||
if (rrlen > 0) {
|
if (rrlen > 0) {
|
||||||
u8_t* rp = p + SIZEOF_DNS_ANSWER;
|
u8_t* rp = p + SIZEOF_DNS_ANSWER;
|
||||||
if (atype==DNS_RRTYPE_A && rrlen==4) {
|
if (atype == DNS_RRTYPE_A && rrlen == 4) {
|
||||||
printf("%d.%d.%d.%d\n",rp[0],rp[1],rp[2],rp[3]);
|
printf("%d.%d.%d.%d\n",rp[0],rp[1],rp[2],rp[3]);
|
||||||
} else if (atype==DNS_RRTYPE_PTR) {
|
} else if (atype == DNS_RRTYPE_PTR) {
|
||||||
mdns_print_name(rp, hp);
|
mdns_print_name(rp, hp);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
} else if (atype==DNS_RRTYPE_TXT) {
|
} else if (atype == DNS_RRTYPE_TXT) {
|
||||||
mdns_print_pstr(rp);
|
mdns_print_pstr(rp);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
} else if (atype==DNS_RRTYPE_SRV && rrlen > SIZEOF_DNS_RR_SRV) {
|
} else if (atype == DNS_RRTYPE_SRV && rrlen > SIZEOF_DNS_RR_SRV) {
|
||||||
struct mdns_rr_srv srvRR;
|
struct mdns_rr_srv srvRR;
|
||||||
memcpy(&srvRR,rp,SIZEOF_DNS_RR_SRV);
|
memcpy(&srvRR, rp, SIZEOF_DNS_RR_SRV);
|
||||||
printf("prio %d, weight %d, port %d, target ", srvRR.prio, srvRR.weight, srvRR.port);
|
printf("prio %d, weight %d, port %d, target ", srvRR.prio, srvRR.weight, ntohs(srvRR.port));
|
||||||
mdns_print_name(rp + SIZEOF_DNS_RR_SRV, hp);
|
mdns_print_name(rp + SIZEOF_DNS_RR_SRV, hp);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
} else {
|
} else {
|
||||||
printf("%db:",rrlen);
|
printf("%db:", rrlen);
|
||||||
mdns_printhex(rp,rrlen);
|
mdns_printhex(rp, rrlen);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -304,50 +309,49 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list
|
||||||
static int mdns_print_msg(u8_t* msgP, int msgLen)
|
static int mdns_print_msg(u8_t* msgP, int msgLen)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
u8_t* tp;
|
u8_t *tp;
|
||||||
u8_t* limP = msgP + msgLen;
|
u8_t *limP = msgP + msgLen;
|
||||||
struct mdns_hdr* hdr;
|
struct mdns_hdr* hdr;
|
||||||
|
|
||||||
hdr = (struct mdns_hdr*) msgP;
|
hdr = (struct mdns_hdr*) msgP;
|
||||||
tp = mdns_print_header(hdr);
|
tp = mdns_print_header(hdr);
|
||||||
for (i=0; i<htons(hdr->numquestions); i++) {
|
for (i = 0; i < htons(hdr->numquestions); i++) {
|
||||||
printf(" Q%d: ",i+1);
|
printf(" Q%d: ", i + 1);
|
||||||
tp = mdns_print_name(tp,hdr);
|
tp = mdns_print_name(tp, hdr);
|
||||||
tp = mdns_print_query(tp);
|
tp = mdns_print_query(tp);
|
||||||
if (tp > limP) return 0;
|
if (tp > limP) return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<htons(hdr->numanswers); i++) {
|
for (i = 0; i < htons(hdr->numanswers); i++) {
|
||||||
printf(" A%d: ",i+1);
|
printf(" A%d: ", i + 1);
|
||||||
tp = mdns_print_name(tp,hdr);
|
tp = mdns_print_name(tp, hdr);
|
||||||
tp = mdns_print_answer(tp,hdr);
|
tp = mdns_print_answer(tp, hdr);
|
||||||
if (tp > limP) return 0;
|
if (tp > limP) return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<htons(hdr->numauthrr); i++) {
|
for (i = 0; i < htons(hdr->numauthrr); i++) {
|
||||||
printf(" AuRR%d: ",i+1);
|
printf(" AuRR%d: ", i + 1);
|
||||||
tp = mdns_print_name(tp,hdr);
|
tp = mdns_print_name(tp, hdr);
|
||||||
tp = mdns_print_answer(tp,hdr);
|
tp = mdns_print_answer(tp, hdr);
|
||||||
if (tp > limP) return 0;
|
if (tp > limP) return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<htons(hdr->numextrarr); i++) {
|
for (i = 0; i < htons(hdr->numextrarr); i++) {
|
||||||
printf(" ExRR%d: ",i+1);
|
printf(" ExRR%d: ", i + 1);
|
||||||
tp = mdns_print_name(tp,hdr);
|
tp = mdns_print_name(tp, hdr);
|
||||||
tp = mdns_print_answer(tp,hdr);
|
tp = mdns_print_answer(tp, hdr);
|
||||||
if (tp > limP) return 0;
|
if (tp > limP) return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif // qLogAllTraffic
|
||||||
|
|
||||||
#endif // qDebugLog
|
#endif // qDebugLog
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
static u8_t* mdns_labels2str(u8_t* hdrP, u8_t* p, char* qStr)
|
|
||||||
// Convert a DNS domain name label sequence into C string with . seperators
|
// Convert a DNS domain name label sequence into C string with . seperators
|
||||||
// Handles compression
|
// Handles compression
|
||||||
|
static u8_t* mdns_labels2str(u8_t* hdrP, u8_t* p, char* qStr)
|
||||||
{
|
{
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
|
@ -362,51 +366,51 @@ static u8_t* mdns_labels2str(u8_t* hdrP, u8_t* p, char* qStr)
|
||||||
printf(">>> mdns_labels2str,label $%X?",n);
|
printf(">>> mdns_labels2str,label $%X?",n);
|
||||||
return p;
|
return p;
|
||||||
} else {
|
} else {
|
||||||
for (i=0; i<n; i++)
|
for (i = 0; i < n; i++)
|
||||||
*qStr++ = *p++;
|
*qStr++ = *p++;
|
||||||
if (n==0) *qStr++ = 0;
|
if (n == 0) *qStr++ = 0;
|
||||||
else *qStr++ = '.';
|
else *qStr++ = '.';
|
||||||
}
|
}
|
||||||
} while (n>0);
|
} while (n>0);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mdns_str2labels(const char* name, u8_t* lseq, int max)
|
|
||||||
// Encode a <string>.<string>.<string> as a sequence of labels, return length
|
// Encode a <string>.<string>.<string> as a sequence of labels, return length
|
||||||
|
static int mdns_str2labels(const char* name, u8_t* lseq, int max)
|
||||||
{
|
{
|
||||||
int i,n,sdx,idx = 0;
|
int i, n, sdx, idx = 0;
|
||||||
int lc = 0;
|
int lc = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
sdx = idx;
|
sdx = idx;
|
||||||
while (name[idx] != '.' && name[idx] != 0) idx++;
|
while (name[idx] != '.' && name[idx] != 0) idx++;
|
||||||
n = idx-sdx;
|
n = idx - sdx;
|
||||||
*lseq++ = n;
|
if (lc + 1 + n > max) {
|
||||||
lc++;
|
printf(">>> mdns_str2labels: oversize (%d)\n", lc + 1 + n);
|
||||||
if (lc+n > max) {
|
|
||||||
printf(">>> mdns_str2labels: oversize (%d)\n",lc+n);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
for (i=0; i<n; i++)
|
*lseq++ = n;
|
||||||
*lseq++ = name[sdx+i];
|
lc++;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
*lseq++ = name[sdx + i];
|
||||||
lc += n;
|
lc += n;
|
||||||
if (name[idx]=='.')
|
if (name[idx] == '.')
|
||||||
idx++;
|
idx++;
|
||||||
} while (n>0);
|
} while (n > 0);
|
||||||
return lc;
|
return lc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8_t* mdns_get_question(u8_t* hdrP, u8_t* qp, char* qStr, uint16_t* qClass, uint16_t* qType, u8_t* qUnicast)
|
|
||||||
// Unpack a DNS question RR at qp, return pointer to next RR
|
// Unpack a DNS question RR at qp, return pointer to next RR
|
||||||
|
static u8_t* mdns_get_question(u8_t* hdrP, u8_t* qp, char* qStr, uint16_t* qClass, uint16_t* qType, u8_t* qUnicast)
|
||||||
{
|
{
|
||||||
struct mdns_query qr;
|
struct mdns_query qr;
|
||||||
uint16_t cls;
|
uint16_t cls;
|
||||||
|
|
||||||
qp = mdns_labels2str(hdrP, qp, qStr);
|
qp = mdns_labels2str(hdrP, qp, qStr);
|
||||||
memcpy(&qr,qp,SIZEOF_DNS_QUERY);
|
memcpy(&qr, qp, SIZEOF_DNS_QUERY);
|
||||||
*qType = htons(qr.type);
|
*qType = htons(qr.type);
|
||||||
cls = htons(qr.class);
|
cls = htons(qr.class);
|
||||||
*qUnicast = cls>>15;
|
*qUnicast = cls >> 15;
|
||||||
*qClass = cls & 0x7FFF;
|
*qClass = cls & 0x7FFF;
|
||||||
return qp + SIZEOF_DNS_QUERY;
|
return qp + SIZEOF_DNS_QUERY;
|
||||||
}
|
}
|
||||||
|
@ -414,8 +418,8 @@ static u8_t* mdns_get_question(u8_t* hdrP, u8_t* qp, char* qStr, uint16_t* qClas
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
static void mdns_add_response(const char* vKey, u16_t vType, u32_t ttl, const void* dataP, u16_t vDataSize)
|
|
||||||
// Add a record to the RR database list
|
// Add a record to the RR database list
|
||||||
|
static void mdns_add_response(const char* vKey, u16_t vType, u32_t ttl, const void* dataP, u16_t vDataSize)
|
||||||
{
|
{
|
||||||
mdns_rsrc* rsrcP;
|
mdns_rsrc* rsrcP;
|
||||||
int keyLen, recSize;
|
int keyLen, recSize;
|
||||||
|
@ -423,9 +427,9 @@ static void mdns_add_response(const char* vKey, u16_t vType, u32_t ttl, const vo
|
||||||
keyLen = strlen(vKey) + 1;
|
keyLen = strlen(vKey) + 1;
|
||||||
recSize = sizeof(mdns_rsrc) - kDummyDataSize + keyLen + vDataSize;
|
recSize = sizeof(mdns_rsrc) - kDummyDataSize + keyLen + vDataSize;
|
||||||
rsrcP = (mdns_rsrc*)malloc(recSize);
|
rsrcP = (mdns_rsrc*)malloc(recSize);
|
||||||
if (rsrcP==NULL)
|
if (rsrcP == NULL) {
|
||||||
printf(">>> mdns_add_response: couldn't alloc %d\n",recSize);
|
printf(">>> mdns_add_response: couldn't alloc %d\n",recSize);
|
||||||
else {
|
} else {
|
||||||
rsrcP->rType = vType;
|
rsrcP->rType = vType;
|
||||||
rsrcP->rTTL = ttl;
|
rsrcP->rTTL = ttl;
|
||||||
rsrcP->rKeySize = keyLen;
|
rsrcP->rKeySize = keyLen;
|
||||||
|
@ -434,20 +438,21 @@ static void mdns_add_response(const char* vKey, u16_t vType, u32_t ttl, const vo
|
||||||
memcpy(&rsrcP->rData[keyLen], dataP, vDataSize);
|
memcpy(&rsrcP->rData[keyLen], dataP, vDataSize);
|
||||||
rsrcP->rNext = gDictP;
|
rsrcP->rNext = gDictP;
|
||||||
gDictP = rsrcP;
|
gDictP = rsrcP;
|
||||||
#ifdef qDebugLog
|
#ifdef qDebugLog
|
||||||
printf("mDNS added RR '%s' %s, %d bytes\n", vKey, mdns_qrtype(vType), vDataSize);
|
printf("mDNS added RR '%s' %s, %d bytes\n", vKey, mdns_qrtype(vType), vDataSize);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mdns_add_PTR(const char* rKey, u32_t ttl, const char* nmStr)
|
void mdns_add_PTR(const char* rKey, u32_t ttl, const char* nmStr)
|
||||||
{
|
{
|
||||||
int nl;
|
size_t nl;
|
||||||
u8_t lBuff[kMaxNameSize];
|
u8_t lBuff[kMaxNameSize];
|
||||||
|
|
||||||
nl = mdns_str2labels(nmStr,lBuff,sizeof(lBuff));
|
nl = mdns_str2labels(nmStr, lBuff, sizeof(lBuff));
|
||||||
if (nl>0)
|
if (nl > 0) {
|
||||||
mdns_add_response(rKey, DNS_RRTYPE_PTR, ttl, lBuff, nl);
|
mdns_add_response(rKey, DNS_RRTYPE_PTR, ttl, lBuff, nl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mdns_add_SRV(const char* rKey, u32_t ttl, u16_t rPort, const char* targName)
|
void mdns_add_SRV(const char* rKey, u32_t ttl, u16_t rPort, const char* targName)
|
||||||
|
@ -463,91 +468,101 @@ void mdns_add_SRV(const char* rKey, u32_t ttl, u16_t rPort, const char* targName
|
||||||
temp.srvRR.prio = 0;
|
temp.srvRR.prio = 0;
|
||||||
temp.srvRR.weight = 0;
|
temp.srvRR.weight = 0;
|
||||||
temp.srvRR.port = htons(rPort);
|
temp.srvRR.port = htons(rPort);
|
||||||
nl = mdns_str2labels(targName,temp.lBuff,sizeof(temp.lBuff));
|
nl = mdns_str2labels(targName, temp.lBuff, sizeof(temp.lBuff));
|
||||||
if (nl>0)
|
if (nl > 0)
|
||||||
mdns_add_response(rKey, DNS_RRTYPE_SRV, ttl, &temp, SIZEOF_DNS_RR_SRV + nl);
|
mdns_add_response(rKey, DNS_RRTYPE_SRV, ttl, &temp, SIZEOF_DNS_RR_SRV + nl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mdns_add_TXT(const char* rKey, u32_t ttl, const char* txStr)
|
|
||||||
// Single TXT str, can be concatenated
|
// Single TXT str, can be concatenated
|
||||||
|
void mdns_add_TXT(const char* rKey, u32_t ttl, const char* txStr)
|
||||||
{
|
{
|
||||||
char pstr[256];
|
|
||||||
u16_t n = strlen(txStr);
|
u16_t n = strlen(txStr);
|
||||||
if (n > 255)
|
if (n > 255) {
|
||||||
printf(">>> mdns_add_TXT oversize (%d)\n",n);
|
printf(">>> mdns_add_TXT oversize (%d)\n",n);
|
||||||
else {
|
return;
|
||||||
pstr[0] = n;
|
|
||||||
memcpy(&pstr[1],txStr,n);
|
|
||||||
mdns_add_response(rKey, DNS_RRTYPE_TXT, ttl, txStr, n+1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *pstr = malloc(n + 1);
|
||||||
|
pstr[0] = n;
|
||||||
|
memcpy(&pstr[1], txStr, n);
|
||||||
|
mdns_add_response(rKey, DNS_RRTYPE_TXT, ttl, pstr, n + 1);
|
||||||
|
free(pstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mdns_add_A(const char* rKey, u32_t ttl, ip_addr_t addr)
|
void mdns_add_A(const char* rKey, u32_t ttl, const ip4_addr_t *addr)
|
||||||
{
|
{
|
||||||
mdns_add_response(rKey, DNS_RRTYPE_A, ttl, &addr, sizeof(addr));
|
mdns_add_response(rKey, DNS_RRTYPE_A, ttl, addr, sizeof(ip4_addr_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LWIP_IPV6
|
||||||
|
void mdns_add_AAAA(const char* rKey, u32_t ttl, const ip6_addr_t *addr)
|
||||||
|
{
|
||||||
|
mdns_add_response(rKey, DNS_RRTYPE_AAAA, ttl, addr, sizeof(addr->addr));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void mdns_add_facility( const char* instanceName, // Friendly name, need not be unique
|
void mdns_add_facility( const char* instanceName, // Friendly name, need not be unique
|
||||||
const char* serviceName, // Must be "name", e.g. "hap" or "http"
|
const char* serviceName, // Must be "_name", e.g. "_hap" or "_http"
|
||||||
const char* addText, // Must be <key>=<value>
|
const char* addText, // Must be <key>=<value>
|
||||||
mdns_flags flags, // TCP or UDP
|
mdns_flags flags, // TCP or UDP
|
||||||
u16_t onPort, // port number
|
u16_t onPort, // port number
|
||||||
u32_t ttl // seconds
|
u32_t ttl // seconds
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
char key[64];
|
size_t key_len = strlen(serviceName) + 12;
|
||||||
char fullName[128];
|
char *key = malloc(key_len + 1);
|
||||||
char devName[96];
|
size_t full_name_len = strlen(instanceName) + 1 + key_len;
|
||||||
struct ip_info ipInfo;
|
char *fullName = malloc(full_name_len + 1);
|
||||||
|
size_t dev_name_len = strlen(instanceName) + 7;
|
||||||
|
char *devName = malloc(dev_name_len + 1);
|
||||||
|
|
||||||
#ifdef qDebugLog
|
#ifdef qDebugLog
|
||||||
printf("\nmDNS advertising instance %s protocol %s text %s on port %d %s TTL %d secs\n",
|
printf("\nmDNS advertising instance %s protocol %s", instanceName, serviceName);
|
||||||
instanceName, serviceName, addText, onPort, (flags & mdns_UDP) ? "UDP" : "TCP", ttl);
|
if (addText) {
|
||||||
#endif
|
printf(" text %s", addText);
|
||||||
|
}
|
||||||
|
printf(" on port %d %s TTL %d secs\n", onPort, (flags & mdns_UDP) ? "UDP" : "TCP", ttl);
|
||||||
|
#endif
|
||||||
|
|
||||||
snprintf(key, sizeof(key), "%s.%s.local.", serviceName, (flags & mdns_UDP) ? "_udp" :"_tcp");
|
snprintf(key, key_len + 1, "%s.%s.local.", serviceName, (flags & mdns_UDP) ? "_udp" :"_tcp");
|
||||||
snprintf(fullName, sizeof(fullName), "%s.%s", instanceName, key);
|
snprintf(fullName, full_name_len + 1, "%s.%s", instanceName, key);
|
||||||
snprintf(devName, sizeof(devName), "%s.local.", instanceName);
|
snprintf(devName, dev_name_len + 1, "%s.local.", instanceName);
|
||||||
|
|
||||||
if (!sdk_wifi_get_ip_info(STATION_IF,&ipInfo))
|
|
||||||
ipInfo.ip.addr = IPADDR_NONE;
|
|
||||||
|
|
||||||
// Order has significance for extraRR feature
|
// Order has significance for extraRR feature
|
||||||
mdns_add_TXT(fullName, ttl, addText);
|
if (addText) {
|
||||||
mdns_add_A(devName, ttl, ipInfo.ip);
|
mdns_add_TXT(fullName, ttl, addText);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_IPV6
|
||||||
|
const ip6_addr_t addr6 = { {0ul, 0ul, 0ul, 0ul} };
|
||||||
|
mdns_add_AAAA(devName, ttl, &addr6);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const ip4_addr_t addr4 = { 0 };
|
||||||
|
mdns_add_A(devName, ttl, &addr4);
|
||||||
|
|
||||||
mdns_add_SRV(fullName, ttl, onPort, devName);
|
mdns_add_SRV(fullName, ttl, onPort, devName);
|
||||||
mdns_add_PTR(key, ttl, fullName);
|
mdns_add_PTR(key, ttl, fullName);
|
||||||
|
|
||||||
// Optional, makes us browsable
|
// Optional, makes us browsable
|
||||||
if (flags & mdns_Browsable)
|
if (flags & mdns_Browsable) {
|
||||||
mdns_add_PTR("_services._dns-sd._udp.local.",ttl,key);
|
mdns_add_PTR("_services._dns-sd._udp.local.", ttl, key);
|
||||||
}
|
|
||||||
|
|
||||||
static void mdns_update_ipaddr(struct ip_info* ipInfo)
|
|
||||||
// IP address has been defined/changed: update any A records with the new IP
|
|
||||||
{
|
|
||||||
mdns_rsrc* rp = gDictP;
|
|
||||||
while (rp != NULL) {
|
|
||||||
if (rp->rType==DNS_RRTYPE_A) {
|
|
||||||
#ifdef qDebugLog
|
|
||||||
printf("Updating A record for '%s' to %d.%d.%d.%d\n", rp->rData,
|
|
||||||
ip4_addr1(&ipInfo->ip), ip4_addr2(&ipInfo->ip), ip4_addr3(&ipInfo->ip), ip4_addr4(&ipInfo->ip));
|
|
||||||
#endif
|
|
||||||
memcpy(&rp->rData[rp->rKeySize], &ipInfo->ip, sizeof(ip_addr_t));
|
|
||||||
}
|
|
||||||
rp = rp->rNext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(key);
|
||||||
|
free(fullName);
|
||||||
|
free(devName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static mdns_rsrc* mdns_match(const char* qstr, u16_t qType)
|
static mdns_rsrc* mdns_match(const char* qstr, u16_t qType)
|
||||||
{
|
{
|
||||||
mdns_rsrc* rp = gDictP;
|
mdns_rsrc* rp = gDictP;
|
||||||
while (rp != NULL) {
|
while (rp != NULL) {
|
||||||
if (rp->rType==qType || qType==DNS_RRTYPE_ANY) {
|
if (rp->rType == qType || qType == DNS_RRTYPE_ANY) {
|
||||||
if (strcasecmp(rp->rData,qstr)==0) {
|
if (strcasecmp(rp->rData, qstr) == 0) {
|
||||||
#ifdef qDebugLog
|
#ifdef qDebugLog
|
||||||
printf(" - matched '%s' %s\n",qstr,mdns_qrtype(rp->rType));
|
printf(" - matched '%s' %s\n", qstr, mdns_qrtype(rp->rType));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,11 +571,22 @@ static mdns_rsrc* mdns_match(const char* qstr, u16_t qType)
|
||||||
return rp;
|
return rp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mdns_add_to_answer(mdns_rsrc* rsrcP, u8_t* resp, int respLen)
|
|
||||||
// Create answer RR and append to resp[respLen], return new length
|
// Create answer RR and append to resp[respLen], return new length
|
||||||
|
static int mdns_add_to_answer(mdns_rsrc* rsrcP, u8_t* resp, int respLen)
|
||||||
{
|
{
|
||||||
// Key is stored as C str, convert to labels
|
// Key is stored as C str, convert to labels
|
||||||
respLen += mdns_str2labels(rsrcP->rData, &resp[respLen], DNS_MSG_SIZE-respLen);
|
size_t rem = MDNS_RESPONDER_REPLY_SIZE - respLen;
|
||||||
|
size_t len = mdns_str2labels(rsrcP->rData, &resp[respLen], rem);
|
||||||
|
if (len == 0) {
|
||||||
|
// Overflow, skip this answer.
|
||||||
|
return respLen;
|
||||||
|
}
|
||||||
|
if ((len + SIZEOF_DNS_ANSWER + rsrcP->rDataSize) > rem) {
|
||||||
|
// Overflow, skip this answer.
|
||||||
|
printf(">>> mdns_add_to_answer: oversize (%d)\n", len + SIZEOF_DNS_ANSWER + rsrcP->rDataSize);
|
||||||
|
return respLen;
|
||||||
|
}
|
||||||
|
respLen += len;
|
||||||
|
|
||||||
// Answer fields: may be misaligned, so build and memcpy
|
// Answer fields: may be misaligned, so build and memcpy
|
||||||
struct mdns_answer ans;
|
struct mdns_answer ans;
|
||||||
|
@ -580,29 +606,43 @@ static int mdns_add_to_answer(mdns_rsrc* rsrcP, u8_t* resp, int respLen)
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
static void mdns_send_mcast(u8_t* msgP, int nBytes)
|
|
||||||
// Send UDP to multicast address
|
// Send UDP to multicast address
|
||||||
|
static void mdns_send_mcast(const ip_addr_t *addr, u8_t* msgP, int nBytes)
|
||||||
{
|
{
|
||||||
struct pbuf* p;
|
struct pbuf* p;
|
||||||
err_t err;
|
err_t err;
|
||||||
|
|
||||||
|
#ifdef qLogAllTraffic
|
||||||
|
mdns_print_msg(msgP, nBytes);
|
||||||
|
#endif
|
||||||
|
|
||||||
p = pbuf_alloc(PBUF_TRANSPORT, nBytes, PBUF_RAM);
|
p = pbuf_alloc(PBUF_TRANSPORT, nBytes, PBUF_RAM);
|
||||||
if (p) {
|
if (p) {
|
||||||
memcpy(p->payload, msgP, nBytes);
|
memcpy(p->payload, msgP, nBytes);
|
||||||
err = udp_sendto(gMDNS_pcb, p, &gMulticastAddr, DNS_MDNS_PORT);
|
const ip_addr_t *dest_addr;
|
||||||
if (err==ERR_OK) {
|
if (IP_IS_V6_VAL(*addr)) {
|
||||||
#ifdef qDebugLog
|
#if LWIP_IPV6
|
||||||
printf(" - responded with %d bytes err %d\n",nBytes,err);
|
dest_addr = &gMulticastV6Addr;
|
||||||
#endif
|
#endif
|
||||||
|
} else {
|
||||||
|
dest_addr = &gMulticastV4Addr;
|
||||||
|
}
|
||||||
|
struct netif *netif = ip_current_input_netif();
|
||||||
|
err = udp_sendto_if(gMDNS_pcb, p, dest_addr, LWIP_IANA_PORT_MDNS, netif);
|
||||||
|
if (err == ERR_OK) {
|
||||||
|
#ifdef qDebugLog
|
||||||
|
printf(" - responded with %d bytes err %d\n", nBytes, err);
|
||||||
|
#endif
|
||||||
} else
|
} else
|
||||||
printf(">>> mdns_send failed %d\n",err);
|
printf(">>> mdns_send failed %d\n", err);
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
} else
|
} else {
|
||||||
printf(">>> mdns_send: alloc failed[%d]\n",nBytes);
|
printf(">>> mdns_send: alloc failed[%d]\n", nBytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdns_reply(struct mdns_hdr* hdrP)
|
|
||||||
// Message has passed tests, may want to send an answer
|
// Message has passed tests, may want to send an answer
|
||||||
|
static void mdns_reply(const ip_addr_t *addr, struct mdns_hdr* hdrP)
|
||||||
{
|
{
|
||||||
int i, nquestions, respLen;
|
int i, nquestions, respLen;
|
||||||
struct mdns_hdr* rHdr;
|
struct mdns_hdr* rHdr;
|
||||||
|
@ -611,9 +651,9 @@ static void mdns_reply(struct mdns_hdr* hdrP)
|
||||||
u8_t* qp;
|
u8_t* qp;
|
||||||
u8_t* mdns_response;
|
u8_t* mdns_response;
|
||||||
|
|
||||||
mdns_response = malloc(DNS_MSG_SIZE);
|
mdns_response = malloc(MDNS_RESPONDER_REPLY_SIZE);
|
||||||
if (mdns_response==NULL) {
|
if (mdns_response == NULL) {
|
||||||
printf(">>> mdns_reply could not alloc %d\n",DNS_MSG_SIZE);
|
printf(">>> mdns_reply could not alloc %d\n", MDNS_RESPONDER_REPLY_SIZE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,25 +672,63 @@ static void mdns_reply(struct mdns_hdr* hdrP)
|
||||||
qp = qBase + SIZEOF_DNS_HDR;
|
qp = qBase + SIZEOF_DNS_HDR;
|
||||||
nquestions = htons(hdrP->numquestions);
|
nquestions = htons(hdrP->numquestions);
|
||||||
|
|
||||||
for (i=0; i<nquestions; i++) {
|
for (i = 0; i < nquestions; i++) {
|
||||||
char qStr[kMaxQStr];
|
char qStr[kMaxQStr];
|
||||||
u16_t qClass, qType;
|
u16_t qClass, qType;
|
||||||
u8_t qUnicast;
|
u8_t qUnicast;
|
||||||
mdns_rsrc* rsrcP;
|
mdns_rsrc* rsrcP;
|
||||||
|
|
||||||
qp = mdns_get_question(qBase, qp, qStr, &qClass, &qType, &qUnicast);
|
qp = mdns_get_question(qBase, qp, qStr, &qClass, &qType, &qUnicast);
|
||||||
if (qClass==DNS_RRCLASS_IN || qClass==DNS_RRCLASS_ANY) {
|
if (qClass == DNS_RRCLASS_IN || qClass == DNS_RRCLASS_ANY) {
|
||||||
rsrcP = mdns_match(qStr, qType);
|
rsrcP = mdns_match(qStr, qType);
|
||||||
if (rsrcP) {
|
if (rsrcP) {
|
||||||
respLen = mdns_add_to_answer(rsrcP, mdns_response, respLen);
|
#if LWIP_IPV6
|
||||||
rHdr->numanswers = htons( htons(rHdr->numanswers) + 1 );
|
if (rsrcP->rType == DNS_RRTYPE_AAAA) {
|
||||||
|
// Emit an answer for each ipv6 address.
|
||||||
|
struct netif *netif = ip_current_input_netif();
|
||||||
|
for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||||
|
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
|
||||||
|
const ip6_addr_t *addr6 = netif_ip6_addr(netif, i);
|
||||||
|
#ifdef qDebugLog
|
||||||
|
char addr6_str[IP6ADDR_STRLEN_MAX];
|
||||||
|
ip6addr_ntoa_r(addr6, addr6_str, IP6ADDR_STRLEN_MAX);
|
||||||
|
printf("Updating AAAA record for '%s' to %s\n", rsrcP->rData, addr6_str);
|
||||||
|
#endif
|
||||||
|
memcpy(&rsrcP->rData[rsrcP->rKeySize], addr6, sizeof(addr6->addr));
|
||||||
|
size_t new_len = mdns_add_to_answer(rsrcP, mdns_response, respLen);
|
||||||
|
if (new_len > respLen) {
|
||||||
|
rHdr->numanswers = htons(htons(rHdr->numanswers) + 1);
|
||||||
|
respLen = new_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (rsrcP->rType == DNS_RRTYPE_A) {
|
||||||
|
struct netif *netif = ip_current_input_netif();
|
||||||
|
#ifdef qDebugLog
|
||||||
|
char addr4_str[IP4ADDR_STRLEN_MAX];
|
||||||
|
ip4addr_ntoa_r(netif_ip4_addr(netif), addr4_str, IP4ADDR_STRLEN_MAX);
|
||||||
|
printf("Updating A record for '%s' to %s\n", rsrcP->rData, addr4_str);
|
||||||
|
#endif
|
||||||
|
memcpy(&rsrcP->rData[rsrcP->rKeySize], netif_ip4_addr(netif), sizeof(ip4_addr_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t new_len = mdns_add_to_answer(rsrcP, mdns_response, respLen);
|
||||||
|
if (new_len > respLen) {
|
||||||
|
rHdr->numanswers = htons(htons(rHdr->numanswers) + 1);
|
||||||
|
respLen = new_len;
|
||||||
|
}
|
||||||
|
|
||||||
// Extra RR logic: if SRV follows PTR, or A follows SRV, volunteer it in extraRR
|
// Extra RR logic: if SRV follows PTR, or A follows SRV, volunteer it in extraRR
|
||||||
// Not required, but could do more here, see RFC6763 s12
|
// Not required, but could do more here, see RFC6763 s12
|
||||||
if (qType==DNS_RRTYPE_PTR) {
|
if (qType == DNS_RRTYPE_PTR) {
|
||||||
if (rsrcP->rNext && rsrcP->rNext->rType==DNS_RRTYPE_SRV)
|
if (rsrcP->rNext && rsrcP->rNext->rType == DNS_RRTYPE_SRV)
|
||||||
extra = rsrcP->rNext;
|
extra = rsrcP->rNext;
|
||||||
} else if (qType==DNS_RRTYPE_SRV) {
|
} else if (qType == DNS_RRTYPE_SRV) {
|
||||||
if (rsrcP->rNext && rsrcP->rNext->rType==DNS_RRTYPE_A)
|
if (rsrcP->rNext && rsrcP->rNext->rType == DNS_RRTYPE_A)
|
||||||
extra = rsrcP->rNext;
|
extra = rsrcP->rNext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -659,16 +737,29 @@ static void mdns_reply(struct mdns_hdr* hdrP)
|
||||||
|
|
||||||
if (respLen > SIZEOF_DNS_HDR) {
|
if (respLen > SIZEOF_DNS_HDR) {
|
||||||
if (extra) {
|
if (extra) {
|
||||||
respLen = mdns_add_to_answer(extra, mdns_response, respLen);
|
if (extra->rType == DNS_RRTYPE_A) {
|
||||||
rHdr->numextrarr = htons( htons(rHdr->numextrarr) + 1 );
|
struct netif *netif = ip_current_input_netif();
|
||||||
|
#ifdef qDebugLog
|
||||||
|
char addr4_str[IP4ADDR_STRLEN_MAX];
|
||||||
|
ip4addr_ntoa_r(netif_ip4_addr(netif), addr4_str, IP4ADDR_STRLEN_MAX);
|
||||||
|
printf("Updating A record for '%s' to %s\n", extra->rData, addr4_str);
|
||||||
|
#endif
|
||||||
|
memcpy(&extra->rData[extra->rKeySize], netif_ip4_addr(netif), sizeof(ip4_addr_t));
|
||||||
|
}
|
||||||
|
size_t new_len = mdns_add_to_answer(extra, mdns_response, respLen);
|
||||||
|
if (new_len > respLen) {
|
||||||
|
rHdr->numextrarr = htons(htons(rHdr->numextrarr) + 1);
|
||||||
|
respLen = new_len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mdns_send_mcast(mdns_response, respLen);
|
mdns_send_mcast(addr, mdns_response, respLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(mdns_response);
|
free(mdns_response);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
|
|
||||||
// Callback from udp_recv
|
// Callback from udp_recv
|
||||||
|
static void mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||||
{
|
{
|
||||||
UNUSED_ARG(pcb);
|
UNUSED_ARG(pcb);
|
||||||
UNUSED_ARG(port);
|
UNUSED_ARG(port);
|
||||||
|
@ -676,30 +767,32 @@ static void mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t
|
||||||
u8_t* mdns_payload;
|
u8_t* mdns_payload;
|
||||||
int plen;
|
int plen;
|
||||||
|
|
||||||
// Sanity checks on size
|
|
||||||
plen = p->tot_len;
|
plen = p->tot_len;
|
||||||
if (plen > DNS_MSG_SIZE) {
|
#ifdef qLogIncoming
|
||||||
|
char addr_str[IPADDR_STRLEN_MAX];
|
||||||
|
ipaddr_ntoa_r(addr, addr_str, IPADDR_STRLEN_MAX);
|
||||||
|
printf("\n\nmDNS IPv%d got %d bytes from %s\n", IP_IS_V6(addr) ? 6 : 4, plen, addr_str);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Sanity checks on size
|
||||||
|
if (plen > MDNS_RESPONDER_REPLY_SIZE) {
|
||||||
printf(">>> mdns_recv: pbuf too big\n");
|
printf(">>> mdns_recv: pbuf too big\n");
|
||||||
} else if (plen < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + 1 + SIZEOF_DNS_ANSWER + 1)) {
|
} else if (plen < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + 1 + SIZEOF_DNS_ANSWER + 1)) {
|
||||||
printf(">>> mdns_recv: pbuf too small\n");
|
printf(">>> mdns_recv: pbuf too small\n");
|
||||||
} else {
|
} else {
|
||||||
#ifdef qLogIncoming
|
|
||||||
printf("\n\nmDNS got %d bytes from %d.%d.%d.%d\n",plen, ip4_addr1(addr), ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr));
|
|
||||||
#endif
|
|
||||||
mdns_payload = malloc(plen);
|
mdns_payload = malloc(plen);
|
||||||
if (!mdns_payload)
|
if (!mdns_payload) {
|
||||||
printf(">>> mdns_recv, could not alloc %d\n",plen);
|
printf(">>> mdns_recv, could not alloc %d\n",plen);
|
||||||
else {
|
} else {
|
||||||
if (pbuf_copy_partial(p, mdns_payload, plen, 0) == plen) {
|
if (pbuf_copy_partial(p, mdns_payload, plen, 0) == plen) {
|
||||||
struct mdns_hdr* hdrP = (struct mdns_hdr*) mdns_payload;
|
struct mdns_hdr* hdrP = (struct mdns_hdr*) mdns_payload;
|
||||||
|
#ifdef qLogAllTraffic
|
||||||
#ifdef qLogAllTraffic
|
mdns_print_msg(mdns_payload, plen);
|
||||||
mdns_print_msg(mdns_payload, plen);
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( (hdrP->flags1 & (DNS_FLAG1_RESP + DNS_FLAG1_OPMASK + DNS_FLAG1_TRUNC) ) == 0
|
if ( (hdrP->flags1 & (DNS_FLAG1_RESP + DNS_FLAG1_OPMASK + DNS_FLAG1_TRUNC) ) == 0
|
||||||
&& hdrP->numquestions > 0 )
|
&& hdrP->numquestions > 0 )
|
||||||
mdns_reply(hdrP);
|
mdns_reply(addr, hdrP);
|
||||||
}
|
}
|
||||||
free(mdns_payload);
|
free(mdns_payload);
|
||||||
}
|
}
|
||||||
|
@ -707,92 +800,82 @@ static void mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdns_start()
|
|
||||||
// If we are in station mode and have an IP address, start a multicast UDP receive
|
// If we are in station mode and have an IP address, start a multicast UDP receive
|
||||||
|
void mdns_init()
|
||||||
{
|
{
|
||||||
struct ip_info ipInfo;
|
|
||||||
err_t err;
|
err_t err;
|
||||||
|
|
||||||
if (sdk_wifi_get_opmode() != STATION_MODE) {
|
struct netif *station_netif = sdk_system_get_netif(STATION_IF);
|
||||||
printf(">>> mDNS_start: wifi opmode not station\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sdk_wifi_get_ip_info(STATION_IF,&ipInfo)) {
|
if (station_netif) {
|
||||||
printf(">>> mDNS_start: no IP addr\n");
|
// Start IGMP on the netif for our interface: this isn't done for us
|
||||||
return;
|
if (!(station_netif->flags & NETIF_FLAG_IGMP)) {
|
||||||
}
|
station_netif->flags |= NETIF_FLAG_IGMP;
|
||||||
|
err = igmp_start(station_netif);
|
||||||
mdns_update_ipaddr(&ipInfo);
|
if (err != ERR_OK) {
|
||||||
|
printf(">>> mDNS_init: igmp_start on %c%c failed %d\n", station_netif->name[0], station_netif->name[1],err);
|
||||||
// Start IGMP on the netif for our interface: this isn't done for us
|
return;
|
||||||
struct netif* nfp = netif_list;
|
|
||||||
while (nfp!=NULL) {
|
|
||||||
if ( ip_addr_cmp(&ipInfo.ip, &(nfp->ip_addr)) ) {
|
|
||||||
if (!(nfp->flags & NETIF_FLAG_IGMP)) {
|
|
||||||
nfp->flags |= NETIF_FLAG_IGMP;
|
|
||||||
err = igmp_start(nfp);
|
|
||||||
if (err != ERR_OK) {
|
|
||||||
printf(">>> mDNS_start: igmp_start on %c%c failed %d\n",nfp->name[0], nfp->name[1],err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nfp = nfp->next;
|
|
||||||
|
if ((err = igmp_joingroup_netif(station_netif, ip_2_ip4(&gMulticastV4Addr))) != ERR_OK) {
|
||||||
|
printf(">>> mDNS_init: igmp_join failed %d\n",err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_IPV6
|
||||||
|
if ((err = mld6_joingroup_netif(station_netif, ip_2_ip6(&gMulticastV6Addr))) != ERR_OK) {
|
||||||
|
printf(">>> mDNS_init: igmp_join failed %d\n",err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
gMDNS_pcb = udp_new();
|
struct netif *softap_netif = sdk_system_get_netif(SOFTAP_IF);
|
||||||
|
if (softap_netif) {
|
||||||
|
if (softap_netif == NULL) {
|
||||||
|
printf(">>> mDNS_init: wifi opmode not softap\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start IGMP on the netif for our interface: this isn't done for us
|
||||||
|
if (!(softap_netif->flags & NETIF_FLAG_IGMP)) {
|
||||||
|
softap_netif->flags |= NETIF_FLAG_IGMP;
|
||||||
|
err = igmp_start(softap_netif);
|
||||||
|
if (err != ERR_OK) {
|
||||||
|
printf(">>> mDNS_init: igmp_start on %c%c failed %d\n", softap_netif->name[0], softap_netif->name[1],err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = igmp_joingroup_netif(softap_netif, ip_2_ip4(&gMulticastV4Addr))) != ERR_OK) {
|
||||||
|
printf(">>> mDNS_init: igmp_join failed %d\n",err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LWIP_IPV6
|
||||||
|
if ((err = mld6_joingroup_netif(softap_netif, ip_2_ip6(&gMulticastV6Addr))) != ERR_OK) {
|
||||||
|
printf(">>> mDNS_init: igmp_join failed %d\n",err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (station_netif == NULL && softap_netif == NULL) {
|
||||||
|
printf(">>> mDNS_init: wifi opmode none\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gMDNS_pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
|
||||||
if (!gMDNS_pcb) {
|
if (!gMDNS_pcb) {
|
||||||
printf(">>> mDNS_start: udp_new failed\n");
|
printf(">>> mDNS_init: udp_new failed\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((err=igmp_joingroup(&ipInfo.ip, &gMulticastAddr)) != ERR_OK) {
|
if ((err = udp_bind(gMDNS_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_MDNS)) != ERR_OK) {
|
||||||
printf(">>> mDNS_start: igmp_join failed %d\n",err);
|
printf(">>> mDNS_init: udp_bind failed %d\n",err);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((err=udp_bind(gMDNS_pcb, IP_ADDR_ANY, DNS_MDNS_PORT)) != ERR_OK) {
|
|
||||||
printf(">>> mDNS_start: udp_bind failed %d\n",err);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
udp_recv(gMDNS_pcb, mdns_recv, NULL);
|
udp_recv(gMDNS_pcb, mdns_recv, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdns_close()
|
|
||||||
{
|
|
||||||
udp_remove(gMDNS_pcb);
|
|
||||||
gMDNS_pcb = NULL;
|
|
||||||
#ifdef qDebugLog
|
|
||||||
printf("Closing mDNS\n");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mdns_task(void *pvParameters)
|
|
||||||
{
|
|
||||||
uint8_t hasIP = 0;
|
|
||||||
uint8_t status;
|
|
||||||
UNUSED_ARG(pvParameters);
|
|
||||||
|
|
||||||
ipaddr_aton(DNS_MULTICAST_ADDRESS, &gMulticastAddr);
|
|
||||||
// Wait until we have joined AP and are assigned an IP
|
|
||||||
while (1) {
|
|
||||||
status = (sdk_wifi_station_get_connect_status() == STATION_GOT_IP);
|
|
||||||
if (status != hasIP) {
|
|
||||||
if (status) mdns_start();
|
|
||||||
else mdns_close();
|
|
||||||
hasIP = status;
|
|
||||||
}
|
|
||||||
vTaskDelayMs(status ? 1000 : 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mdns_init()
|
|
||||||
{
|
|
||||||
#if LWIP_IGMP
|
|
||||||
xTaskCreate(mdns_task, "MDNS", kMDNSStackSize, NULL, 2, NULL);
|
|
||||||
#else
|
|
||||||
#error "LWIP_IGMP needs to be defined in lwipopts.h"
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,20 +1,25 @@
|
||||||
#ifndef __MDNSRESPONDER_H__
|
|
||||||
#define __MDNSRESPONDER_H__
|
|
||||||
|
|
||||||
#include <lwip/ip_addr.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic multicast DNS responder
|
* Basic multicast DNS responder
|
||||||
*
|
*
|
||||||
* Advertises the IP address, port, and characteristics of a service to other devices using multicast DNS on the same LAN,
|
* Advertises the IP address, port, and characteristics of a service to other
|
||||||
* so they can find devices with addresses dynamically allocated by DHCP. See avahi, Bonjour, etc
|
* devices using multicast DNS on the same LAN, so they can find devices with
|
||||||
* See RFC6762, RFC6763
|
* addresses dynamically allocated by DHCP. See avahi, Bonjour, etc See RFC6762,
|
||||||
|
* RFC6763
|
||||||
*
|
*
|
||||||
* This sample code is in the public domain.
|
* This sample code is in the public domain.
|
||||||
*
|
*
|
||||||
* by M J A Hamel 2016
|
* by M J A Hamel 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef __MDNSRESPONDER_H__
|
||||||
|
#define __MDNSRESPONDER_H__
|
||||||
|
|
||||||
|
#include <lwip/ip_addr.h>
|
||||||
|
|
||||||
|
/* The default maximum reply size, increase as necessary. */
|
||||||
|
#ifndef MDNS_RESPONDER_REPLY_SIZE
|
||||||
|
#define MDNS_RESPONDER_REPLY_SIZE 320
|
||||||
|
#endif
|
||||||
|
|
||||||
// Starts the mDNS responder task, call first
|
// Starts the mDNS responder task, call first
|
||||||
void mdns_init();
|
void mdns_init();
|
||||||
|
@ -42,7 +47,10 @@ void mdns_add_facility( const char* instanceName, // Short user-friendly insta
|
||||||
void mdns_add_PTR(const char* rKey, u32_t ttl, const char* nameStr);
|
void mdns_add_PTR(const char* rKey, u32_t ttl, const char* nameStr);
|
||||||
void mdns_add_SRV(const char* rKey, u32_t ttl, u16_t rPort, const char* targname);
|
void mdns_add_SRV(const char* rKey, u32_t ttl, u16_t rPort, const char* targname);
|
||||||
void mdns_add_TXT(const char* rKey, u32_t ttl, const char* txtStr);
|
void mdns_add_TXT(const char* rKey, u32_t ttl, const char* txtStr);
|
||||||
void mdns_add_A (const char* rKey, u32_t ttl, ip_addr_t addr);
|
void mdns_add_A (const char* rKey, u32_t ttl, const ip4_addr_t *addr);
|
||||||
|
#if LWIP_IPV6
|
||||||
|
void mdns_add_AAAA(const char* rKey, u32_t ttl, const ip6_addr_t *addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Sample usage, advertising a secure web service
|
/* Sample usage, advertising a secure web service
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue