인터페이스와 주고받는 패킷을 전처리합니다.

인터페이스와 주고받는 패킷을 전처리합니다.

패킷 데이터가 인터페이스에 도달하기 전과 수신된 후에 가로채는 것이 가능합니까? 예를 들어 전처리해서 다시 보내나요?

다음과 같은 맞춤형 솔루션을 만들고 싶습니다.이 멋진 프로그램은 vtun이라고 합니다. 인터페이스 역할을 하는 가상 장치를 생성합니다. 이를 통해 트래픽 압축, 암호화, 쉐이핑 등 다양한 작업을 수행할 수 있습니다.

이제 좀 더 쉽게 할 수 있지 않을까 싶습니다(vtun은 꽤 오래됐네요...). 내 대상 운영 체제는 Ubuntu 14.04입니다.

답변1

예, Linux 커널의 Netfilter 프레임워크는 이를 가능하게 할 만큼 충분히 유연합니다.

네 기대가 어땠는지 모르겠어"맞춤형 솔루션"그리고"이제 좀 더 쉽게 할 수 있다면". 나는 당신이 낮은 수준의 패킷 처리를 수행하는 코드를 작성할 것이라고 가정합니다.

일반적인 아이디어는 다음과 같습니다.

  1. iptables원하는 테이블( filter, nat, mangle)의 트래픽을 대상을 통해 사용자 공간으로 전달하는 규칙을 만듭니다 QUEUE.
  2. 다음 명령을 사용하여 대기열로 전송된 패킷에 액세스할 수 있습니다.libnetfilter_queue도서관이나nfqueue 바인딩(Perl이나 Python을 사용하는 경우)
  3. 적절하다고 판단되는 대로 패킷을 처리하고 원래대로 다시 보내십시오.

처리하려는 트래픽 유형에 따라 원시 IP 패킷, TCP 조각 또는 UDP 데이터그램을 사용하게 되며 트래픽을 올바르게 재조립하고 패킷 수준 체크섬 정확성과 기타 모든 항목을 유지하는 것은 귀하의 책임입니다. 운영 체제의 TCP/IP 스택은 뒤에서 마술처럼 처리합니다.

Python으로 작업할 계획이라면 다음을 사용하는 것이 좋습니다.DPKT또는패킷 또는 TCP 세그먼트를 처리합니다. 이렇게 하면 일이 훨씬 쉬워질 것입니다.

답변2

다음은 @dkaragasidis 제안을 사용한 샘플 코드입니다. 패킷 데이터를 읽고 전달합니다. 핸들러 기능에서 패킷을 수정할 수 있습니다.

엮다:-lnetfilter_queue -lnfnetlink

규칙 추가(예):sudo iptables -A OUTPUT -p udp --dport 4444 -j NFQUEUE --queue-num 0

삭제 규칙(예):sudo iptables -D OUTPUT -p udp --dport 4444 -j NFQUEUE --queue-num 0

테스트: nc -lu 4444nc -u YOUR_IP 4444

#include <netinet/in.h>
#include <linux/netfilter.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <stdio.h>

int handler(struct nfq_q_handle *myQueue, struct nfgenmsg *msg, struct nfq_data *pkt,   void *cbData) {
    int id = 0;
    struct nfqnl_msg_packet_hdr *header;

    if( header = nfq_get_msg_packet_hdr(pkt) )
        id = ntohl(header->packet_id);

    unsigned char *pktData;

    int len = nfq_get_payload(pkt, &pktData);

    printf("data[ %d ]:\n", len);

    int i;
    for (i = 0; i < len; i++)
        printf("%2d 0x%02x %3d %c\n", i, pktData[i], pktData[i], pktData[i]);

    printf("\n");

    return nfq_set_verdict(myQueue, id, NF_ACCEPT, len, pktData);
}

int main(int argc, char **argv) {
    struct nfq_handle *nfqHandle;
    struct nfq_q_handle *myQueue;
    struct nfnl_handle *netlinkHandle;

    int fd, res;
    char buf[4096];

    // queue connection
    if (!(nfqHandle = nfq_open())) {
        perror("Error in nfq_open()");
        return(-1);
    }

    // bind this handler
    if (nfq_bind_pf(nfqHandle, AF_INET) < 0) {
        perror("Error in nfq_bind_pf()");
        return(1);
    }

    // define a handler
    if (!(myQueue = nfq_create_queue(nfqHandle, 0, &handler, NULL))) {
        perror("Error in nfq_create_queue()");
        return(1);
    }

    // turn on packet copy mode
    if (nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) < 0) {
        perror("Could not set packet copy mode");
        return(1);
    }

    netlinkHandle = nfq_nfnlh(nfqHandle);
    fd = nfnl_fd(netlinkHandle);

    while ((res = recv(fd, buf, sizeof(buf), 0)) && res >= 0)
        nfq_handle_packet(nfqHandle, buf, res);

    nfq_destroy_queue(myQueue);
    nfq_close(nfqHandle);

    return 0;
}

관련 정보