Documentation ¶
Overview ¶
Package probednet offers utilities for probing constructions of the net package.
Note that packet capture usually requires elevated permissions and the functions in this package are no exception.
This package requires the following system libraries:
Linux: libpcap-dev Windows: npcap or winpcap Mac OS: libpcap (installed by default)
Example ¶
package main import ( "fmt" "github.com/getlantern/probednet" ) func main() { // Dial can be used just as it would with the standard library's net package. conn, err := probednet.Dial("tcp4", "golang.org:80") if err != nil { panic(fmt.Sprintf("dial failed: %v", err)) } // All packets transmitted as part of the connection can be read out of the connection's // CapturedPackets channel. done := make(chan struct{}) go func() { for pkt := range conn.CapturedPackets() { fmt.Println("captured packet:") fmt.Println(pkt.Data) fmt.Println() } close(done) }() go func() { for err := range conn.CaptureErrors() { fmt.Println("capture error:", err) } }() // We can use the connection like a regular net.Conn. _, err = conn.Write([]byte("hello golang!")) if err != nil { panic(fmt.Sprintf("failed to write: %v", err)) } conn.Close() // After closing the connection, we can wait for the remaining packets to come through by // waiting for the CapturedPackets channel to close. <-done }
Output:
Example (DecodingWithGopacket) ¶
ExampleDecodingWithGopacket demonstrates how a consumer of the probednet package might decode captured packets. Libraries like github.com/google/gopacket work well for this.
package main import ( "bytes" "fmt" "net" "github.com/google/gopacket" "github.com/google/gopacket/layers" "github.com/getlantern/probednet" ) var tcpFlags = []struct { name string present func(layers.TCP) bool }{ {"SYN", func(p layers.TCP) bool { return p.SYN }}, {"FIN", func(p layers.TCP) bool { return p.FIN }}, {"ACK", func(p layers.TCP) bool { return p.ACK }}, {"URG", func(p layers.TCP) bool { return p.URG }}, {"PSH", func(p layers.TCP) bool { return p.PSH }}, {"RST", func(p layers.TCP) bool { return p.RST }}, {"ECE", func(p layers.TCP) bool { return p.ECE }}, {"CWR", func(p layers.TCP) bool { return p.CWR }}, {"NS", func(p layers.TCP) bool { return p.NS }}, } // Note that captured packets will be link-layer packets. If we were connecting to a host on the // loopback interface, we may need to use loopback decoders instead of ethernet decoders below. This // depends on your OS. func sprintTCP(linkPacket []byte) string { var ( ip4 layers.IPv4 ip6 layers.IPv6 tcp layers.TCP payload gopacket.Payload layerTypes = []gopacket.LayerType{} ) parser := gopacket.NewDecodingLayerParser( layers.LayerTypeEthernet, &layers.Ethernet{}, &ip4, &ip6, &tcp, &payload, ) if err := parser.DecodeLayers(linkPacket, &layerTypes); err != nil { return fmt.Sprintf("failed to decode packet: %v", err) } var srcIP, dstIP net.IP for _, layerType := range layerTypes { switch layerType { case layers.LayerTypeIPv4: srcIP, dstIP = ip4.SrcIP, ip4.DstIP case layers.LayerTypeIPv6: srcIP, dstIP = ip6.SrcIP, ip6.DstIP } } buf := new(bytes.Buffer) fmt.Fprintf(buf, "[%s]:%d -> [%s]:%d\n", srcIP, tcp.SrcPort, dstIP, tcp.DstPort) fmt.Fprintf(buf, "seq: %d\n", tcp.Seq) fmt.Fprintf(buf, "ack: %d\n", tcp.Ack) for _, flag := range tcpFlags { if flag.present(tcp) { fmt.Fprint(buf, flag.name, " ") } } fmt.Fprintln(buf) if len(payload) > 0 { fmt.Fprintln(buf, "payload:", payload) } return buf.String() } // ExampleDecodingWithGopacket demonstrates how a consumer of the probednet package might decode // captured packets. Libraries like github.com/google/gopacket work well for this. func main() { conn, err := probednet.Dial("tcp4", "golang.org:80") if err != nil { panic(fmt.Sprintf("dial failed: %v", err)) } done := make(chan struct{}) go func() { for pkt := range conn.CapturedPackets() { fmt.Println(sprintTCP(pkt.Data)) } close(done) }() go func() { for err := range conn.CaptureErrors() { fmt.Println("capture error:", err) } }() _, err = conn.Write([]byte("hello golang!")) if err != nil { panic(fmt.Sprintf("failed to write: %v", err)) } conn.Close() <-done // Running this will produce output like the following: // // [172.16.1.237]:53260 -> [172.217.164.113]:80 // seq: 620108986 // ack: 0 // SYN // [172.217.164.113]:80 -> [172.16.1.237]:53260 // seq: 3098406713 // ack: 620108987 // SYN ACK // [172.16.1.237]:53260 -> [172.217.164.113]:80 // seq: 620108987 // ack: 3098406714 // ACK // [172.16.1.237]:53260 -> [172.217.164.113]:80 // seq: 620108987 // ack: 3098406714 // ACK PSH // payload: 13 byte(s) // [172.16.1.237]:53260 -> [172.217.164.113]:80 // seq: 620109000 // ack: 3098406714 // FIN ACK // [172.217.164.113]:80 -> [172.16.1.237]:53260 // seq: 3098406714 // ack: 620109000 // ACK // [172.217.164.113]:80 -> [172.16.1.237]:53260 // seq: 3098406714 // ack: 620109001 // FIN ACK // [172.16.1.237]:53260 -> [172.217.164.113]:80 // seq: 620109001 // ack: 3098406715 // ACK }
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Conn ¶
type Conn interface { net.Conn // CapturedPackets can be used to read packets trasmitted as part of the connection. Packets on // this channel will be link-layer packets. The specific type depends on the network interface // used for the connection. Usually, these will be ethernet frames. For connections through the // loopback interface, these will be loopback packets and the exact structure depends on your // operating system. // // Note that there is a delay in capturing packets. // // This channel will be closed when the connection is closed or CaptureComplete is called. When // the connection is closed, there will be a short delay before the channel is closed to ensure // that the final packets are captured. CapturedPackets() <-chan Packet // CaptureErrors holds errors associated with packet capture. Errors on this channel do not // necessarily indicate errors on the connection. // // This channel will be closed when the connection is closed or CaptureComplete is called. CaptureErrors() <-chan error // CaptureComplete can be used to stop packet capture. The connection itself is unaffected. CaptureComplete() }
Conn is a network connection with probes capturing packets on the connection.
func Dial ¶
Dial behaves like net.Dial, but attaches a probe to the connection.
Supported networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func DialContextWith ¶
DialContextWith behaves like d.DialContext, but attaches a probe to the connection.
Supported networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func DialTimeout ¶
DialTimeout behaves like net.DialTimeout, but attaches a probe to the connection.
Supported networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
type Packet ¶
type Packet struct { Data []byte // Timestamp is the time the packet was captured, if that is known. Timestamp time.Time }
Packet represents a network packet.
type TCPConn ¶
TCPConn - like net.TCPConn - is the implementation of the Conn interface for TCP network connections.
func (TCPConn) CaptureComplete ¶
func (c TCPConn) CaptureComplete()
func (TCPConn) CaptureErrors ¶
func (c TCPConn) CaptureErrors() <-chan error
func (TCPConn) CapturedPackets ¶
func (c TCPConn) CapturedPackets() <-chan Packet
type UDPConn ¶
UDPConn - like net.UDPConn - is the implementation of the Conn and net.PacketConn interfaces for UDP network connections.
func (UDPConn) CaptureComplete ¶
func (c UDPConn) CaptureComplete()
func (UDPConn) CaptureErrors ¶
func (c UDPConn) CaptureErrors() <-chan error
func (UDPConn) CapturedPackets ¶
func (c UDPConn) CapturedPackets() <-chan Packet