0

TCP ポートをリッスンする非常に安全な C/C++ アプリを作成するためのアドバイスを探しています。他の人が自分のマシンに何をしようとしているのかをのぞき見したいのですが、非常に短いプログラムで必要なことを実行できるのであれば、手の込んだハニーポット アプリをインストールしたくありません。私の目標はシンプルで安全であるため、少なくとも次のことを確実に処理したいと考えてい
ます
。接続が多すぎるサーバー、および
3) クライアントが接続を無期限に開いたままにできないようにする必要があります。
私の現在のアプリは小さくて機能的であるため、サードパーティのライブラリはこのプロジェクトには適していないようです。ただし、アプリをさらに簡素化する小さなライブラリは興味深いものです。また、C++ 標準ライブラリがコードの簡素化に役立つことを期待しています。

以下は、私の最初の試みからのいくつかの重要な機能です。このコードは、Windows、OSX、および Linux でコンパイルされます。

アプリをより安全に、またはよりシンプルにするにはどうすればよいですか?

void SafeClose(SOCKET s)
{
    if (s == INVALID_SOCKET)
        return;
    shutdown(s, SHUT_RDWR);
    closesocket(s);
}

void ProcessConnection(SOCKET sock, sockaddr_in *sockAddr)
{
    time_t time1;
    char szTime[TIME_BUF_SIZE];
    char readBuf[READ_BUF_SIZE];

    time(&time1);
    strftime(szTime, TIME_BUF_SIZE-1, "%Y/%m/%d %H:%M:%S", localtime(&time1)); 
    printf("%s - %s\n", szTime, inet_ntoa(sockAddr->sin_addr));
    usleep(1000000);       // Wait 1 second for client to send something
    int actualReadCount = recv(sock, readBuf, READ_BUF_SIZE-1, 0); 

    if (actualReadCount < 0 || actualReadCount >= READ_BUF_SIZE){
        actualReadCount = 0;
        strcpy(readBuf, "(Nothing)");
    } else {
        CleanString(readBuf, actualReadCount); // Replace non-printable characters
        readBuf[actualReadCount] = 0;
    }

    printf("%s\n\n", readBuf);
    SafeClose(sock);
}


int main(int argc, char* argv[])
{
    int             port            = 80;
    char            cmd[CMD_BUF_SIZE]   = {0};
    sockaddr_in     newSockAddr;
    sockaddr_in     localSockAddr;

    if(argc < 2){
        printf("Usage: safelisten PORT\n\n");
        return error_code;
    }

    error_code++;
    port = atoi(argv[1]); 
    BuildCleanAsciiMap(); // Used to replace non-printable characters

    localSockAddr.sin_family        = AF_INET;              
    localSockAddr.sin_addr.s_addr   = INADDR_ANY;           
    localSockAddr.sin_port          = htons(port);          
    sizeNewSockAddr                 = sizeof newSockAddr;

    CHK( listenSocket = socket(AF_INET, SOCK_STREAM, 0));
    CHK( setsockopt(listenSocket, SOL_SOCKET,  SO_REUSEADDR, (char *)&on, sizeof(on)));
    CHK( bind(listenSocket, (sockaddr*)&localSockAddr, sizeof localSockAddr));
    CHK( listen(listenSocket, BACKLOG));
    CHK( SetNonBlocking(listenSocket));
    CHK( SetNonBlocking(0));        // Set STDIN to nonblocking for linux    
    printf ("Listening on port: %d\nEnter q to quit.\n\n", port);

    while(strcmp(cmd, "q")) // While the user has not entered q ...
    {
        newSocket = accept(listenSocket, (sockaddr*)&newSockAddr, &sizeNewSockAddr);
        ReadCmd(cmd, CMD_BUF_SIZE);

        if(newSocket == INVALID_SOCKET) { 
            // accept() would have blocked, thus we wait and try again
            usleep(10000);
            continue;   
        }

        // Set to nonblocking because we don't want the client to dictate how 
        // long we are connected.
        CHK( SetNonBlocking(newSocket)); 
        ProcessConnection(newSocket, &newSockAddr);
    }

    SafeClose(listenSocket);
    return 0;
}
4

1 に答える 1

1

2)クライアントは、接続数が多すぎてサーバーに過負荷をかけないようにする必要があります。

プログラムが接続情報を取得するまでに、システムリソースがすでに割り当てられているため、ルーターにIPアドレスが確立する接続の数を制限させるのが最善のオプションです。

1)クライアントは無制限の量のデータを送信できないようにする必要があります。

最良のオプションは、送信できる妥当な最大値を用意し、読んだ量を追跡し、最大値に達したら接続を閉じることです。

3)クライアントは、接続を無期限に開いたままにできないようにする必要があります。

このためには、カウントダウンを開始するスレッドを作成するだけでよいので、接続が特定の時間開いていると、タイムアウトになり、接続を閉じることができます。

他にももっと複雑な解決策がありますが、これは良い出発点になると思います。

(2)について何かをしたい場合は、ハッシュマップをメモリに保持し、確立された接続の数を増やすだけですが、時間を追跡することもできます。データ構造を非常に高速にする必要があるため、接続を早期に切断する必要があるかどうかを判断できます。

たとえば、ハッシュマップに2つのlongがある場合、最初の接続の時間を(unixtimeまたはticksで)入れて増分し、1分以内に10の接続を取得した場合は、次のようになるまで超過分を閉じ始めます。 1分が経過しました。次に、攻撃していないと信頼できるほど長い接続があった場合は、その要素を削除します。

また、渡されるすべてのパラメーターを検証し、すべての文字列に対して妥当な最大値を持っていることを確認してください。

于 2011-10-02T19:34:09.360 に答える