c++multithreadingqtqtcpsocketqtcpserver

How to compare IP of the requested client connection to one of the recognized IP's in QTcpSocket class?


My main issue is: I have a list of recognised IPs and I am carrying out Multi threaded TCP Client-Server Communication; so whenever a new connection request comes from any random client (server is constantly listening), I want to first compare that IP to the stored IP's and allow a new connection only if it is one of my recognised IP's. There can be a .txt file on hard disk or a QList or QString whichever is a better soluion.

EDIT: To make myself clear, Following is the server.cpp file I've developed so far and the errors I am confronted with at the moment.

#include "myserver.h"
#include "ioprogram.h"
#include <string>
#include <iostream>

using namespace std;

//string ClientInfo;

MyServer::MyServer(QObject *parent): QTcpServer(parent)
{
    QStringList accepted_ip_list;   //List of remote IPs that can be accepted in QString list format
    accepted_ip_list.append("127.0.0.1");   // IPv4 local address
    accepted_ip_list.append("::1");         // IPv6 local address

    // Convert from QString to integer format, generating new list
    foreach (const QString &ip, accepted_ip_list)
    {
        QHostAddress host_address(ip);
        my_accepted_ip_list.append(host_address);
    }

    myserver = new QTcpServer(this);

    connect(myserver, &QTcpServer::incomingConnection, this, &MyServer::incomingConnection);

    myserver->listen(QHostAddress::Any, 1234);
}

void MyServer::startServer()
{
    if(!this->listen(QHostAddress::Any,1234))
    {
        qDebug() << "Could not start server.";
    }
    else
    {
        qDebug() << "Listening...";
    }
}

void MyServer::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << socketDescriptor << "Connecting...";

    while (myserver->hasPendingConnections())
    {
        QTcpSocket *socket = myserver->nextPendingConnection();
        QHostAddress host_address = socket->peerAddress();

        bool contains = false;

        for(int i=0; i < my_accepted_ip_list.size(); i++)
        {
            if(my_accepted_ip_list[i].isEqual(host_address,QHostAddress::ConvertV4MappedToIPv4))
            {
                contains = true;
                break;
            }
        }

        if(contains)
        {
            MyThread *thread = new MyThread(socketDescriptor, this);

            connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
            thread->start();
        }
        else
        {
            socket->abort();        // Reject peer by disconnecting it
            socket->deleteLater();  // Schedule the socket removal from memory
        }
    }
}

And here are the errors:

1) @line10 --- prototype for 'MyServer::MyServer(QObject*)' does not match any in class 'MyServer'

2) @line55 --- class 'QHostAddress' has no member named 'isEqual'

3) @line55 --- 'ConvertV4MappedToIPv4' is not a member of 'QHostAddress'

and here is the header file:

#ifndef MYSERVER_H
#define MYSERVER_H

#include <QTcpServer>
#include <QDebug>
#include "mythread.h"
//#include "ioprogram.h"

class MyServer : public QTcpServer
{
    Q_OBJECT
public:
    explicit MyServer(QTcpServer *parent = nullptr);
    void startServer();

signals:

private slots:
//    void newConnection();

private:
    QTcpServer *myserver;
    QList<QHostAddress> my_accepted_ip_list;    //List of IPv4 addresses allowed by the server, in quint32 not QString

protected:
    void incomingConnection(qintptr socketDescriptor);
};
#endif // MYSERVER_H

and here is one error in the header file: candidates are: MyServer::MyServer(MyServer&&)


Solution

  • If i'm correct, you're looking for peerAddress with gives to you a QHostAddress.

    Simple example of how to accept and reject peers:

    EDIT: Since you're using the IP as a security resource, i suggest you use QSslSocket for encryption and authenticity. And contact some security expert, that i am not ;)

    EDIT2: Added support for IPv6 comparison.

    EDIT3: Modified method of comparison.

    Header example (myserver.h file):

    #ifndef MYSERVER_H
    #define MYSERVER_H
    
    #include <QTcpServer>
    #include <QTcpSocket>
    #include <QDebug>
    
    class MyServer : public QTcpServer
    {
        Q_OBJECT
    public:
        explicit MyServer(QObject *parent = nullptr);
    
        void startServer();
    
    private:
        QList<QHostAddress> my_accepted_ip_list;    //List of addresses allowed by the server, in QHostAddress not QString
    
    protected:
        void incomingConnection(qintptr socketDescriptor);
    };
    
    #endif // MYSERVER_H
    

    CPP file example (myserver.cpp file):

    #include "myserver.h"
    
    MyServer::MyServer(QObject *parent) : QTcpServer(parent)
    {
        QStringList accepted_ip_list;   //List of remote IPs that can be accepted in QString list format
        accepted_ip_list.append("127.0.0.1");   // IPv4 local address
        accepted_ip_list.append("::1");         // IPv6 local address
    
        // Convert from QString to QHostAddress format, generating new list
        foreach (const QString &ip, accepted_ip_list)
        {
            QHostAddress host_address(ip);
            my_accepted_ip_list.append(host_address);
        }
    }
    
    void MyServer::startServer()
    {
        if (!listen(QHostAddress::Any, 1234))
        {
            qDebug() << "Could not start server.";
        }
        else
        {
            qDebug() << "Listening...";
        }
    }
    
    void MyServer::incomingConnection(qintptr socketDescriptor)
    {
        QTcpSocket *socket = new QTcpSocket(this);
        socket->setSocketDescriptor(socketDescriptor);
    
        QHostAddress host_address = socket->peerAddress();
    
        quint32 ipv4 = host_address.toIPv4Address();
    
        QByteArray ipv6 = QByteArray((char*)host_address.toIPv6Address().c, 16);
    
        bool contains = false;
    
        for (int i = 0; i < my_accepted_ip_list.size(); i++)
        {
            quint32 accepted_ipv4 = my_accepted_ip_list[i].toIPv4Address();
            QByteArray accepted_ipv6 = QByteArray((char*)my_accepted_ip_list[i].toIPv6Address().c, 16);
    
            if (accepted_ipv4 == ipv4 || accepted_ipv6 == ipv6)
            {
                contains = true;
                break;
            }
        }
    
        if (contains)
        {
            qDebug() << qPrintable(socket->peerAddress().toString()) << "Accepted";
        }
        else
        {
            qDebug() << qPrintable(socket->peerAddress().toString()) << "Rejected";
            socket->abort();        // Reject peer by disconnecting it
            socket->deleteLater();  // Schedule the socket removal from memory
        }
    }