Network Engine
The core of my network stack is based on masscan. Here's a diagram of the three threads used:
Sending Thread
Construct Ethernet Packet: Create the Ethernet frame with appropriate source and destination MAC addresses. Construct IP Packet: Create the IP packet with source and destination IP addresses. Generate Sequence Number: Generate a unique sequence number based on the source/destination IP and port pairs. Create TCP Packet: Construct the TCP packet with the generated sequence number and other necessary fields. Send Packet: Send the constructed packet over the network. Send Status: Notify the status report thread that a packet has been sent.
Receiving Thread
Listen for Incoming Packets: Continuously listen for incoming packets on the network. Filter Relevant Packets: Filter out packets that are not relevant based on the unique sequence number. Handle Packet: Process the relevant packet (e.g., extract data, acknowledge receipt). Send Status: Notify the status report thread that a packet has been received and handled.
Status Report Thread
Receive Status Updates: Continuously receive status updates from the sending and receiving threads. Update Status and Statistics: Update the current status and statistics of the scan based on the received updates. Print Status and Statistics: Print the updated status and statistics to the console or log. This diagram and description should help visualize the flow and interaction between the threads in your scanning application. If you have any further questions or need additional details, feel free to ask!
graph TD
A[Main Thread] -->|Start| B[Sending Thread]
A -->|Start| C[Receiving Thread]
A -->|Start| D[Status Report Thread]
B --> B1[Construct Ethernet Packet]
B1 --> B2[Construct IP Packet]
B2 --> B3[Generate Sequence Number]
B3 --> B4[Create TCP Packet]
B4 --> B5[Send Packet]
B5 -->|Send Status| D
C --> C1[Listen for Incoming Packets]
C1 --> C2[Filter Relevant Packets]
C2 --> C3[Handle Packet]
C3 -->|Send Status| D
D --> D1[Receive Status Updates]
D1 --> D2[Update Status and Statistics]
D2 --> D3[Print Status and Statistics]
Rate limiting
The transmit_handler function implements a rate limit bucket algorithm to control the rate at which packets are sent. The rate limit bucket algorithm is a mechanism to control the rate of packet transmission. It works as follows:
-
Initialization
- A token bucket is initialized with a certain number of tokens (
RATE_LIMIT_PACKETS_PER_INTERVAL). - Each token represents permission to send one packet.
- The bucket is refilled at regular intervals (
RATE_LIMIT_INTERVAL).
- A token bucket is initialized with a certain number of tokens (
-
Packet Transmission
- For each packet to be sent, the algorithm checks if there are tokens available in the bucket.
- If tokens are available, a token is consumed, and the packet is sent.
- If no tokens are available, the algorithm waits until the bucket is refilled.
-
Refilling the Bucket
- The bucket is refilled at a fixed interval (
RATE_LIMIT_INTERVAL). - When the interval elapses, the bucket is refilled to its maximum capacity (
RATE_LIMIT_PACKETS_PER_INTERVAL).
- The bucket is refilled at a fixed interval (
-
Handling Buffer Full Errors
- If the packet transmission fails due to a full buffer (
NO_BUFFER_SPACE_AVAILABLE_ERROR), the algorithm waits for a short period (100ms) before retrying.
- If the packet transmission fails due to a full buffer (
This algorithm ensures that packets are sent at a controlled rate, preventing network congestion and ensuring fair usage of network resources.
Great reads
This blog post nicely describes the pro's and con's of async Rust vs normal threads. It nicely illustrates that async Rust is not always the best choice for all use cases.
Obviously we would need to include how masscan works
And the bulk of the masscan code can be found in main.c