Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

network interface selector, eliminate localhost mDNS advertisements #258

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/Device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { GeneralCommissioningCluster, RegulatoryLocationType } from "./matter/cl
import { OperationalCredentialsCluster } from "./matter/cluster/OperationalCredentialsCluster";
import { DEVICE } from "./matter/common/DeviceTypes";
import { MdnsBroadcaster } from "./matter/mdns/MdnsBroadcaster";
import { commandExecutor } from "./util/CommandLine";
import { commandExecutor, getParameter } from "./util/CommandLine";
import { OnOffCluster } from "./matter/cluster/OnOffCluster";
import { GeneralCommissioningClusterHandler } from "./matter/cluster/server/GeneralCommissioningServer";
import { OperationalCredentialsClusterHandler } from "./matter/cluster/server/OperationalCredentialsServer";
Expand All @@ -51,9 +51,12 @@ import { CertificationDeclarationManager } from "./matter/certificate/Certificat
const logger = Logger.get("Device");

class Device {

vves marked this conversation as resolved.
Show resolved Hide resolved

async start() {
logger.info(`node-matter@${packageJson.version}`);

const broadcastInterface = getParameter("broadcastInterface");
const deviceName = "Matter test device";
const deviceType = 257 /* Dimmable bulb */;
const vendorName = "node-matter";
Expand Down Expand Up @@ -88,7 +91,7 @@ class Device {
.addNetInterface(await UdpInterface.create(5540, "udp4"))
.addNetInterface(await UdpInterface.create(5540, "udp6"))
.addScanner(await MdnsScanner.create())
.addBroadcaster(await MdnsBroadcaster.create())
.addBroadcaster(await MdnsBroadcaster.create(broadcastInterface))
.addProtocolHandler(secureChannelProtocol)
.addProtocolHandler(new InteractionServer()
.addEndpoint(0x00, DEVICE.ROOT, [
Expand Down
5 changes: 3 additions & 2 deletions src/matter/mdns/MdnsBroadcaster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { AAAARecord, ARecord, PtrRecord, Record, SrvRecord, TxtRecord } from "../../codec/DnsCodec";
import { AAAARecord, ARecord, PtrRecord, SrvRecord, TxtRecord } from "../../codec/DnsCodec";
import { Crypto } from "../../crypto/Crypto";
import { Broadcaster } from "../common/Broadcaster";
import { getDeviceMatterQname, getFabricQname, MATTER_COMMISSION_SERVICE_QNAME, MATTER_SERVICE_QNAME, SERVICE_DISCOVERY_QNAME } from "./MdnsConsts";
Expand All @@ -30,7 +30,7 @@ export class MdnsBroadcaster implements Broadcaster {
) {}

setCommissionMode(mode: number,deviceName: string, deviceType: number, vendorId: VendorId, productId: number, discriminator: number) {
logger.debug(`announce commissioning mode ${mode} ${deviceName} ${deviceType} ${vendorId} ${productId} ${discriminator}`);
logger.debug(`announce commissioning mode ${mode} ${deviceName} ${deviceType} ${vendorId.id} ${productId} ${discriminator}`);

const shortDiscriminator = (discriminator >> 8) & 0x0F;
const instanceId = Crypto.getRandomData(8).toHex().toUpperCase();
Expand All @@ -46,6 +46,7 @@ export class MdnsBroadcaster implements Broadcaster {
if (ipMac === undefined) return [];
const { mac, ips } = ipMac;
const hostname = mac.replace(/:/g, "").toUpperCase() + "0000.local";
logger.debug(`${netInterface} on IP Addrs: ${ips.join(", ")} host: ${hostname}`)
const records = [
PtrRecord(SERVICE_DISCOVERY_QNAME, MATTER_COMMISSION_SERVICE_QNAME),
PtrRecord(SERVICE_DISCOVERY_QNAME, vendorQname),
Expand Down
8 changes: 5 additions & 3 deletions src/net/node/NetworkNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { networkInterfaces, NetworkInterfaceInfo } from "os";
import { UdpChannelOptions, UdpChannel } from "../UdpChannel";
import { UdpChannelNode } from "./UdpChannelNode";
import { Network } from "../Network";
import { onSameNetwork } from "../../util/Ip.js";
import { isMatterAddressableIPv6Address, onSameNetwork } from "../../util/Ip.js";
import { Cache } from "../../util/Cache.js";

export class NetworkNode extends Network {
Expand Down Expand Up @@ -38,7 +38,7 @@ export class NetworkNode extends Network {
(ip: string) => this.getNetInterfaceForIpInternal(ip),
5 * 60 * 1000, /* 5mn */
)

private static getNetInterfaceForIpInternal(ip: string) {
if (ip.indexOf("%") !== -1) {
// IPv6 address with scope
Expand Down Expand Up @@ -72,7 +72,9 @@ export class NetworkNode extends Network {
getIpMac(netInterface: string): { mac: string; ips: string[]; } | undefined {
const netInterfaceInfo = networkInterfaces()[netInterface];
if (netInterfaceInfo === undefined) return undefined;
return { mac: netInterfaceInfo[0].mac, ips: netInterfaceInfo.map(({address}) => address) };
const ips = netInterfaceInfo.map(({address}) => address).filter(ip => isMatterAddressableIPv6Address(ip))
if (ips.length === 0) return undefined;
return { mac: netInterfaceInfo[0].mac, ips: ips };
vves marked this conversation as resolved.
Show resolved Hide resolved
}

override createUdpChannel(options: UdpChannelOptions): Promise<UdpChannel> {
Expand Down
16 changes: 15 additions & 1 deletion src/util/Ip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function iPv4ToNumber(ip: string) {
return dataView.getUint32(0);
}

export function iPv6ToArray(ip: string) {
export function iPv6ToArray(ip: string) : Uint16Array {
const array = new Uint16Array(8);
let ipParts = ip.split(":");
const valueCount = ipParts.filter(value => value !== "").length;
Expand Down Expand Up @@ -60,4 +60,18 @@ export function onSameNetwork(ip1: string, ip2: string, mask: string) {
if ((ip1Array[i] & mask) !== (ip2Array[i] & mask)) return false;
}
}
return false
vves marked this conversation as resolved.
Show resolved Hide resolved
}


/**
* return true if ipV6 address meets the Matter Spec to advertise in MDNS
* filter out IPv6 Loopback addresses - fe80 - for obvious reasons
*/
export function isMatterAddressableIPv6Address(targetIpAddr: string): boolean {
return !(
targetIpAddr.toLowerCase().startsWith("fe80") ||
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vves Hm ... why you now sort out link local too? fe80 are all link locals ... why not announce them? In my eyes they are valid

Copy link
Contributor Author

@vves vves Mar 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have come to the conclusion based on empirical testing and the spec that while fe80 is valid, it is NOT valid when it's the ONLY address on an interface. The larger issue that I have come across is that if an interface only provides on they IPV6 fe80 address the HomeApp and SmartThings will not resolve the endpoint. The solution is to validate a network interface provides at least ONE valid IPv6 address that is not a loopback address or IPv4 Address, but NOT remove the loopback and IPv4 Addresses. If there is not at least one Matter addressable IPv6 address, the library should not advertise that interface.

Below is the list from my test machine. Only the en0 interface is addressable from HomeApp or SmartThings.

This function is valid for as named, but the use of it needs to be in conjuntion with a network interface validator.

2023-03-15 09:39:46.336 DEBUG MdnsBroadcaster anpi0 on IP Addrs: fe80::5082:3eff:fe47:1cdc host: 52823E471CDC0000.local
2023-03-15 09:39:46.336 DEBUG MdnsBroadcaster anpi2 on IP Addrs: fe80::5082:3eff:fe47:1cde host: 52823E471CDE0000.local
2023-03-15 09:39:46.337 DEBUG MdnsBroadcaster en0 on IP Addrs: fe80::85e:cc32:9f1:c265, fd69:48a4:185f:1:10eb:e991:a821:617e, 2601:285:500:bf9:14a5:cb4d:2f38:873f, 2601:285:500:bf9:3885:23da:3b72:902d, fd68:9b7f:6836:44cd:25:de98:15d:375c, 10.0.10.145 host: F02F4B09EDFA0000.local
2023-03-15 09:39:46.337 DEBUG MdnsBroadcaster awdl0 on IP Addrs: fe80::80ab:7dff:fe1a:4df host: 82AB7D1A04DF0000.local
2023-03-15 09:39:46.338 DEBUG MdnsBroadcaster llw0 on IP Addrs: fe80::80ab:7dff:fe1a:4df host: 82AB7D1A04DF0000.local
2023-03-15 09:39:46.338 DEBUG MdnsBroadcaster utun0 on IP Addrs: fe80::9ae3:6419:5975:cc9 host: 0000000000000000.local
2023-03-15 09:39:46.339 DEBUG MdnsBroadcaster utun1 on IP Addrs: fe80::97e2:cfd3:445a:8763 host: 0000000000000000.local
2023-03-15 09:39:46.339 DEBUG MdnsBroadcaster utun2 on IP Addrs: fe80::ce81:b1c:bd2c:69e host: 0000000000000000.local
2023-03-15 09:39:46.340 DEBUG MdnsBroadcaster utun3 on IP Addrs: fe80::e81a:e66d:611a:b465 host: 0000000000000000.local
2023-03-15 09:39:46.340 DEBUG MdnsBroadcaster utun4 on IP Addrs: fe80::5120:d18f:4b0e:ed81 host: 0000000000000000.local
2023-03-15 09:39:46.341 DEBUG MdnsBroadcaster utun5 on IP Addrs: fe80::1c2a:4bb3:bf2:39b4 host: 0000000000000000.local
2023-03-15 09:39:46.341 DEBUG MdnsBroadcaster utun6 on IP Addrs: fe80::557c:6550:d754:c9c host: 0000000000000000.local
2023-03-15 09:39:46.341 DEBUG MdnsBroadcaster utun7 on IP Addrs: fe80::f4d0:e8d5:2bde:f628 host: 0000000000000000.local
2023-03-15 09:39:46.342 DEBUG MdnsBroadcaster utun8 on IP Addrs: fe80::b396:3357:d6aa:fd8e host: 0000000000000000.local```

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry but then I'm back to: How does your network structure looks like? Completely fine that you tested it on your side, but I can not reproduce this at all behaving that way and "Link local" adresses are valid and used when devices are on the same switch. please check your firewall settings not that you have any kind of firewall active that blpocks connections on the link local adress?

targetIpAddr.startsWith('::1') ||
targetIpAddr.startsWith('0::1') ||
targetIpAddr.startsWith('127.'))
}