pothosware / SoapyRemote

Use any Soapy SDR remotely
https://github.com/pothosware/SoapyRemote/wiki
Boost Software License 1.0
122 stars 22 forks source link

SoapySDRServer --bind doesn't listen on all IPs #59

Closed troffasky closed 5 years ago

troffasky commented 5 years ago

https://github.com/pothosware/SoapyRemote/wiki says "By default, the Soapy SDR server will bind to both IPv4 and IPv6 by default". Running SoapySDRServer --bind I find that clients are aware of the presence of the server on the network but can't connect to it:

[ERROR] SoapyRemote::find() -- connect(tcp://192.168.1.3:55132) FAIL: connect(tcp://192.168.1.3:55132) [111: Connection refused]

Looking at lsof, I see that SoapySDRServer is listening on 55132 but only on IPv6:

lsof -i -n | grep Soapy

SoapySDRS 9913 root 3u IPv6 73890223 0t0 TCP :55132 (LISTEN) SoapySDRS 9913 root 4u IPv4 73890225 0t0 UDP :1900 SoapySDRS 9913 root 5u IPv6 73890226 0t0 UDP *:1900

It is listening on port 1900 on both v4 and v6 which is perhaps where the confusion [on the client side] is coming from.

If I run "SoapySDRServer --bind=192.168.1.3:55132" to specifically bind to the v4 address, it listens on specified IP:port [although it still listens on *:1900]:

lsof -i -n | grep Soapy

SoapySDRS 28621 root 3u IPv4 71829139 0t0 TCP 192.168.1.3:55132 (LISTEN) SoapySDRS 28621 root 4u IPv4 71829141 0t0 UDP :1900 SoapySDRS 28621 root 5u IPv6 71829142 0t0 UDP :1900

and the client is able to connect to the discovered address.

I am not sure what the "real" problem is here; is the server sending its v4 address in the MDNS response, even though it's not actually listening on the v4 address? I don't think the server should be listening to MDNS on the v4 address if the server service isn't listening on the v4 address. I think the server should be listening on both ports on all IPs if no IP is passed to --bind.

I think the server should honour the --bind argument for both 1900 and 55132.

zuckschwerdt commented 5 years ago

I sometimes notice similar connection problems. If you use netstat (Debian net-tools package) you get

$ netstat -tulpn |grep Soapy
tcp6       0      0 :::55132                :::*                    LISTEN      1169/SoapySDRServer
udp        0      0 0.0.0.0:1900            0.0.0.0:*                           1169/SoapySDRServer
udp6       0      0 :::1900                 :::*                                1169/SoapySDRServer

the [::] address also supports IPv4. You can confirm this with e.g. socat tcp:REMOTEIP:55132 - which for me connects and shows the IPv4-mapped IPv6 address in the SoapyRemote output: SoapyServerListener::accept([::ffff:LOCALIP]:59523). Perhaps you can test that and see if the bind is really the problem?

troffasky commented 5 years ago

netstat output is analogous to that of lsof. It doesn't matter if I socat, telnet or use a Soapy client, it's not accepting connections on the IPv4 address unless I pass an argument to --bind when starting the server. When it is listening on IPv4, it shows the client's IPv4 address "normally" rather than as a pseudo IPv6 address.

guruofquality commented 5 years ago

The port 1900 stuff is SSDP, and there is also an avahi build option which will essentially do the same thing. It looks like calls to "registerService" for SSDP and MDNS do not respect the bind option if its only v4. So that should be fixed but its not the issue here.

By default the server binds to the unspecified address "::". And I think this is supposed to be the universal way to bind a tcp server to listen for ipv6 and v4 on all interfaces. For the life of this project, this is the first time I have heard of this. After-all, almost anyone using this has probably bound with no server args and connected via ipv4.

That said, when connecting with ipv4 when its bound to "::" I see prints like SoapyServerListener::accept([::ffff:192.168.1.242]:43492) whereas on ipv4 "0.0.0.0", its SoapyServerListener::accept(192.168.1.242:43630) So something about this pseudo-addressing, or whatever supports it, is broken for you -- and I would like to figure out why. Just to document the fix, or change the code accordingly.

Do you have anything interesting in ifconfig? What is your OS (linux flavor, version, etc)

Just curious, what happens when you bind normally (no options) and request to use an ipv6 address (https://github.com/pothosware/SoapyRemote/wiki#the-remoteipver-key) SoapySDRUtil --find="remote:ipver=6"

troffasky commented 5 years ago

Debian SID, kernel 4.19. The interface in use is "interesting" in the sense that it's a bridged interface but I doubt that would have any effect. Checking other listening services, apache2 listens "only" on v4 but definitely works for v4 and v6 clients. sshd listens on each and works with both.

troffasky commented 5 years ago

SoapySDRUtil --find="remote:ipver=6" ... Found device 2 available = Yes driver = remote label = Dexatek DK DVB-T Dongle (Logilink VG0002A) :: 00000991 manufacturer = Realtek product = DVB-T Dongle remote = tcp://[fe80::219:99ff:fef4:bbd3%10]:55132 remote:driver = rtlsdr rtl = 0 serial = 00000991 tuner = Fitipower FC0013

That IP is the link-local IP on the expected interface.

guruofquality commented 5 years ago

It looks like the trick to getting both ip versions to show in netstat is setting "IPV6_V6ONLY" on the socket for ipv6 and then binding another socket to v4. So without the special option and extra socket, netstat will only show tcp6, but it will support ipv4 normally.

Binding both IPV6_V6ONLY=1

tcp        0      0 0.0.0.0:55132           0.0.0.0:*               LISTEN     
tcp6       0      0 [::]:55132              [::]:*                  LISTEN   

ipv6 IPV6_V6ONLY = 0

tcp6       0      0 [::]:55132              [::]:*                  LISTEN

Major TCP based socket applications like SSH probably use two sockets and IPV6_V6ONLY to be portable on platforms without ipv4 mapped ipv6 addresses (like OpenBSD). That said, I'm not sure why IPv4-mapped IPv6 is broken for you.

Perhaps its turned off, can you check sysctl? On Linux systems, address mapping is controlled by a sysctl knob called net.ipv6.bindv6only; it is set to zero (enabling address mapping) by default.

Other references:

troffasky commented 5 years ago

Well, whaddya know...sysctl net.ipv6.bindv6only=0 is the fix! Clients are now shown as v6-mapped-v4 addresses as well. Seems like I have an /etc/sysctl.d/bindv6only.conf and according to this: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=560238 this was briefly the default in Debian Testing in 2009.