HedongGao opened a new pull request, #17658:
URL: https://github.com/apache/nuttx/pull/17658
## Summary
According to RFC 792 page 4, do the icmp checksum when recieve icmp packet
if CONFIG_NET_ICMP_CHECKSUMS is set.
## Impact
Before processing the message, the icmp stack first checks the validity of
the checksum. And discard the icmp message that failed verification.
## Testing
Turn on the compilation option of NET-ICPCHECK SUMS and enable the icmp
checksum function.
Set up a SIM environment and construct an ICMP request message with checksum
error on the host side, and compare the performance before and after
modification.
Before the problem was fixed, the correctness of the physical checksum could
result in an ICMP reply message, but after the fix, no checksum error message
would be replied. The contracting code is as follows:
`import socket
import struct
import binascii
# -------------------------- Configuration Parameters
--------------------------
# Source/Destination MAC (convert string to bytes, colon-separated)
SRC_MAC = "fa:b1:d9:6d:a0:d3"
DST_MAC = "42:e1:c4:3f:48:dd"
# Source/Destination IP
SRC_IP = "10.0.1.1"
DST_IP = "10.0.1.2"
# Network interface name (modify according to actual environment, e.g.,
eth0, ens33)
INTERFACE = "eth0"
# -------------------------- Utility Functions --------------------------
def mac_to_bytes(mac_str):
"""Convert MAC address string to bytes (e.g., fa:b1:d9:6d:a0:d3 ->
b'\xfa\xb1\xd9\x6d\xa0\xd3')"""
return binascii.unhexlify(mac_str.replace(":", ""))
def ip_to_bytes(ip_str):
"""Convert IP address string to bytes (e.g., 10.0.1.1 ->
b'\n\x00\x01\x01')"""
return socket.inet_aton(ip_str)
def calculate_checksum(data):
"""Calculate standard checksum (RFC 1071)"""
sum_val = 0
# Sum by 16-bit chunks
for i in range(0, len(data), 2):
if i + 1 < len(data):
chunk = (data[i] << 8) + data[i+1]
else:
chunk = data[i] << 8 # Pad 0 for odd length
sum_val += chunk
sum_val = (sum_val & 0xffff) + (sum_val >> 16) # Handle carry
checksum = ~sum_val & 0xffff # Invert and keep 16 bits
return checksum
# -------------------------- Packet Construction --------------------------
# 1. Ethernet Frame Header (14 bytes)
# Format: Destination MAC(6) + Source MAC(6) + Type(2, 0x0800 for IP)
eth_header = struct.pack(
"!6s6sH",
mac_to_bytes(DST_MAC),
mac_to_bytes(SRC_MAC),
0x0800 # ETH_P_IP
)
# 2. IP Header (20 bytes, no options)
ip_version = 4 # IPV4
ip_ihl = 5 # Internet Header Length (5*4=20 bytes)
ip_tos = 0 # Type of Service
ip_total_len = 20 + 8 # IP header(20) + ICMP(8)
ip_id = 12345 # Identification
ip_flags = 0 # Flags
ip_frag_off = 0 # Fragment Offset
ip_ttl = 64 # Time to Live
ip_proto = 1 # Protocol (1=ICMP)
ip_checksum = 0 # Fill 0 first, calculate later
ip_src = ip_to_bytes(SRC_IP)
ip_dst = ip_to_bytes(DST_IP)
# Assemble IP header (fill 0 for checksum first)
ip_header = struct.pack(
"!BBHHHBBH4s4s",
(ip_version << 4) + ip_ihl, # Version + IHL
ip_tos,
ip_total_len,
ip_id,
(ip_flags << 13) + ip_frag_off, # Flags + Fragment Offset
ip_ttl,
ip_proto,
ip_checksum,
ip_src,
ip_dst
)
# Calculate IP header checksum and reassemble
ip_checksum = calculate_checksum(ip_header)
ip_header = struct.pack(
"!BBHHHBBH4s4s",
(ip_version << 4) + ip_ihl,
ip_tos,
ip_total_len,
ip_id,
(ip_flags << 13) + ip_frag_off,
ip_ttl,
ip_proto,
ip_checksum,
ip_src,
ip_dst
)
# 3. ICMP Request Packet (8 bytes, echo request)
icmp_type = 8 # Type (8=echo request)
icmp_code = 0 # Code (0)
icmp_checksum = 0# Fill 0 first
icmp_id = 5678 # Identifier
icmp_seq = 1 # Sequence Number
# Assemble ICMP header (fill 0 for checksum first)
icmp_header = struct.pack(
"!BBHHH",
icmp_type,
icmp_code,
icmp_checksum,
icmp_id,
icmp_seq
)
# 【Key】Intentionally construct wrong ICMP checksum (correct checksum + 1 to
break validity)
correct_icmp_checksum = calculate_checksum(icmp_header)
wrong_icmp_checksum = (correct_icmp_checksum + 1) & 0xffff # Ensure 16 bits
# Reassemble ICMP header (fill wrong checksum)
icmp_header = struct.pack(
"!BBHHH",
icmp_type,
icmp_code,
wrong_icmp_checksum,
icmp_id,
icmp_seq
)
# 4. Complete packet: Ethernet header + IP header + ICMP header
packet = eth_header + ip_header + icmp_header
# -------------------------- Send Packet --------------------------
def send_raw_packet():
try:
# Create raw socket (SOCK_RAW + ETH_P_ALL)
# ETH_P_ALL=0x0003: Receive all Ethernet frames, manually construct
link layer header when sending
sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW,
socket.htons(0x0003))
sock.bind((INTERFACE, 0)) # Bind to specified network interface
# Send packet
sock.send(packet)
print("Raw ICMP packet sent successfully!")
print(f"Key Information:")
print(f" Source MAC: {SRC_MAC} | Destination MAC: {DST_MAC}")
print(f" Source IP: {SRC_IP} | Destination IP: {DST_IP}")
print(f" Correct ICMP Checksum: 0x{correct_icmp_checksum:04x}")
print(f" Wrong ICMP Checksum: 0x{wrong_icmp_checksum:04x} (sent)")
except PermissionError:
print("Error: Need root privileges to run (sudo python3 xxx.py)")
except Exception as e:
print(f"Failed to send: {e}")
finally:
if 'sock' in locals():
sock.close()
if __name__ == "__main__":
send_raw_packet()`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]