问题
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_PACKETcan be used with aSOCK_RAWsocket 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_ALLorETH_P_IPas the protocol argument tosocketto 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_PACKETfamily can receive or send to endpoints of typesockaddr_ll, which is associated with a particular MAC address (EUI-48 address), along with a particular network interface (such aseth0or whatever).
What I DON'T understand:
I don't understand if
AF_PACKETis 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 useAF_PACKETon 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_PACKETcan be used with non-Ethernet devices, does theETH_P_ALLprotocol 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