Today I wanted to sniff on TLS traffic of hell, a “mastodon client” that seemed to not want to work with things that aren’t Mastodon. The network calls are mostly made from within a library, hellclient-go-mastodon fork of go-mastodon.
SSLKEYLOGFILE turned out to be a standard, now even RFC 9850, for TLS client instrumentation. But Go standard library doesn’t simply write the secrets to a log file in coupling with the obscure environment variable. Not much libraries seem to do it β just programs like major web browsers and curl. (Perhaps bizarrely, this Haskell package adds it coupled with an environment variable β introduced to one’s Haskell code by means of adding nothing more than an import statement.)
After a while I figured it out, with help from among others https://endorama.dev/2023/inspecting-tls-traffic-golang/ and https://stackoverflow.com/questions/72719194/extracting-tls-secrets-in-go.
Importing library from own sources
As the project used go.mod, I could clone the library alongside and add
replace codeberg.org/penny64/hellclient-go-mastodon => ../hellclient-go-mastodon
Setting the TLS config
Then in the library, I found mastodon.go using *http.DefaultClient (which is just &http.Client{},as I even saw someone complain) β as client put into a field in its own Client struct. In the function that created that struct, I just added (importing os and crypto/tls)
fi, _ := os.Create("/tmp/klw")
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
KeyLogWriter: fi,
}
β to create a key log file and add a TLSClientConfig to the variable http.DefaultTransport instance of struct http.Transport, which is used by default whenΒ Transport field in http.Client is nil.
There was therefore no need to replace it with a new &http.Client{ Transport: β¦ }, and it had the potential to work in random additional places in the whole program.
But there was then also no need to bother with importing the library from own sources, since we’re just setting standard library global variable defaults. Putting those few lines on top of func main() body turned out to work just as fineimport "net/http". Run go build ., the resulting executable will appear in the directory.
Running Wireshark
Before you read the official wiki page, you may wander around the Wireshark GUI and find Tools β TLS Keylog Launcher. That seems to be nothing more but a tool that:
- sets the TLS (Pre)-Master-Secret log file path (tls.keylog_file) setting
- lets you execute a command line with the SSLKEYLOGFILE environment variable set.
β and you still have to remember to start recording beforehand, and there is no additional benefits (think, some filtering) that come from using it. If you want to be able to interact with your TUI program, the Run button is not for you in this dialog. But you can set the filename setting there (remember to clickΒ Save), just as well as you can in Edit β Preferences β Protocol β TLS settings as (Pre)-Master-Secret log filename.
Steps:
- Delete the file if it exists, because otherwise Wireshark doesn’t seem to detect its truncation.
- Start recording
- Run your application
- Use
ip.addr == β¦filter if you know the IP, ortls and (http or http2 or http3)(I don’t include quic because I’m not sure if it even works and also it tends to clutter with results from browser activity)
If you want to isolate traffic from just your program because things are too messy to filter, you can probably experiment with running both the capture and the program in ip netns exec (see man 8 ip-netns).