Detect If Interface Is in Promiscuous Mode with C

How to properly put network interface into promiscuous mode on Linux

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]

Reading from a promiscuous network device

On Linux you use a PF_PACKET socket to read data from a raw device, such as an ethernet interface running in promiscuous mode:

s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))

This will send copies of every packet received up to your socket. It is quite likely that you don't really want every packet, though. The kernel can perform a first level of filtering using BPF, the Berkeley Packet Filter. BPF is essentially a stack-based virtual machine: it handles a small set of instructions such as:

ldh = load halfword (from packet)  
jeq = jump if equal
ret = return with exit code

BPF's exit code tells the kernel whether to copy the packet to the socket or not. It is possible to write relatively small BPF programs directly, using setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, ). (WARNING: The kernel takes a struct sock_fprog, not a struct bpf_program, do not mix those up or your program will not work on some platforms).

For anything reasonably complex, you really want to use libpcap. BPF is limited in what it can do, in particular in the number of instructions it can execute per packet. libpcap will take care of splitting a complex filter up into two pieces, with the kernel performing a first level of filtering and the more-capable user-space code dropping the packets it didn't actually want to see.

libpcap also abstracts the kernel interface out of your application code. Linux and BSD use similar APIs, but Solaris requires DLPI and Windows uses something else.

Golang - get promiscuous mode status of network interfaces

The working environment is Ubuntu, I used the ifconfig command and checked each interface details to see if it contains the word PROMISC. Something like this:

//
// get the interfaces
//
interfaces, err := net.Interfaces()

//
// run the ifconfig command
//
out, err := exec.Command("/bin/sh", "-c", "ifconfig").Output()

var ifc Iface
var ifaceset []Iface

//
// split the output to handle each interface separately
//
var ifaceDetails = strings.Split(string(out), "\n\n")

//
// iterate interfaces
//
for _, i := range interfaces {
ifc.Name = i.Name
if strings.Contains(i.Flags.String(), "up") {
ifc.Status = "UP"
} else {
ifc.Status = "DOWN"
}
if strings.Contains(i.Flags.String(), "multicast") {
ifc.Multicast = true
} else {
ifc.Multicast = false
}
if strings.Contains(i.Flags.String(), "broadcast") {
ifc.Broadcast = true
} else {
ifc.Broadcast = false
}

//
// try to find the word PROMISC to check if it is UP
//
for _, ifdetails := range ifaceDetails {
if strings.Contains(ifdetails, i.Name) {
if strings.Contains(ifdetails, "PROMISC") {
ifc.Promisc = true
} else {
ifc.Promisc = false
}

}
}
ifaceset = append(ifaceset, ifc)
}

}

How do I discover a process that has made an interface promiscuous?

Kernel will printk() a message when an interface is put into promiscuous mode. That message should end up in the system logs (usually in /var/log), though most likely your intruder will be smart enough to censor logs and hide his/her/its trail. The only correct answer to this challenge, in my humble opinion, is to have a remote logging server where at least some of the system messages are redirected in addition to storing them to a local disk.

To get more information into logs you could turn on kernel auditing by adding audit=1 to kernel command line.

An interface can be in promiscuous mode without any process actively "keeping" it as such. Actually, you can just turn on promiscuous mode for an interface with ip link set <interface> promisc on. Try it on your loopback interface with ip link set lo promisc on, see what netstat -i produces on your terminal, then turn promiscuous mode again off with ip link set lo promisc off and check once again with netstat -i how flags for the loopback interface have changed.

To answer your first question: there is no way to know which process keeps an interface in promiscuous mode as there might be such a process in the first place. The kernel doesn't have detailed process information at the point of __dev_set_promiscuity():

