우분투에서 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가 변경되었네요~~
댓글 달기