패킷 캡쳐 Netfilter로 구현시 파일로 저장할때 문제가..

syia의 이미지

패킷을 파일로 저장이 되긴 한데..

패킷을쓸때마다 커널 스택이 화면에 주르륵 나오네요
정상적이라면 안나와야 할것같은데;

몇시간째 잡고 헤메는 중입니다;

고수님들의 조언 한마디만 부탁드립니다 -_ㅜ

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>

#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/in.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/ip.h>
#include <linux/time.h>

#include <linux/fs.h>
#include <linux/file.h>
#include <asm/uaccess.h>

//#include <arpa/inet.h>
//#include <netinet/ip.h>
//#include <netinet/ip_icmp.h>


#define DRIVER_AUTHOR "syia"
#define DRIVER_DESC "packet caputre test"

static struct nf_hook_ops nfho_in;
static struct nf_hook_ops nfho_out;
static struct file *fp;
static char bufpool[10100];

int write_packet(struct sk_buff *sb,int typelen);

unsigned int hook_func(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int(*ofkn)(struct sk_buff*))
{
        //printk("<1>Packet arrived.\n");
        struct sk_buff *sb = *skb;
        struct iphdr *iph = (*skb)->nh.iph;
        __u8 *ipsaddr;
        __u8 *ipdaddr;
        

        if(!sb) return NF_ACCEPT;
        if(!sb->nh.iph) return NF_ACCEPT;

        ipsaddr = (__u8*)&(iph->saddr);
        ipdaddr = (__u8*)&(iph->daddr);


        
        if(sb->nh.iph->protocol == IPPROTO_TCP)
        {
                
                printk("<1>TCP packet recieved.(send:%d.%d.%d.%d, recv:%d.%d.%d.%d)\n",
                        *ipsaddr,*(ipsaddr+1),*(ipsaddr+2),*(ipsaddr+3)
                        ,*(ipdaddr+32),*(ipdaddr+33),*(ipdaddr+34),*(ipdaddr+35)
                );
                write_packet(sb,sizeof(struct tcphdr));
        }
        else if(sb->nh.iph->protocol == IPPROTO_UDP)
        {
                printk("<1>UDP packet recieved.(send:%d.%d.%d.%d, recv:%d.%d.%d.%d)\n"
                        ,*ipsaddr,*(ipsaddr+1),*(ipsaddr+2),*(ipsaddr+3)
                        ,*(ipdaddr+32),*(ipdaddr+33),*(ipdaddr+34),*(ipdaddr+35)
                );
                write_packet(sb,sizeof(struct udphdr));
        }
        else if(sb->nh.iph->protocol == IPPROTO_ICMP)
        {
                printk("<1>ICMP packet recieved.(send:%d.%d.%d.%d, recv:%d.%d.%d.%d)\n",
                        *ipsaddr,*(ipsaddr+1),*(ipsaddr+2),*(ipsaddr+3)
                        ,*(ipdaddr+32),*(ipdaddr+33),*(ipdaddr+34),*(ipdaddr+35)
                );
                write_packet(sb,sizeof(struct icmphdr));
        }

        return NF_ACCEPT;
}

int write_packet(struct sk_buff *sb, int typelen)
{
        int write_len;        
        static char *buf = bufpool;
        static char *limit = bufpool + 10000;

        int size = 0;
        mm_segment_t old_fs;

        if(buf> limit) buf = bufpool;
        
        memcpy(buf,&(sb->stamp),sizeof(struct timeval));
        size+= sizeof(struct timeval);
        memcpy(buf+size,sb->nh.iph,sizeof(struct iphdr));
        size+= sizeof(struct iphdr);
        memcpy(buf+size,sb->nh.iph + sb->nh.iph->ihl,typelen);
        size+= typelen;

        if(fp && fp->f_op && fp->f_op->write)
        {
                old_fs = get_fs();
                set_fs(KERNEL_DS);
                write_len = fp->f_op->write(fp,buf,size,&fp->f_pos);        
                set_fs(old_fs);
                buf += size;
                return write_len;
        }

        printk("<1>PC write_packet failed.\n");

        return 0;
}


                
                        

int init_module()
{
        nfho_in.hook = hook_func;
        nfho_in.hooknum = NF_IP_PRE_ROUTING;
        nfho_in.pf = PF_INET;
        nfho_in.priority = NF_IP_PRI_FIRST;

        nfho_out.hook = hook_func;
        nfho_out.hooknum = NF_IP_POST_ROUTING;
        nfho_out.pf = PF_INET;
        nfho_out.priority = NF_IP_PRI_FIRST;
        
        nf_register_hook(&nfho_in);
        nf_register_hook(&nfho_out);

        printk("<1>PC module initialized.\n");

        if((fp = filp_open("/root/pc/pc.dat",O_CREAT | O_APPEND,0600)) == NULL)
        {
                printk("<1>PC data file open failed.\n");
        }
        else
        {
                printk("<1>PC data file open succeed.\n");
        }
        
        return 0;
}

