diff --git a/extras/mdnsresponder/mdnsresponder.c b/extras/mdnsresponder/mdnsresponder.c index 98d0897..0a8781d 100644 --- a/extras/mdnsresponder/mdnsresponder.c +++ b/extras/mdnsresponder/mdnsresponder.c @@ -1,9 +1,10 @@ /* * 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 + * 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. * @@ -26,22 +27,21 @@ #include #include #include +#include #include #include #include #include "mdnsresponder.h" +#if !LWIP_IGMP +#error "LWIP_IGMP needs to be defined in lwipopts.h" +#endif + #define qDebugLog // Log activity generally #define qLogIncoming // Log all arriving multicast 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 @@ -120,13 +120,15 @@ typedef struct mdns_rsrc { } mdns_rsrc; 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 //---------------------- Debug/logging utilities ------------------------- -#ifdef qDebugLog - // DNS field TYPE used for "Resource Records", some additions #define DNS_RRTYPE_AAAA 28 /* IPv6 host address */ #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_RESMASK 0x0F +#ifdef qDebugLog static char qstr[12]; 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_ANY : return ("ANY"); } - sprintf(qstr,"type %d",typ); + sprintf(qstr, "type %d", typ); return qstr; } - #ifdef qLogAllTraffic +#ifdef qLogAllTraffic static void mdns_printhex(u8_t* p, int n) { @@ -183,7 +186,9 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list n = *p++; cp = (char*)p; - for (i=0; i",n); n = 0; } else { - for (i=0; i0); + } while (n > 0); return (u8_t*)cp; } @@ -230,10 +235,10 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list if (hdr->flags1 & 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"); + 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 ); + 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] "); @@ -249,13 +254,13 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list return (u8_t*)hdr + SIZEOF_DNS_HDR; } - static u8_t* mdns_print_query(u8_t* p) // Copy needed because it may be misaligned + static u8_t* mdns_print_query(u8_t* p) { struct mdns_query q; uint16_t c; - memcpy(&q,p,SIZEOF_DNS_QUERY); + memcpy(&q, p, SIZEOF_DNS_QUERY); c = htons(q.class); printf(" %s %s", mdns_qrtype(htons(q.type)), mdns_qclass(c & 0x7FFF) ); if (c & 0x8000) printf(" unicast-req"); @@ -263,8 +268,8 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list 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 + static u8_t* mdns_print_answer(u8_t* p, struct mdns_hdr* hp) { struct mdns_answer ans; u16_t rrlen, atype, rrClass;; @@ -278,23 +283,23 @@ static mdns_rsrc* gDictP = NULL; // RR database, linked list printf("cache-flush "); if (rrlen > 0) { 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]); - } else if (atype==DNS_RRTYPE_PTR) { + } else if (atype == DNS_RRTYPE_PTR) { mdns_print_name(rp, hp); printf("\n"); - } else if (atype==DNS_RRTYPE_TXT) { + } else if (atype == DNS_RRTYPE_TXT) { mdns_print_pstr(rp); 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; - memcpy(&srvRR,rp,SIZEOF_DNS_RR_SRV); - printf("prio %d, weight %d, port %d, target ", srvRR.prio, srvRR.weight, srvRR.port); + memcpy(&srvRR, rp, SIZEOF_DNS_RR_SRV); + printf("prio %d, weight %d, port %d, target ", srvRR.prio, srvRR.weight, ntohs(srvRR.port)); mdns_print_name(rp + SIZEOF_DNS_RR_SRV, hp); printf("\n"); } else { - printf("%db:",rrlen); - mdns_printhex(rp,rrlen); + printf("%db:", rrlen); + mdns_printhex(rp, rrlen); } } else 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) { int i; - u8_t* tp; - u8_t* limP = msgP + msgLen; + u8_t *tp; + u8_t *limP = msgP + msgLen; struct mdns_hdr* hdr; hdr = (struct mdns_hdr*) msgP; tp = mdns_print_header(hdr); - for (i=0; inumquestions); i++) { - printf(" Q%d: ",i+1); - tp = mdns_print_name(tp,hdr); + for (i = 0; i < htons(hdr->numquestions); i++) { + printf(" Q%d: ", i + 1); + tp = mdns_print_name(tp, hdr); tp = mdns_print_query(tp); if (tp > limP) return 0; } - for (i=0; inumanswers); i++) { - printf(" A%d: ",i+1); - tp = mdns_print_name(tp,hdr); - tp = mdns_print_answer(tp,hdr); + for (i = 0; i < htons(hdr->numanswers); i++) { + printf(" A%d: ", i + 1); + tp = mdns_print_name(tp, hdr); + tp = mdns_print_answer(tp, hdr); if (tp > limP) return 0; } - for (i=0; inumauthrr); i++) { - printf(" AuRR%d: ",i+1); - tp = mdns_print_name(tp,hdr); - tp = mdns_print_answer(tp,hdr); + for (i = 0; i < htons(hdr->numauthrr); i++) { + printf(" AuRR%d: ", i + 1); + tp = mdns_print_name(tp, hdr); + tp = mdns_print_answer(tp, hdr); if (tp > limP) return 0; } - for (i=0; inumextrarr); i++) { - printf(" ExRR%d: ",i+1); - tp = mdns_print_name(tp,hdr); - tp = mdns_print_answer(tp,hdr); + for (i = 0; i < htons(hdr->numextrarr); i++) { + printf(" ExRR%d: ", i + 1); + tp = mdns_print_name(tp, hdr); + tp = mdns_print_answer(tp, hdr); if (tp > limP) return 0; } return 1; } - #endif - +#endif // qLogAllTraffic #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 // Handles compression +static u8_t* mdns_labels2str(u8_t* hdrP, u8_t* p, char* qStr) { 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); return p; } else { - for (i=0; i0); return p; } -static int mdns_str2labels(const char* name, u8_t* lseq, int max) // Encode a .. 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; do { sdx = idx; while (name[idx] != '.' && name[idx] != 0) idx++; - n = idx-sdx; - *lseq++ = n; - lc++; - if (lc+n > max) { - printf(">>> mdns_str2labels: oversize (%d)\n",lc+n); + n = idx - sdx; + if (lc + 1 + n > max) { + printf(">>> mdns_str2labels: oversize (%d)\n", lc + 1 + n); return 0; } - for (i=0; i0); + } while (n > 0); 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 +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; uint16_t cls; qp = mdns_labels2str(hdrP, qp, qStr); - memcpy(&qr,qp,SIZEOF_DNS_QUERY); + memcpy(&qr, qp, SIZEOF_DNS_QUERY); *qType = htons(qr.type); cls = htons(qr.class); - *qUnicast = cls>>15; + *qUnicast = cls >> 15; *qClass = cls & 0x7FFF; 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 +static void mdns_add_response(const char* vKey, u16_t vType, u32_t ttl, const void* dataP, u16_t vDataSize) { mdns_rsrc* rsrcP; 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; recSize = sizeof(mdns_rsrc) - kDummyDataSize + keyLen + vDataSize; rsrcP = (mdns_rsrc*)malloc(recSize); - if (rsrcP==NULL) + if (rsrcP == NULL) { printf(">>> mdns_add_response: couldn't alloc %d\n",recSize); - else { + } else { rsrcP->rType = vType; rsrcP->rTTL = ttl; 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); rsrcP->rNext = gDictP; gDictP = rsrcP; - #ifdef qDebugLog - printf("mDNS added RR '%s' %s, %d bytes\n", vKey, mdns_qrtype(vType), vDataSize); - #endif +#ifdef qDebugLog + printf("mDNS added RR '%s' %s, %d bytes\n", vKey, mdns_qrtype(vType), vDataSize); +#endif } } void mdns_add_PTR(const char* rKey, u32_t ttl, const char* nmStr) { - int nl; + size_t nl; u8_t lBuff[kMaxNameSize]; - nl = mdns_str2labels(nmStr,lBuff,sizeof(lBuff)); - if (nl>0) + nl = mdns_str2labels(nmStr, lBuff, sizeof(lBuff)); + if (nl > 0) { 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) @@ -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.weight = 0; temp.srvRR.port = htons(rPort); - nl = mdns_str2labels(targName,temp.lBuff,sizeof(temp.lBuff)); - if (nl>0) + nl = mdns_str2labels(targName, temp.lBuff, sizeof(temp.lBuff)); + if (nl > 0) 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 +void mdns_add_TXT(const char* rKey, u32_t ttl, const char* txStr) { - char pstr[256]; u16_t n = strlen(txStr); - if (n > 255) + if (n > 255) { printf(">>> mdns_add_TXT oversize (%d)\n",n); - else { - pstr[0] = n; - memcpy(&pstr[1],txStr,n); - mdns_add_response(rKey, DNS_RRTYPE_TXT, ttl, txStr, n+1); + return; } + + 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 - 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 = mdns_flags flags, // TCP or UDP u16_t onPort, // port number u32_t ttl // seconds ) { - char key[64]; - char fullName[128]; - char devName[96]; - struct ip_info ipInfo; + size_t key_len = strlen(serviceName) + 12; + char *key = malloc(key_len + 1); + size_t full_name_len = strlen(instanceName) + 1 + key_len; + char *fullName = malloc(full_name_len + 1); + size_t dev_name_len = strlen(instanceName) + 7; + char *devName = malloc(dev_name_len + 1); - #ifdef qDebugLog - printf("\nmDNS advertising instance %s protocol %s text %s on port %d %s TTL %d secs\n", - instanceName, serviceName, addText, onPort, (flags & mdns_UDP) ? "UDP" : "TCP", ttl); - #endif +#ifdef qDebugLog + printf("\nmDNS advertising instance %s protocol %s", instanceName, serviceName); + if (addText) { + 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(fullName, sizeof(fullName), "%s.%s", instanceName, key); - snprintf(devName, sizeof(devName), "%s.local.", instanceName); - - if (!sdk_wifi_get_ip_info(STATION_IF,&ipInfo)) - ipInfo.ip.addr = IPADDR_NONE; + snprintf(key, key_len + 1, "%s.%s.local.", serviceName, (flags & mdns_UDP) ? "_udp" :"_tcp"); + snprintf(fullName, full_name_len + 1, "%s.%s", instanceName, key); + snprintf(devName, dev_name_len + 1, "%s.local.", instanceName); // Order has significance for extraRR feature - mdns_add_TXT(fullName, ttl, addText); - mdns_add_A(devName, ttl, ipInfo.ip); + if (addText) { + 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_PTR(key, ttl, fullName); // Optional, makes us browsable - if (flags & mdns_Browsable) - 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; + if (flags & mdns_Browsable) { + mdns_add_PTR("_services._dns-sd._udp.local.", ttl, key); } + + free(key); + free(fullName); + free(devName); } static mdns_rsrc* mdns_match(const char* qstr, u16_t qType) { mdns_rsrc* rp = gDictP; while (rp != NULL) { - if (rp->rType==qType || qType==DNS_RRTYPE_ANY) { - if (strcasecmp(rp->rData,qstr)==0) { - #ifdef qDebugLog - printf(" - matched '%s' %s\n",qstr,mdns_qrtype(rp->rType)); - #endif + if (rp->rType == qType || qType == DNS_RRTYPE_ANY) { + if (strcasecmp(rp->rData, qstr) == 0) { +#ifdef qDebugLog + printf(" - matched '%s' %s\n", qstr, mdns_qrtype(rp->rType)); +#endif break; } } @@ -556,11 +571,22 @@ static mdns_rsrc* mdns_match(const char* qstr, u16_t qType) 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 +static int mdns_add_to_answer(mdns_rsrc* rsrcP, u8_t* resp, int respLen) { // 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 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 +static void mdns_send_mcast(const ip_addr_t *addr, u8_t* msgP, int nBytes) { struct pbuf* p; err_t err; +#ifdef qLogAllTraffic + mdns_print_msg(msgP, nBytes); +#endif + p = pbuf_alloc(PBUF_TRANSPORT, nBytes, PBUF_RAM); if (p) { memcpy(p->payload, msgP, nBytes); - err = udp_sendto(gMDNS_pcb, p, &gMulticastAddr, DNS_MDNS_PORT); - if (err==ERR_OK) { - #ifdef qDebugLog - printf(" - responded with %d bytes err %d\n",nBytes,err); - #endif + const ip_addr_t *dest_addr; + if (IP_IS_V6_VAL(*addr)) { +#if LWIP_IPV6 + dest_addr = &gMulticastV6Addr; +#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 - printf(">>> mdns_send failed %d\n",err); + printf(">>> mdns_send failed %d\n", err); pbuf_free(p); - } else - printf(">>> mdns_send: alloc failed[%d]\n",nBytes); + } else { + 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 +static void mdns_reply(const ip_addr_t *addr, struct mdns_hdr* hdrP) { int i, nquestions, respLen; struct mdns_hdr* rHdr; @@ -611,9 +651,9 @@ static void mdns_reply(struct mdns_hdr* hdrP) u8_t* qp; u8_t* mdns_response; - mdns_response = malloc(DNS_MSG_SIZE); - if (mdns_response==NULL) { - printf(">>> mdns_reply could not alloc %d\n",DNS_MSG_SIZE); + mdns_response = malloc(MDNS_RESPONDER_REPLY_SIZE); + if (mdns_response == NULL) { + printf(">>> mdns_reply could not alloc %d\n", MDNS_RESPONDER_REPLY_SIZE); return; } @@ -632,25 +672,63 @@ static void mdns_reply(struct mdns_hdr* hdrP) qp = qBase + SIZEOF_DNS_HDR; nquestions = htons(hdrP->numquestions); - for (i=0; inumanswers = htons( htons(rHdr->numanswers) + 1 ); +#if LWIP_IPV6 + 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 // Not required, but could do more here, see RFC6763 s12 - if (qType==DNS_RRTYPE_PTR) { - if (rsrcP->rNext && rsrcP->rNext->rType==DNS_RRTYPE_SRV) + if (qType == DNS_RRTYPE_PTR) { + if (rsrcP->rNext && rsrcP->rNext->rType == DNS_RRTYPE_SRV) extra = rsrcP->rNext; - } else if (qType==DNS_RRTYPE_SRV) { - if (rsrcP->rNext && rsrcP->rNext->rType==DNS_RRTYPE_A) + } else if (qType == DNS_RRTYPE_SRV) { + if (rsrcP->rNext && rsrcP->rNext->rType == DNS_RRTYPE_A) extra = rsrcP->rNext; } } @@ -659,16 +737,29 @@ static void mdns_reply(struct mdns_hdr* hdrP) if (respLen > SIZEOF_DNS_HDR) { if (extra) { - respLen = mdns_add_to_answer(extra, mdns_response, respLen); - rHdr->numextrarr = htons( htons(rHdr->numextrarr) + 1 ); + if (extra->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", 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); } -static void mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) // 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(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; int plen; - // Sanity checks on size 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"); } else if (plen < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + 1 + SIZEOF_DNS_ANSWER + 1)) { printf(">>> mdns_recv: pbuf too small\n"); } 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); - if (!mdns_payload) + if (!mdns_payload) { printf(">>> mdns_recv, could not alloc %d\n",plen); - else { + } else { if (pbuf_copy_partial(p, mdns_payload, plen, 0) == plen) { struct mdns_hdr* hdrP = (struct mdns_hdr*) mdns_payload; - - #ifdef qLogAllTraffic - mdns_print_msg(mdns_payload, plen); - #endif +#ifdef qLogAllTraffic + mdns_print_msg(mdns_payload, plen); +#endif if ( (hdrP->flags1 & (DNS_FLAG1_RESP + DNS_FLAG1_OPMASK + DNS_FLAG1_TRUNC) ) == 0 && hdrP->numquestions > 0 ) - mdns_reply(hdrP); + mdns_reply(addr, hdrP); } 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); } -static void mdns_start() // 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; - if (sdk_wifi_get_opmode() != STATION_MODE) { - printf(">>> mDNS_start: wifi opmode not station\n"); - return; - } + struct netif *station_netif = sdk_system_get_netif(STATION_IF); - if (!sdk_wifi_get_ip_info(STATION_IF,&ipInfo)) { - printf(">>> mDNS_start: no IP addr\n"); - return; - } - - mdns_update_ipaddr(&ipInfo); - - // Start IGMP on the netif for our interface: this isn't done for us - 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; - } - } + if (station_netif) { + // Start IGMP on the netif for our interface: this isn't done for us + if (!(station_netif->flags & NETIF_FLAG_IGMP)) { + station_netif->flags |= NETIF_FLAG_IGMP; + err = igmp_start(station_netif); + if (err != ERR_OK) { + printf(">>> mDNS_init: igmp_start on %c%c failed %d\n", station_netif->name[0], station_netif->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) { - printf(">>> mDNS_start: udp_new failed\n"); + printf(">>> mDNS_init: udp_new failed\n"); return; } - if ((err=igmp_joingroup(&ipInfo.ip, &gMulticastAddr)) != ERR_OK) { - printf(">>> mDNS_start: igmp_join 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); + if ((err = udp_bind(gMDNS_pcb, IP_ANY_TYPE, LWIP_IANA_PORT_MDNS)) != ERR_OK) { + printf(">>> mDNS_init: udp_bind failed %d\n",err); return; } 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 -} diff --git a/extras/mdnsresponder/mdnsresponder.h b/extras/mdnsresponder/mdnsresponder.h index 0008464..01c6dd2 100644 --- a/extras/mdnsresponder/mdnsresponder.h +++ b/extras/mdnsresponder/mdnsresponder.h @@ -1,20 +1,25 @@ -#ifndef __MDNSRESPONDER_H__ -#define __MDNSRESPONDER_H__ - -#include - /* * 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 + * 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 */ +#ifndef __MDNSRESPONDER_H__ +#define __MDNSRESPONDER_H__ + +#include + +/* 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 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_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_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