/* Copyright (c) 2007, Rob Bloom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the <organization> nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ROB BLOOM ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ROB BLOOM BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

 #include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/kd.h>
#include <net/if.h>
#include <unistd.h>
#include <pcap.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <elf.h>

#define DEFAULT_INTERFACE "eth0"

void packet_handler(u_char *user, const struct pcap_pkthdr *hdr, const u_char *pkt);

time_t start;

u_char hwaddr[6];


FILE *tty;
int main(int argc, char *argv[]) {
  tty = fopen("/dev/tty0", "r");
  if (!tty) {
    printf("Couldn't open tty0, using current terminal only.\n");
    tty = stdin;
  }

  char errbuf[PCAP_ERRBUF_SIZE];
  
  char *ifname;
  if (argc != 1) {
    ifname = malloc(strlen(argv[1])+2);
    strcpy(ifname,argv[1]);
  } else {
    ifname = malloc(strlen(DEFAULT_INTERFACE)+2);
    strcpy(ifname,DEFAULT_INTERFACE);
  }
  printf ("Opening interface %s for sniffing.\n",ifname);
    
  pcap_t *cap = pcap_open_live(ifname, 16384, 0, 0, errbuf);
  if (!cap) {
    printf("Unable to open interface: %s\n",errbuf);
    exit(1);
  }
  
  struct ifreq ifr;
  strcpy(ifr.ifr_name,ifname);
  ioctl(pcap_fileno(cap), SIOCGIFHWADDR, &ifr);
  
  printf("Local address: " );
  
  ioctl(fileno(stdin), KDSETLED, 0);

  int i;
  for (i = 0; i < 6; i++) {
    printf("%02X%s", ifr.ifr_hwaddr.sa_data[i] & 0xFF, (i == 5 ? "\n" : ":"));
  }
  memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);
  
  start = time(0);
  while (1) {
    pcap_dispatch(cap, -1, (pcap_handler) packet_handler, NULL);
  }
  exit (0);
}

void packet_handler(u_char *user, const struct pcap_pkthdr *hdr, const u_char *pkt) {
  /*
  if ( memcmp(hwaddr, pkt + 6, 6) == 0) {
    printf("OUTGOING PACKET: ");
  } else {
    printf("INCOMING PACKET: ");
  }
    printf("(%02X%02X) ",pkt[12], pkt[13]);
    printf("%3i: Read a packet of length %i\n",
      (int)difftime( (time_t)hdr->ts.tv_sec, (time_t)start),
      hdr->len);
  */
  
  
  // Assuming layer-2 is Ethernet...
  
  // Determine the layer-3 protocol of this (IP4, IP6, ???)
  uint16_t nwproto = (pkt[12] << 8) | pkt[13];
  
  const u_char *ip = pkt + 14;
  
  enum protos { ARP=LED_SCR,UNDEF=LED_SCR,TCP=LED_NUM,UDP=LED_CAP };
  int finalproto = UNDEF; // Proto we'll group this packet to.
  
  //printf("Datalink %04X\n",nwproto);
  if (nwproto == 0x0800) { // IPv4
    // Determine the layer-4 protocol of this (UDP, TCP, ???) 
    u_char trproto = ip[9];
    if (trproto == 6) {
      finalproto = TCP;
    } else if (trproto == 17) {
      finalproto = UDP;
    }
  } else if (nwproto == 0x86DD) {
    u_char trproto = ip[6];
    // printf("IPv6 nextheader: %i\n",trproto);
    if (trproto == 6) {
      finalproto = TCP;
    } else if (trproto == 17) {
      finalproto = UDP;
    }
  } else if (nwproto == 0x0806) {
    finalproto = ARP;
  }
  //printf("Packet of type %i\n",finalproto);
  
  if (finalproto != 0) {
    ioctl(fileno(stdin), KDSETLED, finalproto);
    
    // 100mb/s ==  12.5mB/s.  bytes / 12.5mb/s = sec
    // 13107200 bytes/sec
    // 1/13107200 sec/byte
    // 13.1072 usec/byte
    usleep( (13.1072 *  hdr->len /2) );
    ioctl(fileno(stdin), KDSETLED, 0);
  }
 
}

