AF_PACKET and Ethernet

谁说我不能喝 提交于 2020-12-29 04:12:58

问题


I'm very confused about exactly how the AF_PACKET socket family (for SOCK_RAW sockets) specifically relates to Ethernet (IEEE 802.3).

What I understand so far:

  • I understand the OSI Model, and how Layer 2 technologies like Ethernet fit into the model.

  • I understand that AF_PACKET can be used with a SOCK_RAW socket to receive datagrams that contain a 14-byte Ethernet header, followed by some other higher layer protocol header(s), such as IPv4, IPv6, etc., followed by optionally a transport layer protocol like TCP, and finally a payload.

  • I understand you can pass flags such as ETH_P_ALL or ETH_P_IP as the protocol argument to socket to have the kernel filter packets for you, by only sending you packets containing headers of a certain type.

  • I understand that sockets created with the AF_PACKET family can receive or send to endpoints of type sockaddr_ll, which is associated with a particular MAC address (EUI-48 address), along with a particular network interface (such as eth0 or whatever).

What I DON'T understand:

  • I don't understand if AF_PACKET is supposed to exclusively work with Ethernet devices, as opposed to other Layer 2 technologies, such as Wifi, Bluetooth, Token Ring, Infiniband, etc.

  • I don't understand the relationship between Ethernet devices versus Layer 2 protocols that use the 14-byte Ethernet header. The Ethernet header is 14-bytes, and can be defined as something like: struct eth_hdr { char dest_address[6]; char source_address[6]; uint16_t ethertype; }; In other words, is this header only used with physical Ethernet devices? It seems the answer is no, because if I use AF_PACKET on the loopback interface, I still receive packets containing 14-byte Ethernet headers. But loopback is not an Ethernet device. So why does it receive packets containing Ethernet headers?

  • If AF_PACKET can be used with non-Ethernet devices, does the ETH_P_ALL protocol flag indicate to only accept packets that specifically have a 14-byte Ethernet header?


My question(s):

Does using AF_PACKET imply you are guaranteed to always receive packets with 14-byte Ethernet headers?

If so, does that also imply that AF_PACKET is meant to be used ONLY with Ethernet devices (as opposed to other Layer 2 technologies, like Wifi, Token Ring, Bluetooth, Infiniband, etc.)?

If the answer to either of these questions is NO, then how can an application programatically determine what type of Layer 2 header to expect when receiving a datagram on an AF_PACKET socket?


回答1:


Caveat: This comes from cannibalizing some code I wrote for production software that used PF_PACKET, which was only for ethernet, so it may be incomplete/inaccurate.

You're using ETH_P_ALL which will give you anything. But, there are many ETH_P_* symbols to choose from (e.g. ETH_P_802_3_MIN).

The binding/selection is not based on not merely the socket call, but is based on a given interface as well.

First you need the interface name you want (e.g. eth0) from the list you can get from ifconfig.

Then, get the interface index using ioctl(SIOCGIFINDEX,...) from the interface name [or, you could just hard code it as ifconfig will print them out in index order].

Then, bind to that interface, based on the interface index.

Since you know the type of interface (e.g. you chose eth0 or wifi, etc.), after that, you should be able to digest the physical layer header because you know whether it's struct eth_hdr or not.

Note that there are a number of other SIOCGIF* ioctls that you can use to get a list of interfaces and other information that may allow you to discern the interface type [and, therefore, what physical header to expect].

Anyway, here's some sample code from what I did:

int
init(const char *intf)
// intf -- interface name (e.g. eth0, etc. -- whatever comes from ifconfig)
{
    int err;

#if 1
    int styp = SOCK_RAW;
#else
    int styp = SOCK_DGRAM;
#endif

    int netsock = socket(PF_PACKET,styp,htons(ETH_P_ALL));

    struct ifreq ifr;
    memset(&ifr,0,sizeof(ifr));
    strncpy(ifr.ifr_name,intf,sizeof(ifr.ifr_name));

    // get the index number of the interface
    err = ioctl(netsock,SIOCGIFINDEX,&ifr);
    if (err < 0)
        do_whatever;

    printf("init: IFRIDX ifr_ifindex=%d\n",ifr.ifr_ifindex);
    int ifidx = ifr.ifr_ifindex;

    struct sockaddr_ll addr;
    addr.sll_family = AF_PACKET;
    addr.sll_protocol = htons(ETH_P_ALL);
    addr.sll_ifindex = ifidx;

    err = bind(netsock,(struct sockaddr *) &addr,
        sizeof(struct sockaddr_ll));
    if (err < 0)
        do_whatever;

    return netsock;
}


来源:https://stackoverflow.com/questions/54056426/af-packet-and-ethernet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!