|
14 | 14 | from asyncio import CancelledError, StreamReader, StreamWriter
|
15 | 15 | from collections import namedtuple
|
16 | 16 | from contextlib import asynccontextmanager, suppress
|
17 |
| -from os import chown, getenv |
| 17 | + |
| 18 | +if sys.platform != 'win32': |
| 19 | + from os import chown |
| 20 | + |
| 21 | +from os import getenv |
18 | 22 | from pathlib import Path
|
19 | 23 | from socket import AF_INET6, create_connection
|
20 | 24 | from ssl import VerifyMode
|
|
33 | 37 | from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
|
34 | 38 | from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
35 | 39 | from opack import dumps
|
36 |
| -from pytun_pmd3 import TunTapDevice |
| 40 | + |
| 41 | +if sys.platform != 'win32': |
| 42 | + from pytun_pmd3 import TunTapDevice |
| 43 | +else: |
| 44 | + from pywintunx_pmd3 import TunTapDevice, set_logger |
| 45 | + |
37 | 46 | from qh3.asyncio import QuicConnectionProtocol
|
38 | 47 | from qh3.asyncio.client import connect as aioquic_connect
|
39 | 48 | from qh3.asyncio.protocol import QuicStreamHandler
|
|
61 | 70 | else:
|
62 | 71 | LOOKBACK_HEADER = b'\x00\x00\x86\xdd'
|
63 | 72 |
|
| 73 | +if sys.platform == 'win32': |
| 74 | + def wintun_logger(level: int, timestamp: int, message: str) -> None: |
| 75 | + logging.getLogger('wintun').info(message) |
| 76 | + |
| 77 | + set_logger(wintun_logger) |
| 78 | + |
64 | 79 | IPV6_HEADER_SIZE = 40
|
65 | 80 | UDP_HEADER_SIZE = 8
|
66 | 81 |
|
@@ -140,12 +155,18 @@ async def wait_closed(self) -> None:
|
140 | 155 | @asyncio_print_traceback
|
141 | 156 | async def tun_read_task(self) -> None:
|
142 | 157 | read_size = self.tun.mtu + len(LOOKBACK_HEADER)
|
143 |
| - async with aiofiles.open(self.tun.fileno(), 'rb', opener=lambda path, flags: path, buffering=0) as f: |
| 158 | + if sys.platform != 'win32': |
| 159 | + async with aiofiles.open(self.tun.fileno(), 'rb', opener=lambda path, flags: path, buffering=0) as f: |
| 160 | + while True: |
| 161 | + packet = await f.read(read_size) |
| 162 | + assert packet.startswith(LOOKBACK_HEADER) |
| 163 | + packet = packet[len(LOOKBACK_HEADER):] |
| 164 | + await self.send_packet_to_device(packet) |
| 165 | + else: |
144 | 166 | while True:
|
145 |
| - packet = await f.read(read_size) |
146 |
| - assert packet.startswith(LOOKBACK_HEADER) |
147 |
| - packet = packet[len(LOOKBACK_HEADER):] |
148 |
| - await self.send_packet_to_device(packet) |
| 167 | + packet = await asyncio.get_running_loop().run_in_executor(None, self.tun.read) |
| 168 | + if packet: |
| 169 | + await self.send_packet_to_device(packet) |
149 | 170 |
|
150 | 171 | def start_tunnel(self, address: str, mtu: int) -> None:
|
151 | 172 | self.tun = TunTapDevice()
|
@@ -398,7 +419,7 @@ def save_pair_record(self) -> None:
|
398 | 419 | 'private_key': self.ed25519_private_key.private_bytes_raw(),
|
399 | 420 | 'remote_unlock_host_key': self.remote_unlock_host_key
|
400 | 421 | }))
|
401 |
| - if getenv('SUDO_UID'): |
| 422 | + if getenv('SUDO_UID') and sys.platform != 'win32': |
402 | 423 | chown(self.pair_record_path, int(getenv('SUDO_UID')), int(getenv('SUDO_GID')))
|
403 | 424 |
|
404 | 425 | @property
|
|
0 commit comments