4

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.

  1. you read flags via ioctl
  2. you update flags
  3. someone else modified flags
  4. 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.

jww
  • 97,681
  • 90
  • 411
  • 885
dbrank0
  • 9,026
  • 2
  • 37
  • 55

1 Answers1

5

PACKET_MR_PROMISC turns on promiscuous mode for the device. That will not be reflected in the status shown by ifconfig as it does not modify the state of the global IFF_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:

> IFF_PROMISC is not set,
It's not supposed to be set.
The correct way to put into promiscuous mode the device to which a
PF_PACKET socket is to do a SOL_PACKET/PACKET_ADD_MEMBERSHIP
"setsockopt()" call with PACKET_MR_PROMISC as the argument (see the
"packet(7)" man page), and that's what libpcap is doing.
The old way of directly setting IFF_PROMISC had problems - to quote the
comment at the front of "pcap-linux.c":
[snipped]
Gil Hamilton
  • 11,973
  • 28
  • 51
  • Thanks for properly reading that for me. O:-) ("ip link" also does not show P flag...) Upvoting immediately and accepting this if testing shows it really works, although one could say this is broken for other reasons (people expecting to see mode configured with ifconfig and so on). – dbrank0 Jan 16 '17 at 16:20
  • Ok. Yes, it works. For reference: promiscuous mode is retained only until socket is closed. After this, previously effective mode is restored. So if I understand correctly, one can no set promiscuous mode and exit (keeping mode) using this interface. Which is ok for my use. – dbrank0 Jan 19 '17 at 13:43