2025-12-25 upload
This commit is contained in:
350
venv/Lib/site-packages/pydivert/packet/__init__.py
Normal file
350
venv/Lib/site-packages/pydivert/packet/__init__.py
Normal file
@@ -0,0 +1,350 @@
|
||||
# -*- 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 ctypes
|
||||
import pprint
|
||||
import socket
|
||||
|
||||
from pydivert import windivert_dll
|
||||
from pydivert.consts import Direction, IPV6_EXT_HEADERS, Protocol, Layer
|
||||
from pydivert.packet.header import Header
|
||||
from pydivert.packet.icmp import ICMPv4Header, ICMPv6Header
|
||||
from pydivert.packet.ip import IPv4Header, IPv6Header
|
||||
from pydivert.packet.tcp import TCPHeader
|
||||
from pydivert.packet.udp import UDPHeader
|
||||
from pydivert.util import cached_property, indexbyte as i, PY2
|
||||
|
||||
|
||||
class Packet(object):
|
||||
"""
|
||||
A single packet, possibly including an IP header, a TCP/UDP header and a payload.
|
||||
Creation of packets is cheap, parsing is done on first attribute access.
|
||||
"""
|
||||
|
||||
def __init__(self, raw, interface, direction):
|
||||
if isinstance(raw, bytes):
|
||||
raw = memoryview(bytearray(raw))
|
||||
self.raw = raw # type: memoryview
|
||||
self.interface = interface
|
||||
self.direction = direction
|
||||
|
||||
def __repr__(self):
|
||||
def dump(x):
|
||||
if isinstance(x, Header) or isinstance(x, Packet):
|
||||
d = {}
|
||||
for k in dir(x):
|
||||
v = getattr(x, k)
|
||||
if k.startswith("_") or callable(v):
|
||||
continue
|
||||
if k in {"address_family", "protocol", "ip", "icmp"}:
|
||||
continue
|
||||
if k == "payload" and v and len(v) > 20:
|
||||
v = v[:20] + b"..."
|
||||
d[k] = dump(v)
|
||||
if isinstance(x, Packet):
|
||||
return pprint.pformat(d)
|
||||
return d
|
||||
return x
|
||||
|
||||
return "Packet({})".format(dump(self))
|
||||
|
||||
@property
|
||||
def is_outbound(self):
|
||||
"""
|
||||
Indicates if the packet is outbound.
|
||||
Convenience method for ``.direction``.
|
||||
"""
|
||||
return self.direction == Direction.OUTBOUND
|
||||
|
||||
@property
|
||||
def is_inbound(self):
|
||||
"""
|
||||
Indicates if the packet is inbound.
|
||||
Convenience method for ``.direction``.
|
||||
"""
|
||||
return self.direction == Direction.INBOUND
|
||||
|
||||
@property
|
||||
def is_loopback(self):
|
||||
"""
|
||||
- True, if the packet is on the loopback interface.
|
||||
- False, otherwise.
|
||||
"""
|
||||
return self.interface[0] == 1
|
||||
|
||||
@cached_property
|
||||
def address_family(self):
|
||||
"""
|
||||
The packet address family:
|
||||
- socket.AF_INET, if IPv4
|
||||
- socket.AF_INET6, if IPv6
|
||||
- None, otherwise.
|
||||
"""
|
||||
if len(self.raw) >= 20:
|
||||
v = i(self.raw[0]) >> 4
|
||||
if v == 4:
|
||||
return socket.AF_INET
|
||||
if v == 6:
|
||||
return socket.AF_INET6
|
||||
|
||||
@cached_property
|
||||
def protocol(self):
|
||||
"""
|
||||
- | A (ipproto, proto_start) tuple.
|
||||
| ``ipproto`` is the IP protocol in use, e.g. Protocol.TCP or Protocol.UDP.
|
||||
| ``proto_start`` denotes the beginning of the protocol data.
|
||||
| If the packet does not match our expectations, both ipproto and proto_start are None.
|
||||
"""
|
||||
if self.address_family == socket.AF_INET:
|
||||
proto = i(self.raw[9])
|
||||
start = (i(self.raw[0]) & 0b1111) * 4
|
||||
elif self.address_family == socket.AF_INET6:
|
||||
proto = i(self.raw[6])
|
||||
|
||||
# skip over well-known ipv6 headers
|
||||
start = 40
|
||||
while proto in IPV6_EXT_HEADERS:
|
||||
if start >= len(self.raw):
|
||||
# less than two bytes left
|
||||
start = None
|
||||
proto = None
|
||||
break
|
||||
if proto == Protocol.FRAGMENT:
|
||||
hdrlen = 8
|
||||
elif proto == Protocol.AH:
|
||||
hdrlen = (i(self.raw[start + 1]) + 2) * 4
|
||||
else:
|
||||
# Protocol.HOPOPT, Protocol.DSTOPTS, Protocol.ROUTING
|
||||
hdrlen = (i(self.raw[start + 1]) + 1) * 8
|
||||
proto = i(self.raw[start])
|
||||
start += hdrlen
|
||||
else:
|
||||
start = None
|
||||
proto = None
|
||||
|
||||
out_of_bounds = (
|
||||
(proto == Protocol.TCP and start + 20 > len(self.raw)) or
|
||||
(proto == Protocol.UDP and start + 8 > len(self.raw)) or
|
||||
(proto in {Protocol.ICMP, Protocol.ICMPV6} and start + 4 > len(self.raw))
|
||||
)
|
||||
if out_of_bounds:
|
||||
# special-case tcp/udp so that we can rely on .protocol for the port properties.
|
||||
start = None
|
||||
proto = None
|
||||
|
||||
return proto, start
|
||||
|
||||
@cached_property
|
||||
def ipv4(self):
|
||||
"""
|
||||
- An IPv4Header instance, if the packet is valid IPv4.
|
||||
- None, otherwise.
|
||||
"""
|
||||
if self.address_family == socket.AF_INET:
|
||||
return IPv4Header(self)
|
||||
|
||||
@cached_property
|
||||
def ipv6(self):
|
||||
"""
|
||||
- An IPv6Header instance, if the packet is valid IPv6.
|
||||
- None, otherwise.
|
||||
"""
|
||||
if self.address_family == socket.AF_INET6:
|
||||
return IPv6Header(self)
|
||||
|
||||
@cached_property
|
||||
def ip(self):
|
||||
"""
|
||||
- An IPHeader instance, if the packet is valid IPv4 or IPv6.
|
||||
- None, otherwise.
|
||||
"""
|
||||
return self.ipv4 or self.ipv6
|
||||
|
||||
@cached_property
|
||||
def icmpv4(self):
|
||||
"""
|
||||
- An ICMPv4Header instance, if the packet is valid ICMPv4.
|
||||
- None, otherwise.
|
||||
"""
|
||||
ipproto, proto_start = self.protocol
|
||||
if ipproto == Protocol.ICMP:
|
||||
return ICMPv4Header(self, proto_start)
|
||||
|
||||
@cached_property
|
||||
def icmpv6(self):
|
||||
"""
|
||||
- An ICMPv6Header instance, if the packet is valid ICMPv6.
|
||||
- None, otherwise.
|
||||
"""
|
||||
ipproto, proto_start = self.protocol
|
||||
if ipproto == Protocol.ICMPV6:
|
||||
return ICMPv6Header(self, proto_start)
|
||||
|
||||
@cached_property
|
||||
def icmp(self):
|
||||
"""
|
||||
- An ICMPHeader instance, if the packet is valid ICMPv4 or ICMPv6.
|
||||
- None, otherwise.
|
||||
"""
|
||||
return self.icmpv4 or self.icmpv6
|
||||
|
||||
@cached_property
|
||||
def tcp(self):
|
||||
"""
|
||||
- An TCPHeader instance, if the packet is valid TCP.
|
||||
- None, otherwise.
|
||||
"""
|
||||
ipproto, proto_start = self.protocol
|
||||
if ipproto == Protocol.TCP:
|
||||
return TCPHeader(self, proto_start)
|
||||
|
||||
@cached_property
|
||||
def udp(self):
|
||||
"""
|
||||
- An TCPHeader instance, if the packet is valid UDP.
|
||||
- None, otherwise.
|
||||
"""
|
||||
ipproto, proto_start = self.protocol
|
||||
if ipproto == Protocol.UDP:
|
||||
return UDPHeader(self, proto_start)
|
||||
|
||||
@cached_property
|
||||
def _port(self):
|
||||
"""header that implements PortMixin"""
|
||||
return self.tcp or self.udp
|
||||
|
||||
@cached_property
|
||||
def _payload(self):
|
||||
"""header that implements PayloadMixin"""
|
||||
return self.tcp or self.udp or self.icmpv4 or self.icmpv6
|
||||
|
||||
@property
|
||||
def src_addr(self):
|
||||
"""
|
||||
- The source address, if the packet is valid IPv4 or IPv6.
|
||||
- None, otherwise.
|
||||
"""
|
||||
if self.ip:
|
||||
return self.ip.src_addr
|
||||
|
||||
@src_addr.setter
|
||||
def src_addr(self, val):
|
||||
self.ip.src_addr = val
|
||||
|
||||
@property
|
||||
def dst_addr(self):
|
||||
"""
|
||||
- The destination address, if the packet is valid IPv4 or IPv6.
|
||||
- None, otherwise.
|
||||
"""
|
||||
if self.ip:
|
||||
return self.ip.dst_addr
|
||||
|
||||
@dst_addr.setter
|
||||
def dst_addr(self, val):
|
||||
self.ip.dst_addr = val
|
||||
|
||||
@property
|
||||
def src_port(self):
|
||||
"""
|
||||
- The source port, if the packet is valid TCP or UDP.
|
||||
- None, otherwise.
|
||||
"""
|
||||
if self._port:
|
||||
return self._port.src_port
|
||||
|
||||
@src_port.setter
|
||||
def src_port(self, val):
|
||||
self._port.src_port = val
|
||||
|
||||
@property
|
||||
def dst_port(self):
|
||||
"""
|
||||
- The destination port, if the packet is valid TCP or UDP.
|
||||
- None, otherwise.
|
||||
"""
|
||||
if self._port:
|
||||
return self._port.dst_port
|
||||
|
||||
@dst_port.setter
|
||||
def dst_port(self, val):
|
||||
self._port.dst_port = val
|
||||
|
||||
@property
|
||||
def payload(self):
|
||||
"""
|
||||
- The payload, if the packet is valid TCP, UDP, ICMP or ICMPv6.
|
||||
- None, otherwise.
|
||||
"""
|
||||
if self._payload:
|
||||
return self._payload.payload
|
||||
|
||||
@payload.setter
|
||||
def payload(self, val):
|
||||
self._payload.payload = val
|
||||
|
||||
def recalculate_checksums(self, flags=0):
|
||||
"""
|
||||
(Re)calculates the checksum for any IPv4/ICMP/ICMPv6/TCP/UDP checksum present in the given packet.
|
||||
Individual checksum calculations may be disabled via the appropriate flag.
|
||||
Typically this function should be invoked on a modified packet before it is injected with WinDivert.send().
|
||||
Returns the number of checksums calculated.
|
||||
|
||||
See: https://reqrypt.org/windivert-doc.html#divert_helper_calc_checksums
|
||||
"""
|
||||
buff, buff_ = self.__to_buffers()
|
||||
num = windivert_dll.WinDivertHelperCalcChecksums(ctypes.byref(buff_), len(self.raw), flags)
|
||||
if PY2:
|
||||
self.raw = memoryview(buff)[:len(self.raw)]
|
||||
return num
|
||||
|
||||
def __to_buffers(self):
|
||||
buff = bytearray(self.raw.tobytes()) if PY2 else self.raw.obj
|
||||
return buff, (ctypes.c_char * len(self.raw)).from_buffer(buff)
|
||||
|
||||
@property
|
||||
def wd_addr(self):
|
||||
"""
|
||||
Gets the interface and direction as a `WINDIVERT_ADDRESS` structure.
|
||||
:return: The `WINDIVERT_ADDRESS` structure.
|
||||
"""
|
||||
address = windivert_dll.WinDivertAddress()
|
||||
address.IfIdx, address.SubIfIdx = self.interface
|
||||
address.Direction = self.direction
|
||||
return address
|
||||
|
||||
def matches(self, filter, layer=Layer.NETWORK):
|
||||
"""
|
||||
Evaluates the packet against the given packet filter string.
|
||||
|
||||
The remapped function is::
|
||||
|
||||
BOOL WinDivertHelperEvalFilter(
|
||||
__in const char *filter,
|
||||
__in WINDIVERT_LAYER layer,
|
||||
__in PVOID pPacket,
|
||||
__in UINT packetLen,
|
||||
__in PWINDIVERT_ADDRESS pAddr
|
||||
);
|
||||
|
||||
See: https://reqrypt.org/windivert-doc.html#divert_helper_eval_filter
|
||||
|
||||
:param filter: The filter string.
|
||||
:param layer: The network layer.
|
||||
:return: True if the packet matches, and False otherwise.
|
||||
"""
|
||||
buff, buff_ = self.__to_buffers()
|
||||
return windivert_dll.WinDivertHelperEvalFilter(filter.encode(), layer, ctypes.byref(buff_), len(self.raw),
|
||||
ctypes.byref(self.wd_addr))
|
||||
91
venv/Lib/site-packages/pydivert/packet/header.py
Normal file
91
venv/Lib/site-packages/pydivert/packet/header.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# -*- 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 struct
|
||||
|
||||
|
||||
class Header(object):
|
||||
def __init__(self, packet, start=0):
|
||||
self._packet = packet # type: "pydivert.Packet"
|
||||
self._start = start
|
||||
|
||||
@property
|
||||
def raw(self):
|
||||
"""
|
||||
The raw header, possibly including payload.
|
||||
"""
|
||||
return self._packet.raw[self._start:]
|
||||
|
||||
@raw.setter
|
||||
def raw(self, val):
|
||||
if len(val) == len(self.raw):
|
||||
self.raw[:] = val
|
||||
else:
|
||||
self._packet.raw = memoryview(bytearray(
|
||||
self._packet.raw[:self._start].tobytes() + val
|
||||
))
|
||||
self._packet.ip.packet_len = len(self._packet.raw)
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
if key in dir(self) or key in {"_packet", "_start"}:
|
||||
return super(Header, self).__setattr__(key, value)
|
||||
raise AttributeError("AttributeError: '{}' object has no attribute '{}'".format(
|
||||
type(self).__name__,
|
||||
key
|
||||
))
|
||||
|
||||
|
||||
class PayloadMixin(object):
|
||||
@property
|
||||
def header_len(self):
|
||||
raise NotImplementedError() # pragma: no cover
|
||||
|
||||
@property
|
||||
def payload(self):
|
||||
"""
|
||||
The packet payload data.
|
||||
"""
|
||||
return self.raw[self.header_len:].tobytes()
|
||||
|
||||
@payload.setter
|
||||
def payload(self, val):
|
||||
if len(val) == len(self.raw) - self.header_len:
|
||||
self.raw[self.header_len:] = val
|
||||
else:
|
||||
self.raw = self.raw[:self.header_len].tobytes() + val
|
||||
|
||||
|
||||
class PortMixin(object):
|
||||
@property
|
||||
def src_port(self):
|
||||
"""
|
||||
The source port.
|
||||
"""
|
||||
return struct.unpack_from("!H", self.raw, 0)[0]
|
||||
|
||||
@property
|
||||
def dst_port(self):
|
||||
"""
|
||||
The destination port.
|
||||
"""
|
||||
return struct.unpack_from("!H", self.raw, 2)[0]
|
||||
|
||||
@src_port.setter
|
||||
def src_port(self, val):
|
||||
self.raw[0:2] = struct.pack("!H", val)
|
||||
|
||||
@dst_port.setter
|
||||
def dst_port(self, val):
|
||||
self.raw[2:4] = struct.pack("!H", val)
|
||||
53
venv/Lib/site-packages/pydivert/packet/icmp.py
Normal file
53
venv/Lib/site-packages/pydivert/packet/icmp.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# -*- 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/>.
|
||||
from pydivert.packet.header import Header, PayloadMixin
|
||||
from pydivert.util import indexbyte as i, raw_property
|
||||
|
||||
|
||||
class ICMPHeader(Header, PayloadMixin):
|
||||
header_len = 4
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
The ICMP message type.
|
||||
"""
|
||||
return i(self.raw[0])
|
||||
|
||||
@type.setter
|
||||
def type(self, val):
|
||||
self.raw[0] = i(val)
|
||||
|
||||
@property
|
||||
def code(self):
|
||||
"""
|
||||
The ICMP message code.
|
||||
"""
|
||||
return i(self.raw[1])
|
||||
|
||||
@code.setter
|
||||
def code(self, val):
|
||||
self.raw[1] = i(val)
|
||||
|
||||
cksum = raw_property('!H', 2, docs='The ICMP header checksum field.')
|
||||
|
||||
|
||||
class ICMPv4Header(ICMPHeader):
|
||||
pass
|
||||
|
||||
|
||||
class ICMPv6Header(ICMPHeader):
|
||||
pass
|
||||
216
venv/Lib/site-packages/pydivert/packet/ip.py
Normal file
216
venv/Lib/site-packages/pydivert/packet/ip.py
Normal file
@@ -0,0 +1,216 @@
|
||||
# -*- 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 socket
|
||||
import struct
|
||||
|
||||
from pydivert.packet.header import Header
|
||||
from pydivert.util import PY2, PY34, flag_property, indexbyte as i, raw_property
|
||||
|
||||
|
||||
class IPHeader(Header):
|
||||
_src_addr = slice(0, 0)
|
||||
_dst_addr = slice(0, 0)
|
||||
_af = None
|
||||
|
||||
@property
|
||||
def src_addr(self):
|
||||
"""
|
||||
The packet source address.
|
||||
"""
|
||||
try:
|
||||
return socket.inet_ntop(self._af, self.raw[self._src_addr].tobytes())
|
||||
except (ValueError, socket.error):
|
||||
pass
|
||||
|
||||
@src_addr.setter
|
||||
def src_addr(self, val):
|
||||
self.raw[self._src_addr] = socket.inet_pton(self._af, val)
|
||||
|
||||
@property
|
||||
def dst_addr(self):
|
||||
"""
|
||||
The packet destination address.
|
||||
"""
|
||||
try:
|
||||
return socket.inet_ntop(self._af, self.raw[self._dst_addr].tobytes())
|
||||
except (ValueError, socket.error):
|
||||
pass
|
||||
|
||||
@dst_addr.setter
|
||||
def dst_addr(self, val):
|
||||
self.raw[self._dst_addr] = socket.inet_pton(self._af, val)
|
||||
|
||||
@property
|
||||
def packet_len(self):
|
||||
"""
|
||||
The total packet length, including *all* headers, as reported by the IP header.
|
||||
"""
|
||||
raise NotImplementedError() # pragma: no cover
|
||||
|
||||
@packet_len.setter
|
||||
def packet_len(self, val):
|
||||
raise NotImplementedError() # pragma: no cover
|
||||
|
||||
|
||||
class IPv4Header(IPHeader):
|
||||
_src_addr = slice(12, 16)
|
||||
_dst_addr = slice(16, 20)
|
||||
_af = socket.AF_INET
|
||||
|
||||
@property
|
||||
def header_len(self):
|
||||
"""
|
||||
The IP header length in bytes.
|
||||
"""
|
||||
return self.hdr_len * 4
|
||||
|
||||
@property
|
||||
def hdr_len(self):
|
||||
"""
|
||||
The header length in words of 32bit.
|
||||
"""
|
||||
return i(self.raw[0]) & 0x0F
|
||||
|
||||
@hdr_len.setter
|
||||
def hdr_len(self, val):
|
||||
if val < 5:
|
||||
raise ValueError("IP header length must be greater or equal than 5.")
|
||||
struct.pack_into('!B', self.raw, 0, 0x40 | val)
|
||||
|
||||
packet_len = raw_property('!H', 2, docs=IPHeader.packet_len.__doc__)
|
||||
tos = raw_property('!B', 1, docs='The Type Of Service field (six-bit DiffServ field and a two-bit ECN field).')
|
||||
ident = raw_property('!H', 4, docs='The Identification field.')
|
||||
|
||||
reserved = flag_property('reserved', 6, 0b10000000)
|
||||
evil = flag_property('evil', 6, 0b10000000, docs='Just an april\'s fool joke for the RESERVED flag.')
|
||||
df = flag_property('df', 6, 0b01000000)
|
||||
mf = flag_property('mf', 6, 0b00100000)
|
||||
|
||||
ttl = raw_property('!B', 8, docs='The Time To Live field.')
|
||||
protocol = raw_property('!B', 9, docs='The Protocol field.')
|
||||
cksum = raw_property('!H', 10, docs='The IP header Checksum field.')
|
||||
|
||||
@property
|
||||
def flags(self):
|
||||
"""
|
||||
The flags field: RESERVED (the evil bit), DF (don't fragment), MF (more fragments).
|
||||
"""
|
||||
return i(self.raw[6]) >> 5
|
||||
|
||||
@flags.setter
|
||||
def flags(self, val):
|
||||
struct.pack_into('!B', self.raw, 6, (val << 5) | (self.frag_offset & 0xFF00))
|
||||
|
||||
@property
|
||||
def frag_offset(self):
|
||||
"""
|
||||
The Fragment Offset field in blocks of 8 bytes.
|
||||
"""
|
||||
return struct.unpack_from("!H", self.raw, 6)[0] & 0x1FFF
|
||||
|
||||
@frag_offset.setter
|
||||
def frag_offset(self, val):
|
||||
self.raw[6:8] = struct.pack("!H", (self.flags << 13) | (val & 0x1FFF))
|
||||
|
||||
@property
|
||||
def dscp(self):
|
||||
"""
|
||||
The Differentiated Services Code Point field (originally defined as Type of Service) also known as DiffServ.
|
||||
"""
|
||||
return (i(self.raw[1]) >> 2) & 0x3F
|
||||
|
||||
@dscp.setter
|
||||
def dscp(self, val):
|
||||
struct.pack_into('!B', self.raw, 1, (val << 2) | self.ecn)
|
||||
|
||||
diff_serv = dscp
|
||||
|
||||
@property
|
||||
def ecn(self):
|
||||
"""
|
||||
The Explicit Congestion Notification field.
|
||||
"""
|
||||
return i(self.raw[1]) & 0x03
|
||||
|
||||
@ecn.setter
|
||||
def ecn(self, val):
|
||||
struct.pack_into('!B', self.raw, 1, (self.dscp << 2) | (val & 0x03))
|
||||
|
||||
|
||||
class IPv6Header(IPHeader):
|
||||
_src_addr = slice(8, 24)
|
||||
_dst_addr = slice(24, 40)
|
||||
_af = socket.AF_INET6
|
||||
header_len = 40
|
||||
|
||||
payload_len = raw_property('!H', 4, docs='The Payload Length field.')
|
||||
next_hdr = raw_property('!B', 6, docs='The Next Header field. Replaces the Protocol field in IPv4.')
|
||||
hop_limit = raw_property('!B', 7, docs='The Hop Limit field. Replaces the TTL field in IPv4.')
|
||||
|
||||
@property
|
||||
def packet_len(self):
|
||||
return self.payload_len + self.header_len
|
||||
|
||||
@packet_len.setter
|
||||
def packet_len(self, val):
|
||||
self.payload_len = val - self.header_len
|
||||
|
||||
@property
|
||||
def traffic_class(self):
|
||||
"""
|
||||
The Traffic Class field (six-bit DiffServ field and a two-bit ECN field).
|
||||
"""
|
||||
return (struct.unpack_from('!H', self.raw, 0)[0] >> 4) & 0x00FF
|
||||
|
||||
@traffic_class.setter
|
||||
def traffic_class(self, val):
|
||||
struct.pack_into('!H', self.raw, 0, 0x6000 | (val << 4) | (self.flow_label & 0x000F0000))
|
||||
|
||||
@property
|
||||
def flow_label(self):
|
||||
"""
|
||||
The Flow Label field.
|
||||
"""
|
||||
return struct.unpack_from('!I', self.raw, 0)[0] & 0x000FFFFF
|
||||
|
||||
@flow_label.setter
|
||||
def flow_label(self, val):
|
||||
struct.pack_into('!I', self.raw, 0, 0x60000000 | (self.traffic_class << 20) | (val & 0x000FFFFF))
|
||||
|
||||
@property
|
||||
def diff_serv(self):
|
||||
"""
|
||||
The DiffServ field.
|
||||
"""
|
||||
return (self.traffic_class & 0xFC) >> 2
|
||||
|
||||
@diff_serv.setter
|
||||
def diff_serv(self, val):
|
||||
self.traffic_class = self.ecn | (val << 2)
|
||||
|
||||
@property
|
||||
def ecn(self):
|
||||
"""
|
||||
The Explicit Congestion Notification field.
|
||||
"""
|
||||
return self.traffic_class & 0x03
|
||||
|
||||
@ecn.setter
|
||||
def ecn(self, val):
|
||||
self.traffic_class = (self.diff_serv << 2) | val
|
||||
|
||||
if not PY2 and not PY34:
|
||||
packet_len.__doc__ = IPHeader.packet_len.__doc__
|
||||
82
venv/Lib/site-packages/pydivert/packet/tcp.py
Normal file
82
venv/Lib/site-packages/pydivert/packet/tcp.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# -*- 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 struct
|
||||
|
||||
from pydivert.packet.header import Header, PayloadMixin, PortMixin
|
||||
from pydivert.util import indexbyte as i, flag_property, raw_property
|
||||
|
||||
|
||||
class TCPHeader(Header, PayloadMixin, PortMixin):
|
||||
ns = flag_property("ns", 12, 0b00000001)
|
||||
|
||||
cwr = flag_property("cwr", 13, 0b10000000)
|
||||
ece = flag_property("ece", 13, 0b01000000)
|
||||
|
||||
urg = flag_property("syn", 13, 0b00100000)
|
||||
ack = flag_property("ack", 13, 0b00010000)
|
||||
psh = flag_property("psh", 13, 0b00001000)
|
||||
rst = flag_property("rst", 13, 0b00000100)
|
||||
syn = flag_property("syn", 13, 0b00000010)
|
||||
fin = flag_property("fin", 13, 0b00000001)
|
||||
|
||||
@property
|
||||
def header_len(self):
|
||||
"""
|
||||
The TCP header length.
|
||||
"""
|
||||
return self.data_offset * 4
|
||||
|
||||
seq_num = raw_property('!I', 4, docs='The sequence number field.')
|
||||
ack_num = raw_property('!I', 8, docs='The acknowledgement number field.')
|
||||
|
||||
window_size = raw_property('!H', 14, docs='The size of the receive window in bytes.')
|
||||
cksum = raw_property('!H', 16, docs='The TCP header checksum field.')
|
||||
urg_ptr = raw_property('!H', 18, docs='The Urgent Pointer field.')
|
||||
|
||||
@property
|
||||
def data_offset(self):
|
||||
"""
|
||||
The size of TCP header in 32bit words.
|
||||
"""
|
||||
return i(self.raw[12]) >> 4
|
||||
|
||||
@data_offset.setter
|
||||
def data_offset(self, val):
|
||||
if val < 5 or val > 15:
|
||||
raise ValueError("TCP data offset must be greater or equal than 5 and less than 15.")
|
||||
struct.pack_into('!B', self.raw, 12, (val << 4) | (self.reserved << 1) | self.ns)
|
||||
|
||||
@property
|
||||
def reserved(self):
|
||||
"""
|
||||
The reserved field.
|
||||
"""
|
||||
return (i(self.raw[12]) >> 1) & 0x07
|
||||
|
||||
@reserved.setter
|
||||
def reserved(self, val):
|
||||
struct.pack_into('!B', self.raw, 12, (self.data_offset << 4) | (val << 1) | self.ns)
|
||||
|
||||
@property
|
||||
def control_bits(self):
|
||||
"""
|
||||
The Control Bits field.
|
||||
"""
|
||||
return struct.unpack_from('!H', self.raw, 12)[0] & 0x01FF
|
||||
|
||||
@control_bits.setter
|
||||
def control_bits(self, val):
|
||||
struct.pack_into('!H', self.raw, 12, (self.data_offset << 12) | (self.reserved << 9) | (val & 0x01FF))
|
||||
45
venv/Lib/site-packages/pydivert/packet/udp.py
Normal file
45
venv/Lib/site-packages/pydivert/packet/udp.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# -*- 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 struct
|
||||
|
||||
from pydivert.packet.header import Header, PayloadMixin, PortMixin
|
||||
from pydivert.util import PY2, PY34, raw_property
|
||||
|
||||
|
||||
class UDPHeader(Header, PayloadMixin, PortMixin):
|
||||
header_len = 8
|
||||
|
||||
@property
|
||||
def payload(self):
|
||||
return PayloadMixin.payload.fget(self)
|
||||
|
||||
@payload.setter
|
||||
def payload(self, val):
|
||||
PayloadMixin.payload.fset(self, val)
|
||||
self.payload_len = len(val)
|
||||
|
||||
if not PY2 and not PY34:
|
||||
payload.__doc__ = PayloadMixin.payload.__doc__
|
||||
|
||||
@property
|
||||
def payload_len(self):
|
||||
return struct.unpack_from("!H", self.raw, 4)[0] - 8
|
||||
|
||||
@payload_len.setter
|
||||
def payload_len(self, val):
|
||||
self.raw[4:6] = struct.pack("!H", val + 8)
|
||||
|
||||
cksum = raw_property('!H', 6, docs='The UDP header checksum field.')
|
||||
Reference in New Issue
Block a user