So how do you do this properly?
I know how to do it by creating socket, then setting IFF_PROMISC flag using ioctl (as explained in "howto check a network devices status in C?" and elsewhere), but this looks flawed at least in theory.
- you read flags via ioctl
- you update flags
- someone else modified flags
- you set updated flags via ioctl
Is there a better way or do I simply worry too much?
Later I found that one should add interface to PACKET_MR_PROMISC via setsockopt (which also does not have a race) like this:
void set_promisc(const char *ifname, bool enable)
{
struct packet_mreq mreq = {0};
int sfd;
int action;
if ((sfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("unable to open socket");
return;
}
mreq.mr_ifindex = if_nametoindex(ifname);
mreq.mr_type = PACKET_MR_PROMISC;
if (mreq.mr_ifindex == 0) {
perror("unable to get interface index");
return;
}
if (enable)
action = PACKET_ADD_MEMBERSHIP;
else
action = PACKET_DROP_MEMBERSHIP;
if (setsockopt(sfd, SOL_PACKET, action, &mreq, sizeof(mreq)) != 0) {
perror("unable to enter promiscouous mode");
return;
}
close(sfd);
}
Unfortunately this has no effect whatsoever on interface, although it should, if I unserstand the doc correctly. Possibly broken since 2001 (tm)? Comments in pcap source also complain about this.
PACKET_MR_PROMISC
turns on promiscuous mode for the device. That will not be reflected in the status shown byifconfig
as it does not modify the state of the globalIFF_PROMISC
flag on the device. That does not mean it hasn't been done though. This is how the pcap library works now and the fact that wireshark (and a dozen other utilities) can open a device and see packets not addressed to the local system shows that it works.There is an internal counter on each device that is incremented each time a process uses
PACKET_MR_PROMISC
, and decremented when that process goes away. That solves the race you originally described.From the last link you provided: