<feed xmlns='http://www.w3.org/2005/Atom'>
<title>mdnsd, branch master</title>
<subtitle>OpenWrt MDNS daemon</subtitle>
<id>https://git-03.infra.openwrt.org/project/mdnsd/atom?h=master</id>
<link rel='self' href='https://git-03.infra.openwrt.org/project/mdnsd/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/'/>
<updated>2026-10-04T16:21:00Z</updated>
<entry>
<title>tests: add fuzz corpus entry for the dns_query() AVL walk</title>
<updated>2026-10-04T16:21:00Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-10-04T16:05:21Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=defe7ccfd20281b9ef4dfa45437813386a64f8ba'/>
<id>urn:sha1:defe7ccfd20281b9ef4dfa45437813386a64f8ba</id>
<content type='text'>
A single mDNS response with the PTR answer
_http._tcp.local -&gt; myweb._http._tcp.local makes cache_refresh_service()
queue myweb.local for TYPE_A and then TYPE_AAAA. That entry sorts last
in the queries tree, so the TYPE_AAAA lookup steps past the end of the
tree.

Without "dns: bound dns_query() AVL walk with avl_is_last()" both
dhpf-san and test-fuzz abort on this input with an AddressSanitizer
global-buffer-overflow 10 bytes after the queries global, in the
strcmp() in dns_query(). With it the input is processed cleanly.

Assisted-by: Claude:claude-opus-5-5
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>tests: stub the udebug helpers</title>
<updated>2026-10-04T16:20:56Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-10-04T16:05:14Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=5b9638a1363198cc414500d0c37a00708b37c141'/>
<id>urn:sha1:5b9638a1363198cc414500d0c37a00708b37c141</id>
<content type='text'>
umdns_udebug_printf() and umdns_udebug_config() are defined in main.c,
which the test tools replace with their own main(). cache.c and ubus.c
reference them, so dhpf, dhpf-san and test-fuzz fail to link with
undefined references.

Provide empty stubs next to the existing cfg_proto and cfg_no_subnet
ones; the tests do not need udebug logging.

Fixes: b1e023eda358 ("add udebug support")
Assisted-by: Claude:claude-opus-5-5
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>dns: include stdbool.h in dns.h</title>
<updated>2026-10-04T16:20:50Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-10-04T16:05:10Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=e035293d1d2b3d6eb562d0b954b1da8942be2b04'/>
<id>urn:sha1:e035293d1d2b3d6eb562d0b954b1da8942be2b04</id>
<content type='text'>
dns.h declares dns_packet_question() and dns_packet_send() with bool
but does not include stdbool.h, so it only compiles when the including
file happens to pull it in first. The test tools include dns.h before
anything else and fail to build with "unknown type name 'bool'".

Include stdbool.h in the header that uses it.

Fixes: ca9b8765aea3 ("dns: rework packet API")
Assisted-by: Claude:claude-opus-5-5
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>interface: compare full IPv6 address in source check</title>
<updated>2026-10-04T16:20:46Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-09-29T22:43:01Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=126426e66e19a6e7006ed8ae00dd73a495482bab'/>
<id>urn:sha1:126426e66e19a6e7006ed8ae00dd73a495482bab</id>
<content type='text'>
read_socket6() validates the packet source against each configured
interface address via interface_valid_src(), but passed a length of 6
where an IPv6 address is 16 bytes, so the subnet comparison only looked
at the first 6 bytes of the address and mask. The IPv4 path correctly
passes 4. Only link-local addresses are stored, which share the first
bytes, so the practical effect is limited, but the check should cover the
whole address.

Fixes: 4035fe42df58 ("interface: use a global socket instead of per-interface ones")
Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>dns: reset packet after each batch in dns_query_pending()</title>
<updated>2026-10-04T16:20:41Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-09-29T22:42:46Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=e115784cb334dd80361c17ca7cc9efd45eb63853'/>
<id>urn:sha1:e115784cb334dd80361c17ca7cc9efd45eb63853</id>
<content type='text'>
dns_query_pending() flushes queued questions in batches of
QUERY_BATCH_SIZE, calling dns_packet_broadcast() once a batch fills. That
helper only sends the packet; it does not reset it. Because the packet is
initialised only once before the loop, questions from an already-sent
batch stay in the buffer and are broadcast again with the next batch.

This is not an overflow (dns_query() drains the queue past 16 entries, so
at most 17 questions are ever pending and pkt_q[32] is never exceeded),
only redundant traffic. Re-init the packet after each mid-loop broadcast
so every question is sent once.

