#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/sockios.h>
#include <net/ethernet.h>

int open_interface(char *name)
{
   struct sockaddr addr;
   struct ifreq ifr;
   int sockfd;

   /* otwarcie gniazda i powiazanie go z okreslonym interfejsem */

   sockfd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL));
   if (sockfd < 0)
         return -1;

   memset(&addr, 0, sizeof(addr));
   addr.sa_family = AF_INET;
   strncpy(addr.sa_data, name, sizeof(addr.sa_data));

   if (bind(sockfd, &addr, sizeof(addr)) != 0) {
         close(sockfd);
         return -1;
   }

   /* sprawdzenie czy okreslony interfejs to ethernet, jesli nie - wyjscie */

   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));

   if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
         close(sockfd);
         return -1;
   }

   if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
         close(sockfd);
         return -1;
   }

   /* ustawienie trybu odbierania */

   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
   if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
         close(sockfd);
         return -1;
   }
   ifr.ifr_flags |= IFF_PROMISC;
   if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
      close(sockfd);
      return -1;
   }

   return sockfd;
}

/* odczyt pakietow ethernetowych, wydrukowanie adresu zrodlowego i docelowego */

int read_loop(sockfd)
{
   struct sockaddr_in from;
   char buf[1792], *ptr;
   int size, fromlen, c;
   struct ether_header *hdr;

   while (1) {

         /* odczyt kolejnego dostepnego pakietu */

         size = recvfrom(sockfd, buf, sizeof(buf), 0, &from, &fromlen);
         if (size < 0)
               return -1;
         if (size < sizeof(struct ether_header))
               continue;

         hdr = (struct ether_header *)buf;

         /* wydrukowanie naglowka ethernetowego */

         for (c = 0; c < ETH_ALEN; c++)
               printf("%s%02x",c == 0 ? "" : ":",hdr->ether_shost[c]);

         printf(" > ");
         for (c = 0; c < ETH_ALEN; c++)
               printf("%s%02x",c == 0 ? "" : ":",hdr->ether_dhost[c]);

         printf(" typ: %i\n", hdr->ether_type);
   }
}

int main(int argc, char **argv)
{
   int sockfd;
   char *name = argv[1];

   if (!argv[1]) {
         fprintf(stderr, "Podaj nazwe interfejsu\n");
         return -1;
   }

   if ((sockfd = open_interface(name)) < 0) {
         fprintf(stderr, "Nie mozna otworzyc interfejsu\n");
         return -1;
   }

   if (read_loop(sockfd) < 0) {
         fprintf(stderr, "Blad odczytu pakietu\n");
         return -1;
   }

   return 0;
}
