Skip to content

add IPv6 support#189

Closed
jg1uaa wants to merge 11 commits into
LX3JL:masterfrom
jg1uaa:ipv6
Closed

add IPv6 support#189
jg1uaa wants to merge 11 commits into
LX3JL:masterfrom
jg1uaa:ipv6

Conversation

@jg1uaa

@jg1uaa jg1uaa commented Mar 5, 2021

Copy link
Copy Markdown

No need to say. This is reconstruction of previous PR, #122 or #162.
Brandmeister and MMDVMHost/DMRGateway is already IPv6 supported, how about xlxd?

@K2IE

K2IE commented Mar 31, 2021

Copy link
Copy Markdown
Contributor

I gave this a try and it is not binding to udp6 sockets as expected.

@K2IE

K2IE commented Mar 31, 2021

Copy link
Copy Markdown
Contributor

So apparently IPv6 binds require a specific address rather than "::". In my case, a bind to "::" is needed so I can use both my external address and use the link address within my local environment because my cloud provider does not bill for local traffic.

@jg1uaa

jg1uaa commented Mar 31, 2021

Copy link
Copy Markdown
Author

how about to run "xlxd <xlxd_ipv4> <ambed_ipv4> <xlxxd_ipv6>" as root? (xlxd uses both ipv4 and ipv6 address)

@LX1IQ

LX1IQ commented Mar 31, 2021

Copy link
Copy Markdown
Collaborator

how about to run "xlxd <xlxd_ipv4> <ambed_ipv4> <xlxxd_ipv6>" as root? (xlxd uses both ipv4 and ipv6 address)

Hi Takayoshi, can you please send me your E-Mail via dvc@rlx.lu

Tnx, Luc -

@jg1uaa

jg1uaa commented Mar 31, 2021

Copy link
Copy Markdown
Author

Due to added D-STAR G3 support (it is not IPv6 friendly), current xlxd needs IPv4 address first (IPv4 address is required).

@yo2loj

yo2loj commented Mar 31, 2021

Copy link
Copy Markdown
Contributor

