Skip to content

Commit 8eac5f5

Browse files
committed
Calculate checksums of known protocols for RAW payload.
1 parent 7cf6438 commit 8eac5f5

File tree

4 files changed

+78
-16
lines changed

4 files changed

+78
-16
lines changed

examples/icmp_echo_client.py

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -114,20 +114,38 @@ def _create_icmp4_message(cls, identifier: int, sequence: int) -> bytes:
114114
Create ICMPv4 Echo Request packet.
115115
"""
116116

117-
def header(cksum: int = 0) -> bytes:
118-
return struct.pack(
119-
"!BBHHH",
120-
ICMP4__ECHO_REQUEST__TYPE,
121-
ICMP4__ECHO_REQUEST__CODE,
122-
cksum,
123-
identifier,
124-
sequence,
125-
)
117+
header = struct.pack(
118+
"!BBHHH",
119+
ICMP4__ECHO_REQUEST__TYPE,
120+
ICMP4__ECHO_REQUEST__CODE,
121+
0,
122+
identifier,
123+
sequence,
124+
)
125+
126+
payload = struct.pack("!d", time.time())
127+
128+
return header + payload
126129

127-
payload = struct.pack("!d", time.time()) # 8-byte timestamp
128-
cksum = cls._checksum(header() + payload)
130+
@classmethod
131+
def _create_icmp6_message(cls, identifier: int, sequence: int) -> bytes:
132+
"""
133+
Create ICMPv6 Echo Request packet.
134+
"""
129135

130-
return header(cksum) + payload
136+
# Create the ICMPv6 header directly (without checksum)
137+
header = struct.pack(
138+
"!BBHHH",
139+
ICMP6_ECHO_REQUEST_TYPE,
140+
ICMP6_ECHO_REQUEST_CODE,
141+
0, # checksum (set to 0)
142+
identifier,
143+
sequence,
144+
)
145+
146+
payload = struct.pack("!d", time.time())
147+
148+
return header + payload
131149

132150
def _thread__client(self) -> None:
133151
"""
@@ -142,6 +160,11 @@ def _thread__client(self) -> None:
142160
self._local_ip_address.version,
143161
self._remote_ip_address.version,
144162
):
163+
case 6, 6:
164+
icmp_message = self._create_icmp6_message(
165+
identifier=os.getpid() & 0xFFFF,
166+
sequence=self._message_count - message_count + 1,
167+
)
145168
case 4, 4:
146169
icmp_message = self._create_icmp4_message(
147170
identifier=os.getpid() & 0xFFFF,

pytcp/protocols/ip4/ip4__base.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@
4444
from pytcp.protocols.ip4.options.ip4_options import Ip4OptionsProperties
4545
from pytcp.protocols.tcp.tcp__assembler import TcpAssembler
4646
from pytcp.protocols.udp.udp__assembler import UdpAssembler
47+
from pytcp.protocols.raw.raw__assembler import RawAssembler
4748

4849
if TYPE_CHECKING:
4950
from pytcp.protocols.icmp4.icmp4__assembler import Icmp4Assembler
5051
from pytcp.protocols.ip4.ip4__header import Ip4Header
5152
from pytcp.protocols.ip4.options.ip4_options import Ip4Options
52-
from pytcp.protocols.raw.raw__assembler import RawAssembler
5353

5454
Ip4Payload: TypeAlias = (
5555
Icmp4Assembler | TcpAssembler | UdpAssembler | RawAssembler
@@ -112,7 +112,9 @@ def __bytes__(self) -> bytes:
112112
)
113113
header_and_options[10:12] = inet_cksum(header_and_options).to_bytes(2)
114114

115-
if isinstance(self._payload, (TcpAssembler, UdpAssembler)):
115+
if isinstance(
116+
self._payload, (TcpAssembler, UdpAssembler, RawAssembler)
117+
):
116118
self._payload.pshdr_sum = self.pshdr_sum
117119

118120
return bytes(header_and_options + bytes(self._payload))

pytcp/protocols/ip6/ip6__base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@
4343
from pytcp.protocols.ip6.ip6__header import Ip6HeaderProperties
4444
from pytcp.protocols.tcp.tcp__assembler import TcpAssembler
4545
from pytcp.protocols.udp.udp__assembler import UdpAssembler
46+
from pytcp.protocols.raw.raw__assembler import RawAssembler
4647

4748
if TYPE_CHECKING:
4849
from pytcp.protocols.ip6.ip6__header import Ip6Header
4950
from pytcp.protocols.ip6_frag.ip6_frag__assembler import Ip6FragAssembler
50-
from pytcp.protocols.raw.raw__assembler import RawAssembler
5151

5252
Ip6Payload: TypeAlias = (
5353
Ip6FragAssembler
@@ -105,7 +105,8 @@ def __bytes__(self) -> bytes:
105105
"""
106106

107107
if isinstance(
108-
self._payload, (TcpAssembler, UdpAssembler, Icmp6Assembler)
108+
self._payload,
109+
(TcpAssembler, UdpAssembler, Icmp6Assembler, RawAssembler),
109110
):
110111
self._payload.pshdr_sum = self.pshdr_sum
111112

pytcp/protocols/raw/raw__base.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
from typing import override
3939

40+
from pytcp.lib.inet_cksum import inet_cksum
4041
from pytcp.lib.proto import Proto
4142
from pytcp.protocols.enums import EtherType, IpProto
4243

@@ -50,6 +51,8 @@ class Raw(Proto):
5051
_ether_type: EtherType
5152
_ip_proto: IpProto
5253

54+
pshdr_sum: int = 0
55+
5356
@override
5457
def __len__(self) -> int:
5558
"""
@@ -80,6 +83,39 @@ def __bytes__(self) -> bytes:
8083
Get the Raw packet as bytes.
8184
"""
8285

86+
# Automatically calculate checksum if IpProto is ICMPv6 packet and checksum is not set.
87+
if (
88+
self._ip_proto == IpProto.ICMP6
89+
and self._payload[2:4] == b"\x00\x00"
90+
):
91+
_payload = bytearray(self._payload)
92+
_payload[2:4] = inet_cksum(_payload, self.pshdr_sum).to_bytes(2)
93+
return bytes(_payload)
94+
95+
# Automatically calculate checksum if IpProto is ICMPv4 packet and checksum is not set.
96+
if (
97+
self._ip_proto == IpProto.ICMP4
98+
and self._payload[2:4] == b"\x00\x00"
99+
):
100+
_payload = bytearray(self._payload)
101+
_payload[2:4] = inet_cksum(_payload).to_bytes(2)
102+
return bytes(_payload)
103+
104+
# Automatically calculate checksum if IpProto is ICMPv4 or ICMPv6 packet and checksum is not set.
105+
if self._ip_proto == IpProto.UDP and self._payload[6:8] == b"\x00\x00":
106+
_payload = bytearray(self._payload)
107+
_payload[6:8] = inet_cksum(_payload, self.pshdr_sum).to_bytes(2)
108+
return bytes(_payload)
109+
110+
# Automatically calculate checksum if IpProto is TCP packet and checksum is not set.
111+
if (
112+
self._ip_proto == IpProto.TCP
113+
and self._payload[16:18] == b"\x00\x00"
114+
):
115+
_payload = bytearray(self._payload)
116+
_payload[16:18] = inet_cksum(_payload, self.pshdr_sum).to_bytes(2)
117+
return bytes(_payload)
118+
83119
return self._payload
84120

85121
@property

0 commit comments

Comments
 (0)