91 lines
1.9 KiB
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
|
|
}
|