대문 / 프로그래밍 / Socket filter

Socket filter

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

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

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

개요

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

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

예제

/*
  Copyright (C) JAEHYUK CHO
  All rights reserved.
  Code by JaeHyuk Cho <mailto:minzkn@minzkn.com>
*/

#if !defined(_ISOC99_SOURCE)
# define _ISOC99_SOURCE (1L)
#endif

#if !defined(_GNU_SOURCE)
# define _GNU_SOURCE (1L)
#endif

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <arpa/inet.h>

#include <linux/filter.h>
#include <linux/if_ether.h>
#include <linux/if.h>

int main(int s_argc, char **s_argv);

static void * (__mz_dump_ex__)(size_t s_s, size_t s_d, void * s_da, size_t s_si)
{ size_t s_o, s_w, s_lo; unsigned char s_b[ 16 + 1 ];
 if(s_da == NULL)return(NULL); s_b[sizeof(s_b) - 1] = (unsigned char)'\0';
 for(s_o = (size_t)0;s_o < s_si;s_o += (size_t)16){
  s_w = ((s_si - s_o) <= ((size_t)16)) ? (s_si - s_o) : ((size_t)16);
  (void)fprintf(stdout, "%08lX", (unsigned long)(s_d + s_o));
  for(s_lo = (size_t)0;s_lo < s_w;s_lo++){
   if(s_lo == ((size_t)(16 >> 1)))(void)fputs(" | ", stdout);
   else (void)fputs(" ", stdout);
   s_b[s_lo] = *(((unsigned char *)s_da) + (s_s + s_o + s_lo));
   (void)fprintf(stdout, "%02X", (int)s_b[s_lo]);
   if((s_b[s_lo] & ((unsigned char)(1 << 7))) || (s_b[s_lo] < ((unsigned char)' ')) ||
      (s_b[s_lo] == ((unsigned char)0x7f)))s_b[s_lo] = (unsigned char)'.';}
  while(s_lo < ((size_t)16)){
   if(s_lo == ((size_t)(16 >> 1)))(void)fputs("     ", stdout);
   else (void)fputs("   ", stdout);
   s_b[s_lo] = (unsigned char)' '; s_lo++;}
  (void)fprintf(stdout, " [%s]\n", (char *)(&s_b[0]));}
 return(s_da);
}
static __inline void * (mz_dump_ex)(size_t s_seek_offset, size_t s_display_offset, void * s_data, size_t s_size)
{ return(__mz_dump_ex__(s_seek_offset, s_display_offset, s_data, s_size)); }
#define mz_dump(m_data,m_size) mz_dump_ex((size_t)0,(size_t)0,(void *)(m_data),(size_t)(m_size))

int main(int s_argc, char **s_argv)
{
    int s_socket;
    unsigned char s_buffer[ 64 << 10 ];
    ssize_t s_recv_bytes;
# if 1L
    struct sock_filter s_bpf_code[] = { /* tcpdump -dd 'tcp[tcpflags] & (tcp-syn) != 0' */
        { 0x28, 0, 0, 0x0000000c },
        { 0x15, 0, 8, 0x00000800 },
        { 0x30, 0, 0, 0x00000017 },
        { 0x15, 0, 6, 0x00000006 },
        { 0x28, 0, 0, 0x00000014 },
        { 0x45, 4, 0, 0x00001fff },
        { 0xb1, 0, 0, 0x0000000e },
        { 0x50, 0, 0, 0x0000001b },
        { 0x45, 0, 1, 0x00000002 },
        { 0x6, 0, 0, 0x0000ffff },
        { 0x6, 0, 0, 0x00000000 },
    };
# else
    struct sock_filter s_bpf_code[] = { /* tcpdump -dd tcp */
        { 0x28, 0, 0, 0x0000000c },
        { 0x15, 0, 2, 0x000086dd },
        { 0x30, 0, 0, 0x00000014 },
        { 0x15, 3, 4, 0x00000006 },
        { 0x15, 0, 3, 0x00000800 },
        { 0x30, 0, 0, 0x00000017 },
        { 0x15, 0, 1, 0x00000006 },
        { 0x6, 0, 0, 0x00000800 },
        { 0x6, 0, 0, 0x00000000 }
    };
# endif
    struct sock_fprog s_filter;
    int s_check;

    (void)s_argc;
    (void)s_argv;

    s_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
    if(s_socket == (-1)) {
        perror("socket");
        return(EXIT_FAILURE);
    }

    s_filter.len = sizeof(s_bpf_code) / sizeof(struct sock_filter);
    s_filter.filter = s_bpf_code;
    s_check = setsockopt(s_socket, SOL_SOCKET, SO_ATTACH_FILTER, (const void *)(&s_filter), (socklen_t)sizeof(s_filter));

    for(;;) {
        s_recv_bytes = recv(s_socket, (void *)(&s_buffer[0]), sizeof(s_buffer), 0);
        if(s_recv_bytes == ((ssize_t)(-1))) {
            perror("recv");
            break;
        }

        (void)fprintf(stdout, "recv %ld bytes\n", (long)s_recv_bytes);
        mz_dump(s_buffer, s_recv_bytes);
    }

    (void)close(s_socket);

    return(EXIT_SUCCESS);
}

/* vim: set expandtab: */
/* End of source */


참고자료


/*
End of page
(RemoteIP=38.107.179.243:41062)
Copyright © HWPORT.COM
All Rights Reserved.
*/