Você provavelmente encontrou um bug do kernel. Talvez eu não devesse ir tão longe como um bug, já que pode ser que o suporte para o identificador específico da placa nunca tenha sido adicionado ao código do kernel.
O código ettercap que lida com a camada física é o seguinte:
switch (ifr.ifr_hwaddr.sa_family)
{
case ARPHRD_ETHER:
case ARPHRD_METRICOM:
#ifdef ARPHRD_LOOPBACK
case ARPHRD_LOOPBACK:
#endif
l->link_type = DLT_EN10MB;
l->link_offset = 0xe;
break;
case ARPHRD_SLIP:
case ARPHRD_CSLIP:
case ARPHRD_SLIP6:
case ARPHRD_CSLIP6:
case ARPHRD_PPP:
l->link_type = DLT_RAW;
break;
case ARPHRD_FDDI:
l->link_type = DLT_FDDI;
l->link_offset = 0x15;
break;
/* Token Ring */
case ARPHRD_IEEE802:
case ARPHRD_IEEE802_TR:
case ARPHRD_PRONET:
l->link_type = DLT_PRONET;
l->link_offset = 0x16;
break;
default:
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
"unknown physical layer type 0x%x",
ifr.ifr_hwaddr.sa_family);
goto bad;
}
E você pode verificar os valores de todos aqueles definidos dentro de /usr/include/net/if_arp.h
. E sim, 0x323 acaba por não ser nenhum deles. Além disso 0x323 não é nenhum dispositivo conhecido para net/if_arp.h
Aqui está um programa de teste para preencher ifr.ifr_hwaddr.sa_family
e imprimi-lo:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stropts.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
int
main(int argc, char** argv)
{
struct ifreq ifr;
int fd = -1;
char *iface = argv[1];
fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
if (fd == -1)
{
if (errno == EPERM) {
printf("UID/EUID 0 or capability CAP_NET_RAW required\n");
} else {
printf("socket: %s\n", strerror(errno));
}
return 1;
}
memset(&ifr, 0, sizeof (ifr));
strncpy(ifr.ifr_name, iface, sizeof (ifr.ifr_name) -1);
ifr.ifr_name[strlen(iface)] = '[root@haps ~]# /home/grochmal/tmp/libnet/test enp3s0
IFR: [24240001] sa_family [00]
[root@haps ~]# /home/grochmal/tmp/libnet/test wlp2s0
IFR: [22000001] sa_family [00]
';
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0 )
{
printf("SIOCGIFHWADDR: %s\n", strerror(errno));
return 1;
}
printf( "IFR: [%08x] sa_family [%02x]\n"
, ifr.ifr_hwaddr, ifr.ifr_hwaddr.sa_family);
return 0;
}
Metade é simplesmente copiada do código do ettercap. De qualquer forma, a compilação deve ser trivial gcc -o prog prog.c
(dado que a fonte é nomeada prog.c
) e você deve executá-la com o nome da interface como seu primeiro argumento. por exemplo,
ioctl(fd, SIOCGIFHWADDR, &ifr)
(na minha máquina)
Podemos ver que sa_family
é preenchido por:
struct net_device *dev = dev_get_by_name_rcu(net, ifr->ifr_name);
...
case SIOCGIFHWADDR:
if (!dev->addr_len)
memset(ifr->ifr_hwaddr.sa_data, 0,
sizeof(ifr->ifr_hwaddr.sa_data));
else
memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr,
min(sizeof(ifr->ifr_hwaddr.sa_data),
(size_t)dev->addr_len));
ifr->ifr_hwaddr.sa_family = dev->type;
return 0;
Que executa isso:
IFR: [********] sa_family [323]
Em que dev_get_by_name_rcu
é uma macro do kernel que preenche o struct net_device
. E como temos ifr->ifr_hwaddr.sa_family = dev->type;
também preenche sa_family
.
Encontrei um relatório de erros na página do Kali Linux sobre esse sa_family
, mas o kali não não use o kernel mais recente.
Portanto, eu executaria o programa de teste acima para garantir que ele seja impresso:
switch (ifr.ifr_hwaddr.sa_family)
{
case ARPHRD_ETHER:
case ARPHRD_METRICOM:
#ifdef ARPHRD_LOOPBACK
case ARPHRD_LOOPBACK:
#endif
l->link_type = DLT_EN10MB;
l->link_offset = 0xe;
break;
case ARPHRD_SLIP:
case ARPHRD_CSLIP:
case ARPHRD_SLIP6:
case ARPHRD_CSLIP6:
case ARPHRD_PPP:
l->link_type = DLT_RAW;
break;
case ARPHRD_FDDI:
l->link_type = DLT_FDDI;
l->link_offset = 0x15;
break;
/* Token Ring */
case ARPHRD_IEEE802:
case ARPHRD_IEEE802_TR:
case ARPHRD_PRONET:
l->link_type = DLT_PRONET;
l->link_offset = 0x16;
break;
default:
snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
"unknown physical layer type 0x%x",
ifr.ifr_hwaddr.sa_family);
goto bad;
}
O programa de teste precisa ser executado como root, já que ele usa um soquete bruto.
E então eu tentaria uma nova versão do kernel para verificar se o bug foi corrigido na ramificação do kernel 4.x (por exemplo, gentoo ou arch). Por exemplo, executando um live CD com gcc
. O programa de teste não possui nenhum requerimento de biblioteca, portanto ele pode ser facilmente compilado em um live CD.
Isso é tão profundo quanto eu posso entrar no código do kernel. Como exatamente o sa_family
é determinado pelo hash do dispositivo , está além de mim.