如何强制应用程序源端口?

如何强制应用程序源端口?

我有一个应用程序在本地 Linux 计算机 A 上运行,它需要能够与另一台计算机 B 通信,侦听端口 12325。当设备默认情况下无法通信时就会出现问题,因此我在 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您将看到连接源自 port 12000

相关内容