您的位置:首页 > 编程语言 > Python开发

python实现tun/tap虚拟设备

2017-03-13 22:13 253 查看
工作中用到了使用tap/tun设备实现虚拟网络,看到网上的例子都是用C实现的。便想试着用python实现一把,主要就是要重新用ctypes定义相关的结构定义。

代码github地址:

https://github.com/happyAnger6/network_programming





这个git库里会不断的用python实现网络相关的编程。

if_tun.py:  主要是相关结构体定义。

import ctypes
import ioctl_def

TUNSETIFF=ioctl_def._IOW(ord('T'), 202, ctypes.c_int)
IFF_TUN=1
IFF_TAP=2

IFNAMSIZ=16

class SockAddr(ctypes.Structure):
_fields_=[("sa_family",ctypes.c_ushort),
("sa_data",ctypes.c_char*14)]

class IfMap(ctypes.Structure):
_fields_=[("mem_start", ctypes.c_ulong),
("mem_end", ctypes.c_ulong),
("base_addr", ctypes.c_ushort),
("irq", ctypes.c_char),
("dma", ctypes.c_char),
("port", ctypes.c_char)]

class Ifs_Ifsu(ctypes.Union):
_fields_=[("raw_hdlc", ctypes.c_void_p),
("cisco", ctypes.c_void_p),
("fr", ctypes.c_void_p),
("fr_pvc", ctypes.c_void_p),
("fr_pvc_info", ctypes.c_void_p),
("sync", ctypes.c_void_p),
("te1", ctypes.c_void_p)]

class IfSettings(ctypes.Structure):
_fields_=[("type", ctypes.c_uint),
("size", ctypes.c_uint),
("ifs_ifsu", Ifs_Ifsu)]

class Ifr_Ifru(ctypes.Union):
_fields_=[("ifru_addr", SockAddr),
("ifru_dstaddr", SockAddr),
("ifru_broadaddr", SockAddr),
("ifru_netmask", SockAddr),
("ifru_hwaddr", SockAddr),
("ifru_flags", ctypes.c_ushort),
("ifru_ivalue", ctypes.c_int),
("ifru_mtu", ctypes.c_int),
("ifru_map", IfMap),
("ifru_slave", ctypes.c_char * IFNAMSIZ),
("ifru_newname", ctypes.c_char * IFNAMSIZ),
("ifru_data", ctypes.c_void_p),
("ifru_settings", IfSettings)]

class Ifr_Ifrn(ctypes.Union):
_fields_=[("ifrn_name", ctypes.c_char * IFNAMSIZ)]

class IfReq(ctypes.Structure):
_fields_=[("ifr_ifrn", Ifr_Ifrn),
("ifr_ifru", Ifr_Ifru)]

if __name__ == "__main__":
ifreq = IfReq()
print(ctypes.sizeof(ifreq.ifr_ifrn))
print(ctypes.sizeof(ifreq.ifr_ifru))

ioctl_def.py:主要是ioctl命令字相关定义:

_IOC_NRBITS=8
_IOC_TYPEBITS=8
_IOC_SIZEBITS=14
_IOC_DIRBITS=2

_IOC_NRMASK=((1 << _IOC_NRBITS) - 1)
_IOC_TYPEMASK=((1 << _IOC_TYPEBITS) - 1)
_IOC_SIZEMASK=((1 << _IOC_SIZEBITS) - 1)
_IOC_DIRMASK=((1 << _IOC_DIRBITS) - 1)

_IOC_NRSHIFT=0
_IOC_TYPESHIFT=(_IOC_NRSHIFT + _IOC_NRBITS)
_IOC_SIZESHIFT=(_IOC_TYPESHIFT + _IOC_TYPEBITS)
_IOC_DIRSHIFT=(_IOC_SIZESHIFT + _IOC_SIZEBITS)

_IOC_NONE=0
_IOC_WRITE=1
_IOC_READ=2

def _IOC(dir, type, nr, size):
return (((dir) << _IOC_DIRSHIFT) | \
((type) << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))

import ctypes
def _IOC_TYPECHECK(t):
return ctypes.sizeof(t)

def _IO(type, nr):
return _IOC(_IOC_NONE, type, nr, 0)

def _IOR(type, nr, size):
return _IOC(_IOC_READ, type, nr, _IOC_TYPECHECK(size))

def _IOW(type, nr, size):
return _IOC(_IOC_WRITE, type, nr, _IOC_TYPECHECK(size))

if __name__ == "__main__":
print(_IOC_TYPESHIFT,_IOC_SIZESHIFT,_IOC_DIRSHIFT)
print(_IOC())

tun_oper.py:创建tun设备并监听数据发送请求.

import fcntl
import os

import ctypes
import struct

from if_tun import IfReq, TUNSETIFF, IFF_TUN

def tun_create(devname, flags):
fd = -1
if not devname:
return -1
fd = os.open("/dev/net/tun", os.O_RDWR)
if fd < 0:
print("open /dev/net/tun err!")
return fd
r=IfReq()
ctypes.memset(ctypes.byref(r), 0, ctypes.sizeof(r))
r.ifr_ifru.ifru_flags |= flags
r.ifr_ifrn.ifrn_name = devname.encode('utf-8')
try:
err = fcntl.ioctl(fd, TUNSETIFF, r)
except Exception as e:
print("err:",e)
os.close(fd)
return -1
return fd

if __name__ == "__main__":
fd = tun_create("tun3", IFF_TUN)
if fd < 0:
raise OSError

MAXSIZE=4096
while(True):
buf = os.read(fd,MAXSIZE)
if not buf:
break
print("read size:%d" % len(buf))

测试:

为tun3设备设置ip:
#ifconfig tun3 10.0.0.1 up



添加静态路由,通过tun3转发:
#route add -net 10.0.0.2 netmask 255.255.255.255 dev tun3



ping一个地址向tun3发送数据:
#ping 10.0.0.2


tun3收到了数据:
read size:88

read size:88

read size:88

read size:88

read size:88

read size:88

read size:88

read size:88
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tap tun python3 if_tun