probednet

package module
v0.0.0-...-22fd9c1 Latest Latest
Warning

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

Go to latest
Published: Dec 16, 2021 License: Apache-2.0 Imports: 9 Imported by: 1

README

probednet

Utilities for probing constructions of the net package

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

func Dial(network, address string) (Conn, error)

Dial behaves like net.Dial, but attaches a probe to the connection.

Supported networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".

func DialContextWith

func DialContextWith(ctx context.Context, d net.Dialer, network, address string) (Conn, error)

DialContextWith behaves like d.DialContext, but attaches a probe to the connection.

Supported networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".

func DialTimeout

func DialTimeout(network, address string, timeout time.Duration) (Conn, error)

DialTimeout behaves like net.DialTimeout, but attaches a probe to the connection.

Supported networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".

func DialWith

func DialWith(d net.Dialer, network, address string) (Conn, error)

DialWith behaves like d.Dial, 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

type TCPConn struct {
	*net.TCPConn
	// contains filtered or unexported fields
}

TCPConn - like net.TCPConn - is the implementation of the Conn interface for TCP network connections.

func DialTCP

func DialTCP(network string, laddr, raddr *net.TCPAddr) (*TCPConn, error)

DialTCP behaves like net.DialTCP, but attaches a probe to the connection.

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

func (*TCPConn) Close

func (c *TCPConn) Close() error

Close the connection.

type UDPConn

type UDPConn struct {
	*net.UDPConn
	// contains filtered or unexported fields
}

UDPConn - like net.UDPConn - is the implementation of the Conn and net.PacketConn interfaces for UDP network connections.

func DialUDP

func DialUDP(network string, laddr, raddr *net.UDPAddr) (*UDPConn, error)

DialUDP behaves like net.DialUDP, but attaches a probe to the connection.

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

func (*UDPConn) Close

func (c *UDPConn) Close() error

Close the connection.

Directories

Path Synopsis
Package pktutil provides utilities for decoding network packets.
Package pktutil provides utilities for decoding network packets.

Jump to

Keyboard shortcuts

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