Fixes: 0ce73d80dc0c ("dns: add cache/queue for outgoing queries")
Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>service: validate txt entries and stop leaking on empty ones</title>
<updated>2026-10-04T16:20:36Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-09-29T22:42:21Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=ba53b7c932e8bbf0bfceef5f92f8a7b7717f2c33'/>
<id>urn:sha1:ba53b7c932e8bbf0bfceef5f92f8a7b7717f2c33</id>
<content type='text'>
service_load_blob() sizes the txt buffer in one pass over the SERVICE_TXT
array and fills it in a second, both via blobmsg_get_string(). Two
problems:

  - The array elements are never type-checked, so a non-string item
    (e.g. "txt":[1234] in a procd service description or an
    /etc/umdns/*.json file) makes blobmsg_get_string()/strlen() read past
    a 4-byte integer attribute.

  - The fill pass did "if (!len) return;" on the first empty string,
    which leaks the service struct allocated just above and, because the
    sizing pass had counted a byte for that entry, could also have left
    part of the txt buffer uninitialised.

Reject the whole txt list unless every element is a string, and make
both passes agree: skip empty entries and clamp over-long ones
identically so the allocation matches what is written, with no early
return.

Fixes: aee2d5582e56 ("load service info from procd")
Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>dns: handle missing unicast interface in parse_question()</title>
<updated>2026-10-04T16:20:31Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-09-29T22:40:53Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=5dc24e8c80d97fb7985d24a4c8edc97dabd58ebe'/>
<id>urn:sha1:5dc24e8c80d97fb7985d24a4c8edc97dabd58ebe</id>
<content type='text'>
For a question with the unicast-response (QU) bit set, parse_question()
looks up the unicast twin of the receiving interface with
interface_get(), which returns NULL when that socket does not exist, for
example when __interface_add() failed to create or bind SOCK_UC_* while
the multicast interface stayed up. The result is used unconditionally by
dns_reply_a() (iface-&gt;name) and dns_packet_send() (interface_send_packet),
so a network question then dereferences NULL and crashes the daemon.

Return early when the unicast interface is missing.

Fixes: 4035fe42df58 ("interface: use a global socket instead of per-interface ones")
Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>service: initialise SRV priority and weight</title>
<updated>2026-10-04T16:20:26Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-09-29T22:40:33Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=93b2903c92f86ed160d76e6afda8b6e154f22176'/>
<id>urn:sha1:93b2903c92f86ed160d76e6afda8b6e154f22176</id>
<content type='text'>
service_add_srv() overlays struct dns_srv_data on mdns_buf and writes
only the port field, so priority and weight carry whatever mdns_buf
held before. Its only caller, service_reply_single(), has just
dn_comp()'d the service instance name into mdns_buf via
service_add_ptr(), so every SRV answer advertises the first four bytes
of that encoded name as priority and weight (1871 and 28773 for an
instance called "OpenWrt"). Older buffer content reaches the wire only
if that dn_comp() fails.

Set both to zero, as RFC 6763 section 5 recommends for a service
described by a single SRV record.

Fixes: cef25024bc6d ("fix excessive stack usage")
Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>ubus: bound TXT copy in umdns_announcements()</title>
<updated>2026-10-04T16:20:21Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-09-29T22:40:02Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=4d3628f8634eae96978286640ff55256b84f7004'/>
<id>urn:sha1:4d3628f8634eae96978286640ff55256b84f7004</id>
<content type='text'>
s-&gt;txt is a packed sequence of length-prefixed strings with no NUL
terminator after the last one. umdns_announcements() copied each entry
with strlcpy(buf, &amp;s-&gt;txt[txt_offset], len + 1), but strlcpy() walks the
source for its full strlen() to compute the return value, so it keeps
reading past the end of the txt allocation until it happens on a zero
byte. The claimed length prefix is also never checked against the bytes
that actually remain in the buffer.

Copy exactly the advertised number of bytes with memcpy(), terminate the
destination explicitly, and skip a length prefix that runs past the end
of the record. Only len bytes were ever emitted, so this is an
out-of-bounds read with no disclosure, reachable by a local ubus caller
of "umdns announcements" whenever a service has TXT entries.

Fixes: 695ac3708aa0 ("ubus: fix ubus announcements txt fields")
Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
<entry>
<title>dns,interface: guard against NULL ifa_addr and getifaddrs() failure</title>
<updated>2026-10-04T16:20:16Z</updated>
<author>
<name>Hauke Mehrtens</name>
</author>
<published>2026-09-29T22:39:34Z</published>
<link rel='alternate' type='text/html' href='https://git-03.infra.openwrt.org/project/mdnsd/commit/?id=7aa74cc1239fc2b69a43dba8f964c910ea9c18e7'/>
<id>urn:sha1:7aa74cc1239fc2b69a43dba8f964c910ea9c18e7</id>
<content type='text'>
The getifaddrs() enumeration loops in interface_add() and in the three
dns_reply_* helpers dereference ifa-&gt;ifa_addr without a NULL check and
ignore the getifaddrs() return value entirely. On musl (OpenWrt libc)
getifaddrs() only fills in ifa_addr for link entries that carry an
IFLA_ADDRESS; WireGuard and tun interfaces have none, so their entry has
ifa_addr == NULL and reading ifa_addr-&gt;sa_family crashes.

Configuring such an interface (ubus call umdns set_config with e.g. a
wg0 member) crashes umdns in interface_add(). Once one is configured, a
network A/AAAA/ANY or reverse-PTR query drives the crash through
dns_reply_a() / dns_reply_reverse_ip*_mapping(). If getifaddrs() itself
fails, ifap is left uninitialised and the loop walks a garbage pointer
that is then handed to freeifaddrs().

Bail out when getifaddrs() fails and skip entries without an address.

Fixes: 338143f9d158 ("properly announce all ips of an interface when asked")
Fixes: 891447c1a9db ("interface.c cleanup")
Fixes: 2b28094d31ca ("dns: add support for reverse address mapping queries")
Assisted-by: Claude:claude-opus-4-8
Link: https://github.com/openwrt/mdnsd/pull/37
Signed-off-by: Hauke Mehrtens &lt;hauke@hauke-m.de&gt;
</content>
</entry>
</feed>
