패킷 캡쳐 Netfilter로 구현시 파일로 저장할때 문제가..
글쓴이: syia / 작성시간: 토, 2005/08/13 - 8:58오후
패킷을 파일로 저장이 되긴 한데..
패킷을쓸때마다 커널 스택이 화면에 주르륵 나오네요
정상적이라면 안나와야 할것같은데;
몇시간째 잡고 헤메는 중입니다;
고수님들의 조언 한마디만 부탁드립니다 -_ㅜ
#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
Forums:
아무리분석해봐도[code:1]old_fs = get_fs(
아무리분석해봐도
이부분이 문제인데 도통 알수가 없네요..
write 하는 부분만 주석처리하니 커널스택이 안뿌려집니다.;
파일에 쓰는건 linuxkernel.net 의 klib를 참고했는데
거기에서도 파일쓰기 할때 더이상 다른걸 해주지는 않았는데
에러가 날까요 ㅠㅠ
원인은 파악한것 같습니다;scheduling while atomi
원인은 파악한것 같습니다;
scheduling while atomic
라고 스택에 나오는데
선점형 커널인 2.6 에서
선점할수 없도록 된 상태에서
schedule을 사용해서 나타나는 것 같군요.
이 문제라면 netfilter내에서는 파일 i/o 자체가 불가능 한다는 뜻일까요?
interrupt 구간에서 i/o
interrupt 구간에서 i/o interrupt를 호출하는것은 안되는 것으로 알고 있습니다. 즉, file i/o를 하시려면, kernel thread를 하나 생성하셔서 해당 kernel thread가 처리하도록 하셔야 합니다.
------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.
------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.
댓글 달기