pcaptui

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2026 License: MIT Imports: 42 Imported by: 0

README

CI Latest release Go reference MIT licence 13 platforms

English · Українською

Wireshark's analysis, where the capture already is.

pcaptui is a terminal interface to tshark: the packet list, the protocol tree and the hex view, over SSH, on a machine with no display — without copying a 2 GB capture back to your desktop first.

Opening a capture, asking what is in it, asking what is wrong with it, and landing on the packets that are wrong

y what is in this file · e what is wrong with it · enter land on those packets

go install github.com/m1rwana12/pcaptui/cmd/pcaptui@latest

pcaptui -r traffic.pcap          # a file
pcaptui -i eth0 'port 443'       # an interface
tcpdump -w - port 53 | pcaptui -r -

Needs tshark on your PATH — anything from the last decade. pcaptui says so plainly if it cannot find it, rather than failing later in a way that looks like a broken capture.


What you get

A capture you can move around in. A scrolling packet list, a protocol tree you can expand, and a hex pane that highlights the bytes of whichever field you select. tcpdump prints lines; this lets you look.

Wireshark's display filters, checked as you type. The same syntax, with the filter box turning red before you press enter. A filter given on the command line is checked too — a typo stops the program with tshark's own explanation instead of opening an empty window.

Every dissector Wireshark has, and every one it gains. pcaptui has no protocol knowledge of its own and no opinions about protocols. It asks tshark. When Wireshark learns a new protocol, so does this — with no release here.

Answers, not just packets. Expert Information says what the dissectors think is wrong with the capture; Protocol Hierarchy says what is in it. Both are tables you can act on: press enter on a row and the packet list narrows to the packets that row is about.

It says when it is showing you less than everything. A column too narrow for its value ends in rather than quietly showing a shorter address; the title bar says how many packets there are and whether a filter is why the list looks short; a statistic that matched nothing says so in words instead of opening an empty box.


Analysis

Eleven views, one key each — the same key that appears beside them in the Analysis menu.

Key
o Overview all three questions at once, on one screen
e Expert Information what the dissectors think is wrong
y Protocol Hierarchy what is in this capture, as a tree
t Endpoints who is on the wire, busiest first
a Credentials logins this capture carries in the clear
w HTTP how the HTTP responses turned out, by status
d DNS what was asked for, and how the answers turned out
v Conversations who talked to whom, by packets and bytes
s Reassemble stream follow the conversation this packet is in; :streams tls/websocket for those
p Capture file properties size, duration, encapsulation, hashes
x Export objects write the files this capture carried out to disk

Expert Information, reporting a suspected retransmission

Both Expert Information and Protocol Hierarchy respect the display filter in force, so you can ask them about a subset, and both name the filter at the top of the result.

Decrypting TLS

If you have the session keys, you see the plaintext:

export SSLKEYLOGFILE=~/keys.log     # then start your browser or run curl
pcaptui --tls-keylog ~/keys.log -r traffic.pcap

pcaptui checks the key log before it starts and refuses to run if the file is missing or unreadable. tshark accepts a key log path that does not exist, starts normally, exits zero and decrypts nothing — so a typo would otherwise be indistinguishable from traffic whose keys you never had.

Moving around

/ display filter
tab switch panes
| \ pane layout, pane zoom
ctrl-f search — by filter, hex, text, or regex
ma 'a mark a packet, jump back to it
c copy mode — packets, fields, or the whole stream
? everything else

Vim keys work throughout. So does the mouse, in most terminals.

Is this for you?

Yes, if the capture is on a server, or is too big to move, or you already know Wireshark's filters and want them where the traffic is.

Probably not, if you are on a desktop with Wireshark installed and the file is in front of you. Wireshark's GUI is better than any terminal can be. This exists for when you cannot have it.

Documentation

  • User Guide — every view, every key, every setting
  • FAQ — colours, terminals, live capture, reporting a bug
  • Changelog — what changed and why it was wrong before
  • Contributing — how to build it and what CI checks

