//go:build linux package dnstt import ( "fmt" "syscall" ) // OpenRawSocket creates an AF_PACKET raw socket for sniffing IPv4 packets. func OpenRawSocket() (int, error) { fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_DGRAM, int(htons(ethPAll))) if err != nil { return -1, fmt.Errorf("open raw socket: %w", err) } tv := syscall.Timeval{Sec: 0, Usec: 500000} _ = syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv) return fd, nil } // CaptureLoop records matching packets until stop is closed. func CaptureLoop(fd int, port int, collector *Collector, stop <-chan struct{}) { buf := make([]byte, 65535) for { select { case <-stop: return default: } n, _, err := syscall.Recvfrom(fd, buf, 0) if err != nil { if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK || err == syscall.EINTR { continue } return } ProcessPacket(buf[:n], port, collector) } } // CloseRawSocket closes a socket opened by OpenRawSocket. func CloseRawSocket(fd int) error { return syscall.Close(fd) } func htons(v uint16) uint16 { return (v << 8) | (v >> 8) } const ethPAll = 0x0003