一、创建设备并拦截数据包
1、打开虚拟设备tun (存在opentun文件夹下)
opentun.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*******************代码说明***********************
打开tun/tap设备 written by fys 2012/4/18
/*******************代码说明***********************
/*
所在头文件:自定义函数
函数原型:int tuntap_create (const char *dev);
函数功能:打开TUN/TAP设备,返回设备文件描述符号
入口参数:设备名字符串,"tun"或"tap"
出口参数:设备文件描述符号
*/
int tuntap_create (const char *dev) //dev可以是字符串“tun”,也可以是“tap”
{
struct ifreq ifr;//ifreq存放接口信息
int fd;
char *device = "/dev/net/tun";
/*打开设备文件描述*/
if ((fd = open (device, O_RDWR)) < 0)
fprintf(stderr, "Cannot open TUN/TAP dev %s", device);
/*打开设备文件描述*/
memset (&ifr,0, sizeof (ifr));
ifr.ifr_flags = IFF_NO_PI;
/*判断参数dev是何种设备*/
if (!strncmp (dev, "tun", 3))//比较dev与tun的前三个字符
{
ifr.ifr_flags |= IFF_TUN;
}
else if (!strncmp (dev, "tap", 3))
{
ifr.ifr_flags |= IFF_TAP;
}
else
{
fprintf(stderr, "I don't recognize device %s as a TUN or TAP device",dev);
}
/*判断参数dev是何种设备*/
if (strlen (dev) > 3)/* unit number specified? */
strncpy (ifr.ifr_name, dev, IFNAMSIZ);
if(ioctl(fd, TUNSETIFF, (void *)&ifr) < 0)//打开虚拟网卡
fprintf(stderr, "Cannot ioctl TUNSETIFF %s", dev);
if(ioctl(fd, TUNSETNOCSUM, (void *)&ifr) < 0)//不校验和
fprintf(stderr, "Cannot ioctl TUNSETIFF %s", dev);
fprintf(stderr, "TUN/TAP device %s opened\n", ifr.ifr_name);
return fd;//返回设备文件描述符号
}
int main()
{
tuntap_create("tun");//打开tun设备,返回tun文件描述符号
system("ifconfig tun0 up");
while(1);//使设备一直处于打开状态,死循环。
return 0;
}
opentun.sh
#!/bin/bash
#开启tun设备
gcc -o opentun.exe opentun.c
./opentun.exe
2、TUN/TAP设备结构 struct tun_struct { char name[8]; //设备名 unsigned long flags; //区分tun和tap设备 struct fasync_struct *fasync; //文件异步通知结构 wait_queue_head_t read_wait; //等待队列 struct net_device dev; //linux 抽象网络设备结构 struct sk_buff_head txq; //网络缓冲区队列 struct net_device_stats stats; //网卡状态信息结构 };
struct net_device结构是linux内核提供的统一网络设备结构,定义了系统统一的访问接口。
Tun/tap驱动中实现的网卡驱动的处理例程:
static int tun_net_open(struct net_device *dev);
static int tun_net_close(struct net_device *dev);
static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev);//数据包发送例程
static void tun_net_mclist(struct net_device *dev);//设置多点传输的地址链表
static struct net_device_stats *tun_net_stats(struct net_device *dev);//当一个应用程序需要知道网络接口的一些统计数据时,可调用该函数,如ifconfig、netstat等。
int tun_net_init(struct net_device *dev);//网络设备初始例程
字符设备部分:
在Linux中,字符设备和块设备统一以文件的方式访问,访问它们的接口是统一的,都是使用open()函数打开设备文件或普通文件,用read()和write()函数实现读写文件等等。Tun/tap驱动定义的字符设备的访问接口如下:
static struct file_operations tun_fops = {
owner: THIS_MODULE,
llseek: tun_chr_lseek,
read tun_chr_read,
write: tun_chr_write,
poll: tun_chr_poll,
ioctl: tun_chr_ioctl,
open: tun_chr_open,
release: tun_chr_close,
fasync: tun_chr_fasync
};
在内核中利用misc_register() 函数将该驱动注册为非标准字符设备驱动,提供字符设备具有的各种程序接口。代码摘自linux-2.4.20\linux-2.4.20\drivers\net\tun.c static struct miscdevice tun_miscdev= { TUN_MINOR, "net/tun", &tun_fops }; int __init tun_init(void) { … if (misc_register(&tun_miscdev)) { printk(KERN_ERR "tun: Can't register misc device %d\n", TUN_MINOR); return -EIO; } return 0; }
3、
截获发往某个地址的数据
OpenTunAndRead.c
#include <stdio.h>
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*****