WIP: implement dnssd

This commit is contained in:
uncor3
2025-10-04 04:10:27 -07:00
parent d8439c7591
commit 4783e5a4f7
7 changed files with 395 additions and 24 deletions
@@ -1,6 +1,7 @@
#ifndef AVAHI_SERVICE_H
#define AVAHI_SERVICE_H
#include "../../../iDescriptor.h"
#include <QList>
#include <QMutex>
#include <QObject>
@@ -14,19 +15,6 @@
#include <avahi-client/lookup.h>
#include <avahi-common/simple-watch.h>
struct NetworkDevice {
QString name; // service name
QString hostname; // e.g., iPhone-2.local
QString address; // IPv4 or IPv6 address
uint16_t port = 22; // SSH port
std::map<std::string, std::string> txt; // TXT records
bool operator==(const NetworkDevice &other) const
{
return name == other.name && address == other.address;
}
};
class AvahiService : public QObject
{
Q_OBJECT
+275
View File
@@ -0,0 +1,275 @@
#include "dnssd_service.h"
#include <QDebug>
#include <QMutexLocker>
#include <cstring>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <arpa/inet.h>
#include <sys/select.h>
#include <unistd.h>
#endif
DnssdService::DnssdService(QObject *parent)
: QObject(parent), m_browseRef(nullptr), m_socketNotifier(nullptr),
m_running(false)
{
}
DnssdService::~DnssdService() { stopBrowsing(); }
void DnssdService::startBrowsing()
{
if (m_running)
return;
qDebug() << "Starting DNS-SD browsing for Apple devices";
DNSServiceErrorType err =
DNSServiceBrowse(&m_browseRef, 0, 0, "_apple-mobdev2._tcp", "local.",
browseCallback, this);
if (err != kDNSServiceErr_NoError) {
qWarning() << "DNSServiceBrowse failed:" << err;
return;
}
int fd = DNSServiceRefSockFD(m_browseRef);
m_socketNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(m_socketNotifier, &QSocketNotifier::activated, this,
&DnssdService::processDnssdEvents);
m_running = true;
}
void DnssdService::stopBrowsing()
{
if (!m_running)
return;
qDebug() << "Stopping DNS-SD browsing";
m_running = false;
cleanupDnssd();
QMutexLocker locker(&m_devicesMutex);
m_networkDevices.clear();
m_pendingDevices.clear();
}
QList<NetworkDevice> DnssdService::getNetworkDevices() const
{
QMutexLocker locker(&m_devicesMutex);
return m_networkDevices;
}
void DnssdService::processDnssdEvents()
{
if (m_browseRef && m_running) {
DNSServiceProcessResult(m_browseRef);
}
}
void DnssdService::cleanupDnssd()
{
if (m_socketNotifier) {
m_socketNotifier->deleteLater();
m_socketNotifier = nullptr;
}
if (m_browseRef) {
DNSServiceRefDeallocate(m_browseRef);
m_browseRef = nullptr;
}
}
void DNSSD_API DnssdService::browseCallback(
DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *serviceName, const char *regtype,
const char *replyDomain, void *context)
{
Q_UNUSED(sdRef)
Q_UNUSED(regtype)
Q_UNUSED(replyDomain)
if (errorCode != kDNSServiceErr_NoError)
return;
DnssdService *service = static_cast<DnssdService *>(context);
if (flags & kDNSServiceFlagsAdd) {
qDebug() << "Found Apple device:" << serviceName;
// Start resolving the service
DNSServiceRef resolveRef;
DNSServiceErrorType err =
DNSServiceResolve(&resolveRef, 0, interfaceIndex, serviceName,
regtype, replyDomain, resolveCallback, context);
if (err == kDNSServiceErr_NoError) {
// Process the resolve synchronously for simplicity
int fd = DNSServiceRefSockFD(resolveRef);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
struct timeval timeout = {5, 0}; // 5 second timeout
if (select(fd + 1, &readfds, nullptr, nullptr, &timeout) > 0) {
if (FD_ISSET(fd, &readfds)) {
DNSServiceProcessResult(resolveRef);
}
}
DNSServiceRefDeallocate(resolveRef);
}
} else {
qDebug() << "Apple device removed:" << serviceName;
emit service->deviceRemoved(QString::fromUtf8(serviceName));
// Remove from our list
QMutexLocker locker(&service->m_devicesMutex);
service->m_networkDevices.removeIf(
[serviceName](const NetworkDevice &dev) {
return dev.name == QString::fromUtf8(serviceName);
});
service->m_pendingDevices.remove(QString::fromUtf8(serviceName));
}
}
void DNSSD_API DnssdService::resolveCallback(
DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget,
uint16_t port, uint16_t txtLen, const unsigned char *txtRecord,
void *context)
{
Q_UNUSED(sdRef)
Q_UNUSED(flags)
if (errorCode != kDNSServiceErr_NoError)
return;
DnssdService *service = static_cast<DnssdService *>(context);
QString serviceName = QString::fromUtf8(fullname);
// Store pending device info
PendingDevice pending;
pending.name = serviceName;
pending.hostname = QString::fromUtf8(hosttarget);
pending.port = ntohs(port);
pending.interfaceIndex = interfaceIndex;
// Parse TXT records
if (txtLen > 0 && txtRecord) {
const unsigned char *ptr = txtRecord;
const unsigned char *end = txtRecord + txtLen;
while (ptr < end) {
uint8_t len = *ptr++;
if (ptr + len > end)
break;
QString record =
QString::fromUtf8(reinterpret_cast<const char *>(ptr), len);
int equalPos = record.indexOf('=');
if (equalPos != -1) {
QString key = record.left(equalPos);
QString value = record.mid(equalPos + 1);
pending.txt[key] = value;
}
ptr += len;
}
}
service->m_pendingDevices[serviceName] = pending;
qDebug() << "Resolved Apple device:" << serviceName
<< "host:" << pending.hostname << "port:" << pending.port;
// Now resolve the IP address
DNSServiceRef addrRef;
DNSServiceErrorType err = DNSServiceGetAddrInfo(
&addrRef, 0, interfaceIndex, kDNSServiceProtocol_IPv4, hosttarget,
addrInfoCallback, context);
if (err == kDNSServiceErr_NoError) {
// Process the address resolution synchronously
int fd = DNSServiceRefSockFD(addrRef);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
struct timeval timeout = {5, 0}; // 5 second timeout
if (select(fd + 1, &readfds, nullptr, nullptr, &timeout) > 0) {
if (FD_ISSET(fd, &readfds)) {
DNSServiceProcessResult(addrRef);
}
}
DNSServiceRefDeallocate(addrRef);
}
}
void DNSSD_API DnssdService::addrInfoCallback(
DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *hostname,
const struct sockaddr *address, uint32_t ttl, void *context)
{
Q_UNUSED(sdRef)
Q_UNUSED(flags)
Q_UNUSED(interfaceIndex)
Q_UNUSED(ttl)
if (errorCode != kDNSServiceErr_NoError)
return;
DnssdService *service = static_cast<DnssdService *>(context);
QString hostnameStr = QString::fromUtf8(hostname);
// Find the pending device with matching hostname
QString deviceName;
for (auto it = service->m_pendingDevices.begin();
it != service->m_pendingDevices.end(); ++it) {
if (it.value().hostname == hostnameStr) {
deviceName = it.key();
break;
}
}
if (deviceName.isEmpty()) {
qWarning() << "Could not find pending device for hostname:"
<< hostnameStr;
return;
}
PendingDevice pending = service->m_pendingDevices[deviceName];
// Convert IP address
char ip[INET_ADDRSTRLEN];
auto *addr_in = reinterpret_cast<const struct sockaddr_in *>(address);
inet_ntop(AF_INET, &addr_in->sin_addr, ip, sizeof(ip));
NetworkDevice device;
device.name = pending.name;
device.hostname = pending.hostname;
device.address = QString::fromUtf8(ip);
device.port = pending.port > 0 ? pending.port : 22; // Default to SSH port
// device.txt = pending.txt;
qDebug() << "Resolved IP for Apple device:" << device.name << "at"
<< device.address << ":" << device.port;
// Add to our list if not already present
{
QMutexLocker locker(&service->m_devicesMutex);
bool exists = std::any_of(service->m_networkDevices.begin(),
service->m_networkDevices.end(),
[&device](const NetworkDevice &existing) {
return existing == device;
});
if (!exists) {
service->m_networkDevices.append(device);
emit service->deviceAdded(device);
}
}
// Remove from pending
service->m_pendingDevices.remove(deviceName);
}
+72
View File
@@ -0,0 +1,72 @@
#ifndef DNSSD_SERVICE_H
#define DNSSD_SERVICE_H
#include "../../../iDescriptor.h"
#include <QList>
#include <QMap>
#include <QMutex>
#include <QObject>
#include <QSocketNotifier>
#include <QString>
#include <map>
#include <string>
#include <dns_sd.h>
class DnssdService : public QObject
{
Q_OBJECT
public:
explicit DnssdService(QObject *parent = nullptr);
~DnssdService();
void startBrowsing();
void stopBrowsing();
QList<NetworkDevice> getNetworkDevices() const;
signals:
void deviceAdded(const NetworkDevice &device);
void deviceRemoved(const QString &deviceName);
private slots:
void processDnssdEvents();
private:
void cleanupDnssd();
static void DNSSD_API browseCallback(
DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *serviceName,
const char *regtype, const char *replyDomain, void *context);
static void DNSSD_API resolveCallback(
DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *fullname,
const char *hosttarget, uint16_t port, uint16_t txtLen,
const unsigned char *txtRecord, void *context);
static void DNSSD_API addrInfoCallback(
DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
DNSServiceErrorType errorCode, const char *hostname,
const struct sockaddr *address, uint32_t ttl, void *context);
DNSServiceRef m_browseRef;
QSocketNotifier *m_socketNotifier;
mutable QMutex m_devicesMutex;
QList<NetworkDevice> m_networkDevices;
bool m_running;
// Temporary storage for devices being resolved
struct PendingDevice {
QString name;
QString hostname;
uint16_t port;
uint32_t interfaceIndex;
QMap<QString, QString> txt;
};
QMap<QString, PendingDevice> m_pendingDevices;
};
#endif // DNSSD_SERVICE_H
+13
View File
@@ -451,3 +451,16 @@ void fetchAppIconFromApple(const QString &bundleId,
afc_error_t afc2_client_new(idevice_t device, afc_client_t *afc);
void get_cable_info(idevice_t device, plist_t &response);
struct NetworkDevice {
QString name; // service name
QString hostname; // e.g., iPhone-2.local
QString address; // IPv4 or IPv6 address
uint16_t port = 22; // SSH port
std::map<std::string, std::string> txt; // TXT records
bool operator==(const NetworkDevice &other) const
{
return name == other.name && address == other.address;
}
};
+21 -7
View File
@@ -1,6 +1,12 @@
#include "jailbrokenwidget.h"
#include "appcontext.h"
#include "core/services/avahi_service.h"
#ifdef __linux__
#include "core/services/avahi/avahi_service.h"
#else
#include "core/services/dnssd/dnssd_service.h"
#endif
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include <QButtonGroup>
@@ -48,12 +54,19 @@ JailbrokenWidget::JailbrokenWidget(QWidget *parent) : QWidget{parent}
connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this,
&JailbrokenWidget::onWiredDeviceRemoved);
// Initialize Avahi service
m_avahiService = new AvahiService(this);
connect(m_avahiService, &AvahiService::deviceAdded, this,
#ifdef __linux__
m_wirelessProvider = new AvahiService(this);
connect(m_wirelessProvider, &AvahiService::deviceAdded, this,
&JailbrokenWidget::onWirelessDeviceAdded);
connect(m_avahiService, &AvahiService::deviceRemoved, this,
connect(m_wirelessProvider, &AvahiService::deviceRemoved, this,
&JailbrokenWidget::onWirelessDeviceRemoved);
#else
m_wirelessProvider = new DnssdService(this);
connect(m_wirelessProvider, &DnssdService::deviceAdded, this,
&JailbrokenWidget::onWirelessDeviceAdded);
connect(m_wirelessProvider, &DnssdService::deviceRemoved, this,
&JailbrokenWidget::onWirelessDeviceRemoved);
#endif
// Right side: Device selection and Terminal
QWidget *rightContainer = new QWidget();
@@ -81,7 +94,7 @@ JailbrokenWidget::JailbrokenWidget(QWidget *parent) : QWidget{parent}
&JailbrokenWidget::checkSshData);
// Start scanning for wireless devices
m_avahiService->startBrowsing();
m_wirelessProvider->startBrowsing();
// Populate initial devices
updateDeviceList();
@@ -164,7 +177,8 @@ void JailbrokenWidget::updateDeviceList()
}
// Add wireless devices
QList<NetworkDevice> wirelessDevices = m_avahiService->getNetworkDevices();
QList<NetworkDevice> wirelessDevices =
m_wirelessProvider->getNetworkDevices();
for (const NetworkDevice &device : wirelessDevices) {
addWirelessDevice(device);
}
+13 -4
View File
@@ -1,7 +1,12 @@
#ifndef JAILBROKENWIDGET_H
#define JAILBROKENWIDGET_H
#include "core/services/avahi_service.h"
#ifdef __linux__
#include "core/services/avahi/avahi_service.h"
#else
#include "core/services/dnssd/dnssd_service.h"
#endif
#include "iDescriptor.h"
#include <QAbstractButton>
#include <QButtonGroup>
@@ -63,10 +68,14 @@ private:
QVBoxLayout *m_wirelessDevicesLayout;
QButtonGroup *m_deviceButtonGroup;
// Avahi service for network discovery
AvahiService *m_avahiService;
#ifdef Q_OS_LINUX
AvahiService *m_wirelessProvider = nullptr;
#endif
#ifdef __APPLE__
DnssdService *m_wirelessProvider = nullptr;
#endif
// Selected device tracking
DeviceType m_selectedDeviceType = DeviceType::None;
iDescriptorDevice *m_selectedWiredDevice = nullptr;
NetworkDevice m_selectedNetworkDevice;