bool QNativeSocketEnginePrivate::checkProxy(const QHostAddress &address) { if (address.isLoopback()) return true; #if !defined(QT_NO_NETWORKPROXY) QObject *parent = q_func()->parent(); QNetworkProxy proxy; if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(parent)) { proxy = socket->proxy(); } else if (QTcpServer *server = qobject_cast<QTcpServer *>(parent)) { proxy = server->proxy(); } else { // no parent -> no proxy return true; } if (proxy.type() == QNetworkProxy::DefaultProxy) proxy = QNetworkProxy::applicationProxy(); if (proxy.type() != QNetworkProxy::DefaultProxy && proxy.type() != QNetworkProxy::NoProxy) { // QNativeSocketEngine doesn't do proxies setError(QAbstractSocket::UnsupportedSocketOperationError, QNativeSocketEnginePrivate::InvalidProxyTypeString); return false; } #endif return true; }
///\brief Returns true if the address is accessible from other devices. bool TorcNetwork::IsExternal(const QHostAddress &Address, bool IncludeLinkLocal /* = false*/) { if (Address.isNull() || Address.isLoopback()) return false; if (Address.isInSubnet(Address.protocol() == QAbstractSocket::IPv4Protocol ? gIPv4LinkLocal : gIPv6LinkLocal)) return IncludeLinkLocal; return true; }
void TcpServerDevice::broadcast(const QByteArray &data) { const QHostAddress address = m_server->serverAddress(); // broadcast announcement only if we are actually listinging to remote connections #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) if (address.toString() == "127.0.0.1" || address.toString() == "::1") #else if (address.isLoopback()) #endif return; m_broadcastSocket->writeDatagram(data.data(), data.size(), QHostAddress::Broadcast, Server::broadcastPort()); }
//I'm the existing device, a new device is kindly introducing itself. //I will create a TcpSocket and try to connect. This can result in either connected() or connectError(). void LanLinkProvider::newUdpConnection() //udpBroadcastReceived { while (mUdpSocket.hasPendingDatagrams()) { QByteArray datagram; datagram.resize(mUdpSocket.pendingDatagramSize()); QHostAddress sender; mUdpSocket.readDatagram(datagram.data(), datagram.size(), &sender); if (sender.isLoopback() && !mTestMode) continue; NetworkPackage* receivedPackage = new NetworkPackage(""); bool success = NetworkPackage::unserialize(datagram, receivedPackage); //qCDebug(KDECONNECT_CORE) << "udp connection from " << receivedPackage->; //qCDebug(KDECONNECT_CORE) << "Datagram " << datagram.data() ; if (!success || receivedPackage->type() != PACKAGE_TYPE_IDENTITY) { delete receivedPackage; continue; } if (receivedPackage->get<QString>("deviceId") == KdeConnectConfig::instance()->deviceId()) { //qCDebug(KDECONNECT_CORE) << "Ignoring my own broadcast"; delete receivedPackage; continue; } int tcpPort = receivedPackage->get<int>("tcpPort", port); //qCDebug(KDECONNECT_CORE) << "Received Udp identity package from" << sender << " asking for a tcp connection on port " << tcpPort; QSslSocket* socket = new QSslSocket(this); receivedIdentityPackages[socket].np = receivedPackage; receivedIdentityPackages[socket].sender = sender; connect(socket, SIGNAL(connected()), this, SLOT(connected())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError())); socket->connectToHost(sender, tcpPort); } }
static bool isBypassed(const QString &host, const QStringList &bypassList) { if (host.isEmpty()) return false; bool isSimple = !host.contains(QLatin1Char('.')) && !host.contains(QLatin1Char(':')); QHostAddress ipAddress; bool isIpAddress = ipAddress.setAddress(host); // always exclude loopback if (isIpAddress && ipAddress.isLoopback()) return true; // does it match the list of exclusions? foreach (const QString &entry, bypassList) { if (entry == QLatin1String("<local>")) { if (isSimple) return true; if (isIpAddress) { //exclude all local subnets foreach (const QNetworkInterface &iface, QNetworkInterface::allInterfaces()) { foreach (const QNetworkAddressEntry netaddr, iface.addressEntries()) { if (ipAddress.isInSubnet(netaddr.ip(), netaddr.prefixLength())) { return true; } } } } } if (isIpAddress && ipAddress.isInSubnet(QHostAddress::parseSubnet(entry))) { return true; // excluded } else { // do wildcard matching QRegExp rx(entry, Qt::CaseInsensitive, QRegExp::Wildcard); if (rx.exactMatch(host)) return true; } }
/*! \brief Convert an IP address to a string literal. * * For an IPv4 address, this is a no-op. For IPv6 addresses, we need to remove the scope Id if present * and wrap the remainder in braces. */ QString TorcNetwork::IPAddressToLiteral(const QHostAddress &Address, int Port, bool UseLocalhost /* = true*/) { QString result; if (UseLocalhost && Address.isLoopback()) { result = QString("localhost"); } else if (Address.protocol() == QAbstractSocket::IPv4Protocol) { result = Address.toString(); } else { QHostAddress address(Address); address.setScopeId(""); result = "[" + address.toString() +"]"; } if (Port) result += ":" + QString::number(Port); return result; }
QUrl TcpServerDevice::externalAddress() const { const QHostAddress address(m_server->serverAddress()); QString myHost; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) if (address == QHostAddress::LocalHost || address == QHostAddress::LocalHostIPv6) { #else if (address.isLoopback()) { #endif myHost = address.toString(); } else { foreach (const QNetworkInterface &inter, QNetworkInterface::allInterfaces()) { if (!(inter.flags() & QNetworkInterface::IsUp) || !(inter.flags() & QNetworkInterface::IsRunning) || (inter.flags() & QNetworkInterface::IsLoopBack)) continue; foreach (const QNetworkAddressEntry &addrEntry, inter.addressEntries()) { const QHostAddress addr = addrEntry.ip(); // Return the ip according to the listening server protocol. if (addr.protocol() != m_server->serverAddress().protocol() || !addr.scopeId().isEmpty()) continue; myHost = addr.toString(); break; } if (!myHost.isEmpty()) break; } } // if localhost is all we got, use that rather than nothing if (myHost.isEmpty()) { switch (m_server->serverAddress().protocol()) { case QAbstractSocket::IPv4Protocol: #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) case QAbstractSocket::AnyIPProtocol: #endif myHost = QHostAddress(QHostAddress::LocalHost).toString(); break; case QAbstractSocket::IPv6Protocol: myHost = QHostAddress(QHostAddress::LocalHostIPv6).toString(); break; case QAbstractSocket::UnknownNetworkLayerProtocol: Q_ASSERT_X(false, "TcpServerDevice::externalAddress", "unknown TCP protocol"); break; } } QUrl url; url.setScheme(QStringLiteral("tcp")); url.setHost(myHost); url.setPort(m_server->serverPort()); return url; } void TcpServerDevice::broadcast(const QByteArray &data) { const QHostAddress address = m_server->serverAddress(); // broadcast announcement only if we are actually listinging to remote connections #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) if (address == QHostAddress::LocalHost || address == QHostAddress::LocalHostIPv6) #else if (address.isLoopback()) #endif return; m_broadcastSocket->writeDatagram(data.data(), data.size(), QHostAddress::Broadcast, Server::broadcastPort()); }
void Discover::acceptRecords (QList<Record> records, bool removeThem, QString senderScope, QString senderAddress, QString senderPort) { // TODO // This function gets its own copy of records // This loop edits each item so it can be used after for (Record& record : records) { // Preprocess the record before considering it Record::decompressReserved(record); // Set the scope based on the address if included, otherwise scope of sender QHostAddress recordAddress; if (record.has("Address")) recordAddress.setAddress(record["Address"]); if (recordAddress.protocol()!=QAbstractSocket::IPv4Protocol) recordAddress = QHostAddress::Null; if (recordAddress==QHostAddress::Broadcast) recordAddress = QHostAddress::Null; if (recordAddress==QHostAddress::AnyIPv4) recordAddress = QHostAddress::Null; if (recordAddress.isNull()) { record["Scope"] = senderScope; } else { if (recordAddress.isLoopback()) record["Scope"] = "Loopback"; else if (addressIsLocal(recordAddress)) record["Scope"] = "Local"; else record["Scope"] = "Global"; } if (record["Address"].isEmpty()) record["Address"] = senderAddress; // Sender may override these if (record["Port"].isEmpty()) record["Port"] = senderPort; // Sender may override these // TODO Extract a custom expiration duration so each record can have its own if (removeThem) { // See if it's new if (foundRecords.contains(record)) { logDebug(QString("Record Departed: %1").arg(record.toString())); foundRecords.remove(record); emit recordLost(record); } } else { // See if it's new if (not foundRecords.contains(record) and passesFilters(record)) { logDebug(QString("Found Record: %1").arg(record.toString())); emit recordFound(record); } // Reset the timer foundRecords[record] = QDateTime::currentMSecsSinceEpoch() + 2500; // Set the expire time } expireTimer->start(0); // In case the next expiration time was changed } // Server: Forward global departures to other global peers if (mServerMode and removeThem and senderScope == "Global") { QByteArray datagram("DSDD"); datagram += makeDatagram(records, false); for (Record& record : foundRecords.keys()) if (record["Scope"] == "Global") { bool ok; globalSocket->writeDatagram(datagram, QHostAddress(record["Address"]), record["Port"].toUInt(&ok, 10)); } } }
void Discover::readDatagrams () { QUdpSocket* socket = qobject_cast<QUdpSocket*>(QObject::sender()); if (socket) while (socket->hasPendingDatagrams()) { // Read it to a buffer QByteArray datagram; datagram.resize(socket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; socket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); // Check the prefix bool respond = false; bool removeThem = false; if (datagram.startsWith("DSDA")) respond = false; // Announcement, do not respond else if (datagram.startsWith("DSDR")) respond = true; // Request, do respond else if (datagram.startsWith("DSDD")) removeThem = true; // This is a departure, remove records following else { // This datagram isn't written for Discover, pass it on QList<Record> matchingRecords; for (Record record : foundRecords.keys()) { if (record.has("Address") and record["Address"]==sender.toString()) if (record.has("Port") and record["Port"]==QString::number(senderPort)) matchingRecords.append(record); } emit gotDatagram(datagram, sender, senderPort, matchingRecords); continue; } datagram.remove(0, 4); // Determine the scope of the sender // See if it's this machine QString scope("Global"); if (sender.isLoopback()) { scope = "Loopback"; } else if (sender.protocol() == QAbstractSocket::IPv4Protocol) { if (addressIsLocal(sender)) scope = "Local"; } // Process the records locally acceptRecords(Record::listFromBytes(datagram), removeThem, scope, sender.toString(), QString::number(senderPort)); // Normal: Respond to only Local requests with only owned Records if (respond and not mServerMode and (scope=="Local" or scope=="Loopback")) { globalSocket->writeDatagram(QByteArray("DSDA")+makeDatagram(ownedRecords, true), sender, senderPort); } // Server: Respond to only global requests with owned and found Records else if (respond and mServerMode and scope=="Global") { globalSocket->writeDatagram(QByteArray("DSDA")+makeDatagram(ownedRecords + foundRecords.keys(), false), sender, senderPort); } } }