From 6157668057a3ae70e6f98ec3a9fa5846bff3fe5c Mon Sep 17 00:00:00 2001 From: James Buren Date: Mon, 5 Aug 2024 13:40:34 -0500 Subject: [PATCH] Update mdns dependency to latest development release --- dependencies/mdns/mdns.h | 352 ++++++++++++++++++++++++--------------- 1 file changed, 217 insertions(+), 135 deletions(-) diff --git a/dependencies/mdns/mdns.h b/dependencies/mdns/mdns.h index 73ca3809..d0794bfa 100644 --- a/dependencies/mdns/mdns.h +++ b/dependencies/mdns/mdns.h @@ -94,6 +94,7 @@ typedef struct mdns_record_ptr_t mdns_record_ptr_t; typedef struct mdns_record_a_t mdns_record_a_t; typedef struct mdns_record_aaaa_t mdns_record_aaaa_t; typedef struct mdns_record_txt_t mdns_record_txt_t; +typedef struct mdns_query_t mdns_query_t; #ifdef _WIN32 typedef int mdns_size_t; @@ -154,6 +155,8 @@ struct mdns_record_t { mdns_record_aaaa_t aaaa; mdns_record_txt_t txt; } data; + uint16_t rclass; + uint32_t ttl; }; struct mdns_header_t { @@ -165,6 +168,12 @@ struct mdns_header_t { uint16_t additional_rrs; }; +struct mdns_query_t { + mdns_record_type_t type; + const char* name; + size_t length; +}; + // mDNS/DNS-SD public API //! Open and setup a IPv4 socket for mDNS/DNS-SD. To bind the socket to a specific interface, pass @@ -233,7 +242,19 @@ static inline int mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length, void* buffer, size_t capacity, uint16_t query_id); -//! Receive unicast responses to a mDNS query sent with mdns_discovery_recv, optionally filtering +//! Send a multicast mDNS query on the given socket for the given service names. The supplied buffer +//! will be used to build the query packet and must be 32 bit aligned. The query ID can be set to +//! non-zero to filter responses, however the RFC states that the query ID SHOULD be set to 0 for +//! multicast queries. Each additional service name query consists of a triplet - a record type +//! (mdns_record_type_t), a name string pointer (const char*) and a name length (size_t). The list +//! of variable arguments should be terminated with a record type of 0. The query will request a +//! unicast response if the socket is bound to an ephemeral port, or a multicast response if the +//! socket is bound to mDNS port 5353. Returns the used query ID, or <0 if error. +static inline int +mdns_multiquery_send(int sock, const mdns_query_t* query, size_t count, void* buffer, + size_t capacity, uint16_t query_id); + +//! Receive unicast responses to a mDNS query sent with mdns_[multi]query_send, optionally filtering //! out any responses not matching the given query ID. Set the query ID to 0 to parse all responses, //! even if it is not matching the query ID set in a specific query. Any data will be piped to the //! given callback for parsing. Buffer must be 32 bit aligned. Parsing is stopped when callback @@ -251,8 +272,8 @@ static inline int mdns_query_answer_unicast(int sock, const void* address, size_t address_size, void* buffer, size_t capacity, uint16_t query_id, mdns_record_type_t record_type, const char* name, size_t name_length, mdns_record_t answer, - mdns_record_t* authority, size_t authority_count, - mdns_record_t* additional, size_t additional_count); + const mdns_record_t* authority, size_t authority_count, + const mdns_record_t* additional, size_t additional_count); //! Send a variable multicast mDNS query answer to any question with variable number of records. Use //! the top bit of the query class field (MDNS_UNICAST_RESPONSE) in the query recieved to determine @@ -260,23 +281,23 @@ mdns_query_answer_unicast(int sock, const void* address, size_t address_size, vo //! aligned. Returns 0 if success, or <0 if error. static inline int mdns_query_answer_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer, - mdns_record_t* authority, size_t authority_count, - mdns_record_t* additional, size_t additional_count); + const mdns_record_t* authority, size_t authority_count, + const mdns_record_t* additional, size_t additional_count); //! Send a variable multicast mDNS announcement (as an unsolicited answer) with variable number of //! records.Buffer must be 32 bit aligned. Returns 0 if success, or <0 if error. Use this on service //! startup to announce your instance to the local network. static inline int mdns_announce_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer, - mdns_record_t* authority, size_t authority_count, mdns_record_t* additional, - size_t additional_count); + const mdns_record_t* authority, size_t authority_count, + const mdns_record_t* additional, size_t additional_count); //! Send a variable multicast mDNS announcement. Use this on service end for removing the resource //! from the local network. The records must be identical to the according announcement. static inline int mdns_goodbye_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer, - mdns_record_t* authority, size_t authority_count, mdns_record_t* additional, - size_t additional_count); + const mdns_record_t* authority, size_t authority_count, + const mdns_record_t* additional, size_t additional_count); // Parse records functions @@ -317,6 +338,9 @@ mdns_string_skip(const void* buffer, size_t size, size_t* offset); static inline size_t mdns_string_find(const char* str, size_t length, char c, size_t offset); +//! Compare if two strings are equal. If the strings are equal it returns >0 and the offset variables are +//! updated to the end of the corresponding strings. If the strings are not equal it returns 0 and +//! the offset variables are NOT updated. static inline int mdns_string_equal(const void* buffer_lhs, size_t size_lhs, size_t* ofs_lhs, const void* buffer_rhs, size_t size_rhs, size_t* ofs_rhs); @@ -829,7 +853,7 @@ mdns_multicast_send(int sock, const void* buffer, size_t size) { return 0; } -static inline const uint8_t mdns_services_query[] = { +static const uint8_t mdns_services_query[] = { // Query ID 0x00, 0x00, // Flags @@ -882,20 +906,18 @@ mdns_discovery_recv(int sock, void* buffer, size_t capacity, mdns_record_callbac // It seems some implementations do not fill the correct questions field, // so ignore this check for now and only validate answer string - /* - if (questions != 1) - return 0; - */ + // if (questions != 1) + // return 0; int i; for (i = 0; i < questions; ++i) { - size_t ofs = MDNS_POINTER_DIFF(data, buffer); - size_t verify_ofs = 12; + size_t offset = MDNS_POINTER_DIFF(data, buffer); + size_t verify_offset = 12; // Verify it's our question, _services._dns-sd._udp.local. - if (!mdns_string_equal(buffer, data_size, &ofs, mdns_services_query, - sizeof(mdns_services_query), &verify_ofs)) + if (!mdns_string_equal(buffer, data_size, &offset, mdns_services_query, + sizeof(mdns_services_query), &verify_offset)) return 0; - data = (const uint16_t*)MDNS_POINTER_OFFSET(buffer, ofs); + data = (const uint16_t*)MDNS_POINTER_OFFSET(buffer, offset); uint16_t rtype = mdns_ntohs(data++); uint16_t rclass = mdns_ntohs(data++); @@ -906,31 +928,33 @@ mdns_discovery_recv(int sock, void* buffer, size_t capacity, mdns_record_callbac } for (i = 0; i < answer_rrs; ++i) { - size_t ofs = MDNS_POINTER_DIFF(data, buffer); - size_t verify_ofs = 12; + size_t offset = MDNS_POINTER_DIFF(data, buffer); + size_t verify_offset = 12; // Verify it's an answer to our question, _services._dns-sd._udp.local. - size_t name_offset = ofs; - int is_answer = mdns_string_equal(buffer, data_size, &ofs, mdns_services_query, - sizeof(mdns_services_query), &verify_ofs); - size_t name_length = ofs - name_offset; - if ((ofs + 10) > data_size) + size_t name_offset = offset; + int is_answer = mdns_string_equal(buffer, data_size, &offset, mdns_services_query, + sizeof(mdns_services_query), &verify_offset); + if (!is_answer && !mdns_string_skip(buffer, data_size, &offset)) + break; + size_t name_length = offset - name_offset; + if ((offset + 10) > data_size) return records; - data = (const uint16_t*)MDNS_POINTER_OFFSET(buffer, ofs); + data = (const uint16_t*)MDNS_POINTER_OFFSET(buffer, offset); uint16_t rtype = mdns_ntohs(data++); uint16_t rclass = mdns_ntohs(data++); uint32_t ttl = mdns_ntohl(data); data += 2; uint16_t length = mdns_ntohs(data++); - if (length > (data_size - ofs)) + if (length > (data_size - offset)) return 0; if (is_answer) { ++records; - ofs = MDNS_POINTER_DIFF(data, buffer); + offset = MDNS_POINTER_DIFF(data, buffer); if (callback && callback(sock, saddr, addrlen, MDNS_ENTRYTYPE_ANSWER, query_id, rtype, rclass, ttl, - buffer, data_size, name_offset, name_length, ofs, length, user_data)) + buffer, data_size, name_offset, name_length, offset, length, user_data)) return records; } data = (const uint16_t*)MDNS_POINTER_OFFSET_CONST(data, length); @@ -975,27 +999,22 @@ mdns_socket_listen(int sock, void* buffer, size_t capacity, mdns_record_callback uint16_t query_id = mdns_ntohs(data++); uint16_t flags = mdns_ntohs(data++); uint16_t questions = mdns_ntohs(data++); - /* - This data is unused at the moment, skip uint16_t answer_rrs = mdns_ntohs(data++); uint16_t authority_rrs = mdns_ntohs(data++); uint16_t additional_rrs = mdns_ntohs(data++); - */ - data += 3; - size_t parsed = 0; + size_t records; + size_t total_records = 0; for (int iquestion = 0; iquestion < questions; ++iquestion) { size_t question_offset = MDNS_POINTER_DIFF(data, buffer); size_t offset = question_offset; - size_t verify_ofs = 12; + size_t verify_offset = 12; int dns_sd = 0; if (mdns_string_equal(buffer, data_size, &offset, mdns_services_query, - sizeof(mdns_services_query), &verify_ofs)) { + sizeof(mdns_services_query), &verify_offset)) { dns_sd = 1; - } else { - offset = question_offset; - if (!mdns_string_skip(buffer, data_size, &offset)) - break; + } else if (!mdns_string_skip(buffer, data_size, &offset)) { + break; } size_t length = offset - question_offset; data = (const uint16_t*)MDNS_POINTER_OFFSET_CONST(buffer, offset); @@ -1004,7 +1023,7 @@ mdns_socket_listen(int sock, void* buffer, size_t capacity, mdns_record_callback uint16_t rclass = mdns_ntohs(data++); uint16_t class_without_flushbit = rclass & ~MDNS_CACHE_FLUSH; - // Make sure we get a question of class IN + // Make sure we get a question of class IN or ANY if (!((class_without_flushbit == MDNS_CLASS_IN) || (class_without_flushbit == MDNS_CLASS_ANY))) { break; @@ -1013,20 +1032,48 @@ mdns_socket_listen(int sock, void* buffer, size_t capacity, mdns_record_callback if (dns_sd && flags) continue; - ++parsed; + ++total_records; if (callback && callback(sock, saddr, addrlen, MDNS_ENTRYTYPE_QUESTION, query_id, rtype, rclass, 0, buffer, data_size, question_offset, length, question_offset, length, user_data)) - break; + return total_records; } - return parsed; + size_t offset = MDNS_POINTER_DIFF(data, buffer); + records = mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset, + MDNS_ENTRYTYPE_ANSWER, query_id, answer_rrs, callback, user_data); + total_records += records; + if (records != answer_rrs) + return total_records; + + records = + mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset, + MDNS_ENTRYTYPE_AUTHORITY, query_id, authority_rrs, callback, user_data); + total_records += records; + if (records != authority_rrs) + return total_records; + + records = mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset, + MDNS_ENTRYTYPE_ADDITIONAL, query_id, additional_rrs, callback, + user_data); + + return total_records; } static inline int mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length, void* buffer, size_t capacity, uint16_t query_id) { - if (capacity < (17 + length)) + mdns_query_t query; + query.type = type; + query.name = name; + query.length = length; + return mdns_multiquery_send(sock, &query, 1, buffer, capacity, query_id); +} + +static inline int +mdns_multiquery_send(int sock, const mdns_query_t* query, size_t count, void* buffer, size_t capacity, + uint16_t query_id) { + if (!count || (capacity < (sizeof(struct mdns_header_t) + (6 * count)))) return -1; // Ask for a unicast response since it's a one-shot query @@ -1046,25 +1093,30 @@ mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t leng struct mdns_header_t* header = (struct mdns_header_t*)buffer; // Query ID - header->query_id = htons(query_id); + header->query_id = htons((unsigned short)query_id); // Flags header->flags = 0; // Questions - header->questions = htons(1); + header->questions = htons((unsigned short)count); // No answer, authority or additional RRs header->answer_rrs = 0; header->authority_rrs = 0; header->additional_rrs = 0; - // Fill in question - // Name string + // Fill in questions void* data = MDNS_POINTER_OFFSET(buffer, sizeof(struct mdns_header_t)); - data = mdns_string_make(buffer, capacity, data, name, length, 0); - if (!data) - return -1; - // Record type - data = mdns_htons(data, type); - //! Optional unicast response based on local port, class IN - data = mdns_htons(data, rclass); + for (size_t iq = 0; iq < count; ++iq) { + // Name string + data = mdns_string_make(buffer, capacity, data, query[iq].name, query[iq].length, 0); + if (!data) + return -1; + size_t remain = capacity - MDNS_POINTER_DIFF(data, buffer); + if (remain < 4) + return -1; + // Record type + data = mdns_htons(data, query[iq].type); + //! Optional unicast response based on local port, class IN + data = mdns_htons(data, rclass); + } size_t tosend = MDNS_POINTER_DIFF(data, buffer); if (mdns_multicast_send(sock, buffer, (size_t)tosend)) @@ -1100,19 +1152,16 @@ mdns_query_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn if ((only_query_id > 0) && (query_id != only_query_id)) return 0; // Not a reply to the wanted one-shot query - if (questions > 1) - return 0; - // Skip questions part int i; for (i = 0; i < questions; ++i) { - size_t ofs = MDNS_POINTER_DIFF(data, buffer); - if (!mdns_string_skip(buffer, data_size, &ofs)) + size_t offset = MDNS_POINTER_DIFF(data, buffer); + if (!mdns_string_skip(buffer, data_size, &offset)) return 0; - data = (const uint16_t*)MDNS_POINTER_OFFSET_CONST(buffer, ofs); - /* Record type and class not used, skip - uint16_t rtype = mdns_ntohs(data++); - uint16_t rclass = mdns_ntohs(data++);*/ + data = (const uint16_t*)MDNS_POINTER_OFFSET_CONST(buffer, offset); + // Record type and class not used, skip + // uint16_t rtype = mdns_ntohs(data++); + // uint16_t rclass = mdns_ntohs(data++); data += 2; } @@ -1161,7 +1210,7 @@ mdns_answer_add_question_unicast(void* buffer, size_t capacity, void* data, static inline void* mdns_answer_add_record_header(void* buffer, size_t capacity, void* data, mdns_record_t record, - uint16_t rclass, uint32_t ttl, mdns_string_table_t* string_table) { + mdns_string_table_t* string_table) { data = mdns_string_make(buffer, capacity, data, record.name.str, record.name.length, string_table); if (!data) return 0; @@ -1170,20 +1219,20 @@ mdns_answer_add_record_header(void* buffer, size_t capacity, void* data, mdns_re return 0; data = mdns_htons(data, record.type); - data = mdns_htons(data, rclass); - data = mdns_htonl(data, ttl); + data = mdns_htons(data, record.rclass); + data = mdns_htonl(data, record.ttl); data = mdns_htons(data, 0); // Length, to be filled later return data; } static inline void* mdns_answer_add_record(void* buffer, size_t capacity, void* data, mdns_record_t record, - uint16_t rclass, uint32_t ttl, mdns_string_table_t* string_table) { + mdns_string_table_t* string_table) { // TXT records will be coalesced into one record later if (!data || (record.type == MDNS_RECORDTYPE_TXT)) return data; - data = mdns_answer_add_record_header(buffer, capacity, data, record, rclass, ttl, string_table); + data = mdns_answer_add_record_header(buffer, capacity, data, record, string_table); if (!data) return 0; @@ -1234,8 +1283,20 @@ mdns_answer_add_record(void* buffer, size_t capacity, void* data, mdns_record_t return data; } +static inline void +mdns_record_update_rclass_ttl(mdns_record_t* record, uint16_t rclass, uint32_t ttl) { + if (!record->rclass) + record->rclass = rclass; + if (!record->ttl || !ttl) + record->ttl = ttl; + record->rclass &= (uint16_t)(MDNS_CLASS_IN | MDNS_CACHE_FLUSH); + // Never flush PTR record + if (record->type == MDNS_RECORDTYPE_PTR) + record->rclass &= ~(uint16_t)MDNS_CACHE_FLUSH; +} + static inline void* -mdns_answer_add_txt_record(void* buffer, size_t capacity, void* data, mdns_record_t* records, +mdns_answer_add_txt_record(void* buffer, size_t capacity, void* data, const mdns_record_t* records, size_t record_count, uint16_t rclass, uint32_t ttl, mdns_string_table_t* string_table) { // Pointer to length of record to be filled at end @@ -1247,17 +1308,19 @@ mdns_answer_add_txt_record(void* buffer, size_t capacity, void* data, mdns_recor if (records[irec].type != MDNS_RECORDTYPE_TXT) continue; + mdns_record_t record = records[irec]; + mdns_record_update_rclass_ttl(&record, rclass, ttl); if (!record_data) { - data = mdns_answer_add_record_header(buffer, capacity, data, records[irec], rclass, ttl, - string_table); + data = mdns_answer_add_record_header(buffer, capacity, data, record, string_table); + if (!data) + return data; record_length = MDNS_POINTER_OFFSET(data, -2); record_data = data; } // TXT strings are unlikely to be shared, just make then raw. Also need one byte for // termination, thus the <= check - size_t string_length = - records[irec].data.txt.key.length + records[irec].data.txt.value.length + 1; + size_t string_length = record.data.txt.key.length + record.data.txt.value.length + 1; if (!data) return 0; remain = capacity - MDNS_POINTER_DIFF(data, buffer); @@ -1266,11 +1329,11 @@ mdns_answer_add_txt_record(void* buffer, size_t capacity, void* data, mdns_recor unsigned char* strdata = (unsigned char*)data; *strdata++ = (unsigned char)string_length; - memcpy(strdata, records[irec].data.txt.key.str, records[irec].data.txt.key.length); - strdata += records[irec].data.txt.key.length; + memcpy(strdata, record.data.txt.key.str, record.data.txt.key.length); + strdata += record.data.txt.key.length; *strdata++ = '='; - memcpy(strdata, records[irec].data.txt.value.str, records[irec].data.txt.value.length); - strdata += records[irec].data.txt.value.length; + memcpy(strdata, record.data.txt.value.str, record.data.txt.value.length); + strdata += record.data.txt.value.length; data = strdata; } @@ -1283,7 +1346,7 @@ mdns_answer_add_txt_record(void* buffer, size_t capacity, void* data, mdns_recor } static inline uint16_t -mdns_answer_get_record_count(mdns_record_t* records, size_t record_count) { +mdns_answer_get_record_count(const mdns_record_t* records, size_t record_count) { // TXT records will be coalesced into one record uint16_t total_count = 0; uint16_t txt_record = 0; @@ -1300,12 +1363,15 @@ static inline int mdns_query_answer_unicast(int sock, const void* address, size_t address_size, void* buffer, size_t capacity, uint16_t query_id, mdns_record_type_t record_type, const char* name, size_t name_length, mdns_record_t answer, - mdns_record_t* authority, size_t authority_count, - mdns_record_t* additional, size_t additional_count) { + const mdns_record_t* authority, size_t authority_count, + const mdns_record_t* additional, size_t additional_count) { if (capacity < (sizeof(struct mdns_header_t) + 32 + 4)) return -1; - uint16_t rclass = MDNS_CACHE_FLUSH | MDNS_CLASS_IN; + // According to RFC 6762: + // The cache-flush bit MUST NOT be set in any resource records in a response message + // sent in legacy unicast responses to UDP ports other than 5353. + uint16_t rclass = MDNS_CLASS_IN; uint32_t ttl = 10; // Basic answer structure @@ -1325,21 +1391,31 @@ mdns_query_answer_unicast(int sock, const void* address, size_t address_size, vo &string_table); // Fill in answer - data = mdns_answer_add_record(buffer, capacity, data, answer, rclass, ttl, &string_table); + answer.rclass = rclass; + answer.ttl = ttl; + data = mdns_answer_add_record(buffer, capacity, data, answer, &string_table); // Fill in authority records - for (size_t irec = 0; data && (irec < authority_count); ++irec) - data = mdns_answer_add_record(buffer, capacity, data, authority[irec], rclass, ttl, - &string_table); - data = mdns_answer_add_txt_record(buffer, capacity, data, authority, authority_count, rclass, - ttl, &string_table); + for (size_t irec = 0; data && (irec < authority_count); ++irec) { + mdns_record_t record = authority[irec]; + record.rclass = rclass; + if (!record.ttl) + record.ttl = ttl; + data = mdns_answer_add_record(buffer, capacity, data, record, &string_table); + } + data = mdns_answer_add_txt_record(buffer, capacity, data, authority, authority_count, + rclass, ttl, &string_table); // Fill in additional records - for (size_t irec = 0; data && (irec < additional_count); ++irec) - data = mdns_answer_add_record(buffer, capacity, data, additional[irec], rclass, ttl, - &string_table); - data = mdns_answer_add_txt_record(buffer, capacity, data, additional, additional_count, rclass, - ttl, &string_table); + for (size_t irec = 0; data && (irec < additional_count); ++irec) { + mdns_record_t record = additional[irec]; + record.rclass = rclass; + if (!record.ttl) + record.ttl = ttl; + data = mdns_answer_add_record(buffer, capacity, data, record, &string_table); + } + data = mdns_answer_add_txt_record(buffer, capacity, data, additional, additional_count, + rclass, ttl, &string_table); if (!data) return -1; @@ -1347,11 +1423,11 @@ mdns_query_answer_unicast(int sock, const void* address, size_t address_size, vo return mdns_unicast_send(sock, address, address_size, buffer, tosend); } - static inline int -mdns_answer_multicast_rclass_ttl(int sock, void* buffer, size_t capacity, uint16_t rclass, - mdns_record_t answer, mdns_record_t* authority, size_t authority_count, - mdns_record_t* additional, size_t additional_count, uint32_t ttl) { +mdns_answer_multicast_rclass_ttl(int sock, void* buffer, size_t capacity, mdns_record_t answer, + const mdns_record_t* authority, size_t authority_count, + const mdns_record_t* additional, size_t additional_count, + uint16_t rclass, uint32_t ttl) { if (capacity < (sizeof(struct mdns_header_t) + 32 + 4)) return -1; @@ -1368,21 +1444,27 @@ mdns_answer_multicast_rclass_ttl(int sock, void* buffer, size_t capacity, uint16 void* data = MDNS_POINTER_OFFSET(buffer, sizeof(struct mdns_header_t)); // Fill in answer - data = mdns_answer_add_record(buffer, capacity, data, answer, rclass, ttl, &string_table); + mdns_record_t record = answer; + mdns_record_update_rclass_ttl(&record, rclass, ttl); + data = mdns_answer_add_record(buffer, capacity, data, record, &string_table); // Fill in authority records - for (size_t irec = 0; data && (irec < authority_count); ++irec) - data = mdns_answer_add_record(buffer, capacity, data, authority[irec], rclass, ttl, - &string_table); - data = mdns_answer_add_txt_record(buffer, capacity, data, authority, authority_count, rclass, - ttl, &string_table); + for (size_t irec = 0; data && (irec < authority_count); ++irec) { + record = authority[irec]; + mdns_record_update_rclass_ttl(&record, rclass, ttl); + data = mdns_answer_add_record(buffer, capacity, data, record, &string_table); + } + data = mdns_answer_add_txt_record(buffer, capacity, data, authority, authority_count, + rclass, ttl, &string_table); // Fill in additional records - for (size_t irec = 0; data && (irec < additional_count); ++irec) - data = mdns_answer_add_record(buffer, capacity, data, additional[irec], rclass, ttl, - &string_table); - data = mdns_answer_add_txt_record(buffer, capacity, data, additional, additional_count, rclass, - ttl, &string_table); + for (size_t irec = 0; data && (irec < additional_count); ++irec) { + record = additional[irec]; + mdns_record_update_rclass_ttl(&record, rclass, ttl); + data = mdns_answer_add_record(buffer, capacity, data, record, &string_table); + } + data = mdns_answer_add_txt_record(buffer, capacity, data, additional, additional_count, + rclass, ttl, &string_table); if (!data) return -1; @@ -1390,39 +1472,32 @@ mdns_answer_multicast_rclass_ttl(int sock, void* buffer, size_t capacity, uint16 return mdns_multicast_send(sock, buffer, tosend); } -static inline int -mdns_answer_multicast_rclass(int sock, void* buffer, size_t capacity, uint16_t rclass, - mdns_record_t answer, mdns_record_t* authority, size_t authority_count, - mdns_record_t* additional, size_t additional_count) { - return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, rclass, answer, authority, - authority_count, additional, additional_count, 60); -} - static inline int mdns_query_answer_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer, - mdns_record_t* authority, size_t authority_count, - mdns_record_t* additional, size_t additional_count) { - uint16_t rclass = MDNS_CLASS_IN; - return mdns_answer_multicast_rclass(sock, buffer, capacity, rclass, answer, authority, - authority_count, additional, additional_count); + const mdns_record_t* authority, size_t authority_count, + const mdns_record_t* additional, size_t additional_count) { + return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, answer, authority, + authority_count, additional, additional_count, + MDNS_CLASS_IN, 60); } static inline int mdns_announce_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer, - mdns_record_t* authority, size_t authority_count, mdns_record_t* additional, - size_t additional_count) { - uint16_t rclass = MDNS_CLASS_IN | MDNS_CACHE_FLUSH; - return mdns_answer_multicast_rclass(sock, buffer, capacity, rclass, answer, authority, - authority_count, additional, additional_count); + const mdns_record_t* authority, size_t authority_count, + const mdns_record_t* additional, size_t additional_count) { + return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, answer, authority, + authority_count, additional, additional_count, + MDNS_CLASS_IN | MDNS_CACHE_FLUSH, 60); } static inline int mdns_goodbye_multicast(int sock, void* buffer, size_t capacity, mdns_record_t answer, - mdns_record_t* authority, size_t authority_count, mdns_record_t* additional, - size_t additional_count) { - uint16_t rclass = MDNS_CLASS_IN | MDNS_CACHE_FLUSH; - return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, rclass, answer, authority, - authority_count, additional, additional_count, 0); + const mdns_record_t* authority, size_t authority_count, + const mdns_record_t* additional, size_t additional_count) { + // Goodbye should have ttl of 0 + return mdns_answer_multicast_rclass_ttl(sock, buffer, capacity, answer, authority, + authority_count, additional, additional_count, + MDNS_CLASS_IN, 0); } static inline mdns_string_t @@ -1497,14 +1572,19 @@ mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t len strdata = (const char*)MDNS_POINTER_OFFSET(buffer, offset); size_t sublength = *(const unsigned char*)strdata; + if (sublength >= (end - offset)) + break; + ++strdata; offset += sublength + 1; - size_t separator = 0; + size_t separator = sublength; for (size_t c = 0; c < sublength; ++c) { // DNS-SD TXT record keys MUST be printable US-ASCII, [0x20, 0x7E] - if ((strdata[c] < 0x20) || (strdata[c] > 0x7E)) + if ((strdata[c] < 0x20) || (strdata[c] > 0x7E)) { + separator = 0; break; + } if (strdata[c] == '=') { separator = c; break; @@ -1522,6 +1602,8 @@ mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t len } else { records[parsed].key.str = strdata; records[parsed].key.length = sublength; + records[parsed].value.str = 0; + records[parsed].value.length = 0; } ++parsed;