/***************************************************************************
- * Copyright (C) 2005-2019 by the Quassel Project *
+ * Copyright (C) 2005-2020 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
bool IdentServer::startListening()
{
- uint16_t port = Quassel::optionValue("ident-port").toUShort();
-
bool success = false;
- if (_v6server.listen(QHostAddress("::1"), port)) {
- qInfo() << qPrintable(tr("Listening for identd clients on IPv6 %1 port %2").arg("::1").arg(_v6server.serverPort()));
-
- success = true;
- }
- if (_server.listen(QHostAddress("127.0.0.1"), port)) {
- qInfo() << qPrintable(tr("Listening for identd clients on IPv4 %1 port %2").arg("127.0.0.1").arg(_server.serverPort()));
+ uint16_t port = Quassel::optionValue("ident-port").toUShort();
- success = true;
+ const QString listen = Quassel::optionValue("ident-listen");
+ const QStringList listen_list = listen.split(",", QString::SkipEmptyParts);
+ for (const QString &listen_term : listen_list) { // TODO: handle multiple interfaces for same TCP version gracefully
+ QHostAddress addr;
+ if (!addr.setAddress(listen_term)) {
+ qCritical() << qPrintable(
+ tr("Invalid listen address %1")
+ .arg(listen_term)
+ );
+ }
+ else {
+ switch (addr.protocol()) {
+ case QAbstractSocket::IPv6Protocol:
+ if (_v6server.listen(addr, port)) {
+ qInfo() << qPrintable(
+ tr("Listening for identd requests on IPv6 %1 port %2")
+ .arg(addr.toString())
+ .arg(_v6server.serverPort())
+ );
+ success = true;
+ }
+ else
+ qWarning() << qPrintable(
+ tr("Could not open IPv6 interface %1:%2: %3")
+ .arg(addr.toString())
+ .arg(port)
+ .arg(_v6server.errorString()));
+ break;
+ case QAbstractSocket::IPv4Protocol:
+ if (_server.listen(addr, port)) {
+ qInfo() << qPrintable(
+ tr("Listening for identd requests on IPv4 %1 port %2")
+ .arg(addr.toString())
+ .arg(_server.serverPort())
+ );
+ success = true;
+ }
+ else {
+ // if v6 succeeded on Any, the port will be already in use - don't display the error then
+ if (!success || _server.serverError() != QAbstractSocket::AddressInUseError)
+ qWarning() << qPrintable(
+ tr("Could not open IPv4 interface %1:%2: %3")
+ .arg(addr.toString())
+ .arg(port)
+ .arg(_server.errorString()));
+ }
+ break;
+ default:
+ qCritical() << qPrintable(
+ tr("Invalid listen address %1, unknown network protocol")
+ .arg(listen_term)
+ );
+ break;
+ }
+ }
}
if (!success) {
else if (query.endsWith("\n"))
query.chop(1);
+ qDebug() << "Received identd query" << query << "from" << socket->peerAddress();
+
QList<QByteArray> split = query.split(',');
- bool success = false;
+ bool successLocalPort = false;
+ bool successRemotePort = false;
quint16 localPort = 0;
- if (!split.empty()) {
- localPort = split[0].trimmed().toUShort(&success, 10);
+ quint16 remotePort = 0;
+ if (split.length() == 2) {
+ localPort = split[0].trimmed().toUShort(&successLocalPort, 10);
+ remotePort = split[1].trimmed().toUShort(&successRemotePort, 10);
}
- Request request{socket, localPort, query, transactionId, _requestId++};
- if (!success) {
+ Request request{socket, localPort, remotePort, query, transactionId, _requestId++};
+ if (!successLocalPort || !successRemotePort) {
request.respondError("INVALID-PORT");
}
else if (responseAvailable(request)) {
void Request::respondSuccess(const QString& user)
{
if (socket) {
- QString data = query + " : USERID : Quassel : " + user + "\r\n";
+ QString data = QString("%1, %2 : USERID : Quassel : %3\r\n")
+ .arg(QString::number(localPort))
+ .arg(QString::number(remotePort))
+ .arg(user);
+ qDebug() << "answering identd request from" << socket->peerAddress() << "with" << data;
socket->write(data.toUtf8());
socket->flush();
- socket->close();
+ QTimer::singleShot(DISCONNECTION_TIMEOUT, socket, &QTcpSocket::close);
}
}
void Request::respondError(const QString& error)
{
if (socket) {
- QString data = query + " : ERROR : " + error + "\r\n";
+ QString data = QString("%1, %2 : ERROR : %3\r\n")
+ .arg(QString::number(localPort))
+ .arg(QString::number(remotePort))
+ .arg(error);
+ qDebug() << "answering identd request from" << socket->peerAddress() << "with" << data;
socket->write(data.toUtf8());
socket->flush();
- socket->close();
+ QTimer::singleShot(DISCONNECTION_TIMEOUT, socket, &QTcpSocket::close);
}
}
const CoreNetwork* network = qobject_cast<CoreNetwork*>(sender());
_connections[localPort] = network->coreSession()->strictCompliantIdent(identity);
- ;
+
processWaiting(socketId);
}