2025-12-25 upload
This commit is contained in:
274
venv/Lib/site-packages/pydivert/windivert.py
Normal file
274
venv/Lib/site-packages/pydivert/windivert.py
Normal file
@@ -0,0 +1,274 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2016 Fabio Falcinelli, Maximilian Hils
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import subprocess
|
||||
import sys
|
||||
from ctypes import byref, c_uint64, c_uint, c_char, c_char_p
|
||||
|
||||
from pydivert import windivert_dll
|
||||
from pydivert.consts import Layer, Direction, Flag
|
||||
from pydivert.packet import Packet
|
||||
from pydivert.util import PY2
|
||||
|
||||
DEFAULT_PACKET_BUFFER_SIZE = 1500
|
||||
|
||||
|
||||
class WinDivert(object):
|
||||
"""
|
||||
A WinDivert handle that can be used to capture packets.
|
||||
The main methods are `.open()`, `.recv()`, `.send()` and `.close()`.
|
||||
|
||||
Use it like so::
|
||||
|
||||
with pydivert.WinDivert() as w:
|
||||
for packet in w:
|
||||
print(packet)
|
||||
w.send(packet)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, filter="true", layer=Layer.NETWORK, priority=0, flags=Flag.DEFAULT):
|
||||
self._handle = None
|
||||
self._filter = filter.encode()
|
||||
self._layer = layer
|
||||
self._priority = priority
|
||||
self._flags = flags
|
||||
|
||||
def __repr__(self):
|
||||
return '<WinDivert state="{}" filter="{}" layer="{}" priority="{}" flags="{}" />'.format(
|
||||
"open" if self._handle is not None else "closed",
|
||||
self._filter.decode(),
|
||||
self._layer,
|
||||
self._priority,
|
||||
self._flags
|
||||
)
|
||||
|
||||
def __enter__(self):
|
||||
self.open()
|
||||
return self
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.close()
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
return self.recv()
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
next = __next__
|
||||
|
||||
@staticmethod
|
||||
def register():
|
||||
"""
|
||||
An utility method to register the service the first time.
|
||||
It is usually not required to call this function, as WinDivert will register itself when opening a handle.
|
||||
"""
|
||||
with WinDivert("false"):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def is_registered():
|
||||
"""
|
||||
Check if the WinDivert service is currently installed on the system.
|
||||
"""
|
||||
return subprocess.call("sc query WinDivert1.3", stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE) == 0
|
||||
|
||||
@staticmethod
|
||||
def unregister():
|
||||
"""
|
||||
Unregisters the WinDivert service.
|
||||
This function only requests a service stop, which may not be processed immediately if there are still open
|
||||
handles.
|
||||
"""
|
||||
subprocess.check_call("sc stop WinDivert1.3", stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
@staticmethod
|
||||
def check_filter(filter, layer=Layer.NETWORK):
|
||||
"""
|
||||
Checks if the given packet filter string is valid with respect to the filter language.
|
||||
|
||||
The remapped function is WinDivertHelperCheckFilter::
|
||||
|
||||
BOOL WinDivertHelperCheckFilter(
|
||||
__in const char *filter,
|
||||
__in WINDIVERT_LAYER layer,
|
||||
__out_opt const char **errorStr,
|
||||
__out_opt UINT *errorPos
|
||||
);
|
||||
|
||||
See: https://reqrypt.org/windivert-doc.html#divert_helper_check_filter
|
||||
|
||||
:return: A tuple (res, pos, msg) with check result in 'res' human readable description of the error in 'msg' and the error's position in 'pos'.
|
||||
"""
|
||||
res, pos, msg = False, c_uint(), c_char_p()
|
||||
try:
|
||||
res = windivert_dll.WinDivertHelperCheckFilter(filter.encode(), layer, byref(msg), byref(pos))
|
||||
except OSError:
|
||||
pass
|
||||
return res, pos.value, msg.value.decode()
|
||||
|
||||
def open(self):
|
||||
"""
|
||||
Opens a WinDivert handle for the given filter.
|
||||
Unless otherwise specified by flags, any packet that matches the filter will be diverted to the handle.
|
||||
Diverted packets can be read by the application with receive().
|
||||
|
||||
The remapped function is WinDivertOpen::
|
||||
|
||||
HANDLE WinDivertOpen(
|
||||
__in const char *filter,
|
||||
__in WINDIVERT_LAYER layer,
|
||||
__in INT16 priority,
|
||||
__in UINT64 flags
|
||||
);
|
||||
|
||||
For more info on the C call visit: http://reqrypt.org/windivert-doc.html#divert_open
|
||||
"""
|
||||
if self.is_open:
|
||||
raise RuntimeError("WinDivert handle is already open.")
|
||||
self._handle = windivert_dll.WinDivertOpen(self._filter, self._layer, self._priority,
|
||||
self._flags)
|
||||
|
||||
@property
|
||||
def is_open(self):
|
||||
"""
|
||||
Indicates if there is currently an open handle.
|
||||
"""
|
||||
return bool(self._handle)
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
Closes the handle opened by open().
|
||||
|
||||
The remapped function is WinDivertClose::
|
||||
|
||||
BOOL WinDivertClose(
|
||||
__in HANDLE handle
|
||||
);
|
||||
|
||||
For more info on the C call visit: http://reqrypt.org/windivert-doc.html#divert_close
|
||||
"""
|
||||
if not self.is_open:
|
||||
raise RuntimeError("WinDivert handle is not open.")
|
||||
windivert_dll.WinDivertClose(self._handle)
|
||||
self._handle = None
|
||||
|
||||
def recv(self, bufsize=DEFAULT_PACKET_BUFFER_SIZE):
|
||||
"""
|
||||
Receives a diverted packet that matched the filter.
|
||||
|
||||
The remapped function is WinDivertRecv::
|
||||
|
||||
BOOL WinDivertRecv(
|
||||
__in HANDLE handle,
|
||||
__out PVOID pPacket,
|
||||
__in UINT packetLen,
|
||||
__out_opt PWINDIVERT_ADDRESS pAddr,
|
||||
__out_opt UINT *recvLen
|
||||
);
|
||||
|
||||
For more info on the C call visit: http://reqrypt.org/windivert-doc.html#divert_recv
|
||||
|
||||
:return: The return value is a `pydivert.Packet`.
|
||||
"""
|
||||
if self._handle is None:
|
||||
raise RuntimeError("WinDivert handle is not open")
|
||||
|
||||
packet = bytearray(bufsize)
|
||||
packet_ = (c_char * bufsize).from_buffer(packet)
|
||||
address = windivert_dll.WinDivertAddress()
|
||||
recv_len = c_uint(0)
|
||||
windivert_dll.WinDivertRecv(self._handle, packet_, bufsize, byref(address), byref(recv_len))
|
||||
return Packet(
|
||||
memoryview(packet)[:recv_len.value],
|
||||
(address.IfIdx, address.SubIfIdx),
|
||||
Direction(address.Direction)
|
||||
)
|
||||
|
||||
def send(self, packet, recalculate_checksum=True):
|
||||
"""
|
||||
Injects a packet into the network stack.
|
||||
Recalculates the checksum before sending unless recalculate_checksum=False is passed.
|
||||
|
||||
The injected packet may be one received from recv(), or a modified version, or a completely new packet.
|
||||
Injected packets can be captured and diverted again by other WinDivert handles with lower priorities.
|
||||
|
||||
The remapped function is WinDivertSend::
|
||||
|
||||
BOOL WinDivertSend(
|
||||
__in HANDLE handle,
|
||||
__in PVOID pPacket,
|
||||
__in UINT packetLen,
|
||||
__in PWINDIVERT_ADDRESS pAddr,
|
||||
__out_opt UINT *sendLen
|
||||
);
|
||||
|
||||
For more info on the C call visit: http://reqrypt.org/windivert-doc.html#divert_send
|
||||
|
||||
:return: The return value is the number of bytes actually sent.
|
||||
"""
|
||||
if recalculate_checksum:
|
||||
packet.recalculate_checksums()
|
||||
|
||||
send_len = c_uint(0)
|
||||
if PY2:
|
||||
# .from_buffer(memoryview) does not work on PY2
|
||||
buff = bytearray(packet.raw)
|
||||
else:
|
||||
buff = packet.raw
|
||||
buff = (c_char * len(packet.raw)).from_buffer(buff)
|
||||
windivert_dll.WinDivertSend(self._handle, buff, len(packet.raw), byref(packet.wd_addr),
|
||||
byref(send_len))
|
||||
return send_len
|
||||
|
||||
def get_param(self, name):
|
||||
"""
|
||||
Get a WinDivert parameter. See pydivert.Param for the list of parameters.
|
||||
|
||||
The remapped function is WinDivertGetParam::
|
||||
|
||||
BOOL WinDivertGetParam(
|
||||
__in HANDLE handle,
|
||||
__in WINDIVERT_PARAM param,
|
||||
__out UINT64 *pValue
|
||||
);
|
||||
|
||||
For more info on the C call visit: http://reqrypt.org/windivert-doc.html#divert_get_param
|
||||
|
||||
:return: The parameter value.
|
||||
"""
|
||||
value = c_uint64(0)
|
||||
windivert_dll.WinDivertGetParam(self._handle, name, byref(value))
|
||||
return value.value
|
||||
|
||||
def set_param(self, name, value):
|
||||
"""
|
||||
Set a WinDivert parameter. See pydivert.Param for the list of parameters.
|
||||
|
||||
The remapped function is DivertSetParam::
|
||||
|
||||
BOOL WinDivertSetParam(
|
||||
__in HANDLE handle,
|
||||
__in WINDIVERT_PARAM param,
|
||||
__in UINT64 value
|
||||
);
|
||||
|
||||
For more info on the C call visit: http://reqrypt.org/windivert-doc.html#divert_set_param
|
||||
"""
|
||||
return windivert_dll.WinDivertSetParam(self._handle, name, value)
|
||||
Reference in New Issue
Block a user