daniel-2k / ioBroker.nanoleaf-lightpanels

ioBroker Adapter for nanoleaf Light Panels / Canvas
MIT License
11 stars 4 forks source link

Error: No ssdp:alive detected. Try to reconnect... since 1.0.1 version #16

Closed WernerRH21 closed 4 years ago

WernerRH21 commented 4 years ago

I am a big fan of your iobroker.nanoleaf-lightpanels adapter and it worked really fine, until I updated to version 1.0.1. Every 2 minutes approx., a warning entry „Error: No ssdp:alive detected. Try to reconnect...“ is added tot he iobroker log file. In the meantime, the canvas lightpanels switch correctly to „Power State: true“ when presence detection state is true. My Canvas are correctly installed with firmware 1.6.2. I really appreciate your help. Thanks so far. 2020-07-06 10_22_28-logs - ioBroker

Strunzdesign commented 4 years ago

Just noticed that my tcp dump command will not catch unicast traffic to that random port. Testing again...

Strunzdesign commented 4 years ago

No... there is just no related UDP reply traffic on the line. Seems that the nanoleaf adapter ignores that M-SEACH request.

daniel-2k commented 4 years ago

Yes, it's correct that it's a random port. This is the way the library implements it. The other library will also do it this way. The adapter should reply to this random port. Do you have a firewall enabled that maybe blocks traffic to this random port? In my environment my nanoleaf devices answers with both versions of the adapter. The change I've made since the last test is, that no specific interface is also not used for the msearch socket binding. Both is working for me. If you see the mesearch request message, then nanoleaf devices should reply. You do not get any message back which you can see in your sniffer? Can you ensure that the mesearch request is reaching the nanoleaf device? Then the only thing I can imagine is, as you say, that the device is simply not answering. Which nanoleaf device do you have? Should work for light panels and canvas (both I've tested). Maybe can you restart your nanoloeaf device and see if this works? The exprience shows that the nanoleaf controller is not very stable.

daniel-2k commented 4 years ago

If the MSEARCH-Request was send (I sent it with service type "ssdp:all") all your devices which supports SSDP/UPNP discovery should answer. Not only the nanoleafs. In my network I get very much answers (FritzBox, nanoleafs, Denon AV-Receiver, ...).

Strunzdesign commented 4 years ago

Okay another fault on my side: as the replies are sent as unicasts, it is not possible to sniff that traffic on a different PC as I did. I now restarted the tcpdump session on the ioBroker server / router binding to interface br0 directly. And that worked: I see multiple replies of my devices, including one of my Nanoleaf device. Thus, the M-SEARCH requests reach the Nanoleaf device, and a reply is sent back.

Ok, tcpdump "sees" the traffic, but I'm very sure that my firewall stops these replies. As the return port is (a) random and (b) that return port is not used by preceeding outgoing request traffic, these incoming replies are certainly dropped. They must be dropped! To get that to work properly with a firewall on the ioBroker server one has to be able to specify that UDP port number for the unicast replies as a config option in the adapter. Then, traffic directed to this UDP port can be allowed in the firewall.

Strunzdesign commented 4 years ago

Is it possible to re-use the already existing and already allowed (firewall) UDP port 1900 for the incoming unicast reply?

Strunzdesign commented 4 years ago

FYI: I'm away for about 1-2 weeks. After that I'm assisting you again.

daniel-2k commented 4 years ago

OK. But I will release the version 1.0.3 in this time. We can analyze this after your absence. Using also Port 1900 I can try, yes. But I think there is a reason why a random port is used. I think I multiple services on one host will make msearch request at the same time, it can maybe lead to problems if every service uses the same port. Because this is a unicast, normaly a service cannot bind multiple times to one port on a host. I know for the notify SSDP multicasts it works. But there my network know is not good enough.

Strunzdesign commented 4 years ago

I'm back and ready to test. And yes, you are right, a re-use of port 1900 is not a good idea as this data exchange is unicast. However, having a possibility to provide that return port number via the user interface should enable the adapter to work properly with a firewall.

daniel-2k commented 4 years ago

I think you have also problems with the ioBroker discovery adapter using UPNP to search devices. That's exact the same functionality. And the used SSDP lib there does it the same way. Most firewalls are application based so there are not problems (just allow node.js process incoming traffic). Can you set up your firewall to accept incoming traffic from any IP but from the specific UDP port 1900 to any port? This would also solve the problem.

Strunzdesign commented 4 years ago

That would be VERY dangerous, as an attacker just needs to bind to local port 1900 allowing him to access ANY UDP service on the destination host. This would render the whole point of having a firewall as a security measure useless.

Strunzdesign commented 4 years ago

And, what do you mean with application-based? Applications in terms of the internet protocol family are protocols residing above the transport layer. Thus, port numbers are usually the way to go to identify an application. If you mean "application" in terms of a process running on a system, I have no idea how one could dynamically extract the ports a process is bound to and inject the respective rules into the packet filter. This sounds really complex, hard to maintain, and hard to validate, especially for a server running crucial services such as a home automation framework.

That the ioBroker discovery adapter currently suffers from the same issue is a different story; at least is would not be a valid excuse to copy wrong implementations, given that the current behavior seems not to work if a firewall is present. I have to conduct more tests of the discover adapter, but to be honest, I never used it besides some short tests.

daniel-2k commented 4 years ago

I mean applications in terms of a process. That's the way every firewall for consumers (on Desktop PCs) controls the traffic by specifing processes. No one configures the firewall on a desktop PC by setting rules with IPs and ports (it's also possible but for the normal user too complicated). In this case the MESEARCH request is no problem because nodeJS process is configured to allow incoming traffic. You are working on a server environment with functionality of a router. Of course here we have professional firewalls which don't work with processes (that is also only possible on the local machine but not for Gateways). In the past I used a Microsoft Forefront TMG server as software firewall and router. And as I remember was UPNP a general problem in this environment. So the in-built UPNP function (for example in Windows) is working the same way. There you have not the possibility to specfiy a port. This whole UPNP stuff is only working fine in home networks with firewalls which filter traffic by application. I don't know how to use or configure it in other environments.

And what gives you the idea that the implementation is wrong and copied? That's the way it works.

Strunzdesign commented 4 years ago

Ok, I have to admit that my knowledge of Windows is... very limited. However, at least on GNU/Linux, I have never heard of such a firewall that is able to tie itself to a process, to monitor it, and adapt the firewall rules related to the behavior of that application (or, just "allow a given process"... how to specify such a process? By PID?). IMHO, most experts configure their firewall by directly invoking iptables commands in some startup script. Less efforts are required if an iptables frontend is used such as shorewall. Then I think that some distros bring their own frontends or rules for iptables, but the concept is always the same. Thus, I think that most of the GNU/Linux desktops still have no firewall at all, or "that firewall that the distro installs" without any user interaction. I never heard of such a "desktop firewall" in the GNU/Linux environment, but YMMV.

And, if you are right, and this is really "the way it works", then I have no clue how this can work in a GNU/Linux environment with a Netfilter-based firewall. Regardless of it's a server, a desktop, a raspberry, or whatever: no idea how I would get that UDP access scheme working without giving up a sane set of firewall rules. If this works in the Windows environment: fine. What do we do if this doesn't work in the GNU/Linux world? Of course, this would have impact on more than just this adapter...

Strunzdesign commented 4 years ago

According to https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol, can you please check if your Windows system opens a random port to receive the unicast UDP replies, or if it is one of the mentioned ports 2869 or 5000? I'm diving into the specs of SSDP now, just curious.

Strunzdesign commented 4 years ago

Ok, I have a test setup that works and that can help us here. This article gave me the hint that the return UDP port number for the unicasts can be 1900. Thus, I tested it with netcat, and just bound to port UDP 1900 using the command nc -u -l -p 1900. Then I waited until I received a first broadcast message to let netcat pick that "UDP association" up (think about a UDP "connect" to 239.255.255.250:1900). Then I copied an M-SEARCH message into the netcat shell (see below) and got the unicast responses of all my devices back! I performed this on my server/router where UDP port 1900 was already bound to by multiple multicast listeners! An that works fine! :-)

powerstation upnp # cat message.txt                                           
M-SEARCH * HTTP/1.1
Host:239.255.255.250:1900
ST:ssdp:all
Man:"ssdp:discover"
MX:2

Thus, it is not necessary that the adapter binds to a UDP port that the user specifies after opening it in his firewall. Just take your already existing multicast endpoint at UDP port 1900 (or take another one, which is fine as long as SO_REUSEADDR is set, which is!) and inject the M-SEARCH message via this endpoint. Then you can collect all unicast replies, maybe intertwined with some "cyclic" multicast NOTIFY messages that fly by. NOTIFY messages and answers to M-SEACH request should contain similar information; here on my system they are NOT equal, but they are very simular despite some details that really should not matter.

To conclude, mixing unicast and broadcast / multicast traffic with a local UDP port 1900 is possible, mentioned in the article above, and works here. This falsifies my previous statement that this mixing is not a good idea. In fact, this seems to be the way to go as it circumvents the firewall issue we discussed here.

Regards, Florian

Strunzdesign commented 4 years ago

A question regarding your experience with Windows and desktop firewalls: if you "allow" nodejs in your desktop firewall as you wrote, assuming you have a Windows server for your ioBroker setup, can you attach some rules to that? Such as "allow NodeJS, but only that NodeJS entity of ioBroker, not that of that other NodeJS entity of my other APP there that needs to be kept isolated. And please allow only port UDP 1900 on that local NIC, not on that VPN NIC". For a typical user the "easy" scheme may seem sufficient at first. But if you become more experienced (and start running crucial services), then I assume that you hit limits the earlier the easier the GUI to configure the firewall is. How is your experience with that?

daniel-2k commented 4 years ago

Hello Florian,

much text to read :-). I think the discussion about the firewall we can finish. On Windows you can also work like iptables on Linux by creating rules. But for the normal consumer it's too complicated. So, most firewalls (e.g. Windows built-in firewall, McAfee, Bitdefender firewall etc.) are mainly working with processes. And you only specify the executable. Not the pid. So, you cannot define which NodeJS process is enabled to communicate. All NodeJS processes are handled equal. But we a talking about two different environments. The first one is Desktop environment for most users, the other one is a server environment. I use Windows Server and use a mixed mode. For NodeJS I granted the NodeJS executable to allow incoming traffic. For other services I set up rules. Of course, on Linux environments (which are commonly used with ioBroker such Raspi) you have to use iptables as a basic packet filter. And I assume, I also don't know how to handle that in this case. I have to look on other projects how they handle this.

This what you mean with port 2869 or 5000 is only for event notification and event subscriptions. I ran wireshark and looked for msearches sent from Windows. Here also random ports are used.

Now to make a short story short. I released the version 1.0.3 and this is working good for you and in my development environment. But after releasing it I updated it on my productive ioBroker installation on my Windows Server and I noticed that the SSDP notifications are not received by the nanoleaf adapter. This has something to do with the interface binding which I changed in the version with my own fork of the nods-ssdp lib. On my server I need to bind to the interface which is determined by the ip.address() function. Otherwise I cannot receive the multicasts. So, I decided to implement an interface selection in the admin configuration page of the nanoleaf adapter. There you see all interfaces and you can select the correct one or 0.0.0.0 (bind to all). This is like in the webserver adapter or homematic adapter. The port for receiving the mesearch replies I will test to use also 1900. Maybe we can use another fixed port so you can easily configure your iptables.

daniel-2k commented 4 years ago

Short test with port 1900 as receiving port seems not to work. I cannot receive any answers in the node-ssdp listener. Other ports like 5000 or so will work.

daniel-2k commented 4 years ago

@Strunzdesign Now I released version 1.0.4 (first only on GitHub, after short testing I will push it into latest repo). I added interface selection and use not fixed port 5000 for mesearch replies. It's working on my windows environment. Please, can you test it in your environment? If you open port 5000 you should now receive the mesearch replies from nanoleaf. Hope it works.

Strunzdesign commented 4 years ago

Hi,

it works perfectly now! Without manually opening UDP port 5000 it fails, which is the expected behavior. But after allowing this port inbound for the LAN, clicking on the button reveals my Nanoleaf device. Great work! The temporary UDP listener looks sane as well. For me, it is now working correctly and "solved" :-) Thanks again for this great adapter and your patience solving this.

Regards, Florian

daniel-2k commented 4 years ago

Good to hear. Then I will close this issue.