python实现tun/tap虚拟设备

工作中用到了使用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


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

self-motivation

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值