QOPCUA Endpoints Request with IPV6 Link-Local Addresses using the Open62541 Backend
-
I'm encountering a problem with QOPCUA's handling of IPv6 Link-Local addresses due to URL encoding issues with the zone identifier.
I have been trying to connect to an OPCUA server on my network which is being served over an IPv6 Link-Local address. I am able to successfully connect to it using UAExpert and Open62541, however when I request endpoints from this IP using QOPCUA, it fails.
I have traced this failure in the QOPCUA source code. When providing a Link-Local ipv6 address the 'zone' interface must be specified. Open62541 uses the format specified in rfc4007 for this, which requires the zone interface to be specified after a % sign. This means that if I want to connect to an OPCUA server served on a link-local address using my enp2s0 interface, I use this URL:
opc.tcp://[fe80::da3a:ddff:fe44:168c%enp2s0]:4845/
I have confirmed that this exact URL works in both UAExpert and Open62541's UA_Client_getEndpoints function itself. It seems that the reason for this failure is due to the % sign. Because QOPCUA's QOpcUaClient class's requestEndpoints() method requires a QUrl, I must provide it a QUrl:
// QSharedPointer<QOpcUaClient> m_client; QString urlString = "opc.tcp://[fe80::da3a:ddff:fe44:168c%enp2s0]:4845/"; QUrl url(urlString); m_client->requestEndpoints(url);
Calling requestEndpoints() will in turn call this function in QOPCUA's backend:
void Open62541AsyncBackend::requestEndpoints(const QUrl &url)
This function takes the input QUrl and feeds it into Open62541's UA_Client_getEndpoints function:
UA_StatusCode res = UA_Client_getEndpoints(tmpClient, url.toString(QUrl::RemoveUserInfo).toUtf8().constData(), &numEndpoints, &endpoints);
But when it translates the QUrl to a string, this is what it outputs as:
QString urlString = "opc.tcp://[fe80::da3a:ddff:fe44:168c%enp2s0]:4845/"; QUrl url(urlString); qDebug() << "QURL String is: " << url.toString(QUrl::RemoveUserInfo).toUtf8().constData(); // Output: QURL String is: opc.tcp://[fe80::da3a:ddff:fe44:168c%25enp2s0]:4845/
QUrl's toString() function has added a %25 to represent the % in the original URL String. The issue is, this string is being input to the UA_Client_getEndpoints() function which does not parse URL escape sequences. I have tried running the two strings through Open62541's UA_Client_getEndpoints() function in my own build of Open62541 v1.4 and here is what I get:
// without %25 UA_StatusCode retval = UA_Client_getEndpoints(client, "opc.tcp://[fe80::da3a:ddff:fe44:168c%enp2s0]:4845/", &endpointArraySize, &endpointArray); //Output: 1 endpoints found //Output: URL of endpoint 0 is opc.tcp://[fe80::da3a:ddff:fe44:168c%enp2s0]:4845/
// with %25 UA_StatusCode retval = UA_Client_getEndpoints(client, "opc.tcp://[fe80::da3a:ddff:fe44:168c%25enp2s0]:4845/", &endpointArraySize, &endpointArray); //Output: Lookup of fe80::da3a:ddff:fe44:168c%25enp2s0 failed (Name or service not known) //Output: Could not open a TCP connection to opc.tcp://[fe80::da3a:ddff:fe44:168c%25enp2s0]:4845/
I suspect the added %25 on the toString() output of the QUrl is causing this issue. I have tried many different ways to remove this %25, but have been unsuccessful. Are there any known workarounds or ways to connect to an IPv6 Link-Local OPCUA server using QOPCUA?
Similar issue:
https://www.qtcentre.org/threads/66372-QUrl-handle-ipv6-zone-id-wrongRFC Discussing this issue:
https://datatracker.ietf.org/doc/html/rfc6874I am building on the Qt 6.8 branch on Ubuntu Linux 24.04.