📄 example.c
字号:
#define __KERNEL__
#define MODULE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#define PROC_BUFFER 4096
static ssize_t nfdemo_proc_read(struct file* file, char* buf, size_t count,
loff_t *ppos);
static int info_read_proc(char* buf, char** start, off_t offs, int len);
static int last_read_proc(char* buf, char** start, off_t offs, int len);
struct nf_hook_ops input_filter;
struct nf_hook_ops output_filter;
struct proc_dir_entry *proc_nfdemo = NULL;
struct proc_dir_entry *proc_info = NULL;
struct proc_dir_entry *proc_last = NULL;
static rwlock_t last_lock = RW_LOCK_UNLOCKED;
static struct file_operations nfdemo_fops =
{
NULL, /* lseek */
nfdemo_proc_read, /* read */
NULL, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* flush */
NULL, /* no special release code */
NULL /* can't fsync */
};
static struct inode_operations nfdemo_inode =
{
&nfdemo_fops,
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* truncate */
NULL, /* permission */
NULL /* revalidate */
};
static int counter_input_dropped = 0;
static int counter_input_processed = 0;
static int counter_output_dropped = 0;
static int counter_output_processed = 0;
static char *last_packet_data = NULL;
/* input_handler is called when a packet hits specified hook point */
unsigned int input_handler( unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out)
{
struct iphdr *ip;
struct tcphdr *tcp;
int packet_size;
/* inc processed counter */
counter_input_processed++;
/* IP filtering */
/* as you can see the function receives a pointer to the
* struct sk_buff pointer, so it's possible to replace the
* sk_buff with another one. This can be used to rebuild
* from scratch the packet (the example don't use this) */
ip = (*skb)->nh.iph;
/* save the packet -- for /proc/nfdemo/last */
write_lock_bh(&last_lock);
if (last_packet_data != NULL)
kfree(last_packet_data);
packet_size = ntohs(ip->tot_len);
last_packet_data = kmalloc(packet_size, GFP_KERNEL);
if (last_packet_data)
memcpy(last_packet_data, ip, packet_size);
write_unlock_bh(&last_lock);
/* drop IP packets with options */
if (ip->ihl != 5)
goto drop;
/* TCP filtering */
if (ip->protocol != 6)
goto accepted;
tcp = (struct tcphdr*)((__u32 *)ip+ip->ihl);
/* TCP flags sanity check */
/* drops Xmas || Ymax */
if (tcp->res2 != 0)
goto drop;
/* drops SYN without ACK but with others flags set */
if ((tcp->syn && !tcp->ack)
&& (tcp->fin || tcp->rst || tcp->psh || tcp->urg))
goto drop;
/* drops SYN/ACK with RST and/or FIN set */
if ((tcp->syn && tcp->ack) && (tcp->fin || tcp->rst))
goto drop;
/* drops TCP packets with no-sense flags (or without flags set) */
if (!tcp->fin && !tcp->syn && !tcp->rst && !tcp->ack)
goto drop;
accepted:
return NF_ACCEPT;
drop:
counter_input_dropped++;
return NF_DROP;
}
/* output_handler is called when a packet hits specified hook point */
unsigned int output_handler( unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out)
{
struct iphdr *ip;
struct tcphdr *tcp;
struct icmphdr *icmp;
/* inc processed counter */
counter_output_processed++;
/* IP filtering */
ip = (*skb)->nh.iph;
/* TCP filtering */
if (ip->protocol != 6)
goto icmp_init;
tcp = (struct tcphdr*)((__u32 *)ip+ip->ihl);
icmp_init:
/* ICMP filtering */
if (ip->protocol != 1)
goto accepted;
icmp = (struct icmphdr*)((__u32 *)ip+ip->ihl);
if (icmp->type == 0) /* icmp echo request */
goto drop;
accepted:
return NF_ACCEPT;
drop:
counter_output_dropped++;
return NF_DROP;
}
int init_module(void)
{
int result;
/* input hook */
input_filter.list.next = NULL;
input_filter.list.prev = NULL;
input_filter.hook = input_handler;
input_filter.flush = NULL; /* still unused */
input_filter.pf = PF_INET; /* IPv4 */
input_filter.hooknum = NF_IP_LOCAL_IN;
/* output hook */
output_filter.list.next = NULL;
output_filter.list.prev = NULL;
output_filter.hook = output_handler;
output_filter.flush = NULL; /* still unused */
output_filter.pf = PF_INET; /* IPv4 */
output_filter.hooknum = NF_IP_LOCAL_OUT;
/* proc fs */
proc_nfdemo = proc_mkdir("nfdemo", &proc_root);
if (!proc_nfdemo)
goto proc_failed;
proc_info = create_proc_entry("info", 00400, proc_nfdemo);
if (!proc_info)
goto proc_failed;
proc_info->ops = &nfdemo_inode;
proc_info->get_info = info_read_proc;
proc_last = create_proc_entry("last", 00400, proc_nfdemo);
if (!proc_last)
goto proc_failed;
proc_last->ops = &nfdemo_inode;
proc_last->get_info = last_read_proc;
/* hooks registration */
result = nf_register_hook(&input_filter);
if (result) goto hook_failed;
result = nf_register_hook(&output_filter);
if (result) goto hook_failed;
/* OK */
printk(KERN_INFO "demo netfilter module loaded\n");
return 0;
proc_failed:
printk(KERN_INFO "nfdemo: error registering proc entry\n");
return 1; /* error registering proc entry */
hook_failed:
printk(KERN_INFO "nfdemo: error registering hook (%d)", result);
return result; /* error registering hooks */
}
void cleanup_module(void)
{
/* unregister hooks */
nf_unregister_hook(&input_filter);
nf_unregister_hook(&output_filter);
/* unregister proc fs entry */
if (proc_last)
remove_proc_entry("last", proc_nfdemo);
if (proc_info)
remove_proc_entry("info", proc_nfdemo);
if (proc_nfdemo)
remove_proc_entry("nfdemo", &proc_root);
printk(KERN_INFO "demo netfilter module removed\n");
}
/* this function handles /proc/nfdemo/info reading */
static int info_read_proc(char* buf, char** start, off_t offs, int len)
{
return sprintf( buf,
"netfilter demo info:\n"
"INPUT:\n"
"processed datagrams: %d\n"
"dropped datagrams: %d\n"
"OUTPUT:\n"
"processed datagrams: %d\n"
"dropped datagrams: %d\n",
counter_input_processed,
counter_input_dropped,
counter_output_processed,
counter_output_dropped);
}
/* this function handles /proc/nfdemo/last reading */
static int last_read_proc(char* buf, char** start, off_t offs, int len)
{
struct iphdr *ip;
int packet_size = 0;
read_lock(&last_lock);
if (last_packet_data)
{
ip = (struct iphdr*) last_packet_data;
packet_size = ntohs(ip->tot_len);
if (packet_size > PROC_BUFFER)
packet_size = PROC_BUFFER;
memcpy(buf, ip, packet_size);
}
read_unlock(&last_lock);
return packet_size;
}
/* nfdemo_proc_read() is derived from linux/net/wanrouter/wanproc.c of
linux 2.3.31. This function should be fixed since it can create some
inconguence trying to read from /proc/nfdemo/last calling read(2) more
than one time for packet but since this is just an example it's enought */
#define min(x,y) x<y ? x : y
static ssize_t nfdemo_proc_read(struct file* file, char* buf, size_t count,
loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
struct proc_dir_entry* dent;
char* page;
int pos, offs, len;
if (count <= 0)
return 0;
dent = inode->u.generic_ip;
if ((dent == NULL) || (dent->get_info == NULL))
return 0;
page = kmalloc(PROC_BUFFER, GFP_KERNEL);
if (page == NULL)
return -ENOBUFS;
pos = dent->get_info(page, dent->data, 0, 0);
offs = file->f_pos;
if (offs < pos)
{
len = min(pos - offs, count);
if(copy_to_user(buf, (page + offs), len))
return -EFAULT;
file->f_pos += len;
}
else
len = 0;
kfree(page);
return len;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -