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, andPCAP_ERROR
if another error occurred. IfPCAP_WARNING
orPCAP_ERROR
is returned,pcap_geterr()
orpcap_perror()
may be called with p as an argument to fetch or display a message describing the warning or error. IfPCAP_WARNING_PROMISC_NOTSUP
,PCAP_ERROR_NO_SUCH_DEVICE
, orPCAP_ERROR_PERM_DENIED
is returned,pcap_geterr()
orpcap_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
Sed to Loop Through File and Replace Placeholder Variables
Sending Snmp2 Trap Message from Linux Command Lne
How to Distribute C++11 Shared Library on Centos6
Why Does 'Ping' Not Timeout in Linux
How to Read N-Th Line from a Text File in Bash
Nohup Error No Such File or Directory
Install Python 32 Bit on 64 Bit Linux
Setfacl in Dockerfile Has No Effect
How to Simulate a Iret on Linux X86_64
How to Use Sysfs Inside Kernel Module
Dreaming of Making My Own Os- What Should I Use? (Suggestions)
Tail Logback Log Files with Log Level Coloring in Linux Server
Why Can't Bash Recognize The Existence of a Socket File
How to Find The Version of a Compiled Kernel Module
How to Run Sh File from Another Sh File
How to Delete The Line That Matches a Pattern and The Line After It with Sed