우분투에서 netfilter를 이용한 간단한 패킷 뷰어를 만들려고 하는데요...
글쓴이: ssysu / 작성시간: 화, 2009/06/02 - 5:07오후
printk로 읽어온 sk_buff의 정보를 프린트 하려고 했더니 시스템이 다운되어 버리더라구요.
그래서 교수님께 물어보니 교수님께서는 모듈 프로그램에서 printk를 쓰면 그럴 수 있다고 말씀하시고
다른 방법 2가지를 가르쳐 주셨는데요, 하나는 tty에 직접 출력을 하는 것이고 하나는 proc에 출력을 해서
읽어오는 방법이었습니다. 하지만 그 둘 중에 어떠한 방법을 쓰더라도 제 컴퓨터는 먹통이 되어버리네요;
이 먹통이 되는 상황을 해결하는 법을 아시는 분 계신가요?;;
지금 다른 것 때문에 WireShark가 깔려 있는데 이것 때문인가 싶기도 하고 원인을 명확하게 모르겠네요.
우분투는 9.04, 커널은 2.6.29입니다. 혹시나 해서 소스를 첨부합니다.
#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/netfilter.h> #include <linux/proc_fs.h> #include <linux/netfilter_ipv4.h> #include <linux/ip.h> #include <linux/tcp.h> #include <linux/netdevice.h> #include <asm/uaccess.h> static struct proc_dir_entry *packet_dir=NULL; static struct proc_dir_entry *packets=NULL; static char proc_buf[100]; static int proc_buf_size=0; /*static void print_str(char *str) { struct tty_struct *my_tty; my_tty = current->signal->tty; if(my_tty != NULL) ((my_tty->driver)->write(my_tty,str,strlen(str))); }*/ static int readproc(char * page, char **start, off_t off, int count, int *eof, void *data){ memcpy(page, proc_buf, proc_buf_size); return proc_buf_size; } static int writeproc(struct file *file, const char *buffer, unsigned long count, void *data) { copy_from_user(proc_buf, buffer, count); return count; } unsigned int hook_simple(unsigned int hook_no, struct sk_buff **pskb, const struct net_device *dev_in, const struct net_device *dev_out, int (*handler)(struct sk_buff *)) { struct iphdr *iph = ip_hdr(*pskb); struct tcphdr *th = tcp_hdr(*pskb); //if(iph->protocol == 6) printk(KERN_ERR "TCP\n"); char *data = NULL; int ctr=0; unsigned int length=0; unsigned long saddr=0, daddr=0; unsigned short sport=0, dport=0; //length = ((*pskb)->len) - (iph->ihl*4) - (th->doff*4); // data size //length = ((*pskb)->data_len); //data = kmalloc(length, GFP_KERNEL); saddr = iph->saddr; proc_buf_size += sprintf(proc_buf, "%lu.%lu.%lu.%lu\n", (saddr&0xFF000000)>>24, (saddr&0x00FF0000)>>16, (saddr&0x0000FF00)>>8 , (saddr&0x000000FF)); daddr = iph->daddr; sport = th->source; dport = th->dest; /*memset(data, 0, length); memcpy(data, (unsigned char *)th + th unsigned int length=0;->doff*4, length); saddr = ntohl(iph->saddr); daddr = ntohl(iph->daddr); sport = th->source; dport = th->dest;*/ /*printk(KERN_ALERT "%lu.%lu.%lu.%lu:%5u --> %lu.%lu.%lu.%lu:%5u \n", (saddr&0xFF000000)>>24, (saddr&0x00FF0000)>>16, (saddr&0x0000FF00)>>8 , (saddr&0x000000FF), sport, (daddr&0xFF000000)>>24, (daddr&0x00FF0000)>>16, (daddr&0x0000FF00)>>8 , (daddr&0x000000FF), dport);*/ //for(ctr=0; ctr<length; ctr++); //printk("%02x\n", *(data+ctr)); kfree(data); return NF_ACCEPT; } static struct nf_hook_ops nfilter = { .hook = hook_simple, .pf = PF_INET, .hooknum = NF_IP_LOCAL_IN, .priority = NF_IP_PRI_FIRST }; int nfilter_init(void) { int ret; packet_dir = proc_mkdir("packets", NULL); packets = create_proc_entry("packet", 0, packet_dir); packets->read_proc = readproc; packets->write_proc = writeproc; ret = nf_register_hook(&nfilter); if (ret < 0){ printk(KERN_ALERT "netfilter init error!. \n"); return ret; }else { printk(KERN_ALERT "netfilter start. \n"); return 0; } } void nfilter_exit(void) { nf_unregister_hook(&nfilter); remove_proc_entry("packet", packet_dir); remove_proc_entry("packets", 0); printk(KERN_ALERT "netfilter finish. \n"); } module_init(nfilter_init); module_exit(nfilter_exit);
Forums:
proc_buf, proc_buf_size 를
proc_buf, proc_buf_size 를 보호하지 않고 있고...
proc_buf_size 는 계속 증가만하고...
sk_buff 에 원하는게 모두 있을 거라 가정하고 있고...
아시겠지만, ip_queue 와 libipq 를 사용하면 유저모드에서도 완전히 동일한 일을 할 수 있습니다.
+
kfree() 도 날려버리세요.
그리고, 교수님의 printk 에 관한 견해와 tty 에 대한 제안은 아무리 생각해봐도 좀 깨는군요.
OTL
소스는...
proc 관련부는 대충 테스트 해보려고 급하게 만든 거라서 문제가 많습니다.^^;
여하튼 교수님께서 내준 과제는 무조건 넷필터로 이용하라는 것이었어서 고민이 되네요.
아직 생짜 초보라서 열심히 파보고는 있는데 어렵군요. 여하튼 답변에 감사드립니다.^^
도서관이나 서점으로
도서관이나 서점으로 달려 가셔서 아래 책을 참고해 보세요.
http://kangcom.com/sub/view.asp?sku=200612180006
2.6.x 에서 잘 동작하는 소스가 들어있습니다. ㅡ.ㅡ;;;
유저모드에서 잘 사용할 수 있는 libipq 와 libnetfilter_queue 가 있는데 왜 꼭 커널단에서 흠흠....
제가 발로 프로그램을 짜서 그랬는지는 몰라도 커널단이나 유저단이나 성능은 거기서 거기였습니다. ;;;
unsigned int
unsigned int hook_simple(unsigned int hook_no, struct sk_buff **pskb, const struct net_device *dev_in, const struct net_device *dev_out, int (*handler)(struct sk_buff *)) {
struct iphdr *iph = ip_hdr(*pskb);
struct tcphdr *th = tcp_hdr(*pskb);
위와 같이 작성한 코드를 아래와 같이 변경해 보세요~~
unsigned int hook_simple(unsigned int hook_no, struct sk_buff *skb, const struct net_device *dev_in, const struct net_device *dev_out, int (*handler)(struct sk_buff *)) {
struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb);
2.6.24 부터 nf_hookfn()의 skb argument가 변경되었네요~~
댓글 달기