アプリケーションソースポートを強制する方法は?

アプリケーションソースポートを強制する方法は?

ローカルのLinuxシステムAで実行されているアプリケーションがあり、ポート12325でリッスンしている他のシステムBと通信できる必要があります。デフォルトでは、デバイスが通信できない場合に問題が発生するため、ACLでポート12325を開いていますが、ソースマシンAのアプリケーションポートはランダムです。 iptablesを使用して、変更したいアプリケーションのソースポートを12325に具体的に変換できますか?常に同じユーザー、同じ場所で実行されます。

  1. ソフトウェアはオープンソースではないため、このソフトウェアの側面を強制することはできません。
  2. システム間のすべてのポートを開くことはできません。

答え1

オプション1:コンテナ

明示的なIPアドレスを使用してコンテナ内でアプリケーションを実行し、アウトバウンド接続を許可するようにローカルファイアウォールルールを変更します。その特定のIPアドレスから。これにより、ポートを知る必要がなくなります。そのIPアドレスに関連する規則は、そのアプリケーションの接続にのみ影響し、他のものには影響しません。これは次のようになります。

docker network create app_network --subnet 192.168.51.0/24
docker run --network my_app_network --ip 192.168.51.10 myapimage ...

その後、ローカルファイアウォールに次の項目を追加できます。

iptables -A FORWARD -s 192.168.51.10/32 -j ACCEPT

オプション2:関数の挿入

アプリケーションが動的にリンクされた実行可能ファイルであると仮定すると、以下を使用できます。関数の挿入特定のライブラリ呼び出しをオーバーライドします。この場合、接続が確立される前に呼び出されるようにconnect呼び出しをオーバーライドできます。bindこれは次のようになります。

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>

#ifndef TARGET_PORT
#define TARGET_PORT 80
#endif

#ifndef SOURCE_PORT
#define SOURCE_PORT 12000
#endif

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
    static int (*real_connect)(int, const struct sockaddr *, socklen_t) = NULL;

    if (!real_connect)
        real_connect = dlsym(RTLD_NEXT, "connect");


    /*
     * Only makes changes if you are initiating an AF_INET connection to
     * a specific remote port. Modify the logic here, or modify
     * TARGET_PORT and SOURCE_PORT, above, to change this behavior.
     */
    if (
            addr->sa_family == AF_INET &&
            ((struct sockaddr_in *)addr)->sin_port == htons(TARGET_PORT)
       ) {
        const int enable = 1;

        // Set SO_REUSEADDR, otherwise subsequent connections will fail until
        // the socket exits the TIME_WAIT state.
        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
            return -1;

        struct sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = htonl(INADDR_ANY);
        sin.sin_port = htons(SOURCE_PORT);

        if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
            return -1;
        }
    }

    return real_connect(sockfd, addr, addrlen);
}

コードを共有ライブラリにコンパイルします。

gcc -shared -ldl -fPIC connect_with_port.c -o connect_with_port.so

次に、以下を使用して有効にしますLD_PRELOAD

LD_PRELOAD=./connect_with_port.so nc google.com 80

上記のコマンドを実行すると、tcpdump接続がポートから始まることがわかります12000

関連情報