애플리케이션 소스 포트를 강제하는 방법은 무엇입니까?

애플리케이션 소스 포트를 강제하는 방법은 무엇입니까?

로컬 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연결이 port 에서 시작되는 것을 볼 수 있습니다 12000.

관련 정보