To clarify: G3 needs to provide an IP4 endpoint back to the requestor, so that the terminal knows where to send the DV stream. Terminals do not offer an option for a IPv6 address, nor the address space in the response packet (it's only 4 bytes long).

@K2IE

K2IE commented Mar 31, 2021

Copy link
Copy Markdown
Contributor

@jg1uaa thank you. I had determined by reviewing the code that the IPv6 addr should be argv[4]. I did confirm that I can establish an IPv6 connection to the reflector. Thank you for this.

The problem remains that I need to bind to 2 v6 IP addresses, a global address and a link address. As currently written there seems to be no way to do this. Normally to bind to all IPv6 interface we would use :: (the IPv6 version of 0.0.0.0).

@K2IE

K2IE commented Mar 31, 2021

Copy link
Copy Markdown
Contributor

As a workaround, and acceptable to me, I now have xlxd binding to both the global and link interfaces. I had to change UDP_SOCKET_MAX in cudpsocket.h from 2 to 3 and then in main.cpp I added:

g_Reflector.SetListenIp(2, ( argc >= 6 ) ? CIp(argv[5]) : CIp());

to process an additional argument.

@K2IE

K2IE commented Mar 31, 2021

Copy link
Copy Markdown
Contributor

Update...while the workaround I specified to listen on both the global and link IPv6 addresses did in fact bind to both sockets, xlxd receives the incoming packets but communicates back using the first configured IPv6 address, creating an asynchronous routing problem. The client therefore does not recognize that xlxd has responded.

To disable ICOM G3 support function for testing, add new definition.
@jg1uaa

jg1uaa commented Apr 4, 2021

Copy link
Copy Markdown
Author

For testing, I added disable ICOM G3 support option. Define DEBUG_NO_G3_SUPPORT at main.h if needed.
This can enable xlxd <xlxd_ipv4/v6> <ambed_ipv4> <xlxd_ipv4/v6> configuration.
Due to checking unspecified second <xlxd_ipv4/v6> field, we cannot use 0.0.0.0 to this.

BTW, how many sockets do we have to open simultaneously?

@K2IE

K2IE commented Apr 4, 2021

Copy link
Copy Markdown
Contributor

I can now start xlxd with:

xlxd :: <ambed_Ipv4>

Of course, I do use terminal mode so will need that to work as well.

Here is the output of my netstat -an

udp6       0      0 :::8880                 :::*
udp6       0      0 :::10001                :::*
udp6       0      0 :::10002                :::*
udp6       0      0 :::30001                :::*
udp6       0      0 :::30051                :::*
udp6       0      0 :::10100                :::*
udp6       0      0 :::42000                :::*
udp6       0      0 :::20001                :::*
udp6       0      0 :::62030                :::*

Unfortunately, this does not seem to actually pass audio for the IPv4 connections. Yet they appear as connected on the dashboard. A tcpdump shows the receipt of the IPv4 packets but the reflector does not seem to respond.

If I start xlxd with an IPv6 in the argv[1] field and an IPv4 in the argv[4] field there is no socket opened explicity for IPv4.

The ideal use case for my environment would be if I could use:

xlxd <xlxd_ipv4> <ambed_ipv4> <xlxd_ipv4/ipv6> <xlxd_ipv4/ipv6>

and have everything work, including terminal mode. This is because I'd use 0.0.0.0 for the IPv4 and then 2 specific IPv6s (global and local). Since my transcoders are via remote IPv4 this would be practical.

@K2IE

K2IE commented Apr 5, 2021

Copy link
Copy Markdown
Contributor

I've started like this (real IP addresses from a test server):
xlxd XLX999 0.0.0.0 127.0.0.1 fe80::5400:3ff:fe49:aef0%ens3 2001:19f0:5:5001:5400:3ff:fe49:aef0

All the proper sockets seem to be created, although it does also create IPv6 socks for the terminal mode ports (12345, 12346, 40000). I have not yet tested voice operation. Before I do move on to voice testing, is there anything else you want tested in terms of startup and socket creation?

Also note that to create the link address sockets I did have to specify the scope in the command line, but this is not unexpected for a link address.

@jg1uaa

jg1uaa commented Apr 5, 2021

Copy link
Copy Markdown
Author

well...? (seeing code) I got it.
Maybe you did not use DEBUG_NO_G3_SUPPORT, and the code tries m_ConfigSocket.Open() but error. The result of CG3Protocol::Init() is false (init failed) but created IPv6 socket for G3 as garbage.

Class CUdpSocket handles IPv6/IPv4 equivalently, so I think adding CUdpSocket::Open(uint16 uiPort, int af) to selective open. If there is better idea, please tell me.

jg1uaa added 2 commits April 6, 2021 05:15
Open(uint16 uiPort) -> Open(uint16 uiPort, int af = AF_UNSPEC)
For a while, this code is needed to surpress unwanted UDP port listening.
If ICOM will implement G3 on IPv6, this should be reverted.
@K2IE

K2IE commented Apr 5, 2021

Copy link
Copy Markdown
Contributor

With DEBUG_NO_G3_SUPPORT the Terminal Mode port (40000,12345,12346) are not enabled.

@yo2loj

yo2loj commented Apr 5, 2021

Copy link
Copy Markdown
Contributor

Why not use IPv6 per default? It also support opening a IPv4 connection if the address is translated into the proper format?
Translating IPv4 w.x.y.z into hybrid 0::FFFF:w.x.y.z addresses will actually allow the IPv6 specific code to handle IPv4.

I attached a modified dual stack class based on the one from XLXD, which I used on an unfinished project, which uses this approach...

CIp_IPv6.tar.gz

@yo2loj

yo2loj commented Apr 5, 2021

Copy link
Copy Markdown
Contributor

Regarding the G3 code, it would make sense to migrate all its ports to use cudpmsgsocket instead of udpsocket, which are functional identical and just do things a little different, to be able to get the incoming local IP of a connection, thus keeping G3 IPv4 only (since there is no IPv6 client in existence).

@jg1uaa

jg1uaa commented Apr 6, 2021

Copy link
Copy Markdown
Author

@yo2loj If all users runs xlxd on Linux, using v4-mapped address will be a choice. But I am an OpenBSD user. *BSD prohibits using v4-mapped address as default for security reason. So using both IPv4 and IPv6 socket implementation is required.

And I have a question, does G3 code support multiple client? For example, working G3 with 0.0.0.0 (INADDR_ANY) address, what will happen? If this is causes a problem, I think modified cudpmsgsocket.cpp with multiply sockets might not work.

@yo2loj

yo2loj commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

I have written cudpmsgsocket exactly for this reason, so that G3 works with 0.0.0.0. The methods allow detection of the local IP which is assumed to be known or to be irrelevant in the rest of the code, but not in cudpmsgsocket, since G3 needs it to send it back to the requestor. It can be forced manually in the configuration file for servers behind NAT.
But there is no need to migrate that one to IPv6. G3 does not support IPv6 in its protocol and there is no client on IPv6. So for a IPv6-only node, G3 does not/can not work.

@K2IE

K2IE commented Apr 6, 2021

Copy link
Copy Markdown
Contributor

This disucssion is very enlightening to me. The problem that @yo2loj describes as being solved with cudpmsgsocket seems to be what I have encountered in testing, with voice streams breaking because the expected source address in connections back to the requesting client is not seen.

@jg1uaa

jg1uaa commented Apr 8, 2021

Copy link
Copy Markdown
Author

current xlxd requires:
xlxd <callsign> <IPv4 address (for G3)> <ambed_ip> <additional IPv4 or IPv6 address ...>

but I want to improve:
xlxd <callsign> <IPv4 or IPv6 address> <ambed_ip> <additional IPv4 or IPv6 address ...>

to achieve this, I modified cudpmsgsocket.cpp. Does anyone who can replace to attached file test G3 server with
xlxd <callsign> <IPv6 address> <ambed_ip> <additional IPv4 address> ?
If there is no problem, I will push this file to my repo.

cudpmsgsocket.cpp.gz

@yo2loj

yo2loj commented Apr 8, 2021 via email

Copy link
Copy Markdown
Contributor

jg1uaa added 2 commits April 10, 2021 16:02
This is added for CIp(AF_UNSPEC), uninitialized CIp state.
CIp() is same as CIp(AF_INET) to have backward compatibility
(the default value of CIp() is 0.0.0.0 IPv4 address).
jg1uaa added 2 commits April 10, 2021 17:13
old:
        xlxd callsign xlxdip ambedip (xlxdip2 xlxdip3 ... xlxdipX)

new
        xlxd callsign xlxdip,(xlxdip2,xlxdip3,...,xlxdipX) ambedip

IP address is comma-separated
@jg1uaa

jg1uaa commented Apr 10, 2021

Copy link
Copy Markdown
Author
  • If we have an IPv4 address only it will be the same command line like before
  • If we have an IPv6 address only it will not start G3
  • If both addresses will be there, G3 will only use IPv4, the rest should use both addresses.

All implemented. current limitation is IP addresses should be written IPv4,IPv6 order (the first address should be v4).
To enable flexible IP address order such as IPv6,IPv4, testing new cudpmsgsocket.cpp at #189 (comment) is required.

@jg1uaa

jg1uaa commented Apr 10, 2021

Copy link
Copy Markdown
Author

Sorry, CUdpSocket::Send(everything) has a bug.
This code can work one IP address per address family, so the case that using two IPv4 (or IPv6) addresses will not work.

@yo2loj

yo2loj commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

What would be the use case which would require that to happen? A socket instance is used for each connection, so there is only a single IP involved. Unless you are using IPv6 with hybrid addresses, you need a distinct listening socket for each address family. Clients need one per connection, as a connection is from a single IP only.

@jg1uaa

jg1uaa commented Apr 10, 2021

Copy link
Copy Markdown
Author

@yo2loj for example, running xlxd IPv4-1,IPv4-2 <ambed_ip>.
If interface for IPv4-1 and IPv4-2 are different, what current code will happen?
Listening from both sockets may be work, but I think something is lacked for send().

@K2IE

K2IE commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

@yo2loj I presented this use case earlier in the thread. I require to bind to 0.0.0.0 on IPv4 and to an IPv6 link local and an IPv6 global address.

If I could use 0.0.0.0 and :: that might work as my transcoding is not on the loopback interface at this time.

@yo2loj

yo2loj commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

This is how sockets using the IP protocol work. They send ONLY from the source address of the interface they are bound to.
If you bind to 0.0.0.0 they will send dynamically from the corresponding source. If you bind them to a specific address on an interface, they will send from that one. There is no "third way" for a socket.
They have only a single address family and a single local address, which can be either specific or 'any'. That's why they need the hybrid mode to be able to handle IPv4 and IPv6 on a single socket (internally it is IPv6).
If you want to use any protocol and any address at the same time, you need to use raw sockets and handle the protocol yourself
(you can check the crawsocket.cpp file for an example for ICMP, which needs to do this) and put the interfaces in promiscuous mode, which I think is out of the scope of an application like xlxd.

And regarding ::, it works, I use applications that bind to that address without any issues. So there is definitively something wrong with this approach.

@K2IE

K2IE commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

To clarify my use case and prevent misundertanding, all of my IP addresses, whether v4 or v6 are tied to the same physical interface. This not a multiple interface use case.

Really, just 0.0.0.0 and :: will work fine for me. I presented the need for the global and local IP6 addresses because :: did not work when I tested an earlier iteration.

@yo2loj

yo2loj commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

Ok, I have pushed my version of the IPv6 support on own repositories, if you like to test and compare...
https://github.com/yo2loj/xlxd/tree/IPv6

It works with IPv4 while listening on [::], but I have no IPv6 client to test with.
I will try to put it up on XLX227/xlx227.hamnet.ro to see how its going. Transcoder is on another machine.

LE: Up and running, bound to [::] - everything seems to be fine, all IPv4 clients are back and transcoding is working.
There is still a bug in the raw socket processing of ICMP...

@K2IE

K2IE commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

@yo2loj up now on XLXIP6.

I started with the refelctor address as 0.0.0.0. If I start with [::] it fails.
But, it still bound to udp6 sockets for all. I could connect with via IPv4.

Dashboard shows IP addresses as blank (still have the @jg1uaa) dashbord mods on this host.

Promising.

@yo2loj

yo2loj commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

Ok. I also fixed the disconnect bug on ICMP... So this should be it. I will leave it running on XLX227. No change in the dashbord for now. Feel free to test. There is also a Peanut access for module B which is usually free.

@yo2loj

yo2loj commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

Regarding the question with 2 different IP addresses: that's not possible in the current code. It uses a single socket for listening to each port. So unless someone wants to radically change the software architecture, I see no solution for this.
For the moment, the possible options are:

  • one specific IPv4 (no IPv6)
  • "0.0.0.0", as in any address via IPv4
  • a specific IPv6 (no IPv4)
  • "::" meaning any IPv6 and IPv4
    Other combinations are not possible with the current software layout.

@K2IE

K2IE commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

@yo2loj code also running on XLXIP6.

@yo2loj

yo2loj commented Apr 10, 2021

Copy link
Copy Markdown
Contributor

Now we need to decide which way to go...
My modifications are essentially in cip, cudpsocket, and rawsocket, with minimal intrusion into the rest, by using a unified IPV6 approach.
jg1uaa has a different approach, by clearly splitting the AF.
It makes no sense to pull in two different directions.
Which would be the best way to get this on the road? I understand that for BSD, 2 sets of sockets would be needed... Is this the case even if this hybrid IPv4 in IPv6 is used internally, at sockaddr level only?

@jg1uaa

jg1uaa commented Apr 11, 2021

Copy link
Copy Markdown
Author

@yo2loj Just now I thought using ipv4-mapped-ipv6 address on IPv4/v6 dual socket implementation. Maybe it works same as IPv6 socket only implementation?

IMHO, I have no reason to object against using ipv4-mapped-ipv6 address (simple code is the best way to maintain, I think so!). But dual socket would be required from the point of view of flexible configuration for users.

@K2IE

K2IE commented Apr 11, 2021

Copy link
Copy Markdown
Contributor

I am not sure if this is applicable to the reflector software, but there have long been security concerns about ipv4-mapped-ipv6 addresses.

https://tools.ietf.org/html/draft-itojun-v6ops-v4mapped-harmful-02

@yo2loj

yo2loj commented Apr 11, 2021

Copy link
Copy Markdown
Contributor

@jg1ua yes, the addresses become 0::FFFF. and are handle just as any other IPv6. The same sockaddr size, the same structures in sin6.
@K2IE Just keep in mind, these adresses are internal to the kernel, they never reach any network interface. Outside the system, it is still IPv4 and IPv6.
But I was thinking: maybe we need a listener module, able to listen on multiple addresses, no matter the address family. This would allow an arbitrary number of IPs to be used.
So instead of having that single udp socket per port, we could actually have a group pumping packets to the code doing the processing, This shouldn't be to hard to do.

@K2IE

K2IE commented Nov 2, 2021

Copy link
Copy Markdown
Contributor

@yo2loj Marius, I had been running your IPv6 code for some months now and it works fine and it is completely stable.

However, I just upgraded to the latest xlxd with IMRS support and have lost my IPv6 capability. Would you please consider updating your branch so that it can be merged here and then issue a PR? Perhaps @LX3JL would then consider adding to the master...

@yo2loj

yo2loj commented Nov 2, 2021

Copy link
Copy Markdown
Contributor

I tried to update the code before the IMRS support and had issues with the stability of the build (it crashed somehow every 1-2 weeks). If the current code stabilizes, I will do an migration of the IPv6 code. Unfortunately I am a little pressed for the moment and don't have the necessary time. But the upcoming December would be an excellent option.

@jg1uaa

jg1uaa commented Nov 3, 2021

Copy link
Copy Markdown
Author

continue to #205

@jg1uaa jg1uaa closed this Nov 3, 2021
@jg1uaa
jg1uaa deleted the ipv6 branch November 3, 2021 05:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants