func prepareBPF(fd int, name string) (int, error) { if err := syscall.SetBpfInterface(fd, name); err != nil { return 0, err } if err := syscall.CheckBpfVersion(fd); err != nil { return 0, err } if err := syscall.SetBpfImmediate(fd, 1); err != nil { return 0, err } if err := syscall.SetBpfPromisc(fd, 1); err != nil { return 0, err } buflen, err := syscall.BpfBuflen(fd) if err != nil { return 0, err } if _, err = syscall.BpfHeadercmpl(fd); err != nil { return 0, err } if err := syscall.SetBpfHeadercmpl(fd, 0); err != nil { return 0, err } if _, err := syscall.BpfTimeout(fd); err != nil { return 0, err } tv := syscall.Timeval{Usec: 10} if err := syscall.SetBpfTimeout(fd, &tv); err != nil { return 0, err } if err := syscall.SetBpf(fd, ipv6OverEthernet); err != nil { return 0, nil } if err := syscall.FlushBpf(fd); err != nil { return 0, err } return buflen, nil }
// NewBPFSniffer is used to create BSD-only BPF ethernet sniffer // iface is the network interface device name that you wish to sniff // options can set to nil in order to utilize default values for everything. // Each field of Options also have a default setting if left unspecified by // the user's custome Options struct. func NewBPFSniffer(iface string, options *Options) (*BPFSniffer, error) { var err error enable := 1 sniffer := BPFSniffer{ sniffDeviceName: iface, } if options == nil { sniffer.options = &defaultOptions } else { sniffer.options = options } if sniffer.options.BPFDeviceName == "" { sniffer.pickBpfDevice() } // setup our read buffer if sniffer.options.ReadBufLen == 0 { sniffer.options.ReadBufLen, err = syscall.BpfBuflen(sniffer.fd) if err != nil { return nil, err } } else { sniffer.options.ReadBufLen, err = syscall.SetBpfBuflen(sniffer.fd, sniffer.options.ReadBufLen) if err != nil { return nil, err } } sniffer.readBuffer = make([]byte, sniffer.options.ReadBufLen) err = syscall.SetBpfInterface(sniffer.fd, sniffer.sniffDeviceName) if err != nil { return nil, err } if sniffer.options.Immediate { // turn immediate mode on. This makes the snffer non-blocking. err = syscall.SetBpfImmediate(sniffer.fd, enable) if err != nil { return nil, err } } // the above call to syscall.SetBpfImmediate needs to be made // before setting a timer otherwise the reads will block for the // entire timer duration even if there are packets to return. if sniffer.options.Timeout != nil { err = syscall.SetBpfTimeout(sniffer.fd, sniffer.options.Timeout) if err != nil { return nil, err } } if sniffer.options.PreserveLinkAddr { // preserves the link level source address... // higher level protocol analyzers will not need this err = syscall.SetBpfHeadercmpl(sniffer.fd, enable) if err != nil { return nil, err } } if sniffer.options.Promisc { // forces the interface into promiscuous mode err = syscall.SetBpfPromisc(sniffer.fd, enable) if err != nil { return nil, err } } return &sniffer, nil }