if (dev->flags != old_flags) {
pr_info("device %s %s promiscuous mode\n",
dev->name,
dev->flags & IFF_PROMISC ? "entered" : "left");
if (audit_enabled) {
current_uid_gid(&uid, &gid);
audit_log(current->audit_context, GFP_ATOMIC,
AUDIT_ANOM_PROMISCUOUS,
"dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
dev->name, (dev->flags & IFF_PROMISC),
(old_flags & IFF_PROMISC),
from_kuid(&init_user_ns, audit_get_loginuid(current)),
from_kuid(&init_user_ns, uid),
from_kgid(&init_user_ns, gid),
audit_get_sessionid(current));
}

For details, see file net/core/dev.c in the Linux kernel source tree.

Packet socket in promiscuous mode only receiving local traffic

Along with Rob Jones' suggestion, try a tool like Wireshark to make sure that you're receiving the packets that you expect at the interface. At least that will confirm (or deny) that you have a problem with your code.

Also need to make sure that the interface itself is set to promiscuous mode.
If not then you can use the ioctl() to set it:

ifr.ifr_flags |= IFF_PROMISC;
if( ioctl(sock, SIOCSIFFLAGS, &ifr) != 0 )
{
// handle error here
}

While your application is running, make sure that ifconfig reports the PROMISC flag for that interface.

Note that this will need to be executed as a privileged user.


Tried out the code as presented. Works for me. Of course (due to the test on line 102) this will only print details for TCP traffic.

Is it possible to check if an interface is activated in pcap?

Is it possible to check if an interface is activated in pcap?

Yes. You check by looking at the return value of pcap_activate(). The pcap_activate() man page says:

pcap_activate() returns 0 on success without warnings, PCAP_WARNING_PROMISC_NOTSUP on success on a device that doesn't support promiscuous mode if promiscuous mode was requested, PCAP_WARNING on success with any other warning, PCAP_ERROR_ACTIVATED if the handle has already been activated, PCAP_ERROR_NO_SUCH_DEVICE if the capture source specified when the handle was created doesn't exist, PCAP_ERROR_PERM_DENIED if the process doesn't have permission to open the capture source, PCAP_ERROR_RFMON_NOTSUP if monitor mode was specified but the capture source doesn't support monitor mode, PCAP_ERROR_IFACE_NOT_UP if the capture source is not up, and PCAP_ERROR if another error occurred. If PCAP_WARNING or PCAP_ERROR is returned, pcap_geterr() or pcap_perror() may be called with p as an argument to fetch or display a message describing the warning or error. If PCAP_WARNING_PROMISC_NOTSUP, PCAP_ERROR_NO_SUCH_DEVICE, or PCAP_ERROR_PERM_DENIED is returned, pcap_geterr() or pcap_perror() may be called with p as an argument to fetch or display an message giving additional details about the problem that might be useful for debugging the problem if it's unexpected.

You should also be checking whether pcap_create() returns NULL, by the way.

howto check a network devices status in C?

You need to use the SIOCGIFFLAGS ioctl to retrieve the flags associated with an interface. You can then check if the IFF_PROMISC flag is set:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h> /* ioctl() */
#include <sys/socket.h> /* socket() */
#include <arpa/inet.h>
#include <unistd.h> /* close() */
#include <linux/if.h> /* struct ifreq */

int main(int argc, char* argv[])
{
/* this socket doesn't really matter, we just need a descriptor
* to perform the ioctl on */
int fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

struct ifreq ethreq;

memset(ðreq, 0, sizeof(ethreq));

/* set the name of the interface we wish to check */
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
/* grab flags associated with this interface */
ioctl(fd, SIOCGIFFLAGS, ðreq);
if (ethreq.ifr_flags & IFF_PROMISC) {
printf("%s is in promiscuous mode\n",
ethreq.ifr_name);
} else {
printf("%s is NOT in promiscuous mode\n",
ethreq.ifr_name);
}

close(fd);

return 0;
}

If you want to set the interface to promiscuous mode, you will need root privileges, but you can simply set the field in ifr_flags and use the SIOCSIFFLAGS ioctl:

/* ... */
ethreq.ifr_flags |= IFF_PROMISC;
ioctl(fd, SIOCSIFFLAGS, ðreq);

C++ Sockets: Enabling Promiscuous Mode in Windows

To put a socket into promiscuous mode on Windows, you need to call WSAIoCtl() to issue a SIO_RCVALL control code to the socket.

int main(int argc, char const *argv[])
{
WSADATA wsa;
SOCKET s; //The bound socket
struct sockaddr_in server;
int recv_len; //Size of received data
char udpbuf[BUFLEN]; //A buffer for the incoming data.

//Initialize Winsock
int err = WSAStartup(MAKEWORD(2,0), &wsa);
if (err != 0)
{
printf("Could not initialize Winsock : %d", err);
exit(EXIT_FAILURE);
}

//Create a socket
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_IP)) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
WSACleanup();
exit(EXIT_FAILURE);
}
printf("Socket created.\n");

//Prepare the sockaddr_in structure
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(ADDR);
server.sin_port = htons(PORT);

//Bind socket to address
if (bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d", WSAGetLastError());
closesocket(s);
WSACleanup();
exit(EXIT_FAILURE);
}
puts("Bind done\n");

// enable promiscuous mode
DWORD dwValue = RCVALL_ON;
DWORD dwBytesReturned = 0;
if (WSAIoctl(s, SIO_RCVALL, &dwValue, sizeof(dwValue), NULL, 0, &dwBytesReturned, NULL, NULL) == SOCKET_ERROR)
{
printf("Ioctl failed with error code : %d", WSAGetLastError());
closesocket(s);
WSACleanup();
exit(EXIT_FAILURE);
}
puts("Ioctl done\n");

while (true)
{
//Block statment. Code will wait until it detect packets.
if ((recv_len = recvfrom(s, udpbuf, BUFLEN, 0, 0, 0)) == SOCKET_ERROR)
{
printf("recvfrom() failed with error code : %d", WSAGetLastError());
closesocket(s);
WSACleanup();
exit(EXIT_FAILURE);
}
}

closesocket(s);
WSACleanup();

return 0;
}

Alternatively, Microsoft also has a separate Network Monitor API that allows you to monitor and capture network traffic without using Winsock at all.



Related Topics



Leave a reply



Submit