Skip to content

Commit

Permalink
Send termshark's current pcap with magic wormhole
Browse files Browse the repository at this point in the history
This commit implements a new console command, "wormhole", that allows
you to transfer termshark's open pcap using magic wormhole -
https://github.com/magic-wormhole/magic-wormhole. Magic wormhole is a
secure and convenient way of getting files from one machine to
another. The sender generates a wormhole code e.g.

  $ wormhole send foo
  Sending 1.9 kB file named 'foo'
  Wormhole code is: 9-phonetic-goldfish
  On the other computer, please run:

  wormhole receive 9-phonetic-goldfish

and then the receiver references the code:

  $ wormhole receive 9-phonetic-goldfish
  Receiving file (1.9 kB) into: foo
  ok? (y/N): y
  ...
  Received file written to foo

When you run termshark's wormhole command, termshark generates a
wormhole code and displays it in a dialog. You can then use magic
wormhole locally to transfer the pcap to your desktop. The purpose of
this is to make it easy to get a pcap into Wireshark. Termshark can be
fine for a quick analysis, but Wireshark is much more powerful :-)

To make this process even easier, you can pair this new command with the
tmux-wormhole tmux plugin. You can find it here:
https://github.com/gcla/tmux-wormhole. This can help if your tmux is
local, and within that tmux you are sshed to a remote machine and using
termshark there. As long as the remote machine has internet access, you
should be able to magic-wormhole the pcap. Once you see termshark's
wormhole code on the screen, hit the plugin hotkey - C-b w by default -
and the plugin will detect the code and let you download and open the
pcap. If your desktop association for pcap files is Wireshark, then it
should open in Wireshark. Here's a demo of it in action:

https://drive.google.com/file/d/16qCXyjWS8smzjOeJLGZiplib3frgK4F5/view?usp=sharing

This implementation uses psanford/wormhole-william, a Go implementation
of the magic wormhole protocol.
  • Loading branch information
gcla committed Apr 5, 2021
1 parent 26ee5a1 commit 5fd1548
Show file tree
Hide file tree
Showing 8 changed files with 514 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
- The packet structure view now provides a contextual menu with options to
- apply the structure filter as a custom column
- prepare or apply the same filter as a display filter
- A new console-command, "wormhole", allows you to send termshark's current pcap with magic wormhole. Pair
with the tmux plugin tmux-wormhole to open the pcap quickly in Wireshark.

### Changed

Expand Down
5 changes: 5 additions & 0 deletions cmd/termshark/termshark.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/gcla/termshark/v2/tty"
"github.com/gcla/termshark/v2/ui"
"github.com/gcla/termshark/v2/widgets/filter"
"github.com/gcla/termshark/v2/widgets/wormhole"
"github.com/gdamore/tcell"
flags "github.com/jessevdk/go-flags"
"github.com/mattn/go-isatty"
Expand Down Expand Up @@ -59,6 +60,7 @@ func main() {
capinfo.Goroutinewg = &ensureGoroutinesStopWG
convs.Goroutinewg = &ensureGoroutinesStopWG
ui.Goroutinewg = &ensureGoroutinesStopWG
wormhole.Goroutinewg = &ensureGoroutinesStopWG

res := cmain()
ensureGoroutinesStopWG.Wait()
Expand Down Expand Up @@ -1072,6 +1074,9 @@ Loop:
// will happen next time round because the quitRequested flag is checked.
stopLoaders()
}
if ui.CurrentWormholeWidget != nil {
ui.CurrentWormholeWidget.Close()
}

