diff --git a/extras/mdnsresponder/mdnsresponder.c b/extras/mdnsresponder/mdnsresponder.c index b84f298..d811abf 100644 --- a/extras/mdnsresponder/mdnsresponder.c +++ b/extras/mdnsresponder/mdnsresponder.c @@ -1,7 +1,16 @@ /* * Basic multicast DNS responder + * + * Advertises the IP address, port, and characteristics of a service to other devices using multicast DNS on the same LAN, + * so they can find devices with addresses dynamically allocated by DHCP. See avahi, Bonjour, etc + * See RFC6762, RFC6763 + * + * This sample code is in the public domain. + * + * by M J A Hamel 2016 */ + #include #include @@ -22,46 +31,15 @@ #include "mdnsresponder.h" -//#define qDebugLog // Log activity generally -//#define qLogIncoming // Log all arriving multicast packets -//#define qLogAllTraffic // Log and decode all mDNS packets +#define qDebugLog // Log activity generally +//#define qLogIncoming // Log all arriving multicast packets +//#define qLogAllTraffic // Log and decode all mDNS packets -#define kMDNSStackSize 800 +#define kMDNSStackSize 800 -#define DNS_MULTICAST_ADDRESS "224.0.0.251" // RFC 6762 -#define DNS_MDNS_PORT 5353 // RFC 6762 +#define DNS_MULTICAST_ADDRESS "224.0.0.251" // RFC 6762 +#define DNS_MDNS_PORT 5353 // RFC 6762 -/** DNS field TYPE used for "Resource Records" */ -#define DNS_RRTYPE_A 1 /* a host address */ -#define DNS_RRTYPE_NS 2 /* an authoritative name server */ -#define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ -#define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ -#define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ -#define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ -#define DNS_RRTYPE_WKS 11 /* a well known service description */ -#define DNS_RRTYPE_PTR 12 /* a domain name pointer */ -#define DNS_RRTYPE_HINFO 13 /* host information */ -#define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ -#define DNS_RRTYPE_MX 15 /* mail exchange */ -#define DNS_RRTYPE_TXT 16 /* text strings */ -#define DNS_RRTYPE_AAAA 28 /* IPv6 host address */ -#define DNS_RRTYPE_SRV 33 /* Service record */ -#define DNS_RRTYPE_OPT 41 /* EDNS0 OPT record */ -#define DNS_RRTYPE_NSEC 47 /* NSEC record */ -#define DNS_RRTYPE_TSIG 250 /* Transaction Signature */ -#define DNS_RRTYPE_ANY 255 /* Not a DNS type, but a DNS query type, meaning "all types"*/ - -/* DNS field CLASS used for "Resource Records" */ -#define DNS_RRCLASS_IN 1 /* the Internet */ -#define DNS_RRCLASS_ANY 255 /* Any class (q) */ - -#define DNS_FLAG1_RESP 0x80 -#define DNS_FLAG1_OPMASK 0x78 -#define DNS_FLAG1_AUTH 0x04 -#define DNS_FLAG1_TRUNC 0x02 -#define DNS_FLAG1_RD 0x01 -#define DNS_FLAG2_RA 0x80 -#define DNS_FLAG2_RESMASK 0x0F //------------------------------------------------------------------- #ifdef PACK_STRUCT_USE_INCLUDES @@ -71,13 +49,13 @@ PACK_STRUCT_BEGIN /** DNS message header */ struct mdns_hdr { - PACK_STRUCT_FIELD(u16_t id); - PACK_STRUCT_FIELD(u8_t flags1); - PACK_STRUCT_FIELD(u8_t flags2); - PACK_STRUCT_FIELD(u16_t numquestions); - PACK_STRUCT_FIELD(u16_t numanswers); - PACK_STRUCT_FIELD(u16_t numauthrr); - PACK_STRUCT_FIELD(u16_t numextrarr); + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u8_t flags1); + PACK_STRUCT_FIELD(u8_t flags2); + PACK_STRUCT_FIELD(u16_t numquestions); + PACK_STRUCT_FIELD(u16_t numanswers); + PACK_STRUCT_FIELD(u16_t numauthrr); + PACK_STRUCT_FIELD(u16_t numextrarr); }PACK_STRUCT_STRUCT; PACK_STRUCT_END @@ -86,10 +64,10 @@ PACK_STRUCT_END PACK_STRUCT_BEGIN /** MDNS query message structure */ struct mdns_query { - /* MDNS query record starts with either a domain name or a pointer - to a name already present somewhere in the packet. */ - PACK_STRUCT_FIELD(u16_t type); - PACK_STRUCT_FIELD(u16_t class); + /* MDNS query record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t class); }PACK_STRUCT_STRUCT; PACK_STRUCT_END @@ -98,22 +76,22 @@ PACK_STRUCT_END PACK_STRUCT_BEGIN /** MDNS answer message structure */ struct mdns_answer { - /* MDNS answer record starts with either a domain name or a pointer - to a name already present somewhere in the packet. */ - PACK_STRUCT_FIELD(u16_t type); - PACK_STRUCT_FIELD(u16_t class); - PACK_STRUCT_FIELD(u32_t ttl); - PACK_STRUCT_FIELD(u16_t len); + /* MDNS answer record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t class); + PACK_STRUCT_FIELD(u32_t ttl); + PACK_STRUCT_FIELD(u16_t len); }PACK_STRUCT_STRUCT; PACK_STRUCT_END #define SIZEOF_DNS_ANSWER 10 PACK_STRUCT_BEGIN struct mdns_rr_srv { - /* RR SRV */ - PACK_STRUCT_FIELD(u16_t prio); - PACK_STRUCT_FIELD(u16_t weight); - PACK_STRUCT_FIELD(u16_t port); + /* RR SRV */ + PACK_STRUCT_FIELD(u16_t prio); + PACK_STRUCT_FIELD(u16_t weight); + PACK_STRUCT_FIELD(u16_t port); }PACK_STRUCT_STRUCT; PACK_STRUCT_END #define SIZEOF_DNS_RR_SRV 6 @@ -122,228 +100,244 @@ PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif - - -//------------------------------------------------------------------- - -#define vTaskDelayMs(ms) vTaskDelay((ms)/portTICK_PERIOD_MS) -#define UNUSED_ARG(x) (void)x -#define kDummyDataSize 8 // arbitrary, dynamically resized -#define kMaxNameSize 64 -#define kMaxQStr 128 // max incoming question key handled + +#define vTaskDelayMs(ms) vTaskDelay((ms)/portTICK_PERIOD_MS) +#define UNUSED_ARG(x) (void)x +#define kDummyDataSize 8 // arbitrary, dynamically resized +#define kMaxNameSize 64 +#define kMaxQStr 128 // max incoming question key handled typedef struct mdns_rsrc { - struct mdns_rsrc* rNext; - u16_t rType; - u32_t rTTL; - u16_t rKeySize; - u16_t rDataSize; - char rData[kDummyDataSize]; // Key, as C str with . seperators, followed by data in network-ready form - // at rData[rKeySize] + struct mdns_rsrc* rNext; + u16_t rType; + u32_t rTTL; + u16_t rKeySize; + u16_t rDataSize; + char rData[kDummyDataSize]; // Key, as C str with . seperators, followed by data in network-ready form + // at rData[rKeySize] } mdns_rsrc; static struct udp_pcb* gMDNS_pcb = NULL; -static ip_addr_t gMulticastAddr; -static mdns_rsrc* gDictP = NULL; // RR database, linked list +static ip_addr_t gMulticastAddr; // == DNS_MULTICAST_ADDRESS +static mdns_rsrc* gDictP = NULL; // RR database, linked list //---------------------- Debug/logging utilities ------------------------- #ifdef qDebugLog - static char qstr[12]; - - static char* mdns_qrtype(uint16_t typ) - { - switch(typ) { - case DNS_RRTYPE_A : return ("A"); - case DNS_RRTYPE_NS : return ("NS"); - case DNS_RRTYPE_PTR : return ("PTR"); - case DNS_RRTYPE_TXT : return ("TXT "); - case DNS_RRTYPE_AAAA : return ("AAAA"); - case DNS_RRTYPE_SRV : return ("SRV "); - case DNS_RRTYPE_NSEC : return ("NSEC "); - case DNS_RRTYPE_ANY : return ("ANY"); - } - sprintf(qstr,"type %d",typ); - return qstr; - } - - #ifdef qLogAllTraffic - - static void mdns_printhex(u8_t* p, int n) - { - int i; - for (i=0; i",n); - n = 0; - } else { - for (i=0; i0); - return (u8_t*)cp; - } + static char qstr[12]; + + static char* mdns_qrtype(uint16_t typ) + { + switch(typ) { + case DNS_RRTYPE_A : return ("A"); + case DNS_RRTYPE_NS : return ("NS"); + case DNS_RRTYPE_PTR : return ("PTR"); + case DNS_RRTYPE_TXT : return ("TXT "); + case DNS_RRTYPE_AAAA : return ("AAAA"); + case DNS_RRTYPE_SRV : return ("SRV "); + case DNS_RRTYPE_NSEC : return ("NSEC "); + case DNS_RRTYPE_ANY : return ("ANY"); + } + sprintf(qstr,"type %d",typ); + return qstr; + } + + #ifdef qLogAllTraffic + + static void mdns_printhex(u8_t* p, int n) + { + int i; + for (i=0; iflags1 & DNS_FLAG1_RESP) { - 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_RESMASK)==0) printf("noerr"); - else printf("err %d", hdr->flags2 & DNS_FLAG2_RESMASK); - } else { - 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_TRUNC) printf("[TRUNC] "); - - printf(": %d questions", htons(hdr->numquestions) ); - if (hdr->numanswers != 0) - printf(", %d answers",htons(hdr->numanswers)); - if (hdr->numauthrr != 0) - printf(", %d auth RR",htons(hdr->numauthrr)); - if (hdr->numextrarr != 0) - printf(", %d extra RR",htons(hdr->numextrarr)); - putchar('\n'); - return (u8_t*)hdr + SIZEOF_DNS_HDR; - } + static void mdns_print_pstr(u8_t* p) + { + int i, n; + char* cp; + + n = *p++; + cp = (char*)p; + for (i=0; i 0) { - u8_t* rp = p + SIZEOF_DNS_ANSWER; - if (atype==DNS_RRTYPE_A && rrlen==4) { - printf("%d.%d.%d.%d\n",rp[0],rp[1],rp[2],rp[3]); - } else if (atype==DNS_RRTYPE_PTR) { - mdns_print_name(rp, hp); - printf("\n"); - } else if (atype==DNS_RRTYPE_TXT) { - mdns_print_pstr(rp); - printf("\n"); - } else if (atype==DNS_RRTYPE_SRV && rrlen > SIZEOF_DNS_RR_SRV) { - struct mdns_rr_srv srvRR; - memcpy(&srvRR,rp,SIZEOF_DNS_RR_SRV); - printf("prio %d, weight %d, port %d, target ", srvRR.prio, srvRR.weight, srvRR.port); - mdns_print_name(rp + SIZEOF_DNS_RR_SRV, hp); - printf("\n"); - } else { - printf("%db:",rrlen); - mdns_printhex(rp,rrlen); - } - } else - printf("\n"); - return p + SIZEOF_DNS_ANSWER + rrlen; - } + static u8_t* mdns_print_name(u8_t* p, struct mdns_hdr* hp) + // Sequence of Pascal strings, terminated by zero-length string + // Handles compression, returns ptr to next item + { + char* cp = (char*)p; + int i, n; + + do { + n = *cp++; + if ((n & 0xC0) == 0xC0) { + n = (n & 0x3F) << 8; + n |= (u8_t)*cp++; + mdns_print_name( (u8_t*)hp + n ,hp ); + n = 0; + } else if (n & 0xC0) { + printf("