async def make(cls, parent: Process, addr: ipaddress.IPv4Address, peer: ipaddress.IPv4Address) -> 'Tun': # put each tun in a separate netns; I tried putting them in # the same netns, but got silent packet delivery failures. process = await parent.clone(CLONE.NEWNET | CLONE.FILES) self = cls( process, await process.task.open(await process.ptr("/dev/net/tun"), O.RDWR), 'tun0', addr, await process.task.socket(AF.INET, SOCK.STREAM), ) await self.fd.ioctl( TUNSETIFF, await self.process.ptr(Ifreq(self.name, flags=IFF.TUN | IFF.NO_PI))) # set up the tun - these ioctls don't actually affect the socket await self.sock.ioctl( SIOC.SIFFLAGS, await self.process.ptr(Ifreq(self.name, flags=IFF.UP))) await self.sock.ioctl( SIOC.SIFADDR, await self.process.ptr(Ifreq(self.name, addr=SockaddrIn(0, self.addr)))) await self.sock.ioctl( SIOC.SIFDSTADDR, await self.process.ptr(Ifreq(self.name, addr=SockaddrIn(0, peer)))) await self.sock.bind(await self.process.ptr(SockaddrIn(1234, self.addr))) return self
async def test_dgram(self) -> None: "With DGRAM sockets, without SO.REUSEADDR, binding 0 twice will never give you the same port." sockfd = await self.process.task.socket(AF.INET, SOCK.DGRAM) await sockfd.bind(await self.process.task.ptr(SockaddrIn(0, '127.0.0.1'))) sockfd2 = await self.process.task.socket(AF.INET, SOCK.DGRAM) with self.assertRaises(OSError) as cm: await sockfd2.bind(await self.process.task.ptr( SockaddrIn(0, '127.0.0.1'))) self.assertEqual(cm.exception.errno, errno.EADDRINUSE)
async def test_stream_reuseaddr(self) -> None: "With STREAM sockets, even if you use SO.REUSEADDR, binding 0 twice will never give you the same port." sockfd = await self.process.task.socket(AF.INET, SOCK.STREAM) await sockfd.setsockopt(SOL.SOCKET, SO.REUSEADDR, await self.process.ptr(Int32(1))) await sockfd.bind(await self.process.task.ptr(SockaddrIn(0, '127.0.0.1'))) sockfd2 = await self.process.task.socket(AF.INET, SOCK.STREAM) await sockfd2.setsockopt(SOL.SOCKET, SO.REUSEADDR, await self.process.ptr(Int32(1))) with self.assertRaises(OSError) as cm: await sockfd2.bind(await self.process.task.ptr( SockaddrIn(0, '127.0.0.1'))) self.assertEqual(cm.exception.errno, errno.EADDRINUSE)
async def test_reuseaddr_listen(self) -> None: """If you use SO.REUSEADDR, your local and peer address can be the same This is kind of alarming and surprising, but it's a real behavior. """ sockfd = await self.process.task.socket(AF.INET, SOCK.STREAM) await sockfd.setsockopt(SOL.SOCKET, SO.REUSEADDR, await self.process.ptr(Int32(1))) addr = await self.process.bind_getsockname(sockfd, SockaddrIn(0, '127.0.0.1')) sockfd2 = await self.process.task.socket(AF.INET, SOCK.STREAM) await sockfd2.setsockopt(SOL.SOCKET, SO.REUSEADDR, await self.process.ptr(Int32(1))) await sockfd2.bind(await self.process.ptr(addr)) await sockfd.listen(10) await sockfd2.connect(await self.process.ptr(addr)) sockbuf_ptr = await sockfd2.getsockname(await self.process.ptr( Sockbuf(await self.process.malloc(SockaddrIn)))) self.assertEqual(addr, await (await sockbuf_ptr.read()).buf.read()) sockbuf_ptr = await sockfd2.getpeername(await self.process.ptr( Sockbuf(await self.process.malloc(SockaddrIn)))) self.assertEqual(addr, await (await sockbuf_ptr.read()).buf.read())
def test_ifreq(self) -> None: initial = Ifreq() initial.name = "hello" initial.addr = SockaddrIn(42, "127.0.0.1") output = Ifreq.from_bytes(initial.to_bytes()) self.assertEqual(initial.name, output.name) self.assertEqual(initial.addr.port, output.addr.port) self.assertEqual(initial.addr.addr, output.addr.addr)
async def test_dgram_reuseaddr(self) -> None: """With DGRAM sockets, if you use SO.REUSEADDR, binding 0 *can* give you the same port. But note that you can also just set REUSEADDR after binding. """ sockfd = await self.process.task.socket(AF.INET, SOCK.DGRAM) await sockfd.setsockopt(SOL.SOCKET, SO.REUSEADDR, await self.process.ptr(Int32(1))) addr = await self.process.bind_getsockname(sockfd, SockaddrIn(0, '127.0.0.1')) sockfd2 = await self.process.task.socket(AF.INET, SOCK.DGRAM) await sockfd2.setsockopt(SOL.SOCKET, SO.REUSEADDR, await self.process.ptr(Int32(1))) addr2 = await self.process.bind_getsockname(sockfd2, SockaddrIn(0, '127.0.0.1')) self.assertEqual(addr, addr2)
def test_ifreq(self) -> None: initial = Ifreq() initial.name = "hello" initial.addr = SockaddrIn(42, "127.0.0.1") output = Ifreq.from_bytes(initial.to_bytes()) self.assertEqual(initial.name, output.name) addr = t.cast(SockaddrIn, initial.addr.parse()) self.assertIsInstance(addr, SockaddrIn) self.assertEqual(initial.addr.port, addr.port) self.assertEqual(initial.addr.addr, addr.addr)
async def test_ioctl(self) -> None: await self.process.unshare(CLONE.NEWNET) tun_fd = await self.process.task.open( await self.process.ram.ptr("/dev/net/tun"), O.RDWR) name = 'tun0' ptr = await self.process.ram.ptr(Ifreq(name, flags=IFF.TUN)) await tun_fd.ioctl(TUNSETIFF, ptr) sock = await self.process.task.socket(AF.INET, SOCK.STREAM) await sock.ioctl(SIOC.GIFINDEX, ptr) # this is the second interface in an empty netns self.assertEqual((await ptr.read()).ifindex, 2) # set it up ptr = await ptr.write(Ifreq(name, flags=IFF.UP)) await sock.ioctl(SIOC.SIFFLAGS, ptr) await sock.ioctl(SIOC.GIFFLAGS, ptr) self.assertIn(IFF.UP, (await ptr.read()).flags) # type: ignore # add IP address addr = SockaddrIn(0, '10.0.0.1') ptr = await ptr.write(Ifreq(name, addr=addr)) await sock.ioctl(SIOC.SIFADDR, ptr) await sock.ioctl(SIOC.GIFADDR, ptr) self.assertEqual(addr, (await ptr.read()).addr.parse())
def __set__(self, instance, value: SockaddrIn) -> None: data_bytes = value.to_bytes() ffi.memmove(ffi.addressof(instance.cffi, self.name), ffi.from_buffer(data_bytes), len(data_bytes))
def __get__(self, instance, owner) -> SockaddrIn: data_bytes = bytes(ffi.buffer(ffi.addressof(instance.cffi, self.name))) return SockaddrIn.from_bytes(data_bytes)
async def do_conn(): await conn.sock.connect(await conn.process.ptr( SockaddrIn(1234, acc.addr)))