Closed troffasky closed 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?
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.
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"
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.
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.
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:
https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/rzab6/xacceptboth.htm
/********************************************************************/
/* After the socket descriptor is created, a bind() function gets a */
/* unique name for the socket. In this example, the user sets the */
/* address to in6addr_any, which (by default) allows connections to */
/* be established from any IPv4 or IPv6 client that specifies port */
/* 3005. (that is, the bind is done to both the IPv4 and IPv6 TCP/IP */
/* stacks). This behavior can be modified using the IPPROTO_IPV6 */
/* level socket option IPV6_V6ONLY if required. */
/********************************************************************/
I believe that on Linux, binding to [::] (IPv6) results in receiving both IPv6 and IPv4 traffic (by default). I believe these are referred to as IPv4-mapped IPv6 addresses. netstat simply shows the IPv6 entry only, because there's technically only a single bind, that happens to support both IPv4 and IPv6. It's possible for software to not use IPv4-mapped IPv6 addresses and bind to both 0.0.0.0 and [::] separately and hence show up twice in netstat, but it's a design choice on the part of the developers.
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.
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.