Skip to content

Fix #255: do not treat an all zero MAC as a host identity - #319

Open
quadseven wants to merge 1 commit into
XITRIX:masterfrom
quadseven:fix/255-reject-null-mac
Open

Fix #255: do not treat an all zero MAC as a host identity#319
quadseven wants to merge 1 commit into
XITRIX:masterfrom
quadseven:fix/255-reject-null-mac

Conversation

@quadseven

Copy link
Copy Markdown

Fixes #255.

The bug

A host is not required to report a MAC. Sunshine answers serverinfo with
00:00:00:00:00:00 when it cannot work out its own. Every guard in the
codebase tested for a MAC with !mac.empty(), and an all zero MAC passes
that, so the placeholder was accepted as a real identity in five separate
places.

Here is the relevant part of a real settings.json from a Switch paired to a
Sunshine host:

{ "address": "10.0.0.x", "hostname": "...", "mac": "00:00:00:00:00:00", ... }

Wake-on-LAN, which is #255. normalize_mac_address() turns
00:00:00:00:00:00 into twelve valid hex digits, so can_wake_up_host()
returns true. The user is offered the wake action, a well formed magic packet
is built and broadcast, and it is addressed to a MAC that belongs to nothing.
Nothing wakes, no error is shown, and there is nothing for the user to see.

Host identity. hosts_match() early returns:

if (!lhs.mac.empty() && !rhs.mac.empty())
    return lhs.mac == rhs.mac;

Two different hosts that both report the placeholder compare equal here and
never reach the address comparison below. Add a second Sunshine host and it
merges into the first instead of being added as its own entry.

host_key() has the same problem, and keys m_active_addresses on
"mac:00:00:00:00:00:00", so the resolved address of one host can be served
for a different one.

Forwarders. forwarder_maker.cpp emitted --host=00:00:00:00:00:00
instead of falling back to --ip=<address>, producing a forwarder that cannot
find the host it was made for.

The change

Add is_usable_mac() next to hosts_match() in Settings.hpp. It accepts a
MAC only if it parses as hex and contains at least one nonzero digit, and it
tolerates the usual separators.

Use it at every site that was testing !mac.empty() to mean "this identifies
a host":

  • hosts_match()
  • merge_host() and Settings::add_host()
  • host_key() and merge_discovered_host() in GameStreamClient.cpp
  • the host merge in DiscoverManager.cpp
  • the forwarder argument builder in forwarder_maker.cpp

normalize_mac_address() in WakeOnLanManager.cpp rejects the all zero case
as well, so can_wake_up_host() stops advertising an action that cannot work,
and the existing "Missing or invalid host MAC address" in wake_up_host()
becomes accurate rather than unreachable.

With no usable MAC, all of these fall through to the address based paths that
were already there, which is the behaviour hosts without a MAC field already
got.

The mac.empty() checks in main_args.cpp are deliberately left alone. Those
ask whether the user supplied an argument at all, which is a different
question.

Testing

  • Switch build is green through the repo's own devkitPro workflow, with
    Settings.o, GameStreamClient.o, WakeOnLanManager.o,
    DiscoverManager.o and forwarder_maker.o all rebuilt and the NRO
    produced.
  • Unit tested the predicate over: the empty string, the all zero MAC in colon,
    dash and bare forms, an ordinary MAC, a MAC with a leading zero octet, a
    value whose only nonzero digit is last, the broadcast address, and non hex
    input. All ten cases behave as intended.

On-console confirmation that the wake action now correctly disappears for a
Sunshine host reporting a null MAC is in progress, and I will report back.

A host is not required to report a MAC. Sunshine answers serverinfo with
00:00:00:00:00:00 when it cannot determine its own, and every guard in the
codebase tested that with !mac.empty(), which an all zero MAC passes. So the
placeholder was accepted as a real identity in five separate places.

Wake-on-LAN (XITRIX#255): normalize_mac_address() turns 00:00:00:00:00:00 into
twelve valid hex digits, so can_wake_up_host() returns true, the user is
offered the wake action, and a well formed magic packet is broadcast to a
MAC that belongs to nothing. It fails silently, with no error and nothing
to see.

Host identity: hosts_match() early returns

    if (!lhs.mac.empty() && !rhs.mac.empty())
        return lhs.mac == rhs.mac;

so two different hosts that both report the placeholder compare equal and
never reach the address comparison below. Add a second Sunshine host and it
merges into the first instead of being added. host_key() has the same
problem and keys the m_active_addresses cache on "mac:00:00:00:00:00:00",
so the resolved address of one host is served for another.

Forwarders: forwarder_maker.cpp emitted --host=00:00:00:00:00:00 rather
than falling back to --ip=<address>, producing a forwarder that cannot
find its host.

Add is_usable_mac(), which accepts a MAC only if it parses as hex and has
at least one nonzero digit, and use it at every site that was testing
!mac.empty() for identity: hosts_match(), merge_host(), add_host(),
host_key(), merge_discovered_host(), DiscoverManager's merge, and the
forwarder argument builder. normalize_mac_address() rejects the all zero
case too, so can_wake_up_host() stops advertising an action that cannot
work and wake_up_host()'s existing "Missing or invalid host MAC address"
becomes accurate.

The empty() checks in main_args.cpp are left alone. Those ask whether the
user supplied an argument at all, which is a different question.

Verified with a unit test over the predicate covering the empty string, the
all zero MAC in colon, dash and bare forms, an ordinary MAC, a MAC with a
leading zero octet, and non hex input.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WoL doesn't work

1 participant