패킷 캡쳐 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가 처리하도록 하셔야 합니다.
------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.
------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.
댓글 달기