diff --git a/src/netbrowse/browse.go b/src/netbrowse/browse.go index 0cf74f21..018db4e6 100644 --- a/src/netbrowse/browse.go +++ b/src/netbrowse/browse.go @@ -58,6 +58,9 @@ func scan() map[string][]Service { } hosts := make(map[string][]Service) + vvHosts := make(map[string]bool) // has vv=1 TXT record + legHosts := make(map[string]bool) // has on=Infix TXT record (legacy) + mgmtHosts := make(map[string]bool) // has at least one management service type for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { if line == "" { @@ -88,17 +91,28 @@ func scan() map[string][]Service { displayName = serviceType } - // Parse TXT records for path= and adminurl= + // vv=1 is the platform marker set by confd/services.c, survives OS + // rebranding. We require it together with a management service type + // (ssh, web, netconf, restconf) to avoid false positives from Apple + // devices, which also use vv=1 in their AirPlay/RAOP TXT records. + // on=Infix is kept as a fallback for older firmware predating vv=1. + if known { + mgmtHosts[link] = true + } + + // Parse TXT records var path, adminurl string for _, record := range strings.Split(txt, " ") { stripped := strings.Trim(record, "\"") - if strings.Contains(stripped, "path=") { + switch { + case stripped == "vv=1": + vvHosts[link] = true + case stripped == "on=Infix": + legHosts[link] = true + case path == "" && strings.Contains(stripped, "path="): path = stripped[strings.LastIndex(stripped, "path=")+5:] - break - } - if strings.Contains(stripped, "adminurl=") { + case adminurl == "" && strings.Contains(stripped, "adminurl="): adminurl = stripped[strings.LastIndex(stripped, "adminurl=")+9:] - break } } @@ -148,6 +162,16 @@ func scan() map[string][]Service { }) } + // Default view shows only Infix devices. A host qualifies if it has + // vv=1 on a management service (to exclude Apple AirPlay collisions), + // or on=Infix for older firmware that predates vv=1. + for link := range hosts { + if len(hosts[link]) > 0 { + isInfix := (vvHosts[link] && mgmtHosts[link]) || legHosts[link] + hosts[link][0].Other = !isInfix + } + } + return hosts } diff --git a/utils/libll.sh b/utils/libll.sh index c400d1f3..5698e765 100644 --- a/utils/libll.sh +++ b/utils/libll.sh @@ -204,12 +204,13 @@ llscan_mdns() avahi-browse $flags 2>/dev/null | awk -F';' -v show_all="$all" ' $1 == "=" { - host = $7 + host = $7 proto = $3 - addr = $8 - txt = $10 + addr = $8 + stype = $5 + txt = $10 - on = ""; ov = ""; product = ""; devid = "" + on = ""; ov = ""; product = ""; devid = ""; vv = "" n = split(txt, parts, "\" \"") for (i = 1; i <= n; i++) { gsub(/"/, "", parts[i]) @@ -217,9 +218,17 @@ llscan_mdns() else if (parts[i] ~ /^ov=/) { split(parts[i], kv, "="); ov = kv[2] } else if (parts[i] ~ /^product=/) { split(parts[i], kv, "="); product = kv[2] } else if (parts[i] ~ /^deviceid=/) { split(parts[i], kv, "="); devid = kv[2] } + else if (parts[i] ~ /^vv=/) { split(parts[i], kv, "="); vv = kv[2] } } - if (!show_all && on != "Infix") next + # vv=1 is the platform marker set by confd/services.c, survives OS rebranding. + # We require it together with a management service type to avoid false + # positives from Apple devices, which also use vv=1 in AirPlay/RAOP records. + # on=Infix is kept as a fallback for older firmware that predates vv=1. + mgmt = (stype == "_ssh._tcp" || stype == "_sftp-ssh._tcp" || \ + stype == "_https._tcp" || stype == "_http._tcp" || \ + stype == "_netconf-ssh._tcp" || stype == "_restconf-tls._tcp") + if (!show_all && !(vv == "1" && mgmt) && on != "Infix") next # Use deviceid (MAC) as unique key; fall back to hostname key = devid ? devid : host