Você pode usar o netfilter do Linux para interceptar pings recebidos e enviá-los para o userspace. Isso fará isso:
iptables -I INPUT -p icmp --icmp-type echo-request -j NFLOG
Você pode adicionar qualquer tipo de critério do iptables como -s
(fonte) para interceptar apenas alguns pings e não outros.
Observe que isso não cancela a manipulação do kernel do ping original. Envia apenas uma cópia para o userspace. Se você planeja responder ao ping do userspace, então você irá querer evitar que o kernel também o manipule para que não haja 2 respostas. Para implementar isso, basta seguir o acima com outra regra iptables para soltar o original:
iptables -I INPUT -p icmp --icmp-type echo-request -j DROP
Para receber o ping do userspace, você precisa escrever algum código em C. A biblioteca libnetfilter_log é o que você precisa. Aqui está um exemplo de código que eu escrevi alguns anos atrás e que faz exatamente isso:
#include <libnetfilter_log/libnetfilter_log.h>
[...]
struct nflog_handle *h;
struct nflog_g_handle *qh;
ssize_t rv;
char buf[4096];
h = nflog_open();
if (!h) {
fprintf(stderr, "error during nflog_open()\n");
return 1;
}
if (nflog_unbind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error nflog_unbind_pf()\n");
return 1;
}
if (nflog_bind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nflog_bind_pf()\n");
return 1;
}
qh = nflog_bind_group(h, 0);
if (!qh) {
fprintf(stderr, "no handle for group 0\n");
return 1;
}
if (nflog_set_mode(qh, NFULNL_COPY_PACKET, 0xffff) < 0) {
fprintf(stderr, "can't set packet copy mode\n");
return 1;
}
nflog_callback_register(qh, &callback, NULL);
fd = nflog_fd(h);
while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
nflog_handle_packet(h, buf, rv);
}
callback
é uma função que é chamada para cada pacote de entrada. É definido como algo assim:
static int
callback(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg, struct nflog_data *ldata, void *data)
{
payload_len = nflog_get_payload(ldata, (char **)(&ip));
....
/* now "ip" points to the packet's IP header */
/* ...do something with it... */
....
}