
/* cutredump_libpcap.c
 * Guillem Cantallops Ramis, BkP 2002
 * GNU GPL */

#include <stdio.h>
#include <string.h>
#include <pcap.h>

#define DEBUG			1				/* Booleana */

/* Les funcions de la pcap sembla que tenen dues formes diferents de treure els errors,
   unes el posen a dins 'errbuf' pero altres te'l fan treure amb pcap_perror() :-? */

#define	PCAP_ERRB(X)	{ fprintf(stderr, "%s: %s\n", X, errbuf); exit(-1); }
#define PCAP_PERR(Y,Z)	{ pcap_perror(Y, Z); exit(-1); }

/* Constants varies per a la libpcap */

#define PROMISC			0				/* Booleana */
#define	TO_MS			1000			/* Timeout de lectura en milisegons */
#define MAX_FRAME_LEN	1518			/* Tamany maxim d'una trama Ethernet */
#define ETH_HDR_LEN		14				/* Tamany de la capçalera Ethernet */

/* Filtres per a la libpcap, amb el mateix format els de tcpdump */

#define	F_ARP_REQUEST	"arp[6:2]=0x0001"	/* Captura missatges ARP amb el camp OPERATION=REQUEST */

/* Format dels missatges ARP */

#define	ARP_MSG_LEN		28					/* IP+Ethernet -> missatges ARP de 28 bytes */

typedef	union {
	struct {
		unsigned short int	hw_type;		/* Sempre val 0x0001=ETHERNET */
		unsigned short int	pr_type;		/* Sempre val 0x0800=IP */
		unsigned char		hlen;			/* Sempre HLEN=6, les adreces MAC son de 48 bits!!! */
		unsigned char		plen;			/* Sempre PLEN=4, les adreces IP son de 32 bits!!! */
		unsigned short int	op;				/* arp_request=1, arp_response=2 */
		unsigned char		s_ha[6];		/* Adreça MAC del remitent */
		unsigned char		s_ip[4];		/* Adreça IP del remitent */
		unsigned char		t_ha[6];		/* Adreça MAC del destinatari */
		unsigned char		t_ip[4];		/* Adreça IP del destinatari */
	} s;									/* "s" de "struct" */
	u_char a[ARP_MSG_LEN];					/* "a" de "array" */
} arp_message;

#define	S_IP(A)	A.s.s_ip[0],A.s.s_ip[1],A.s.s_ip[2],A.s.s_ip[3]
#define S_HA(B) B.s.s_ha[0],B.s.s_ha[1],B.s.s_ha[2],B.s.s_ha[3],B.s.s_ha[4],B.s.s_ha[5]

#define	T_IP(A)	A.s.t_ip[0],A.s.t_ip[1],A.s.t_ip[2],A.s.t_ip[3]
#define T_HA(B) B.s.t_ha[0],B.s.t_ha[1],B.s.t_ha[2],B.s.t_ha[3],B.s.t_ha[4],B.s.t_ha[5]

/* Funció "callback", cridada per pcap_dispatch() cada vegada que pilla un paquet */

void processar_peticio_arp(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
{
	arp_message m;			/* "m" de "missatge" */

	memcpy(m.a, sp+ETH_HDR_LEN, ARP_MSG_LEN);	/* fem això per poder llegir els camps facilment :-) */
	printf("Remitent    IP=%d.%d.%d.%d \t MAC=%02x-%02x-%02x-%02x-%02x-%02x\n", S_IP(m), S_HA(m));
	printf("Destinatari IP=%d.%d.%d.%d \t MAC=%02x-%02x-%02x-%02x-%02x-%02x\n", T_IP(m), T_HA(m));
	if(DEBUG)
		fprintf(stderr, "processar_peticio_arp: ok\n");
}



int main (int argc, char **argv)
{
	char errbuf[PCAP_ERRBUF_SIZE];
	char *device;
	pcap_t *p;
	bpf_u_int32 netp, maskp;
	struct bpf_program fp;
	int numread;

	/* Cercam un dispositiu adequat */
	if(!(device=pcap_lookupdev(errbuf)))
		PCAP_ERRB("pcap_lookupdev")
	if(DEBUG)
		fprintf(stderr, "pcap_lookupdev: ok, capturant paquets de %s\n", device);

	/* Obtenim el descriptor de captura de paquets */
	if(!(p=pcap_open_live(device, MAX_FRAME_LEN, PROMISC, TO_MS, errbuf)))
		PCAP_ERRB("pcap_open_live")
	if(DEBUG)
		fprintf(stderr, "pcap_open_live: ok\n");

	/* Obtenim l'adreça i la netmask */
	if(pcap_lookupnet(device, &netp, &maskp, errbuf)<0)
		PCAP_ERRB("pcap_lookupnet")
	if(DEBUG)
		fprintf(stderr, "pcap_lookupnet: ok, netp=0x%08x, maskp=0x%08x\n", netp, maskp);

	/* Compilam el programa de filtrat */
	if(pcap_compile(p, &fp, F_ARP_REQUEST, 1, maskp)<0)
		PCAP_PERR(p, "pcap_compile")
	if(DEBUG)
		fprintf(stderr, "pcap_compile: ok, compilat el filtre \"%s\"\n", F_ARP_REQUEST);

	/* Aplicam el programa de filtrat */
	if(pcap_setfilter(p, &fp)<0)
		PCAP_PERR(p, "pcap_setfilter")
	if(DEBUG)
		fprintf(stderr, "pcap_setfilter: ok, filtre aplicat\n");

	/* Ja podem capturar paquets */
	if((numread=pcap_loop(p, -1, processar_peticio_arp, (u_char *)NULL))<=0)
		PCAP_PERR(p, "pcap_loop")
	if(DEBUG)
		fprintf(stderr, "pcap_loop: ok, llegits %d paquets\n", numread);

	/* Al final, tancam el descriptor de captura de paquets */
	pcap_close(p);
	if(DEBUG)
		fprintf(stderr, "pcap_close: ok\n");

	exit(0);
}

