우분투에서 netfilter를 이용한 간단한 패킷 뷰어를 만들려고 하는데요...

ssysu의 이미지

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);
bushi의 이미지

proc_buf, proc_buf_size 를 보호하지 않고 있고...
proc_buf_size 는 계속 증가만하고...
sk_buff 에 원하는게 모두 있을 거라 가정하고 있고...

아시겠지만, ip_queue 와 libipq 를 사용하면 유저모드에서도 완전히 동일한 일을 할 수 있습니다.

+

kfree() 도 날려버리세요.

그리고, 교수님의 printk 에 관한 견해와 tty 에 대한 제안은 아무리 생각해봐도 좀 깨는군요.

OTL

ssysu의 이미지

proc 관련부는 대충 테스트 해보려고 급하게 만든 거라서 문제가 많습니다.^^;
여하튼 교수님께서 내준 과제는 무조건 넷필터로 이용하라는 것이었어서 고민이 되네요.
아직 생짜 초보라서 열심히 파보고는 있는데 어렵군요. 여하튼 답변에 감사드립니다.^^

monovision의 이미지

도서관이나 서점으로 달려 가셔서 아래 책을 참고해 보세요.

http://kangcom.com/sub/view.asp?sku=200612180006

2.6.x 에서 잘 동작하는 소스가 들어있습니다. ㅡ.ㅡ;;;

유저모드에서 잘 사용할 수 있는 libipq 와 libnetfilter_queue 가 있는데 왜 꼭 커널단에서 흠흠....
제가 발로 프로그램을 짜서 그랬는지는 몰라도 커널단이나 유저단이나 성능은 거기서 거기였습니다. ;;;

minsoo76의 이미지

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가 변경되었네요~~

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.