WIP: Return some ip in ip records

This commit is contained in:
Albert Vaca Cintora 2023-07-10 14:34:26 +02:00
parent d76e7e0eeb
commit 6765f16976
4 changed files with 105 additions and 40 deletions

View file

@ -72,6 +72,7 @@ void LanLinkProvider::onNetworkConfigurationChanged(const QNetworkConfiguration
if (m_lastConfig != config && config.state() == QNetworkConfiguration::Active) { if (m_lastConfig != config && config.state() == QNetworkConfiguration::Active) {
m_lastConfig = config; m_lastConfig = config;
onNetworkChange(); onNetworkChange();
m_mdnsDiscovery.onNetworkChange();
} }
} }

View file

@ -165,6 +165,7 @@ int Discoverer::listenForQueryResponses()
static char buffer[2048]; static char buffer[2048];
size_t num_records = mdns_query_recv(socket, buffer, sizeof(buffer), query_callback, (void *)&discoveredService, 0); size_t num_records = mdns_query_recv(socket, buffer, sizeof(buffer), query_callback, (void *)&discoveredService, 0);
Q_UNUSED(num_records);
// qCDebug(KDECONNECT_CORE) << "Discovered service" << discoveredService.name << "at" << discoveredService.address << "in" << num_records << // qCDebug(KDECONNECT_CORE) << "Discovered service" << discoveredService.name << "at" << discoveredService.address << "in" << num_records <<
// "records via socket" << socket; // "records via socket" << socket;
@ -207,8 +208,41 @@ static mdns_string_t createMdnsString(const QByteArray &str)
return mdns_string_t{str.constData(), (size_t)str.length()}; return mdns_string_t{str.constData(), (size_t)str.length()};
} }
static QHostAddress findBestAddressMatch(QVector<QHostAddress> hostAddresses, const struct sockaddr *fromAddress)
{
if (hostAddresses.size() == 1 || fromAddress == nullptr) {
return hostAddresses[0];
}
// FIXME
return hostAddresses[0];
}
static sockaddr_in qHostAddresstoSockaddr(QHostAddress hostAddress)
{
Q_ASSERT(hostAddress.protocol() == QAbstractSocket::IPv4Protocol);
sockaddr_in socketAddress;
memset(&socketAddress, 0, sizeof(socketAddress));
socketAddress.sin_family = AF_INET;
socketAddress.sin_addr.s_addr = htonl(hostAddress.toIPv4Address());
return socketAddress;
}
static sockaddr_in6 qHostAddresstoSockaddr6(QHostAddress hostAddress)
{
Q_ASSERT(hostAddress.protocol() == QAbstractSocket::IPv6Protocol);
sockaddr_in6 socketAddress;
memset(&socketAddress, 0, sizeof(socketAddress));
socketAddress.sin6_family = AF_INET6;
Q_IPV6ADDR ipv6Address = hostAddress.toIPv6Address();
for (int i = 0; i < 16; ++i) {
socketAddress.sin6_addr.s6_addr[i] = ipv6Address[i];
}
return socketAddress;
}
static mdns_record_t createMdnsRecord(const Announcer::AnnouncedInfo &self, static mdns_record_t createMdnsRecord(const Announcer::AnnouncedInfo &self,
mdns_record_type_t record_type, mdns_record_type_t record_type,
const struct sockaddr *fromAddress = nullptr, // used to determine IP to set in A and AAAA records
QHash<QByteArray, QByteArray>::const_iterator txtIterator = {}) QHash<QByteArray, QByteArray>::const_iterator txtIterator = {})
{ {
mdns_record_t answer; mdns_record_t answer;
@ -228,11 +262,11 @@ static mdns_record_t createMdnsRecord(const Announcer::AnnouncedInfo &self,
break; break;
case MDNS_RECORDTYPE_A: // maps "<hostname>.local." to IPv4 case MDNS_RECORDTYPE_A: // maps "<hostname>.local." to IPv4
answer.name = createMdnsString(self.hostname); answer.name = createMdnsString(self.hostname);
answer.data.a.addr = self.address_ipv4; answer.data.a.addr = qHostAddresstoSockaddr(findBestAddressMatch(self.addressesV4, fromAddress));
break; break;
case MDNS_RECORDTYPE_AAAA: // maps "<hostname>.local." to IPv6 case MDNS_RECORDTYPE_AAAA: // maps "<hostname>.local." to IPv6
answer.name = createMdnsString(self.hostname); answer.name = createMdnsString(self.hostname);
answer.data.aaaa.addr = self.address_ipv6; answer.data.aaaa.addr = qHostAddresstoSockaddr6(findBestAddressMatch(self.addressesV6, fromAddress));
break; break;
case MDNS_RECORDTYPE_TXT: case MDNS_RECORDTYPE_TXT:
answer.name = createMdnsString(self.serviceInstance); answer.name = createMdnsString(self.serviceInstance);
@ -241,7 +275,7 @@ static mdns_record_t createMdnsRecord(const Announcer::AnnouncedInfo &self,
answer.data.txt.value = createMdnsString(txtIterator.value()); answer.data.txt.value = createMdnsString(txtIterator.value());
break; break;
default: default:
assert(false); Q_ASSERT(false);
} }
return answer; return answer;
} }
@ -298,15 +332,15 @@ static int service_callback(int sock, const struct sockaddr* from, size_t addrle
QVector<mdns_record_t> additional; QVector<mdns_record_t> additional;
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_SRV)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_SRV));
if (self.address_ipv4.sin_family == AF_INET) { if (!self.addressesV4.empty()) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_A)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_A, from));
} }
if (self.address_ipv4.sin_family == AF_INET6) { if (!self.addressesV6.empty()) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_AAAA)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_AAAA, from));
} }
for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) { for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, txtIterator)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, nullptr, txtIterator));
} }
// Send the answer, unicast or multicast depending on flag in query // Send the answer, unicast or multicast depending on flag in query
@ -332,15 +366,15 @@ static int service_callback(int sock, const struct sockaddr* from, size_t addrle
mdns_record_t answer = createMdnsRecord(self, MDNS_RECORDTYPE_SRV); mdns_record_t answer = createMdnsRecord(self, MDNS_RECORDTYPE_SRV);
QVector<mdns_record_t> additional; QVector<mdns_record_t> additional;
if (self.address_ipv4.sin_family == AF_INET) { if (!self.addressesV4.empty()) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_A)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_A, from));
} }
if (self.address_ipv4.sin_family == AF_INET6) { if (!self.addressesV6.empty()) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_AAAA)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_AAAA, from));
} }
for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) { for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, txtIterator)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, nullptr, txtIterator));
} }
// Send the answer, unicast or multicast depending on flag in query // Send the answer, unicast or multicast depending on flag in query
@ -358,19 +392,19 @@ static int service_callback(int sock, const struct sockaddr* from, size_t addrle
} }
} else if (name == self.hostname) { } else if (name == self.hostname) {
qWarning() << "Someone queried my host for" << recordTypeToStr(record_type); qWarning() << "Someone queried my host for" << recordTypeToStr(record_type);
if (((record_type == MDNS_RECORDTYPE_A) || (record_type == MDNS_RECORDTYPE_ANY)) && self.address_ipv4.sin_family == AF_INET) { if (((record_type == MDNS_RECORDTYPE_A) || (record_type == MDNS_RECORDTYPE_ANY)) && !self.addressesV4.empty()) {
// The A query was for our qualified hostname and we have an IPv4 address, answer with an A // The A query was for our qualified hostname and we have an IPv4 address, answer with an A
// record mapping the hostname to an IPv4 address, as well as an AAAA record and TXT records // record mapping the hostname to an IPv4 address, as well as an AAAA record and TXT records
mdns_record_t answer = createMdnsRecord(self, MDNS_RECORDTYPE_A); mdns_record_t answer = createMdnsRecord(self, MDNS_RECORDTYPE_A, from);
QVector<mdns_record_t> additional; QVector<mdns_record_t> additional;
if (self.address_ipv4.sin_family == AF_INET6) { if (!self.addressesV6.empty()) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_AAAA)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_AAAA, from));
} }
for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) { for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, txtIterator)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, nullptr, txtIterator));
} }
// Send the answer, unicast or multicast depending on flag in query // Send the answer, unicast or multicast depending on flag in query
@ -385,19 +419,19 @@ static int service_callback(int sock, const struct sockaddr* from, size_t addrle
mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0, mdns_query_answer_multicast(sock, sendbuffer, sizeof(sendbuffer), answer, 0, 0,
additional.constData(), additional.length()); additional.constData(), additional.length());
} }
} else if (((record_type == MDNS_RECORDTYPE_AAAA) || (record_type == MDNS_RECORDTYPE_ANY)) && self.address_ipv6.sin6_family == AF_INET6) { } else if (((record_type == MDNS_RECORDTYPE_AAAA) || (record_type == MDNS_RECORDTYPE_ANY)) && !self.addressesV6.empty()) {
// The AAAA query was for our qualified hostname and we have an IPv6 address, answer with an AAAA // The AAAA query was for our qualified hostname and we have an IPv6 address, answer with an AAAA
// record mapping the hostname to an IPv4 address, as well as an A record and TXT records // record mapping the hostname to an IPv4 address, as well as an A record and TXT records
mdns_record_t answer = createMdnsRecord(self, MDNS_RECORDTYPE_AAAA); mdns_record_t answer = createMdnsRecord(self, MDNS_RECORDTYPE_AAAA, from);
QVector<mdns_record_t> additional; QVector<mdns_record_t> additional;
if (self.address_ipv4.sin_family == AF_INET) { if (!self.addressesV4.empty()) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_A)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_A, from));
} }
for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) { for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, txtIterator)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, nullptr, txtIterator));
} }
// Send the answer, unicast or multicast depending on flag in query // Send the answer, unicast or multicast depending on flag in query
@ -479,11 +513,33 @@ Announcer::Announcer(const QString &serviceName, const QString &serviceType, uin
// mdns.h needs all the qualified names to end with dot for some reason // mdns.h needs all the qualified names to end with dot for some reason
self.serviceType.append('.'); self.serviceType.append('.');
} }
self.port = port;
self.hostname = QHostInfo::localHostName().toLatin1() + QByteArray(".local.");
self.serviceInstance = serviceName.toLatin1() + '.' + self.serviceType; self.serviceInstance = serviceName.toLatin1() + '.' + self.serviceType;
memset(&self.address_ipv4, 0, sizeof(struct sockaddr_in)); self.hostname = QHostInfo::localHostName().toLatin1() + ".local.";
memset(&self.address_ipv6, 0, sizeof(struct sockaddr_in6)); self.port = port;
detectHostAddresses();
}
void Announcer::detectHostAddresses()
{
qWarning() << "detectHostAddresses";
self.addressesV4.clear();
self.addressesV6.clear();
for (const QNetworkInterface &iface : QNetworkInterface::allInterfaces()) {
int flags = iface.flags();
if (!(flags & QNetworkInterface::IsUp) || !(flags & QNetworkInterface::CanMulticast) || (flags & QNetworkInterface::IsLoopBack)) {
continue;
}
for (const QNetworkAddressEntry &ifaceAddress : iface.addressEntries()) {
QHostAddress sourceAddress = ifaceAddress.ip();
if (sourceAddress.protocol() == QAbstractSocket::IPv4Protocol && sourceAddress != QHostAddress::LocalHost) {
qWarning() << "Found ipv4" << sourceAddress;
self.addressesV4.append(sourceAddress);
} else if (sourceAddress.protocol() == QAbstractSocket::IPv6Protocol && sourceAddress != QHostAddress::LocalHostIPv6) {
qWarning() << "Found ipv6" << sourceAddress;
self.addressesV6.append(sourceAddress);
}
}
}
} }
void Announcer::startAnnouncing() void Announcer::startAnnouncing()
@ -520,15 +576,15 @@ void Announcer::sendMulticastAnnounce(bool isGoodbye)
QVector<mdns_record_t> additional; QVector<mdns_record_t> additional;
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_SRV)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_SRV));
if (self.address_ipv4.sin_family == AF_INET) { if (!self.addressesV4.empty()) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_A)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_A));
} }
if (self.address_ipv4.sin_family == AF_INET6) { if (!self.addressesV6.empty()) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_AAAA)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_AAAA));
} }
for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) { for (auto txtIterator = self.txtRecords.cbegin(); txtIterator != self.txtRecords.cend(); txtIterator++) {
additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, txtIterator)); additional.append(createMdnsRecord(self, MDNS_RECORDTYPE_TXT, nullptr, txtIterator));
} }
static char buffer[2048]; static char buffer[2048];

View file

@ -13,13 +13,6 @@
#include <QString> #include <QString>
#include <QVector> #include <QVector>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2ipdef.h>
#else
#include <netinet/in.h>
#endif
/* /*
* A Qt wrapper for the mdns.h header-only library * A Qt wrapper for the mdns.h header-only library
* from https://github.com/mjansson/mdns * from https://github.com/mjansson/mdns
@ -39,7 +32,7 @@ public:
QMap<QString, QString> txtRecords; QMap<QString, QString> txtRecords;
}; };
// serviceType should be of the form _kdeconnect._udp.local // serviceType must be of the form "_<name>._<tcp/udp>.local"
void startDiscovering(const QString &serviceType); void startDiscovering(const QString &serviceType);
void stopDiscovering(); void stopDiscovering();
@ -64,8 +57,8 @@ public:
QByteArray serviceType; // ie: "<_service-type>._tcp.local." QByteArray serviceType; // ie: "<_service-type>._tcp.local."
QByteArray serviceInstance; // ie: "<service-name>.<_service-type>._tcp.local." QByteArray serviceInstance; // ie: "<service-name>.<_service-type>._tcp.local."
QByteArray hostname; // ie: "<hostname>.local." QByteArray hostname; // ie: "<hostname>.local."
struct sockaddr_in address_ipv4; QVector<QHostAddress> addressesV4;
struct sockaddr_in6 address_ipv6; QVector<QHostAddress> addressesV6;
uint16_t port; uint16_t port;
QHash<QByteArray, QByteArray> txtRecords; QHash<QByteArray, QByteArray> txtRecords;
}; };
@ -83,10 +76,19 @@ public:
void sendMulticastAnnounce(bool isGoodbye); void sendMulticastAnnounce(bool isGoodbye);
public Q_SLOTS:
// notify that network interfaces changed since the creation of this Announcer
void onNetworkChange()
{
detectHostAddresses();
}
private: private:
int listenForQueries(); int listenForQueries();
void stopListeningForQueries(); void stopListeningForQueries();
void detectHostAddresses();
AnnouncedInfo self; AnnouncedInfo self;
QSocketNotifier *socketNotifier = nullptr; QSocketNotifier *socketNotifier = nullptr;

View file

@ -29,6 +29,12 @@ public:
void stopAnnouncing(); void stopAnnouncing();
void startAnnouncing(); void startAnnouncing();
public Q_SLOTS:
void onNetworkChange()
{
mdnsAnnouncer.onNetworkChange();
}
private: private:
LanLinkProvider *lanLinkProvider = nullptr; LanLinkProvider *lanLinkProvider = nullptr;
MdnsWrapper::Discoverer mdnsDiscoverer; MdnsWrapper::Discoverer mdnsDiscoverer;