func main() { enable := 1 fd, err := syscall.Open("/dev/bpf0", syscall.O_RDWR, syscall.S_IRUSR|syscall.S_IWUSR) if err != nil { panic(err) } err = syscall.SetBpfInterface(fd, "vtnet0") if err != nil { panic(err) } err = syscall.SetBpfImmediate(fd, enable) if err != nil { panic(err) } err = syscall.SetBpfHeadercmpl(fd, enable) if err != nil { panic(err) } var bufLen int bufLen, err = syscall.BpfBuflen(fd) if err != nil { panic(err) } fmt.Printf("buflen %d\n", bufLen) err = syscall.SetBpfPromisc(fd, enable) if err != nil { panic(err) } var n int for { buf := make([]byte, bufLen) n, err = syscall.Read(fd, buf) if err != nil { panic(err) } //fmt.Printf("% X\n", buf[:n]) fmt.Printf("\npacket of size %d captured\n", n) fmt.Print(hex.Dump(buf[:n])) } }
// configureBPF configures a BPF device with the specified file descriptor to // use the specified network and interface and protocol. func configureBPF(fd int, ifi *net.Interface, proto Protocol) (int, error) { // Use specified interface with BPF device if err := syscall.SetBpfInterface(fd, ifi.Name); err != nil { return 0, err } // Inform BPF to send us its data immediately if err := syscall.SetBpfImmediate(fd, 1); err != nil { return 0, err } // Check buffer size of BPF device buflen, err := syscall.BpfBuflen(fd) if err != nil { return 0, err } // Do not automatically complete source address in ethernet headers if err := syscall.SetBpfHeadercmpl(fd, 0); err != nil { return 0, err } // Only retrieve incoming traffic using BPF device if err := setBPFDirection(fd, bpfDIn); err != nil { return 0, err } // Build and apply base BPF filter which checks for correct EtherType // on incoming packets prog, err := bpf.Assemble(baseInterfaceFilter(proto, ifi.MTU)) if err != nil { return 0, err } if err := syscall.SetBpf(fd, assembleBpfInsn(prog)); err != nil { return 0, err } // Flush any packets currently in the BPF device's buffer if err := syscall.FlushBpf(fd); err != nil { return 0, err } return buflen, nil }
func initialize(iface net.Interface) (err error) { verboseLog.Println("search available /dev/bpfX") for i := 0; i <= 10; i++ { bpfPath := fmt.Sprintf("/dev/bpf%d", i) bpf, err = os.OpenFile(bpfPath, os.O_RDWR, 0666) if err != nil { verboseLog.Printf(" open failed: %s - %s\n", bpfPath, err.Error()) } else { verboseLog.Printf(" open success: %s\n", bpfPath) break } } bpfFd = int(bpf.Fd()) if bpfFd == -1 { return errors.New("unable to open /dev/bpfX") } if err := syscall.SetBpfInterface(bpfFd, iface.Name); err != nil { return err } if err := syscall.SetBpfImmediate(bpfFd, 1); err != nil { return err } buflen, err = syscall.BpfBuflen(bpfFd) if err != nil { return err } if err := syscall.SetBpf(bpfFd, bpfArpFilter); err != nil { return err } if err := syscall.FlushBpf(bpfFd); err != nil { return err } return nil }
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 }