Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- '''
- PyTap module that wraps the Linux TUN/TAP device
- @author: Dominik George
- '''
- # StB, 2.4.2011: Added method "fileno()", so we can use select.select().
- from fcntl import ioctl
- import os
- import struct
- import atexit
- TUNSETIFF = 0x400454ca
- IFF_TUN = 0x0001
- IFF_TAP = 0x0002
- DEFAULT_MTU = 1500
- # StB, 25.4.2011: MTU=1500 means an Ethernet frame size of 1518 Bytes! (with VLAN its max. 1522 Bytes) We need to increase the read buffer in the "read()" method. AFAIK Linux don't use VLAN as default.
- # http://de.wikipedia.org/wiki/Maximum_Transmission_Unit#Beispiel_Ethernet
- # http://de.wikipedia.org/w/index.php?title=Datei:Ethernetpaket.svg&filetimestamp=20090225134531
- ETHERNET_HEADER_SIZE = 18
- class TapDevice:
- ''' TUN/TAP device object '''
- def __init__(self, mode = IFF_TUN, name = '', dev = '/dev/net/tun'):
- '''
- Initialize TUN/TAP device object
- mode is either IFF_TUN or IFF_TAP to select tun or tap device mode.
- name is the name of the new device. An integer will be added to
- build the real device name.
- dev is the device node name the control channel is connected to.
- '''
- # Set interface mdoe in object
- self.mode = mode
- # Create interface name to request from tuntap module
- if name == '':
- if self.mode == IFF_TUN:
- self.name = 'tun%d'
- elif self.mode == IFF_TAP:
- self.name = 'tap%d'
- elif name.endswith('%d'):
- self.name = name
- else:
- self.name = name + '%d'
- # Open control device and request interface
- fd = os.open(dev, os.O_RDWR)
- ifs = ioctl(fd, TUNSETIFF, struct.pack("16sH", self.name, self.mode))
- # Retreive real interface name from control device
- self.name = ifs[:16].strip("\x00")
- # Set default MTU
- self.mtu = DEFAULT_MTU
- # Store fd for later
- self.__fd__ = fd
- # Properly close device on exit
- atexit.register(self.close)
- def fileno(self):
- return self.__fd__
- def read(self):
- '''
- Read data from the device. The device mtu determines how many bytes
- will be read.
- The data read from the device is returned in its raw form.
- '''
- data = os.read(self.__fd__, self.mtu + ETHERNET_HEADER_SIZE)
- return data
- def write(self, data):
- '''
- Write data to the device. No care is taken for MTU limitations or similar.
- '''
- os.write(self.__fd__, data)
- def ifconfig(self, **args):
- '''
- Issue ifconfig command on the device. The method takes the following
- keyword arguments:
- address => IP address of the device, can be in CIDR notation (see man ifconfig)
- netmask => Network mask
- network => Network base address, normally set automatically
- broadcast => Broadcast address, normally set automatically
- mtu => Link MTU, this will also affect the read() method
- hwclass => Hardware class, normally ether for ethernet
- hwaddress => Hardware (MAC) address, in conjunction with hwclass
- '''
- ifconfig = 'ifconfig ' + self.name + ' '
- # IP address ?
- try:
- ifconfig = ifconfig + args['address'] + ' '
- except KeyError:
- pass
- # Network mask ?
- try:
- ifconfig = ifconfig + 'netmask ' + args['netmask'] + ' '
- except KeyError:
- pass
- # Network base address ?
- try:
- ifconfig = ifconfig + 'network ' + args['network'] + ' '
- except KeyError:
- pass
- # Broadcast address ?
- try:
- ifconfig = ifconfig + 'broadcast ' + args['broadcast'] + ' '
- except KeyError:
- pass
- # MTU ?
- try:
- ifconfig = ifconfig + 'mtu ' + str(args['mtu']) + ' '
- except KeyError:
- pass
- # Hardware address ?
- try:
- ifconfig = ifconfig + 'hw ' + args['hwclass'] + ' ' + args['hwaddress'] + ' '
- except KeyError:
- pass
- # Try to set off ifconfig command
- ret = os.system(ifconfig)
- if ret != 0:
- raise IfconfigError()
- # Save MTU if ifconfig was successful so buffer sizes can be adjusted
- try:
- self.mtu = args['mtu']
- except KeyError:
- pass
- def up(self):
- '''
- Bring up device. This will effectively run "ifconfig up" on the device.
- '''
- ret = os.system("ifconfig " + self.name + " up")
- if ret != 0:
- raise IfconfigError()
- def down(self):
- '''
- Bring down device. This will effectively call "ifconfig down" on the device.
- '''
- ret = os.system("ifconfig " + self.name + " down")
- if ret != 0:
- raise IfconfigError()
- def close(self):
- '''
- Close the control channel. This will effectively drop all locks and remove the
- TUN/TAP device.
- You must manually take care that your code does not try to operate on the interface
- after closing the control channel.
- '''
- os.close(self.__fd__)
- class IfconfigError(Exception):
- ''' Exception thrown if an ifconfig command returns with a non-zero exit status. '''
- pass
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement