Is it possible to receive raw ethernet frames in Linux without specifying an interface?

Viewed 304

I'm using mdlayhers (golang) libraries to handle raw ethernet frames to receive and process LLDP packets on a networking device. I'd like to monitor a large number of interfaces (up to 128) for LLDP frames.

In Linux I don't believe it's required to specify an interface to capture device data, but I could be wrong. Is it possible to receive raw ethernet frames across all interfaces by, for example, binding to AF_PACKET in go? I.e. Is there way to specify a wildcard interface in raw.ListenPacket or am I best creating a new goroutine for each interface?

1 Answers

Yes you can. I believe this is what you are looking for:

package main

import (
    "fmt"
    "net"
    "os"
    "syscall"
)

func main() {
    fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(htons(syscall.ETH_P_ALL)))
    if err != nil {
        fmt.Fprintf(os.Stderr, "syscall socket: %s", err.Error())
        os.Exit(1)
    }

    // Make a 32KB buffer
    buf := make([]byte, 1<<16)
    for {
        len, sockaddr, err := syscall.Recvfrom(fd, buf, 0)
        if err != nil {
            fmt.Fprintf(os.Stderr, "syscall recvfrom: %s", err.Error())
            os.Exit(1)
        }

        if llsa, ok := sockaddr.(*syscall.SockaddrLinklayer); ok {
            inter, err := net.InterfaceByIndex(llsa.Ifindex)
            if err != nil {
                fmt.Fprintf(os.Stderr, "interface from ifindex: %s", err.Error())
                os.Exit(1)
            }
            fmt.Print(inter.Name + ": ")
        }

        fmt.Printf("% X\n", buf[:len])
    }
}

// htons converts a short (uint16) from host-to-network byte order.
func htons(i uint16) uint16 {
    return (i<<8)&0xff00 | i>>8
}
Related