Add PCAP logger
Summary
Implement a pcap logger that can be enabled in debug mode to generate a packet dump of a PeerConnection.
Motivation
It's difficult to debug issues in the DTLS or RTP stacks because an external packet logger like tcpdump does not have access to the DTLS encryption keys.
To make it easier to track down issues, it should be possible to save a packet dump for analysis.
Design
To aid debugging, the pcap should include all the types of packets Pion sends and receives over its ICE connections:
- STUN requests
- DTLS handshakes
- Decrypted DTLS packets
- RTP packets
- RTCP packets
These should be mapped to IP addresses and port numbers where possible so that issues with STUN and firewall hole punching can be diagnosed.
It should be possible to:
- Enable or disable the writer on a per-PeerConnection level
- Attach a pcap writer before or after a PeerConnection has been created
- Write packets from multiple PeerConnections to a single pcap
Here's a sketch of a design:
// Logger can be attached via SettingEngine
f, _ := os.Open("out.pcap")
s := &SettingEngine{
PacketLogger: NewPCAPLogger(f),
}
api := NewAPI(WithSettingEngine(s))
pc, _ := api.NewPeerConnection(Configuration{})
(...)
// Later, the logger can be changed or removed
s.PacketLogger = NewPacketLogger(otherfile)
s.PacketLogger = nil
type PacketLogger interface {
WriteUDP(b []byte, dst, src *net.UDPAddr)
WriteTCP(b []byte, dst, src *net.TCPAddr)
}
Notes
Related to pion/website#29 Partially implemented PCAP format: #521
@maxhawkins This is an interesting one! Going back through old tickets and I want to build this! This would be amazing for people to learn and debug.
I don't think we should add toggles to enable/disable it during logging. If users want that they can implement that behavior on their own. I also don't think we can support adding them during runtime. The complexity of plumbing that in I think could be costly/error prone.
What do you think of making it configurable? Via the SettingEngine you can do the following
- STUN Traffic
- DTLS handshakes
- DTLS Packets (Encrypted or Decrypted might be nice?)
- RT(C)P Packets (Encrypted or Decrypted might be nice?)
This could then be broken up into smaller tasks pretty easily.
- [ ] Add a
PacketInterceptorfield that is a PacketConn toice.AgentConfig. If set it would wrap interfaces and write. - [ ] Add a mux before the DTLS connection to get DTLS Handshakes.
- [ ] Add a mux after the DTLS connection to get SCTP Traffic
- [ ] Add a mux before SRTP to get Encrypted RTP
- [ ] Add a
PacketInterceptorContextOptionthat is aio.Writertosrtp. Any packets that are encrypted/decrypted go through that first.
One users told me that the best way for them to learn was via a PCAP. This could be such a huge tool, then we could write a blog post and use screenshots to learn.