Built with

gowid and tcell for the terminal interface, and Wireshark's tshark for every byte of the analysis.

The images above are drawn by the program itself, from scripts/pcaps/demo.pcap and telnet-cooked.pcap, and CI fails if they stop matching what it renders — so they cannot go stale.

Licence

MIT. See LICENSE.

pcaptui is built on the codebase of termshark by Graham Clark, used under the MIT licence.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	UserGuideURL         string = "https://github.com/m1rwana12/pcaptui/blob/main/docs/UserGuide.md"
	FAQURL               string = "https://github.com/m1rwana12/pcaptui/blob/main/docs/FAQ.md"
	BugURL               string = "https://github.com/m1rwana12/pcaptui/issues/new?assignees=&labels=&template=bug_report.md&title="
	FeatureURL           string = "https://github.com/m1rwana12/pcaptui/issues/new?assignees=&labels=&template=feature_request.md&title="
	OriginalEnv          []string
	ShouldSwitchTerminal bool
	ShouldSwitchBack     bool
)
View Source
var BadCommand = BadCommandError{}
View Source
var BadState = BadStateError{}
View Source
var ConfigErr = ConfigError{}
View Source
var InternalErr = InternalError{}
View Source
var TSharkVersionUnknown = fmt.Errorf("Could not determine version of tshark")
View Source
var UnexpectedOutput = fmt.Errorf("Unexpected output")
View Source
var Version string = "v1.2.0"

Functions

func AddKeyMapping

func AddKeyMapping(km KeyMapping)

func AddToRecentFiles

func AddToRecentFiles(pcap string)

func AddToRecentFilters

func AddToRecentFilters(val string)

func ApplyArguments

func ApplyArguments(cmd []string, args []string) ([]string, int)

ApplyArguments turns ["echo", "hello", "$2"] + ["big", "world"] into ["echo", "hello", "world"]

func BrowseUrl

func BrowseUrl(url string) error

func CacheDir

func CacheDir() string

func CacheFile

func CacheFile(bin string) string

func CapinfosBin

func CapinfosBin() string

func CaptureBin

func CaptureBin() string

CaptureBin is the binary the user intends to use to capture packets i.e. with the -i switch. This might be distinct from DumpcapBin because dumpcap can't capture on extcap interfaces like randpkt, but while tshark can, it can drop packets more readily than dumpcap. This value is interpreted as the name of a binary, resolved against PATH. Note that the default is pcaptui - this invokes pcaptui in a special mode where it first tries DumpcapBin, then if that fails, TSharkBin - for the best of both worlds. To detect this, pcaptui will run CaptureBin with PCAPTUI_CAPTURE_MODE=1 in the environment, so when pcaptui itself is invoked with this in the environment, it switches to capture mode.

func ConfFile

func ConfFile(file string) string

func ConvTypes

func ConvTypes() []string

func ConvertArgToTShark

func ConvertArgToTShark(arg string) (string, string, bool)

func CopyCommand

func CopyCommand(input io.Reader, cb interface{}) error

func DateStringForFilename

func DateStringForFilename() string

Down to the second for profiling, etc

func DefaultPcapDir

func DefaultPcapDir() string

DefaultPcapDir returns ~/.cache/pcaps by default. Pcaptui will check a couple of user settings first before using this.

func DirOfPathCommand

func DirOfPathCommand(bin string) (string, error)

func DirOfPathCommandUnsafe

func DirOfPathCommandUnsafe(bin string) string

func Does256ColorTermExist

func Does256ColorTermExist() error

func DumpcapBin

func DumpcapBin() string

func ErrLogger

func ErrLogger(key string, val string) *io.PipeWriter

func FileNewerThan

func FileNewerThan(f1, f2 string) (bool, error)

func FileSizeDifferentTo

func FileSizeDifferentTo(filename string, cur int64) (int64, bool)

Returns true if error, too

func IndentPdml

func IndentPdml(in io.Reader, out io.Writer) error

