内核版本 2.6.30
用户空间源程序
/*
* netlink_user.c
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "netlink.h"
struct msg_to_kernel
{
struct nlmsghdr hdr;
};
struct u_packet_info
{
struct nlmsghdr hdr;
struct packet_info icmp_info;
};
static int sock_fd = -1;
int main()
{
struct sockaddr_nl local; //local {user space}
struct sockaddr_nl kpeer; //peer {kernel space}
struct msg_to_kernel message;
struct u_packet_info info;
int k_peer_len,rcv_len;
struct in_addr addr;
//create netlink socket
sock_fd = socket(AF_NETLINK,SOCK_RAW,NETLINK_TEST);
if(!sock_fd)
{
perror("create netlink socket error\n");
return -1;
}
memset(&local,0,sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pid = getpid();
local.nl_groups = 0;
if(bind(sock_fd,(struct sockaddr *)&local,sizeof(local)) != 0)
{
perror("bind error\n");
return -1;
}
memset(&kpeer,0,sizeof(kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0;
kpeer.nl_groups = 0; //not in multicast
memset(&message,0,sizeof(message));
message.hdr.nlmsg_len = NLMSG_LENGTH(0);
message.hdr.nlmsg_flags = 0;
message.hdr.nlmsg_type = NETLINK_TEST_U_PID;
message.hdr.nlmsg_pid = local.nl_pid;
//send to kernel
sendto(sock_fd,&message,message.hdr.nlmsg_len,0,(struct sockaddr *) &kpeer,sizeof(kpeer));
while(1)
{
k_peer_len = sizeof(struct sockaddr_nl);
rcv_len = recvfrom(sock_fd,&info,sizeof(struct u_packet_info),0,(struct sockaddr *)&kpeer,(socklen_t *)&k_peer_len);
addr.s_addr = info.icmp_info.src;
printf("src: %s,",inet_ntoa(addr));
addr.s_addr = info.icmp_info.dest;
printf("dst: %s\n",inet_ntoa(addr));
}
return 0;
内核空间源程序
/*
* netlink_kernel.c
*/
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "netlink.h"
static struct sock *nl_sock = NULL;
static struct
{
__u32 pid;
rwlock_t lock;
}user_proc;
static DEFINE_MUTEX(nl_mutex);
static void netlink_kernel_rcv(struct sk_buff *skb)
{
struct nlmsghdr *nlh = NULL;
if(skb->len >= nlmsg_total_size(0)){ //sizeof(struct nlmsghdr)
nlh = nlmsg_hdr(skb);
if( (nlh->nlmsg_len >= sizeof(struct nlmsghdr))
&& (skb->len >= nlh->nlmsg_len)){
if(nlh->nlmsg_type == NETLINK_TEST_U_PID){
write_lock_bh(&user_proc.lock);
user_proc.pid = nlh->nlmsg_pid; //record pid
printk("NETLINK_TEST_U_PID: user_proc.pid = %d\n",user_proc.pid);
write_unlock_bh(&user_proc.lock);
}
}
}
}
static int send_to_user(struct packet_info *info)
{
int size,ret;
unsigned char *old_tail;
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct packet_info *pk_info;
size = NLMSG_SPACE(sizeof(*info));
skb = alloc_skb(size,GFP_ATOMIC);
if(!skb){
printk("alloc skb failed\n");
return -1;
}
old_tail = skb->tail;
nlh = NLMSG_PUT(skb,0,0,NETLINK_TEST_K_MSG,size - sizeof(*nlh));
pk_info = NLMSG_DATA(nlh);
memset(pk_info,0,sizeof(struct packet_info));
pk_info->src = info->src;
pk_info->dest = info->dest;
nlh->nlmsg_len = skb->tail - old_tail;
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_group = 0;
read_lock_bh(&user_proc.lock);
ret = netlink_unicast(nl_sock,skb,user_proc.pid,MSG_DONTWAIT);
read_unlock_bh(&user_proc.lock);
nlmsg_failure:
return ret;
}
static unsigned int get_icmp_info(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph = ip_hdr(skb);
struct packet_info info;
if(iph->protocol == IPPROTO_ICMP)
{
read_lock_bh(&user_proc.lock);
if(user_proc.pid != 0)
{
read_unlock_bh(&user_proc.lock);
info.src = iph->saddr;
info.dest = iph->daddr;
send_to_user(&info);
}
else
{
read_unlock_bh(&user_proc.lock);
}
}
return NF_ACCEPT;
}
static struct nf_hook_ops netlink_test_ops =
{
.hook = get_icmp_info,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_FILTER - 1,
};
static int netlink_kernel_init(void)
{
rwlock_init(&user_proc.lock);
nl_sock = netlink_kernel_create(&init_net,NETLINK_TEST,0,netlink_kernel_rcv,&nl_mutex,THIS_MODULE);
if(!nl_sock){
printk("create netlink kernel sock error\n");
return -1;
}
printk("netlink_kernel_init()\n");
return nf_register_hook(&netlink_test_ops);
}
static void netlink_kernel_exit(void)
{
if(nl_sock){
sock_release(nl_sock->sk_socket);
}
nf_unregister_hook(&netlink_test_ops);
printk("netlink_kernel_exit()\n");
}
module_init(netlink_kernel_init);
module_exit(netlink_kernel_exit);
MODULE_LICENSE("GPL");
自定义头文件
/*
* netlink.h
*/
#ifndef __NETLINK_H__
#define __NETLINK_H__
#define NETLINK_TEST_U_PID 0
#define NETLINK_TEST_K_MSG 1
#define NETLINK_TEST_CLOSE 2
#define NETLINK_TEST 31
struct packet_info
{
__u32 src;
__u32 dest;
};
#endif
Makefile
#!/usr/bin/make
CC=gcc
COMMON_FLAGS= -Wall -g -I/usr/include/ -I/usr/src/linux/include
#kernel module
MODULE_NAME=netlink_kernel
obj-m:= $(MODULE_NAME).o
KERNEL_DIR ?=/lib/modules/$(shell uname -r)/build/
PWD :=$(shell pwd)
#user-space app
SRC=netlink_user.c
NETLINK_USR=netlink_usr
all:
$(CC) $(COMMON_FLAGS) -o $(NETLINK_USR) $(SRC)
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
.PHONY:clean
clean:
rm -fr $(NETLINK_USR) *.o *.ko Module.* modules.* $(MODULE_NAME).mod.c
功能
内核在netfilter的prerouting点截获别的主机发来的icmp包,并记录下来,然后通过netlink socket反馈给用户程序,用户程序终端予以显示。