void cleanup_module()
{
        if(fp) fput(fp);
        nf_unregister_hook(&nfho_in);
        nf_unregister_hook(&nfho_out);
        printk("<1>PC module cleaned up.\n");
}


MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

--------------------------------------

출력되는 스택

TCP packet recieved.(send:127.0.0.1, recv:47.48.120.98)
scheduling while atomic: gedit/0x00000105/11606
[<c02e7292>] schedule+0x532/0x540
[<c0167e35>] generic_commit_write+0x85/0xb0
[<c014764b>] generic_file_buffered_write+0x40b/0x600
[<c017eaa7>] inode_update_time+0xa7/0xe0
[<c0147abe>] __generic_file_aio_write_nolock+0x27e/0x4c0
[<c0147e43>] __generic_file_write_nolock+0xa3/0xc0
[<c0117186>] try_to_wake_up+0xa6/0xc0
[<c012f70f>] autoremove_wake_function+0x2f/0x60
[<c0117af1>] __wake_up_common+0x41/0x70
[<c012f6e0>] autoremove_wake_function+0x0/0x60
[<c014805e>] generic_file_write+0x4e/0xd0
[<e018f297>] write_packet+0x87/0x90 [pc]
[<e018f0af>] hook_func+0xaf/0x210 [pc]
[<c028ce0c>] nf_iterate+0x7c/0xd0
[<c0297480>] ip_rcv_finish+0x0/0x250
[<c0297480>] ip_rcv_finish+0x0/0x250
[<c028d1c2>] nf_hook_slow+0x92/0x170
[<c0297480>] ip_rcv_finish+0x0/0x250
[<c02971df>] ip_rcv+0x16f/0x220
[<c0297480>] ip_rcv_finish+0x0/0x250
[<c0281e34>] netif_receive_skb+0x144/0x1c0
[<c0281f2f>] process_backlog+0x7f/0x100
[<c0282024>] net_rx_action+0x74/0x100
[<c011fd2b>] __do_softirq+0x7b/0x90
[<c011fd67>] do_softirq+0x27/0x30
[<c011fdc5>] local_bh_enable+0x55/0x90
[<c0281895>] dev_queue_xmit+0x165/0x270
[<c029c432>] ip_finish_output2+0xc2/0x1c0
[<c029c370>] ip_finish_output2+0x0/0x1c0
[<c028d241>] nf_hook_slow+0x111/0x170
[<c029c370>] ip_finish_output2+0x0/0x1c0
[<c029c340>] dst_output+0x0/0x30
[<c0299e9b>] ip_finish_output+0x4b/0x50
[<c029c370>] ip_finish_output2+0x0/0x1c0
[<c029c354>] dst_output+0x14/0x30
[<c028d241>] nf_hook_slow+0x111/0x170
[<c029c340>] dst_output+0x0/0x30
[<c029a412>] ip_queue_xmit+0x382/0x4b0
[<c029c340>] dst_output+0x0/0x30
[<c01160ac>] do_page_fault+0x3bc/0x5de
[<c0149f30>] __alloc_pages+0x1e0/0x3b0
[<c02b0b88>] tcp_v4_send_check+0x58/0x100
[<c02aad03>] tcp_transmit_skb+0x433/0x710
[<c02ad3ad>] tcp_connect+0x29d/0x340
[<c02affab>] tcp_v4_connect+0x3cb/0x6d0
[<c02bff4b>] inet_stream_connect+0x8b/0x1b0
[<c0278e93>] sys_connect+0x83/0xb0
[<c02a20d7>] tcp_setsockopt+0xc7/0x540
[<c027b706>] sock_common_setsockopt+0x36/0x40
[<c0279336>] sys_setsockopt+0x76/0xc0
[<c01d74a2>] copy_from_user+0x42/0x70
[<c0279921>] sys_socketcall+0xb1/0x260
[<c01030ff>] syscall_call+0x7/0xb
syia의 이미지

아무리분석해봐도

old_fs = get_fs(); 
set_fs(KERNEL_DS); 
write_len = fp->f_op->write(fp,buf,size,&fp->f_pos);        
set_fs(old_fs); 

이부분이 문제인데 도통 알수가 없네요..
write 하는 부분만 주석처리하니 커널스택이 안뿌려집니다.;

파일에 쓰는건 linuxkernel.net 의 klib를 참고했는데
거기에서도 파일쓰기 할때 더이상 다른걸 해주지는 않았는데
에러가 날까요 ㅠㅠ

syia의 이미지

원인은 파악한것 같습니다;

scheduling while atomic

라고 스택에 나오는데

선점형 커널인 2.6 에서

선점할수 없도록 된 상태에서

schedule을 사용해서 나타나는 것 같군요.

이 문제라면 netfilter내에서는 파일 i/o 자체가 불가능 한다는 뜻일까요?

powerson의 이미지


interrupt 구간에서 i/o interrupt를 호출하는것은 안되는 것으로 알고 있습니다. 즉, file i/o를 하시려면, kernel thread를 하나 생성하셔서 해당 kernel thread가 처리하도록 하셔야 합니다.

------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.

------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.