abbel/capture/capture.go

91 lines
1.9 KiB
Go

package capture
import (
"fmt"
"git.freifunk-franken.de/jkimmel/abbel/packet"
"github.com/google/gopacket"
"github.com/google/gopacket/afpacket"
"github.com/google/gopacket/layers"
"golang.org/x/net/bpf"
"inet.af/netaddr"
)
var (
// tcpdump -y RAW -dd ip6 and udp dst port 6696
babelBPFRAW = []bpf.RawInstruction{
{0x30, 0, 0, 0x00000000},
{0x54, 0, 0, 0x000000f0},
{0x15, 0, 5, 0x00000060},
{0x30, 0, 0, 0x00000006},
{0x15, 0, 3, 0x00000011},
{0x28, 0, 0, 0x0000002a},
{0x15, 0, 1, 0x00001a28},
{0x6, 0, 0, 0x00040000},
{0x6, 0, 0, 0x00000000},
}
)
type Handle struct {
tp *afpacket.TPacket
}
func FromInterface(iface string) (Handle, error) {
var h Handle
var err error
if iface != "any" {
h.tp, err = afpacket.NewTPacket(
afpacket.SocketDgram,
afpacket.OptInterface(iface),
)
} else {
h.tp, err = afpacket.NewTPacket(
afpacket.SocketDgram,
)
}
if err != nil {
fmt.Println("here")
return Handle{}, err
}
err = h.tp.SetBPF(babelBPFRAW)
if err != nil {
return Handle{}, err
}
return h, nil
}
func (h Handle) Close() error {
h.tp.Close()
return nil
}
func (h Handle) ReadFrom(b []byte) (body []byte, src netaddr.IP, ifindex int, err error) {
data, ci, err := h.tp.ZeroCopyReadPacketData()
if err != nil {
return nil, netaddr.IP{}, 0, err
}
pckt := gopacket.NewPacket(data, layers.LayerTypeIPv6, gopacket.NoCopy)
ip6, ok := pckt.NetworkLayer().(*layers.IPv6)
if !ok {
return nil, netaddr.IP{}, 0, fmt.Errorf("Expected IPv6 layer, got %v", pckt.NetworkLayer())
}
src, ok = netaddr.FromStdIP(ip6.SrcIP)
if !ok {
return nil, netaddr.IP{}, 0, fmt.Errorf("Error parsing packet src address %q", ip6.SrcIP)
}
payload := pckt.ApplicationLayer().Payload()
copy(b, payload)
b, err = packet.Validate(b[:len(payload)])
if err != nil {
return nil, netaddr.IP{}, 0, err
}
return b, src, ci.InterfaceIndex, nil
}