26 #define strncasecmp _strnicmp
29 #include <sys/socket.h>
30 #include <netinet/in.h>
37 #define MDNS_INVALID_POS ((size_t)-1)
39 #define MDNS_STRING_CONST(s) (s), (sizeof((s)) - 1)
40 #define MDNS_STRING_FORMAT(s) (int)((s).length), s.str
42 #define MDNS_POINTER_OFFSET(p, ofs) ((void*)((char*)(p) + (ptrdiff_t)(ofs)))
43 #define MDNS_POINTER_OFFSET_CONST(p, ofs) ((const void*)((const char*)(p) + (ptrdiff_t)(ofs)))
44 #define MDNS_POINTER_DIFF(a, b) ((size_t)((const char*)(a) - (const char*)(b)))
46 #define MDNS_PORT 5353
47 #define MDNS_UNICAST_RESPONSE 0x8000U
48 #define MDNS_CACHE_FLUSH 0x8000U
79 uint16_t rclass, uint32_t ttl,
const void* data,
size_t size,
80 size_t name_offset,
size_t name_length,
size_t record_offset,
81 size_t record_length,
void* user_data);
186 size_t capacity,
const char* record,
size_t length);
196 size_t capacity, uint16_t query_id);
204 void* user_data,
int query_id);
212 mdns_query_answer(
int sock,
const void* address,
size_t address_size,
void* buffer,
size_t capacity,
213 uint16_t query_id,
const char* service,
size_t service_length,
214 const char* hostname,
size_t hostname_length, uint32_t ipv4,
const uint8_t* ipv6,
215 uint16_t port,
const char* txt,
size_t txt_length);
220 mdns_string_extract(
const void* buffer,
size_t size,
size_t* offset,
char* str,
size_t capacity);
226 mdns_string_equal(
const void* buffer_lhs,
size_t size_lhs,
size_t* ofs_lhs,
const void* buffer_rhs,
227 size_t size_rhs,
size_t* ofs_rhs);
230 mdns_string_make(
void* data,
size_t capacity,
const char* name,
size_t length);
241 char* strbuffer,
size_t capacity);
245 char* strbuffer,
size_t capacity);
247 static struct sockaddr_in*
249 struct sockaddr_in* addr);
251 static struct sockaddr_in6*
253 struct sockaddr_in6* addr);
263 int sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
275 unsigned char ttl = 1;
276 unsigned char loopback = 1;
277 unsigned int reuseaddr = 1;
280 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (
const char*)&reuseaddr,
sizeof(reuseaddr));
282 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (
const char*)&reuseaddr,
sizeof(reuseaddr));
284 setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (
const char*)&ttl,
sizeof(ttl));
285 setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (
const char*)&loopback,
sizeof(loopback));
287 memset(&req, 0,
sizeof(req));
288 req.imr_multiaddr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
290 req.imr_interface = saddr->sin_addr;
291 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (
char*)&req,
sizeof(req)))
294 struct sockaddr_in sock_addr;
297 memset(saddr, 0,
sizeof(
struct sockaddr_in));
298 saddr->sin_family = AF_INET;
299 saddr->sin_addr.s_addr = INADDR_ANY;
301 saddr->sin_len =
sizeof(
struct sockaddr_in);
304 setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (
const char*)&saddr->sin_addr,
305 sizeof(saddr->sin_addr));
307 saddr->sin_addr.s_addr = INADDR_ANY;
311 if (bind(sock, (
struct sockaddr*)saddr,
sizeof(
struct sockaddr_in)))
315 unsigned long param = 1;
316 ioctlsocket(sock, FIONBIO, ¶m);
318 const int flags = fcntl(sock, F_GETFL, 0);
319 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
327 int sock = (int)socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
340 unsigned int loopback = 1;
341 unsigned int reuseaddr = 1;
342 struct ipv6_mreq req;
344 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (
const char*)&reuseaddr,
sizeof(reuseaddr));
346 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (
const char*)&reuseaddr,
sizeof(reuseaddr));
348 setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (
const char*)&hops,
sizeof(hops));
349 setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (
const char*)&loopback,
sizeof(loopback));
351 memset(&req, 0,
sizeof(req));
352 req.ipv6mr_multiaddr.s6_addr[0] = 0xFF;
353 req.ipv6mr_multiaddr.s6_addr[1] = 0x02;
354 req.ipv6mr_multiaddr.s6_addr[15] = 0xFB;
355 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (
char*)&req,
sizeof(req)))
358 struct sockaddr_in6 sock_addr;
361 memset(saddr, 0,
sizeof(
struct sockaddr_in6));
362 saddr->sin6_family = AF_INET6;
363 saddr->sin6_addr = in6addr_any;
365 saddr->sin6_len =
sizeof(
struct sockaddr_in6);
368 unsigned int ifindex = 0;
369 setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (
const char*)&ifindex,
sizeof(ifindex));
371 saddr->sin6_addr = in6addr_any;
375 if (bind(sock, (
struct sockaddr*)saddr,
sizeof(
struct sockaddr_in6)))
379 unsigned long param = 1;
380 ioctlsocket(sock, FIONBIO, ¶m);
382 const int flags = fcntl(sock, F_GETFL, 0);
383 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
400 return (0xC0 == (val & 0xC0));
405 const uint8_t* buffer = (
const uint8_t*)rawdata;
407 if (!buffer[offset]) {
412 if (size < offset + 2)
422 size_t length = (size_t)buffer[offset++];
423 if (size < offset + length)
434 size_t cur = *offset;
452 mdns_string_equal(
const void* buffer_lhs,
size_t size_lhs,
size_t* ofs_lhs,
const void* buffer_rhs,
453 size_t size_rhs,
size_t* ofs_rhs) {
454 size_t lhs_cur = *ofs_lhs;
455 size_t rhs_cur = *ofs_rhs;
467 if (strncasecmp((
const char*)buffer_rhs + rhs_substr.
offset,
468 (
const char*)buffer_lhs + lhs_substr.
offset, rhs_substr.
length))
471 lhs_end = lhs_cur + 2;
473 rhs_end = rhs_cur + 2;
476 }
while (lhs_substr.
length);
479 lhs_end = lhs_cur + 1;
483 rhs_end = rhs_cur + 1;
491 size_t cur = *offset;
498 size_t remain = capacity;
506 size_t to_copy = (substr.
length < remain) ? substr.
length : remain;
507 memcpy(dst, (
const char*)buffer + substr.
offset, to_copy);
522 result.
length = capacity - remain;
529 if (offset >= length)
531 found = memchr(str + offset, c, length - offset);
533 return (
size_t)((
const char*)found - str);
541 size_t remain = capacity;
542 unsigned char* dest = (
unsigned char*)data;
543 while ((last_pos < length) &&
545 size_t sublength = pos - last_pos;
546 if (sublength < remain) {
547 *dest = (
unsigned char)sublength;
548 memcpy(dest + 1, name + last_pos, sublength);
549 dest += sublength + 1;
550 remain -= sublength + 1;
556 if (last_pos < length) {
557 size_t sublength = length - last_pos;
558 if (sublength < remain) {
559 *dest = (
unsigned char)sublength;
560 memcpy(dest + 1, name + last_pos, sublength);
561 dest += sublength + 1;
562 remain -= sublength + 1;
577 uint16_t* udata = (uint16_t*)data;
578 *udata++ = htons(0xC000 | (uint16_t)ref_offset);
587 if (!data || !capacity)
597 int do_callback = (callback ? 1 : 0);
598 for (
size_t i = 0; i < records; ++i) {
599 size_t name_offset = *offset;
601 size_t name_length = (*offset) - name_offset;
602 const uint16_t* data = (
const uint16_t*)((
const char*)buffer + (*offset));
604 uint16_t rtype = ntohs(*data++);
605 uint16_t rclass = ntohs(*data++);
606 uint32_t ttl = ntohl(*(
const uint32_t*)(
const void*)data);
608 uint16_t length = ntohs(*data++);
614 if (callback(sock, from, addrlen, type, query_id, rtype, rclass, ttl, buffer, size,
615 name_offset, name_length, *offset, length, user_data))
627 if (sendto(sock, (
const char*)buffer, (
mdns_size_t)size, 0, (
const struct sockaddr*)address,
635 struct sockaddr_storage addr_storage;
636 struct sockaddr_in addr;
637 struct sockaddr_in6 addr6;
638 struct sockaddr* saddr = (
struct sockaddr*)&addr_storage;
639 socklen_t saddrlen =
sizeof(
struct sockaddr_storage);
640 if (getsockname(sock, saddr, &saddrlen))
642 if (saddr->sa_family == AF_INET6) {
643 memset(&addr6, 0,
sizeof(addr6));
644 addr6.sin6_family = AF_INET6;
646 addr6.sin6_len =
sizeof(addr6);
648 addr6.sin6_addr.s6_addr[0] = 0xFF;
649 addr6.sin6_addr.s6_addr[1] = 0x02;
650 addr6.sin6_addr.s6_addr[15] = 0xFB;
651 addr6.sin6_port = htons((
unsigned short)
MDNS_PORT);
652 saddr = (
struct sockaddr*)&addr6;
653 saddrlen =
sizeof(addr6);
655 memset(&addr, 0,
sizeof(addr));
656 addr.sin_family = AF_INET;
658 addr.sin_len =
sizeof(addr);
660 addr.sin_addr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
661 addr.sin_port = htons((
unsigned short)
MDNS_PORT);
662 saddr = (
struct sockaddr*)&addr;
663 saddrlen =
sizeof(addr);
666 if (sendto(sock, (
const char*)buffer, (
mdns_size_t)size, 0, saddr, saddrlen) < 0)
679 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
681 0x09,
'_',
's',
'e',
'r',
'v',
'i',
'c',
'e',
's', 0x07,
'_',
'd',
'n',
's',
'-',
's',
'd',
682 0x04,
'_',
'u',
'd',
'p', 0x05,
'l',
'o',
'c',
'a',
'l', 0x00,
696 struct sockaddr_in6 addr;
697 struct sockaddr* saddr = (
struct sockaddr*)&addr;
699 memset(&addr, 0,
sizeof(addr));
701 saddr->sa_len =
sizeof(addr);
703 int ret = recvfrom(sock, (
char*)buffer, (
mdns_size_t)capacity, 0, saddr, &addrlen);
707 size_t data_size = (size_t)ret;
709 uint16_t* data = (uint16_t*)buffer;
711 uint16_t query_id = ntohs(*data++);
712 uint16_t flags = ntohs(*data++);
713 uint16_t questions = ntohs(*data++);
714 uint16_t answer_rrs = ntohs(*data++);
715 uint16_t authority_rrs = ntohs(*data++);
716 uint16_t additional_rrs = ntohs(*data++);
719 if (query_id || (flags != 0x8400))
730 for (i = 0; i < questions; ++i) {
731 size_t ofs = (size_t)((
char*)data - (
char*)buffer);
732 size_t verify_ofs = 12;
737 data = (uint16_t*)((
char*)buffer + ofs);
739 uint16_t rtype = ntohs(*data++);
740 uint16_t rclass = ntohs(*data++);
748 for (i = 0; i < answer_rrs; ++i) {
749 size_t ofs = (size_t)((
char*)data - (
char*)buffer);
750 size_t verify_ofs = 12;
752 size_t name_offset = ofs;
755 size_t name_length = ofs - name_offset;
756 data = (uint16_t*)((
char*)buffer + ofs);
758 uint16_t rtype = ntohs(*data++);
759 uint16_t rclass = ntohs(*data++);
760 uint32_t ttl = ntohl(*(uint32_t*)(
void*)data);
762 uint16_t length = ntohs(*data++);
763 if (length >= (data_size - ofs))
766 if (is_answer && do_callback) {
768 ofs = (size_t)((
char*)data - (
char*)buffer);
770 buffer, data_size, name_offset, name_length, ofs, length, user_data))
773 data = (uint16_t*)((
char*)data + length);
776 size_t offset = (size_t)((
char*)data - (
char*)buffer);
790 struct sockaddr_in6 addr;
791 struct sockaddr* saddr = (
struct sockaddr*)&addr;
793 memset(&addr, 0,
sizeof(addr));
795 saddr->sa_len =
sizeof(addr);
797 int ret = recvfrom(sock, (
char*)buffer, (
mdns_size_t)capacity, 0, saddr, &addrlen);
801 size_t data_size = (size_t)ret;
802 uint16_t* data = (uint16_t*)buffer;
804 uint16_t query_id = ntohs(*data++);
805 uint16_t flags = ntohs(*data++);
806 uint16_t questions = ntohs(*data++);
816 for (
int iquestion = 0; iquestion < questions; ++iquestion) {
817 size_t question_offset = (size_t)((
char*)data - (
char*)buffer);
818 size_t offset = question_offset;
819 size_t verify_ofs = 12;
822 if (flags || (questions != 1))
825 offset = question_offset;
829 size_t length = offset - question_offset;
830 data = (uint16_t*)((
char*)buffer + offset);
832 uint16_t rtype = ntohs(*data++);
833 uint16_t rclass = ntohs(*data++);
841 buffer, data_size, question_offset, length, question_offset, length,
852 size_t capacity,
const char* record,
size_t length) {
856 uint16_t* data = (uint16_t*)buffer;
860 uint16_t* flags = data + 1;
861 *flags = htons(0x8400U);
863 uint16_t* answers = data + 3;
869 *data++ = htons(0xC000U | 12U);
875 *(uint32_t*)data = htonl(10);
878 uint16_t* record_length = data++;
879 uint8_t* record_data = (uint8_t*)data;
881 record_data = (uint8_t*)
mdns_string_make(record_data, remain, record, length);
882 *record_length = htons((uint16_t)(record_data - (uint8_t*)data));
885 ptrdiff_t tosend = (
char*)record_data - (
char*)buffer;
891 size_t capacity, uint16_t query_id) {
892 if (capacity < (17 + length))
897 struct sockaddr_storage addr_storage;
898 struct sockaddr* saddr = (
struct sockaddr*)&addr_storage;
899 socklen_t saddrlen =
sizeof(addr_storage);
900 if (getsockname(sock, saddr, &saddrlen) == 0) {
901 if ((saddr->sa_family == AF_INET) &&
902 (ntohs(((
struct sockaddr_in*)saddr)->sin_port) ==
MDNS_PORT))
904 else if ((saddr->sa_family == AF_INET6) &&
905 (ntohs(((
struct sockaddr_in6*)saddr)->sin6_port) ==
MDNS_PORT))
909 uint16_t* data = (uint16_t*)buffer;
911 *data++ = htons(query_id);
926 *data++ = htons(type);
928 *data++ = htons(rclass);
930 ptrdiff_t tosend = (
char*)data - (
char*)buffer;
938 void* user_data,
int only_query_id) {
939 struct sockaddr_in6 addr;
940 struct sockaddr* saddr = (
struct sockaddr*)&addr;
942 memset(&addr, 0,
sizeof(addr));
944 saddr->sa_len =
sizeof(addr);
946 int ret = recvfrom(sock, (
char*)buffer, (
mdns_size_t)capacity, 0, saddr, &addrlen);
950 size_t data_size = (size_t)ret;
951 uint16_t* data = (uint16_t*)buffer;
953 uint16_t query_id = ntohs(*data++);
954 uint16_t flags = ntohs(*data++);
955 uint16_t questions = ntohs(*data++);
956 uint16_t answer_rrs = ntohs(*data++);
957 uint16_t authority_rrs = ntohs(*data++);
958 uint16_t additional_rrs = ntohs(*data++);
961 if ((only_query_id > 0) && (query_id != only_query_id))
969 for (i = 0; i < questions; ++i) {
970 size_t ofs = (size_t)((
char*)data - (
char*)buffer);
973 data = (uint16_t*)((
char*)buffer + ofs);
974 uint16_t rtype = ntohs(*data++);
975 uint16_t rclass = ntohs(*data++);
977 (
void)
sizeof(rclass);
994 mdns_query_answer(
int sock,
const void* address,
size_t address_size,
void* buffer,
size_t capacity,
995 uint16_t query_id,
const char* service,
size_t service_length,
996 const char* hostname,
size_t hostname_length, uint32_t ipv4,
const uint8_t* ipv6,
997 uint16_t port,
const char* txt,
size_t txt_length) {
998 if (capacity < (
sizeof(
struct mdns_header_t) + 32 + service_length + hostname_length))
1001 int unicast = (address_size ? 1 : 0);
1002 int use_ipv4 = (ipv4 != 0);
1003 int use_ipv6 = (ipv6 != 0);
1004 int use_txt = (txt && txt_length && (txt_length <= 255));
1008 uint32_t ttl = (unicast ? 10 : 60);
1009 uint32_t a_ttl = ttl;
1014 header->
flags = htons(0x8400);
1015 header->
questions = htons(unicast ? 1 : 0);
1018 header->
additional_rrs = htons((
unsigned short)(1 + use_ipv4 + use_ipv6 + use_txt));
1022 size_t remain, service_offset = 0, local_offset = 0, full_offset, host_offset;
1027 remain = capacity - service_offset;
1031 if (!data || (remain <= 4))
1034 udata = (uint16_t*)data;
1036 *udata++ = htons(question_rclass);
1047 remain = capacity - service_offset;
1052 if (!data || (remain <= 10))
1054 udata = (uint16_t*)data;
1056 *udata++ = htons(rclass);
1057 *(uint32_t*)udata = htonl(ttl);
1059 uint16_t* record_length = udata++;
1063 remain = capacity - full_offset;
1066 if (!data || (remain <= 10))
1074 if (!data || (remain <= 10))
1076 udata = (uint16_t*)data;
1078 *udata++ = htons(rclass);
1079 *(uint32_t*)udata = htonl(ttl);
1081 record_length = udata++;
1082 *udata++ = htons(0);
1083 *udata++ = htons(0);
1084 *udata++ = htons(port);
1088 remain = capacity - host_offset;
1091 if (!data || (remain <= 10))
1099 if (!data || (remain <= 14))
1101 udata = (uint16_t*)data;
1103 *udata++ = htons(rclass);
1104 *(uint32_t*)udata = htonl(a_ttl);
1106 *udata++ = htons(4);
1107 *(uint32_t*)udata = ipv4;
1117 if (!data || (remain <= 26))
1119 udata = (uint16_t*)data;
1121 *udata++ = htons(rclass);
1122 *(uint32_t*)udata = htonl(a_ttl);
1124 *udata++ = htons(16);
1125 memcpy(udata, ipv6, 16);
1134 if (!data || (remain <= (11 + txt_length)))
1136 udata = (uint16_t*)data;
1138 *udata++ = htons(rclass);
1139 *(uint32_t*)udata = htonl(ttl);
1141 *udata++ = htons((
unsigned short)(txt_length + 1));
1142 char* txt_record = (
char*)udata;
1143 *txt_record++ = (char)txt_length;
1144 memcpy(txt_record, txt, txt_length);
1158 char* strbuffer,
size_t capacity) {
1160 if ((size >= offset + length) && (length >= 2))
1168 char* strbuffer,
size_t capacity) {
1177 if ((size >= offset + length) && (length >= 8)) {
1178 const uint16_t* recorddata = (
const uint16_t*)((
const char*)buffer + offset);
1179 srv.
priority = ntohs(*recorddata++);
1180 srv.
weight = ntohs(*recorddata++);
1181 srv.
port = ntohs(*recorddata++);
1188 static struct sockaddr_in*
1190 struct sockaddr_in* addr) {
1191 memset(addr, 0,
sizeof(
struct sockaddr_in));
1192 addr->sin_family = AF_INET;
1194 addr->sin_len =
sizeof(
struct sockaddr_in);
1196 if ((size >= offset + length) && (length == 4))
1197 addr->sin_addr.s_addr = *(
const uint32_t*)((
const char*)buffer + offset);
1201 static struct sockaddr_in6*
1203 struct sockaddr_in6* addr) {
1204 memset(addr, 0,
sizeof(
struct sockaddr_in6));
1205 addr->sin6_family = AF_INET6;
1207 addr->sin6_len =
sizeof(
struct sockaddr_in6);
1209 if ((size >= offset + length) && (length == 16))
1210 addr->sin6_addr = *(
const struct in6_addr*)((
const char*)buffer + offset);
1218 const char* strdata;
1219 size_t separator, sublength;
1220 size_t end = offset + length;
1225 while ((offset < end) && (parsed < capacity)) {
1226 strdata = (
const char*)buffer + offset;
1227 sublength = *(
const unsigned char*)strdata;
1230 offset += sublength + 1;
1233 for (
size_t c = 0; c < sublength; ++c) {
1235 if ((strdata[c] < 0x20) || (strdata[c] > 0x7E))
1237 if (strdata[c] ==
'=') {
1246 if (separator < sublength) {
1247 records[parsed].
key.
str = strdata;
1249 records[parsed].
value.
str = strdata + separator + 1;
1250 records[parsed].
value.
length = sublength - (separator + 1);
1252 records[parsed].
key.
str = strdata;