Easing IoT device installation with clan.js
Locating things is a pain
A common reason why IoT devices rely on a cloud service is to ease the installation process. The problem is finding your IoT device on your LAN after you've got it connected to your WiFi. By both the device and the user going to a well-known location in the cloud, they can be connected. However, they can also be locked in and broken if the cloud shuts off.
Current Practices
You can usually find a device by looking at the DHCP leases on your router, but this is beyond the capabilities of most users. Another option is creating a custom app, but creating an app is kind of pain. A protocol like mDNS would be ideal, but it's not widely supported.
Mozilla has started to address this with Fly web, but it's only experimental, and only in FireFox.
A little shady
Awhile ago, I happened upon this site that shows you what all your browser can determine about you. The one that caught my attention most was the local IP and ability to scan your LAN.
Looking into it more, this is mainly enabled with some relatively new tech, called WebRTC. The biggest thing it provides, in this case, is the ability to learn your local LAN IP. From there, we have various means to then try to scan your local network.
I also happened upon sonar.js, a framework for finding exploitable devices on a user's LAN. It was close to what I wanted, but not quite.
Introducing clan.js: shady, but useful
So Clan.js provides a basic interface for learning about the web clients local LAN. The idea is that you have a well-known URL you can use to identify the device you're looking for. In your documentation, you reference a single URL in the cloud, that when visited, uses clan.js to scan the local client's LAN to find your device and take them to its web interface. It does have logic to make sure to only scan private RFC1918 address space.
The example.html in the source code is a much better example, that includes trying mDNS first, and also directing the user to their local router, if all else fails. You can imagine other implementations that might set a cookie for where the device was found last time, and trying that first.
function mdns_cb() {
window.location = "http://mydevice.local";
}
function mdns_done() {
clan.find("/r/all", found, find_done);
}
function router_cb(ip) {
document.getElementById('result').textContent = "Sorry, we couldn't find your device. Try this link to access your router";
document.getElementById("link").href = "http://" + ip;
document.getElementById('link').textContent = "http://" + ip;
}
function found(ip, type, content) {
data = JSON.parse(content);
if ('door_mode' in data && 'light_mode' in data) {
window.location = "http://" + ip;
}
}
function find_done(num) {
clan.router(router_cb);
}
clan.check_resource_exists("/r/all", "mydevice.local", mdns_cb, mdns_done);
Caveats
This library is still early on, but I welcome pull requests and feedback. Consider the following before using it:
- This isn't an ideal solution to the problem.
- It assumes a /24 LAN. Which for home users is probably correct. Hopefully corporate LAN folks would already know how to locate the device.
- A client running a port scan may light up some enterprise security tools, or worse, like get you disconnected from the network. It's a good idea to warn people before doing a network scan.
- Web browsers may eventually disable this or add permission controls to it.