case sig := <-sigChan:
if system.IsSigTSTP(sig) {
Expand Down
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ require (
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pkg/errors v0.9.1
github.com/pkg/term v1.1.0
github.com/psanford/wormhole-william v1.0.6-0.20210402190004-049df45b8d5a
github.com/rakyll/statik v0.1.7
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0
github.com/sirupsen/logrus v1.7.0
github.com/spf13/afero v1.5.1 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.7.1
github.com/stretchr/testify v1.7.0
github.com/tevino/abool v1.2.0
Expand All @@ -40,7 +40,6 @@ require (
gopkg.in/fsnotify/fsnotify.v1 v1.4.7
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)

Expand Down
64 changes: 64 additions & 0 deletions go.sum

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions ui/prochandlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,19 @@ func (t StartUIWhenThereArePackets) OnPsmlHeader(code pcap.HandlerCode, app gowi

//======================================================================

type ClearWormholeState struct{}

var _ pcap.INewSource = ClearWormholeState{}

func (t ClearWormholeState) OnNewSource(code pcap.HandlerCode, app gowid.IApp) {
if CurrentWormholeWidget != nil {
CurrentWormholeWidget.Close()
}
CurrentWormholeWidget = nil
}

//======================================================================

type ClearMarksHandler struct{}

var _ pcap.IClear = checkGlobalJumpAfterPsml{}
Expand Down
32 changes: 32 additions & 0 deletions ui/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,23 @@ func ratio(r float64) gowid.RenderWithRatio {
return gowid.RenderWithRatio{R: r}
}

type RenderRatioUpTo struct {
gowid.RenderWithRatio
max int
}

func (r RenderRatioUpTo) String() string {
return fmt.Sprintf("upto(%v,%d)", r.RenderWithRatio, r.max)
}

func (r RenderRatioUpTo) MaxUnits() int {
return r.max
}

func ratioupto(f float64, max int) RenderRatioUpTo {
return RenderRatioUpTo{gowid.RenderWithRatio{R: f}, max}
}

//======================================================================

// run in app goroutine
Expand Down Expand Up @@ -1314,6 +1331,11 @@ func lastLineMode(app gowid.IApp) {
return nil
}))

MiniBuffer.Register("wormhole", minibufferFn(func(gowid.IApp, ...string) error {
openWormhole(app)
return nil
}))

MiniBuffer.Register("menu", minibufferFn(func(gowid.IApp, ...string) error {
openGeneralMenu(app)
return nil
Expand Down Expand Up @@ -2670,6 +2692,7 @@ func RequestLoadInterfaces(psrcs []pcap.IPacketSource, captureFilter string, dis
ManageStreamCache{},
ManageCapinfoCache{},
SetStructWidgets{Loader}, // for OnClear
ClearWormholeState{},
ClearMarksHandler{},
CancelledMessage{},
},
Expand All @@ -2690,6 +2713,7 @@ func RequestLoadPcapWithCheck(pcapf string, displayFilter string, jump termshark
ManageCapinfoCache{},
SetStructWidgets{Loader}, // for OnClear
MakeCheckGlobalJumpAfterPsml(jump),
ClearWormholeState{},
ClearMarksHandler{},
CancelledMessage{},
}
Expand Down Expand Up @@ -3062,6 +3086,14 @@ func Build() (*gowid.App, error) {
reallyClear(app)
},
},
menuutil.SimpleMenuItem{
Txt: "Send Pcap",
Key: gowid.MakeKey('s'),
CB: func(app gowid.IApp, w gowid.IWidget) {
multiMenu1Opener.CloseMenu(generalMenu, app)
openWormhole(app)
},
},
menuutil.SimpleMenuItem{
Txt: "Edit Columns",
Key: gowid.MakeKey('e'),
Expand Down
76 changes: 76 additions & 0 deletions ui/wormhole.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2019-2020 Graham Clark. All rights reserved. Use of this source
// code is governed by the MIT license that can be found in the LICENSE
// file.

// Package ui contains user-interface functions and helpers for termshark.
package ui

import (
"fmt"

"github.com/gcla/gowid"
"github.com/gcla/gowid/widgets/dialog"
"github.com/gcla/gowid/widgets/framed"
"github.com/gcla/termshark/v2"
"github.com/gcla/termshark/v2/widgets/wormhole"
log "github.com/sirupsen/logrus"
)

//======================================================================

var CurrentWormholeWidget *wormhole.Widget

func openWormhole(app gowid.IApp) {

var numWords int
if CurrentWormholeWidget == nil {
numWords = termshark.ConfInt("main.wormhole-length", 2)
} else {
numWords = CurrentWormholeWidget.CodeLength()
}

if CurrentWormholeWidget == nil {
var err error
CurrentWormholeWidget, err = wormhole.New(Loader.PcapPdml, app, wormhole.Options{
ErrorHandler: func(err error, app gowid.IApp) {
msg := fmt.Sprintf("Problem sending pcap: %v", err)
log.Error(msg)
OpenError(msg, app)
},
CodeLength: numWords,
TransitRelayAddress: termshark.ConfString("main.wormhole-transit-relay", ""),
RendezvousURL: termshark.ConfString("main.wormhole-rendezvous-url", ""),
})
if err != nil {
msg := fmt.Sprintf("%v", err)
log.Error(msg)
OpenError(msg, app)
return
}
}

wormholeDialog := dialog.New(
framed.NewSpace(
CurrentWormholeWidget,
),
dialog.Options{
Buttons: []dialog.Button{dialog.CloseD},
NoShadow: true,
BackgroundStyle: gowid.MakePaletteRef("dialog"),
BorderStyle: gowid.MakePaletteRef("dialog"),
ButtonStyle: gowid.MakePaletteRef("dialog-button"),
},
)

// space for the frame; then XXX-word1-word2-... - max length of word in
// pgp word list is 11. Yuck.
maxl := (2 * 3) + len(" - cancelled!") + wormhole.UpperBoundOnLength(numWords)

wormholeDialog.Open(appView, ratioupto(0.8, maxl), app)
}

//======================================================================
// Local Variables:
// mode: Go
// fill-column: 110
// End:
Loading

0 comments on commit 5fd1548

Please sign in to comment.