MINZKN.COM |  |  | Services | About

Socket filter

  • 작성자
    조재혁(Mminzkn@minzkn.com)

  • 고친과정
    2011년 4월 07일 : 처음씀

  • 문서의 작성기준 개발환경
    GNU/Linux

1.1. 개요

RAW socket을 이용하여 패킷을 수신하고자 할때 내가 원하는 패킷을 걸러내기 위해서는 많은 작업과 더불어 많은 성능손실을 감수해야 합니다. 그러나 Socket filter를 이용하여 수신하게 되면 커널레벨에서 내가 원하는 패킷만 응용프로그램으로 전달하므로써 이러한 성능손실을 개선할수 있습니다.

중요한것은 BPF(Berkeley Packet Filter) code의 이해가 필요하며 다행히도 잘 몰라도 "tcpdump -dd '<BPF표현문법>'" 명령을 통해서 얻을수 있습니다.

1.2. 예제소스

  • @socket_filter.tar.gz (1.79 KB) : Linux에서 Application이 Kernel의 Socket filter를 이용하는 방법 (정상적인 동작을 위해서는 root권한이 필요함)
  • 특정 ICMP reply 패킷을 필터링하여 수신하기 위한 BPF설정 예제
    #include <linux/filter.h> /* BPF : SO_ATTACH_FILTER */
    
    struct sock_filter s_bpf_code[] = { /* ident 가 다르거나 ICMP_ECHOREPLY 가 아닌 경우 버림 */
        BPF_STMT(BPF_LDX | BPF_B   | BPF_MSH, 0),          /* Skip IP header due BSD, see ping6. */
        BPF_STMT(BPF_LD  | BPF_H   | BPF_IND, 4),          /* Load icmp echo ident */
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 1, 0), /* Ours? */
        BPF_STMT(BPF_RET | BPF_K, 0),                      /* Echo with wrong ident. Reject. */
        BPF_STMT(BPF_LD  | BPF_B   | BPF_IND, 0),          /* Load icmp type */
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP_ECHOREPLY, 0, 1), /* Echo? */
        BPF_STMT(BPF_RET | BPF_K, ~0U),                    /* Yes, it passes. */
        BPF_STMT(BPF_RET | BPF_K, 0)                       /* Echo with wrong reply. Reject. */
    };
    struct sock_fprog s_filter;
    
    s_filter.len = (unsigned short)(sizeof(s_bpf_code) / sizeof(struct sock_filter));
    s_filter.filter = (struct sock_filter *)(&s_bpf_code[0]);
    
    s_bpf_code[2] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (uint32_t)(s_my_icmp_identification & 0xffffu), 1 /* true jump */, 0 /* false jump */);
    
    setsockopt(s_socket, SOL_SOCKET, (int)(SO_ATTACH_FILTER), (const void *)(&s_filter), (socklen_t)sizeof(s_filter));
    
  • 특정 ICMPv6 reply 패킷을 필터링하여 수신하기 위한 BPF설정 예제
    struct sock_filter s_bpf_code[] = { /* ident 가 다르거나 ICMP6_ECHO_REPLY 가 아닌 경우 버림 */
        BPF_STMT(BPF_LD  | BPF_H   | BPF_ABS, 4),          /* Load icmp echo ident */
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA, 1, 0), /* Ours? */
        BPF_STMT(BPF_RET | BPF_K, 0),                      /* Echo with wrong ident. Reject. */
        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS, 0),          /* Load icmp type */
        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ICMP6_ECHO_REPLY, 0, 1), /* Echo? */
        BPF_STMT(BPF_RET | BPF_K, ~0U),                    /* Yes, it passes. */
        BPF_STMT(BPF_RET | BPF_K, 0)                       /* Echo with wrong reply. Reject. */
    };
    struct sock_fprog s_filter;
    
    s_filter.len = (unsigned short)(sizeof(s_bpf_code) / sizeof(struct sock_filter));
    s_filter.filter = (struct sock_filter *)(&s_bpf_code[0]);
    
    s_bpf_code[1] = (struct sock_filter)BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (uint32_t)(s_my_icmp_identification  & 0xffffu), 1 /* true jump */, 0 /* false jump */);
    
    setsockopt(s_socket, SOL_SOCKET, (int)(SO_ATTACH_FILTER), (const void *)(&s_filter), (socklen_t)sizeof(s_filter));
    

Copyright ⓒ MINZKN.COM
All Rights Reserved.