2026-10-05 20:48:08 +02:00
2026-10-05 20:07:31 +02:00
2026-10-05 20:07:31 +02:00
2026-10-05 20:35:47 +02:00
2026-10-05 20:07:31 +02:00
2026-10-05 20:48:08 +02:00

pcap-web-tools

A small web application with tools for the pcap packet capture format. Plain Go: the standard library, html/template and embedded static files. There is no JavaScript frontend.

Running

make run            # or: go run . -addr localhost:8080

Then open http://localhost:8080.

Flags:

  • -addr: listen address (default localhost:8080).
  • -max-upload-mb: largest accepted file upload in MB (default 1024).

Uploads larger than 1 MB are spooled to temporary files under $TMPDIR (default /tmp) rather than held in memory. The temporary files are removed after each request.

If /tmp is a RAM-backed tmpfs, as on Raspberry Pi OS, uploads still use RAM, and a file bigger than the tmpfs fails. In that case point TMPDIR at a disk directory:

TMPDIR=/path/on/disk ./pcap-web-tools -max-upload-mb 5000

Tools

Hex → pcap (/hex2pcap)

Builds a single-packet pcap file from pasted hex.

  • Three fields: layer 2, layer 3 and payload. Each one is hex-decoded and the three are concatenated. Any field can be empty, so you can also paste a whole packet into one field.

  • The hex input tolerates whitespace, :, -, ,, ., 0x and \x.

  • Recalculate IP lengths and checksums (optional) rewrites:

    • IPv4 total length and header checksum, or the IPv6 payload length
    • the UDP length
    • the TCP, UDP, ICMP, ICMPv6 or SCTP (CRC32c) checksum

    It walks IPv6 extension headers and uses the final destination from a routing header in the pseudo-header. Fragments only get their IP header fixed.

    The end of the layer 3 field marks where the headers end. The fix uses that boundary for two more fields:

    • TCP data offset: set to the length of the TCP header, including options, in the layer 3 field.
    • SCTP chunk length: set for the last chunk whose header starts in the layer 3 field. It covers the rest of the packet, so paste chunk data without padding. If the payload already includes padding, the tool keeps a chunk length that matches. Chunks bundled before it keep their own lengths.

    The IPv4 IHL and the IPv6 extension header lengths are taken as entered, because they are what says where the IP options end. If an IPv4 option doesn't fit inside the IHL, you get a warning. When the layer 3 field is empty, these two fields are left unchanged.

    The IP header is taken to start at the layer 3 field. If that field is empty, the tool parses the link-layer header to find it: Ethernet (including VLAN and QinQ), Linux SLL or SLL2.

  • Link type: Auto picks Raw IP when layer 2 is empty and layer 3 is set, and Ethernet otherwise. You can also pick a link type from the list or enter any numeric LINKTYPE.

  • Preview shows the fixups that were applied and a hex dump coloured by layer, with changed bytes underlined. Download pcap returns the file.

Split pcap (/split)

Splits an uploaded pcap file into parts with at most N packets or at most N KB/MB/GB each. Sizes are decimal (1 MB = 1,000,000 bytes) and count the 24-byte file header and the 16-byte per-packet record headers.

  • The parts are returned as one zip of <name>_001.pcap, <name>_002.pcap, ...
  • Each part starts with the original file header, and packet records are copied byte for byte, so byte order and µs/ns timestamp precision are preserved.
  • A packet larger than the size limit goes into a part by itself.
  • If the capture ends with a truncated packet, that packet is dropped, and the zip comment says so.
  • A split may produce at most 10,000 parts.
  • The upload is checked completely before the zip is sent, so errors show on the page instead of as a broken download.
  • Only classic pcap is supported. Convert pcapng first with editcap -F pcap in.pcapng out.pcap.

Reorder pcap (/reorder)

Sorts the packets of an uploaded pcap file by timestamp and returns the result as <name>_reordered.pcap. The output is byte-identical to reordercap's.

  • The sort is stable, so packets with equal timestamps keep their original order.
  • The file header and packet records are copied unchanged.
  • The response headers report the number of packets (X-Pcap-Packets), the number of packets that were out of order (X-Pcap-Out-Of-Order) and whether a truncated final packet was dropped (X-Pcap-Truncated). These are useful when scripting with curl -F file=@in.pcap.

How it works:

  • Index: one sequential pass keeps a 16-byte index entry per packet (timestamp, plus offset and length), which is then sorted.
  • Write: the packets are copied out in sorted order using 16 parallel reads in 8 MB batches, reading the next batch while the previous one is written. SSDs are much faster at random reads with many requests in flight.
  • Already sorted: if the file is already in order, it is copied straight through.

Measured on a Raspberry Pi 5 with NVMe, for 3 million 1500-byte packets (4.5 GB) with fully random timestamps, the worst case:

Time Peak memory
Server: upload, reorder, download over localhost 95 s 108 MB
reordercap about 3.5 h (extrapolated from 0.35 MB/s) 180 MB

Memory is roughly 16 bytes per packet for the index, plus about 16 MB of copy buffers and Go GC headroom. Captures that are mostly in order, the usual case, read nearly sequentially and are faster.

Layout

main.go                 entry point, HTTP server
internal/web/           handlers, tool registry, embedded templates
internal/web/static/    style.css: one stylesheet shared by all pages, following the
                        utel-frontend design; fonts/ and images/ copied from utel-frontend
internal/pcap/          pcap file reader, writer, splitter and reorderer
internal/inet/          IPv4/IPv6 length and checksum fixups, IP header locator
internal/hexutil/       lenient hex decoding

To add a tool, add an entry to tools in internal/web/server.go, a template in internal/web/templates/, and register its routes in web.New.

S
Description
No description provided
Readme
259 KiB
Languages
Go 75.7%
CSS 14.4%
HTML 9.8%
Makefile 0.1%