使用TUN/TAP设备的程序设计示例
这里简单编写使用TUN/TAP设备的样本程序,并确认其运行结果。
生成点对点连接的TUN设备,对ICMP的ECHO进行处理,来确认TUN设备运行的情况。示例程序为tunpong.c,是在只有ICMP的ECHO REQUEST进入的前提下生成的。这个程序只是为了查看TUN设备的使用方法,不包括错误处理等。
例4-1 tunpong.c
include<fcntl.h>
include<sys/ioctl.h>
include<sys/socket.h>
include<linux/if.h>
include<linux/if_tun.h>
include<unistd.h>
include<stdlib.h>
include<stdio.h>
include<string.h>
int tun_open(void)
{
struct ifreq ifr;
int fd;
char dev[IFNAMSIZ];
char buf[512];
/打开用来操作TUN/TAP设备的文件/
fd=open("/dev/net/tun",O_RDWR);
/生成TUN设备(tun0)/
memset(&ifr,0,sizeof(ifr));
ifr.ifr_flags=IFF_TUN|IFF_NO_PI;
strncpy(ifr.ifr_name,"tun%d",IFNAMSIZ);
ioctl(fd, TUNSETIFF,&ifr);
strncpy(dev, ifr.ifr_name, IFNAMSIZ);
/使用ifconfig命令添加IP地址/
sprintf(buf,"ifconfig%s 192.168.1.1 pointopoint 192.168.1.2",dev);system(buf);
return fd;
}
void dump_pkt(unsigned char*pkt, int len)
{
int i;
for(i=0;i<len;i++)
printf("%02x",pkt[i]);
printf("¥n");
}
void pingpong(int fd)
{
fd_set fds;
int len;
unsigned char pkt[512];
FD_ZERO(&fds);
FD_SET(fd,&fds);
select(fd+1,&fds, NULL, NULL, NULL);
if(FD_ISSET(fd,&fds)){
len=read(fd, pkt,512);
dump_pkt(pkt, len);
/ICMP头部分为0x08(echo request)/
if(pkt[20]!=0x08)
return;
/将IP头的src设为192.168.1.2,dst设为192.168.1.1/
pkt[15]=0x02;
pkt[19]=0x01;
pkt[20]=0x00;/echo reply/
write(fd, pkt, len);
}
}
int main(int argc, char**argv)
{
int fd;
fd=tun_open();
for(;)
pingpong(fd);
return 0;
}
使用下列命令行来进行示例程序的编译。
gcc-g-02-o tunpong tunpong.c
对TUN设备进行操作需要有root权限。请首先成为root用户再尝试运行示例程序tunpong。
./tunpong
在运行后打开另一个终端,使用ifconfig命令来确认。通过示例程序内部运行的ifconfig,可以得知IP地址192.168.1.1和点对点的192.168.1.2被分配到TUN设备(tun0)。
ifconfg tun0
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-
00-00
inet addr:192.168.1.1 P-t-P:192.168.1.2 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0(0.0 b)TX bytes:0(0.0 b)
接下来,执行ping命令,尝试将ICMP ECHO REQUEST发送到192.168.1.2。可以确认,ping命令返回如下REPLY。
$ping 192.168.1.2
PING 192.168.1.2(192.168.1.2)56(84)bytes of data.
64 bytes from 192.168.1.2:icmp_req=1 ttl=64 time=0.100 ms
64 bytes from 192.168.1.2:icmp_req=2 ttl=64 time=0.248 ms
64 bytes from 192.168.1.2:icmp_req=3 ttl=64 time=0.207 ms
另外,还可以看到在tunpong的标准输出中输出了发送到192.168.1.2的数据包(ICMP ECHO REQUEST)的转储结果,程序tunpong通过TUN设备接收数据包。
./tunpong
45 00 00 54 00 00 40 00 40 01 b7 55 c0 a8 01 01 c0 a8 01 02 08 00 e6 31 1a 48 00 01 82 8f 06 4e 00 00 00 00 a2 d4 0d 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37
45 00 00 54 00 00 40 00 40 01 b7 55 c0 a8 01 01 c0 a8 01 02 08 00 9a 30 1a 48 00 02 83 8f 06 4e 00 00 00 00 ed d4 0d 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37
45 00 00 54 00 00 40 00 40 01 b7 55 c0 a8 01 01 c0 a8 01 02 08 00 68 30 1a 48 00 03 84 8f 06 4e 00 00 00 00 1e d4 0d 00 00 00 00 00 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 36 37
最后使用ifconfig命令确认统计信息。RX和TX的packets和bytes同时增加,可以看出成功进行了发送和接收。
ifconfg tun0
tun0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:192.168.1.1 P-t-P:192.168.1.2 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1 RX packets:3 errors:0 dropped:0 overruns:0 frame:0
TX packets:3 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:500
RX bytes:252(252.0 b)TX bytes:252(252.0 b)