Question

I've made a Tun class that wraps pytun.TunTapDevice :

from pytun import TunTapDevice

class Tun(object):
    def __init__(self,name='tun',addr=None,dstaddr=None,netmask=None,mtu=None):

        tun = TunTapDevice(name=name)
        if addr     : tun.addr      = addr
        if dstaddr  : tun.dstaddr   = dstaddr
        if netmask  : tun.netmask   = netmask
        if mtu      : tun.mtu       = mtu
        self._tun = tun
        self.up = self._tun.up
        self.down = self._tun.down
        self.read = self._tun.read
        self.write = self._tun.write
        self.close = self._tun.close


    @property
    def name(self):
        return self._tun.name

    @property
    def mtu(self):
        return self._tun.mtu

The question is not about how to write a tunnel, but about how to write a test-case to ensure it works properly in unix-like oses using python unit-testing.

What should I write out to it to ensure is works? Maybe an ARP request, ICMP, DNS packet or anything else:

class TestTunnel(unittest.TestCase):

    def setUp(self):
        self.tun = Tun(name='tun0', addr='192.168.0.23', netmask='255.255.255.0',mtu=1500)

    def test_tunnel(self):
        self.tun.write(?????)
        self.assertEqual(self.tun.read(),????)

EDIT 1:

finally i got it by this code:

from select import select
import dpkt
import struct

class TunnelTestCase( unittest.TestCase):

    def setUp(self):

        self.tun = Tun(name='testtun',
                       addr='192.168.6.92',
                       dstaddr='192.168.6.93',
                       netmask='255.255.255.0', 
                       mtu=1500)
        self.tun.up()

    def _ip2str(self,ip):
        return '.'.join([str(i) for i in struct.unpack('!BBBB',ip)])

    def test_echo(self):
        reqPack = dpkt.ip.IP('E\x00\x00T\x00\x00@\x00@\x01\xac\x9f\xc0\xa8\x06]\xc0\xa8\x06\\\x08\x00\x1c\xae\t\xc7\x00\x01\x0f\x8adQq\xab\x01\x00\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567')
        self.tun.write(reqPack.pack())

        r,_w,_ex = select([self.tun],[],[],4)
        if len(r) and r[0] == self.tun:
            replyPack = dpkt.ip.IP(self.tun.read())
            self.assertEqual(self._ip2str(replyPack.src), self.tun.addr)
            self.assertEqual(self._ip2str(replyPack.dst), self.tun.dstaddr)
            return

        self.assert_(False, 'ICMP Echo timeout, the tunnel interface may not works properly in your system.')
Was it helpful?

Solution

You may simply be able to borrow the test cases from pytun and simplify them. In fact, I think that testing actual connectivity is done in their package, so unless you are trying to test something significantly different, you might be able to get away with just running there tests without modification. https://github.com/montag451/pytun/tree/master/test

Since it's a raw socket, you can simply try to send a plain ascii message from the client and verify it is received by the server, and then have the server send back an acknowledgement, which you can assert against.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top