/* gcc src.c -lpcap */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <pcap/pcap.h>
#include <netinet/ether.h>

void show_packet(char *buf, int len)
{
	unsigned char ch;
	int i, j, k, space;

	for (i = 0; i < len; i+=16) {
		printf("\t0x%04x  ", i);
		for (j = i; j < i+16 && j < len; j++) {
			ch = (unsigned char)buf[j];
			printf("%02X ", ch);
		}
 
		if (j == i+16)
			space = 1;
		else
			space = 1 + (16*3) - (j-i)*3;
 
		for (k = 0; k < space; k++)
			printf(" ");
 
		for (j = i; j < i+16 && j < len; j++) {
			ch = (unsigned char)buf[j];
			if (ch <= 32 || ch >= 127)
				ch = '.';
			printf("%c", ch);
		}
		printf("\n");
	}
	printf("\n");
}

char *ether_ntoa_padded(const struct ether_addr *addr, char *buf)
{
	sprintf (buf, "%02x:%02x:%02x:%02x:%02x:%02x",
		addr->ether_addr_octet[0], addr->ether_addr_octet[1],
		addr->ether_addr_octet[2], addr->ether_addr_octet[3],
		addr->ether_addr_octet[4], addr->ether_addr_octet[5]);
	return buf;
}

void show_ethernet_header(char *packet, int len)
{
	/* man 3 ether_aton */
	/* /usr/include/linux/if_ether.h */

	struct ethhdr *h;
	h = (struct ethhdr *)packet;

	struct ether_addr *dst;
	dst = (struct ether_addr *)(h->h_dest);

	struct ether_addr *src;
	src = (struct ether_addr *)(h->h_source);
	
	char addr_str[INET6_ADDRSTRLEN];
	printf("Ethernet header info:\n");
	printf("\tdst: %s (%s)\n", ether_ntoa(dst), ether_ntoa_padded(dst, addr_str));
	printf("\tsrc: %s (%s)\n", ether_ntoa(src), ether_ntoa_padded(src, addr_str));
	printf("\ttype: 0x%04X\n", ntohs(h->h_proto));
	printf("\n");
}

void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
{
	static int packet_count = 0;
	for (int i = 0;i < 80; i++) putchar('#');
	printf("\n# Packet: %d , Size: %d\n", ++packet_count, h->len);
	show_packet((char *)bytes, h->len);
	show_ethernet_header((char *)bytes, h->len);
}

int main()
{
	pcap_t *p;
	char errbuf[PCAP_ERRBUF_SIZE];
	p = pcap_open_offline("capture.pcap", errbuf);
	if (p == NULL) {
		fprintf(stderr, "\npcap_open_offline() failed: %s\n", errbuf);
		exit(EXIT_FAILURE);
	}

	if (pcap_loop(p, 0, packet_handler, NULL) < 0) {
		fprintf(stderr, "\npcap_loop() failed: %s\n", pcap_geterr(p));
		exit(EXIT_FAILURE);
	}

	return 0;
}