Estou seguindo este exemplo de aplicação C de um sniffer de soquete bruto:
https://www.binarytides.com/packet-sniffer-code-c-linux/
Exceto que vinculei o soquete à minha interface depois de criar o soquete:
const std::string& iff = "wlp3s0";
int r = setsockopt(sock_raw, SOL_SOCKET, SO_BINDTODEVICE, iff.c_str(), iff.length());
if (r == -1)
{
std::abort();
}
Deixo então o aplicativo em execução:
sudo ./the_app
Abro o Wireshark e ouço a interface sem fio wlp3s0. Removi a interface Ethernet com fio da captura.
Em seguida, executo sudo dhclient -r
e sudo dhclient
paro/inicio o DHCP e o Wireshark detecta 4 ou 5 pacotes DHCP, conforme esperado:
No entanto, o sniffer de soquete bruto C não mostra absolutamente nenhum pacote UDP recebido.
Se eu abrir um navegador da web, ele começará a mostrar pacotes TCP (o Wireshark relatou que os pacotes DHCP eram UDP).
O que está acontecendo? Estou usando Ubuntu 22.04
Exemplo mínimo:
#include<stdio.h> //For standard things
#include<stdlib.h> //malloc
#include<string.h> //memset
#include<netinet/ip_icmp.h> //Provides declarations for icmp header
#include<netinet/udp.h> //Provides declarations for udp header
#include<netinet/tcp.h> //Provides declarations for tcp header
#include<netinet/ip.h> //Provides declarations for ip header
#include<sys/socket.h>
#include<arpa/inet.h>
#include <unistd.h>
void ProcessPacket(unsigned char* , int);
int tcp=0,udp=0,icmp=0,others=0,igmp=0,total=0,i,j;
struct sockaddr_in source,dest;
int main()
{
unsigned char *buffer = (unsigned char *)malloc(65536); //Its Big!
printf("Starting...\n");
int sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_TCP);
if(sock_raw < 0)
{
std::abort();
}
int r = setsockopt(sock_raw, SOL_SOCKET, SO_BINDTODEVICE, "wlp3s0", strlen("wlp3s0"));
if (r == -1)
{
std::abort();
}
while(1)
{
int data_size = recv(sock_raw , buffer , 65536 , 0);
if(data_size <0 )
{
std::abort();
}
ProcessPacket(buffer , data_size);
}
::close(sock_raw);
return 0;
}
void ProcessPacket(unsigned char* buffer, int size)
{
//Get the IP Header part of this packet
struct iphdr *iph = (struct iphdr*)buffer;
++total;
switch (iph->protocol) //Check the Protocol and do accordingly...
{
case 1: //ICMP Protocol
++icmp;
//print_icmp_packet(buffer, size);
break;
case 2: //IGMP Protocol
++igmp;
break;
case 6: //TCP Protocol
++tcp;
//print_tcp_packet(buffer , size);
break;
case 17: //UDP Protocol
++udp;
//print_udp_packet(buffer , size);
break;
default: //Some Other Protocol like ARP etc.
++others;
break;
}
printf("TCP : %d UDP : %d ICMP : %d IGMP : %d Others : %d Total : %d\r",tcp,udp,icmp,igmp,others,total);
}
Bem, é claro que você não está recebendo pacotes UDP. Você está solicitando explicitamente apenas pacotes TCP com
IPPROTO_TCP
:Afinal, o próprio guia que você está seguindo diz o seguinte:
Agora você pode pensar em usar
IPPROTO_RAW
, mas isso só é possível para envio , conformeman 7 raw
explica:Portanto, você não pode receber vários protocolos com um
AF_INET
soquete. Você precisará de umAF_PACKET
soquete e de um código um pouco mais complexo. Vejaman 7 packet
para mais informações.Observe que neste caso você terá que vincular usando
bind(2)
estruct sockaddr_ll
, não pode usarsetsockopt(SO_BINDTODEVICE, ...)
comAF_PACKET
soquetes, comoman 7 socket
afirma: