Implement a wrapper program under Linux according to this high-level specification:
The system is a transparent process wrapper designed to execute a fixed target binary. It acts as a middleman between the calling environment and the target, intercepting standard I/O (stdin, stdout, stderr), execution arguments/environment, and the final exit status. All intercepted data is encapsulated into forged Ethernet/IPv4/UDP packets and safely multiplexed into a shared PCAP file using file-level locking.
- Environment Variable: Read
STDIO_PCAP. If unset or empty, default to/tmp/stdio.pcap. - File Descriptor & Global Header:
- Open the PCAP file in
O_WRONLY | O_CREAT | O_APPENDmode. - Acquire an exclusive lock using
flock(fd, LOCK_EX). - Check the file size (e.g., via
fstat). - If the size is
0, write the 24-byte Global PCAP Header (Magic number0xa1b2c3d4, version 2.4, snaplen 65535, network/linktype1for Ethernet). - Release the lock:
flock(fd, LOCK_UN).
- Open the PCAP file in
To adhere to the 9000 MTU constraint and ensure Wireshark parses the file natively, each captured event is encapsulated into a structure resembling a network frame.
- Buffer Sizing: Maximum Transmission Unit (MTU) = 9000 bytes.
- Ethernet Header: 14 bytes
- IPv4 Header: 20 bytes
- UDP Header: 8 bytes
- Max Payload Size:
9000 - 14 - 20 - 8 = 8958 bytes. We further reduce it to 8192 bytes. - Read buffers for I/O should be allocated to exactly 8192 bytes.
- Frame Structure (Per Write):
- PCAP Packet Header: 16 bytes (Epoch seconds, microseconds, captured length, original length).
- Fake Ethernet Header: Dummy source/dest MAC addresses, EtherType
0x0800(IPv4). - Fake IPv4 Header: Dummy source/dest IP addresses, Protocol
17(UDP), proper length fields. - Fake UDP Header:
Source Port (sport)= Target Process ID (PID).Destination Port (dport)= Determined by the event type (0, 1, 2, 3, or 4).- Length and Checksum (Checksum can be
0x0000to skip validation).
- Payload: The intercepted data.
PTY allocation is forbidden, standard anonymous pipes should be used for IPC.
- Create three unidirectional pipes:
pipe_in,pipe_out,pipe_err. - Fork the process:
- Child:
- Duplicate (
dup2) the read end ofpipe_intoSTDIN_FILENO. - Duplicate the write end of
pipe_outtoSTDOUT_FILENO. - Duplicate the write end of
pipe_errtoSTDERR_FILENO. - Close all unused pipe file descriptors.
- Execute the fixed target using
execve().
- Duplicate (
- Parent (Wrapper Engine):
- Close the child's ends of the pipes.
- Obtain the child's PID for the UDP
sport.
- Child:
Immediately after the fork, the parent writes the first packet, then enters the I/O loop, and finally writes the exit status.
-
dport 3 (Execve Details):
- Trigger: Logged by the parent immediately after
fork()but before entering the I/O loop. - Payload: Iterate through the
argvarray, copying each null-terminated string sequentially into the buffer. Add an extra\0after the lastargvstring. Then, iterate throughenvpdoing the same. - Note: If the combined argv/envp size exceeds the 8958-byte MTU payload limit, it should be split into multiple
dport=3packets.
- Trigger: Logged by the parent immediately after
-
dport 0 (Stdin):
- Trigger: Parent reads from its own stdin.
- Payload: The raw bytes read.
- Action: Parent formats/writes the PCAP packet, then forwards the exact same bytes to the write-end of
pipe_inso the child receives them.
-
dport 1 (Stdout):
- Trigger: Parent reads from the read-end of
pipe_out(child's output). - Payload: The raw bytes read.
- Action: Parent formats/writes the PCAP packet, then writes the bytes to its own stdout.
- Trigger: Parent reads from the read-end of
-
dport 2 (Stderr):
- Trigger: Parent reads from the read-end of
pipe_err(child's errors). - Payload: The raw bytes read.
- Action: Parent formats/writes the PCAP packet, then writes the bytes to its own stderr.
- Trigger: Parent reads from the read-end of
-
dport 4 (Exit Status):
- Trigger: The child process terminates, and
waitpid()returns. - Payload: A structured representation (e.g., 4-byte integer) of the exit status yielded by the wait system call macros (
WEXITSTATUS,WTERMSIG, etc.).
- Trigger: The child process terminates, and
The parent operates an event-driven loop (using poll, select, or epoll):
- Monitor parent's
stdin, child'sstdout_pipe, and child'sstderr_pipefor readability. - When a file descriptor is readable, read up to 8192 bytes.
- Construct the full PCAP packet (PCAP Header + Eth + IP + UDP + Payload) in memory.
- Locking / Writing:
flock(pcap_fd, LOCK_EX)write(pcap_fd, complete_packet_buffer, total_packet_size)flock(pcap_fd, LOCK_UN)
- Forward the data to the appropriate destination (e.g., from parent stdin to child stdin pipe).
- Loop continues until all child pipes are closed (EOF) and the child process has been reaped.
- Because the PCAP file is opened in
O_APPENDmode, standard POSIX writes are typically atomic. However, utilizingflockaround every single packet write ensures that even if multiple wrappers are writing simultaneously, interleaved or fragmented packets (which would corrupt the PCAP parsing in Wireshark) are strictly prevented. - File locks are advisory, but since all instances of this wrapper will respect the exact same locking routine, concurrency is safely managed.