IndentPdml reindents XML, disregarding content between tags (because we knoe PDML doesn't use that capability of XML)

func Interfaces

func Interfaces() (map[int][]string, error)

Use tshark's output, because the indices can then be used to select an interface to sniff on, and net.Interfaces returns the interfaces in a different order.

func IsCommandInPath

func IsCommandInPath(bin string) bool

func IsTerminal

func IsTerminal(fd uintptr) bool

func KeyPressIsPrintable

func KeyPressIsPrintable(key gowid.IKey) bool

func KeyValueErrorString

func KeyValueErrorString(err gowid.KeyValueError) string

KeyValueErrorString returns a string representation of a gowid KeyValueError intended to be suitable for displaying in a pcaptui error dialog.

func KillIfPossible

func KillIfPossible(p IProcess) error

func LoadGlobalMarks

func LoadGlobalMarks(m map[rune]GlobalJumpPos) error

func LoadOffsetFromConfig

func LoadOffsetFromConfig(name string) ([]resizable.Offset, error)

func LocalIPs

func LocalIPs() []string

func ParseCount added in v1.1.0

func ParseCount(s string) (int, bool)

ParseCount reads a whole number that tshark may have grouped for readability.

Groups are stripped only when they are groups of exactly three. Stripping unconditionally would read "1,5" - one and a half, on a machine like this one - as fifteen, and a wrong number is worse than no number.

A space separator, which some locales use, would have split the number into two fields before it ever reached here; if that appears it needs a different fix, and it announces itself as an empty table rather than as a wrong count.

func ParseDecimal added in v1.1.0

func ParseDecimal(s string) (float64, bool)

ParseDecimal reads a number tshark printed with a fractional part - a duration, a relative start time, a rate.

The decimal separator is whichever of "." and "," comes last, because a number carrying both has its groups first. A lone separator is a decimal point unless it looks exactly like one group of three, which is the same call ParseCount makes and for the same reason: "1,234" is far more often twelve hundred than one and a fifth.

Times and durations do not hit that ambiguity - tshark prints nine decimals for a start and four for a duration, neither of which is three - so the columns this was written for are read correctly either way.

func PcapDir

func PcapDir() string

A separate dir from CacheDir because I need to use inotify under some circumstances for a non-existent file, meaning I need to track a directory, and I don't want to be constantly triggered by log file updates.

func PrivilegedBin

func PrivilegedBin() string

PrivilegedBin returns a capture binary that may require setcap privileges on Linux. This is a simple UI to cover the fact that pcaptui's default capture method is to run dumpcap and tshark as a fallback. I don't want to tell the user the capture binary is pcaptui - that'd be confusing. We know that on Linux, pcaptui will run dumpcap first, then fall back to tshark if needed. Only dumpcap should need access to live interfaces; tshark is needed for extcap interfaces only. This is used to provide advice to the user if packet capture fails.

func ProfileCPUFor

func ProfileCPUFor(secs int) bool

func ProfileHeap

func ProfileHeap()

func PrunePcapCache

func PrunePcapCache() error

func ReadGob

func ReadGob(filePath string, object interface{}) error

func RemoveFromStringSlice

func RemoveFromStringSlice(pcap string, comps []string) []string

func RemoveKeyMapping

func RemoveKeyMapping(kp vim.KeyPress)

func ReverseStringSlice

func ReverseStringSlice(s []string)

func RootCause

func RootCause(err error) error

func RunForExitCode

func RunForExitCode(prog string, args []string, env []string) (int, error)

func RunForStderr

func RunForStderr(prog string, args []string, env []string, stderr io.Writer) (int, error)

func RunOnDoubleTicker

func RunOnDoubleTicker(ch <-chan struct{}, fn func(), dur1 time.Duration, dur2 time.Duration, loops int)

func RunningRemotely

func RunningRemotely() bool

func SafePid

func SafePid(p IProcess) int

func SaveGlobalMarks

func SaveGlobalMarks(m map[rune]GlobalJumpPos)

func SaveKeyMappings

func SaveKeyMappings(mappings []KeyMapping)

func SaveOffsetToConfig

func SaveOffsetToConfig(name string, offsets2 []resizable.Offset)

func SetConvTypes

func SetConvTypes(convs []string)

func SetTsharkExtras added in v1.1.0

func SetTsharkExtras(decodeAs []string, args []string)

SetTsharkExtras records the arguments, once, at startup. decodeAs is the list of -d values; args is everything else already in tshark's own spelling.

func StringInSlice

func StringInSlice(a string, list []string) bool

func StringIsArgPrefixOf

func StringIsArgPrefixOf(a string, list []string) bool

func TSharkBin

func TSharkBin() string

func TSharkPath

func TSharkPath() (string, *gowid.KeyValueError)

TSharkPath will return the full path of the tshark binary, if it's found in the path, otherwise an error

func TSharkSupportsColor

func TSharkSupportsColor(tshark string) (bool, error)

Depends on empty.pcap being present

func TSharkVersion

func TSharkVersion(tshark string) (semver.Version, error)

func TSharkVersionFromOutput

func TSharkVersionFromOutput(output string) (semver.Version, error)

func TailCommand

func TailCommand() []string

func TemplateToString

func TemplateToString(tmpl *template.Template, name string, data interface{}) string

Must succeed - use on internal templates

func TrackedGo

func TrackedGo(fn func(), wgs ...*sync.WaitGroup)

func TsharkExtras added in v1.1.0

func TsharkExtras() []string

TsharkExtras returns a copy, because callers append their own arguments to what they get back and the slice is shared by every loader in the program.

func TsharkSetting

func TsharkSetting(field string) (string, error)

$ env TMPDIR=/foo tshark -G folders Temp Temp: /foo Personal configuration: /home/gcla/.config/wireshark Global configuration: /usr/share/wireshark

func TsharkSettings

func TsharkSettings(fields ...string) (map[string]string, error)

func ValidateTerm

func ValidateTerm(term string) error

func WiresharkProfileNames

func WiresharkProfileNames() []string

func WriteEmptyPcap

func WriteEmptyPcap(filename string) error

func WriteGob

func WriteGob(filePath string, object interface{}) error

Types

type BadCommandError

type BadCommandError struct{}

func (BadCommandError) Error

func (e BadCommandError) Error() string

type BadStateError

type BadStateError struct{}

func (BadStateError) Error

func (e BadStateError) Error() string

type ConfigError

type ConfigError struct{}

func (ConfigError) Error

func (e ConfigError) Error() string

type ConvFloatCompare added in v1.1.0

type ConvFloatCompare struct{}

ConvFloatCompare orders the Start and Duration columns of the conversations table.

gowid's FloatCompare is strconv.ParseFloat, which rejects "0,000000000" outright - and that is what tshark prints here. Both columns were therefore unsortable on any machine whose tshark writes a decimal comma: clicking the header did nothing at all, silently.

func (ConvFloatCompare) Less added in v1.1.0

func (s ConvFloatCompare) Less(i, j string) bool

type ConvPktsCompare

type ConvPktsCompare struct{}

ConvPktsCompare orders the byte columns of the conversations table, which tshark writes with a unit: "900", "2 kB", "1 MB".

The number goes through ParseCount rather than having its commas stripped. Stripping them read "1,5 kB" - one and a half kilobytes, on a machine whose tshark writes a decimal comma, as this one's does - as fifteen kilobytes, and put the row in the wrong place under a header that says it is sorted.

func (ConvPktsCompare) Less

func (s ConvPktsCompare) Less(i, j string) bool

type GlobalJumpPos

type GlobalJumpPos struct {
	JumpPos
	Filename string `json:"filename"`
}

func (GlobalJumpPos) Base

func (g GlobalJumpPos) Base() string

For ease of use in the template

type ICommandDone

type ICommandDone interface {
	ProcessCommandDone()
}

type ICommandError

type ICommandError interface {
	ProcessCommandError(err error) error
}

type ICommandKillError

type ICommandKillError interface {
	ProcessKillError(err error) error
}

type ICommandOutput

type ICommandOutput interface {
	ProcessOutput(output string) error
}

type ICommandTimeout

type ICommandTimeout interface {
	ProcessCommandTimeout() error
}

type ICommandWaitTicker

type ICommandWaitTicker interface {
	ProcessWaitTick() error
}

type IPCompare

type IPCompare struct{}

IPCompare is a unit type that satisfies ICompare, and can be used for numerically comparing IP addresses.

func (IPCompare) Less

func (s IPCompare) Less(i, j string) bool

type IProcess

type IProcess interface {
	Kill() error
	Pid() int
}

type InternalError

type InternalError struct{}

func (InternalError) Error

func (e InternalError) Error() string

type JumpPos

type JumpPos struct {
	Summary string `json:"summary"`
	Pos     int    `json:"position"`
}

Need to publish fields for template use

type KeyMapping

type KeyMapping struct {
	From vim.KeyPress
	To   vim.KeySequence
}

func LoadKeyMappings

func LoadKeyMappings() []KeyMapping

type KeyState

type KeyState struct {
	NumberPrefix    int
	PartialgCmd     bool
	PartialZCmd     bool
	PartialCtrlWCmd bool
	PartialmCmd     bool
	PartialQuoteCmd bool
}

type MACCompare

type MACCompare struct{}

MacCompare is a unit type that satisfies ICompare, and can be used for numerically comparing MAC addresses.

func (MACCompare) Less

func (s MACCompare) Less(i, j string) bool

Directories

Path Synopsis
cmd
pcaptui command
configs
internal
screenshot
Package screenshot turns the contents of a tcell simulation screen into something that can be committed to the repository: plain text for tests to compare against, and SVG for the documentation.
Package screenshot turns the contents of a tcell simulation screen into something that can be committed to the repository: plain text for tests to compare against, and SVG for the documentation.
tsharktest
Package tsharktest decides whether a test that drives a real tshark can run at all.
Package tsharktest decides whether a test that drives a real tshark can run at all.
pkg
cli
export
Package export pulls the files carried by a capture out of it, using tshark's --export-objects.
Package export pulls the files carried by a capture out of it, using tshark's --export-objects.
format
Package format implements useful string/byte formatting functions.
Package format implements useful string/byte formatting functions.
pdmltree
Package pdmltree contains a type used as the model for a PDML document for a packet, and associated functions.
Package pdmltree contains a type used as the model for a PDML document for a packet, and associated functions.
stats
Package stats exposes tshark's -z statistics as panels pcaptui can show.
Package stats exposes tshark's -z statistics as panels pcaptui can show.
theme
package theme provides utilities for customizing the styling of pcaptui.
package theme provides utilities for customizing the styling of pcaptui.
theme/modeswap
package modeswap provides an IColor-conforming type Color that renders differently if in low-color mode
package modeswap provides an IColor-conforming type Color that renders differently if in low-color mode
tty
ui
Package ui contains user-interface functions and helpers for pcaptui.
Package ui contains user-interface functions and helpers for pcaptui.
menuutil
Package menuutil contains user-interface functions and helpers for pcaptui.
Package menuutil contains user-interface functions and helpers for pcaptui.
tableutil
Package tableutil contains user-interface functions and helpers for pcaptui's tables - in particular, helpers for vim key sequences like 5gg and G
Package tableutil contains user-interface functions and helpers for pcaptui's tables - in particular, helpers for vim key sequences like 5gg and G
appkeys
Package appkeys provides a widget which responds to keyboard input.
Package appkeys provides a widget which responds to keyboard input.
copymodetable
Package copymodetable provides a wrapper around a table that supports copy mode.
Package copymodetable provides a wrapper around a table that supports copy mode.
copymodetree
Package copymodetree provides a wrapper around a tree that supports copy mode.
Package copymodetree provides a wrapper around a tree that supports copy mode.
elided
Package elided renders text that says when it has been cut short.
Package elided renders text that says when it has been cut short.
enableselected
Package enableselected provides a widget that turns on focus.Selected.
Package enableselected provides a widget that turns on focus.Selected.
expander
Package expander provides a widget that renders in one line when not in focus but that may render using more than one line when in focus.
Package expander provides a widget that renders in one line when not in focus but that may render using more than one line when in focus.
fileviewer
Package fileviewer provides a widget to view a text file in a terminal via a pager program.
Package fileviewer provides a widget to view a text file in a terminal via a pager program.
filter
Package filter provides a pcaptui-specific edit widget which changes color according to the validity of its input, and which activates a drop-down menu of possible completions for the term at point.
Package filter provides a pcaptui-specific edit widget which changes color according to the validity of its input, and which activates a drop-down menu of possible completions for the term at point.
framefocus
Package framefocus provides a very specific widget to apply a frame around the widget in focus and an empty frame if not.
Package framefocus provides a very specific widget to apply a frame around the widget in focus and an empty frame if not.
hexdumper2
Package hexdumper2 provides a widget which displays selectable hexdump-like output.
Package hexdumper2 provides a widget which displays selectable hexdump-like output.
ifwidget
Package ifwidget provides a simple widget that behaves differently depending on the condition supplied.
Package ifwidget provides a simple widget that behaves differently depending on the condition supplied.
keepselected
Package keepselected turns on the selected bit when Render or UserInput is called.
Package keepselected turns on the selected bit when Render or UserInput is called.
mapkeys
Package mapkeys provides a widget that can map one keypress to a sequence of keypresses.
Package mapkeys provides a widget that can map one keypress to a sequence of keypresses.
minibuffer
Package minibuffer todo
Package minibuffer todo
number
Package number provides a numeric widget with a couple of buttons that increase or decrease its value.
Package number provides a numeric widget with a couple of buttons that increase or decrease its value.
regexstyle
Package regexstyle provides a widget that highlights the content of its subwidget according to a regular expression.
Package regexstyle provides a widget that highlights the content of its subwidget according to a regular expression.
renderfocused
Package renderfocused will render a widget with focus true
Package renderfocused will render a widget with focus true
resizable
Package resizable provides columns and piles that can be adjusted.
Package resizable provides columns and piles that can be adjusted.
rossshark
Package rossshark provides a widget that draws a hi-tech shark fin over the background and allows it to move across the screen.
Package rossshark provides a widget that draws a hi-tech shark fin over the background and allows it to move across the screen.
scrollabletable
Package scrollabletable makes a widget that some scrollbar interfaces suitable for passing to withscrollbar.New()
Package scrollabletable makes a widget that some scrollbar interfaces suitable for passing to withscrollbar.New()
scrollabletext
Package scrollabletext provides a text widget that can be placed inside withscrollbar.Widget
Package scrollabletext provides a text widget that can be placed inside withscrollbar.Widget
search
Package search provides pcaptui's search widget including the various drop down menus to control the type of search to be issued.
Package search provides pcaptui's search widget including the various drop down menus to control the type of search to be issued.
streamwidget
Package streamwidget provides a very specific stream reassembly pcaptui widget.
Package streamwidget provides a very specific stream reassembly pcaptui widget.
trackfocus
Package trackfocus provides a widget that issues callbacks when a widget loses or gains the focus.
Package trackfocus provides a widget that issues callbacks when a widget loses or gains the focus.
withscrollbar
Package withscrollbar provides a widget that renders with a scrollbar on the right
Package withscrollbar provides a widget that renders with a scrollbar on the right
wormhole
Package wormhole contains a widget that provides the UI for pcaptui's magic-wormhole pcap sending feature.
Package wormhole contains a widget that provides the UI for pcaptui's magic-wormhole pcap sending feature.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL