/* Asirmata Diktya kai Kinites Epikoinonies
Onomateponymo   : Minas Gjokas
Mitroo          : 3000017
*/

#define MODULE
#define __KERNEL__
#define __OPTIMIZE__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <asm/byteorder.h>
#include <linux/proc_fs.h>
#include <linux/file.h>
#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>

#define LOGFILE      "/tmp/sniff.txt"

enum {
  IPPROTO_ICMP = 1,             /* Internet Control Message Protocol    */
  IPPROTO_TCP = 6,               /* Transmission Control Protocol        */
  IPPROTO_UDP = 17,             /* User Datagram Protocol               */
};

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Minas Gjokas");

static int info_read_proc(char* buf, char** start, off_t offs, int len);

struct proc_dir_entry *proc_capture = NULL;
struct proc_dir_entry *proc_info = NULL;

//static int *kmalloc_ptr = NULL;

static int total_packets_passed = 0;
static int total_bytes_passed = 0;
//static int tcp_bytes_passed = 0;
static int tcp_packets_passed = 0;
//static int udp_bytes_passed = 0;
static int udp_packets_passed = 0;
//static int icmp_bytes_passed = 0;
static int icmp_packets_passed = 0;
//static int other_bytes_passed = 0;
static int other_packets_passed = 0;

void handlepacket(struct sk_buff *pskb);

static int info_read_proc(char* buf, char** start, off_t offs, int len)
{
   return sprintf(   buf, "Total Captured packets : %u\n"
               "Total Captured bytes : %u\n"
               "Tcp Captured packets : %u\n"
               "Udp Captured packets : %u\n" 
               "Icmp Captured packets : %u\n" 
               "Other Captured packets: %u\n",
               total_packets_passed, 
               total_bytes_passed,
               tcp_packets_passed,
               udp_packets_passed,
               icmp_packets_passed,
               other_packets_passed);
}


static unsigned int capture_funct(unsigned int hook, struct sk_buff **pskb, const struct net_device *indev, const struct net_device *outdev, int (*okfn)(struct sk_buff *))
{
   struct iphdr     *iph  = (*pskb)->nh.iph;
   struct tcphdr    *tcph;
   struct udphdr    *udph;
   struct icmphdr   *icmph;
   unsigned short srcport = 0;
   unsigned short dstport = 0;
   int packet_size,i;
//if(strcmp(indev->name,CLIENT) == 0){ printk ("WIRELESS LAN"); }   
    
   printk("-Packet Arrived-\n");
   packet_size = ntohs(iph->tot_len);
   total_bytes_passed = total_bytes_passed + packet_size;
   total_packets_passed++;

   switch (iph->protocol) {
      case IPPROTO_TCP: {
//         tcph = (*pskb)->h.th;
         tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
         printk("PROTOCOL=TCP ");
         srcport = ntohs((tcph)->source);
         dstport = ntohs((tcph)->dest);
         printk("FLAGS=%c%c%c%c%c%c ",
                              tcph->urg ? 'U' : '-',
                              tcph->ack ? 'A' : '-',
                              tcph->psh ? 'P' : '-',
                              tcph->rst ? 'R' : '-',
                              tcph->syn ? 'S' : '-',
                              tcph->fin ? 'F' : '-');
         tcp_packets_passed++;
         break;
       }
       case IPPROTO_UDP: {
//      udph = (*pskb)->h.uh;
         udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
         printk("PROTOCOL=UDP ");
         srcport = ntohs((udph)->source);
         dstport = ntohs((udph)->dest);
         udp_packets_passed++;
         break;
      }
      case IPPROTO_ICMP: {
         printk("PROTOCOL=ICMP ");
         icmp_packets_passed++;
         break;
      }
      default: {
         other_packets_passed++;       
      }
   };
   printk ("IN=%s IP_Packet_Length=%hu "
      "TOS=0x%2.2hX ID=%hu FRAG=0x%4.4hX TTL=%hu",
       indev->name, 
       packet_size, iph->tos, ntohs(iph->id),
       ntohs(iph->frag_off), iph->ttl);
   printk("\n[SRC=%u.%u.%u.%u:%u] ---> [DST=%u.%u.%u.%u:%u]\n", NIPQUAD(iph->saddr),srcport , NIPQUAD(iph->daddr),dstport);
   
   for (i=0; i<packet_size; i++) {
      printk("%2.2X", (char *) (*pskb)->data[i]);
   }
   printk("-Packet Logged-\n");

   /*struct file *file = NULL;
   mm_segment_t fs;
   spinlock_t fipra_lock= SPIN_LOCK_UNLOCKED;   
   unsigned long flags;
   
   file = filp_open(LOGFILE, O_WRONLY|O_APPEND, 0);
   spin_lock_irqsave(&fipra_lock, flags);
   local_irq_disable();
   fs = get_fs();
        set_fs(KERNEL_DS);
        file->f_op->write(file, (char *) (*pskb)->data , packet_size-2, &file->f_pos);
        set_fs(fs);
   local_irq_enable();
   spin_unlock_irqrestore(&fipra_lock, flags);*/
   return NF_ACCEPT;
}


static struct nf_hook_ops capture_hook = {   { NULL, NULL },  capture_funct, PF_INET, NF_IP_FORWARD /* NF_IP_PRE_ROUTING*/ , 0 };

static int __init init(void)
{
   int result;

//Proc file actions...
   proc_capture = proc_mkdir("asoe", &proc_root);
   if (!proc_capture)
      goto proc_failed;
   proc_info = create_proc_entry("info", 00444, proc_capture);
   if (!proc_info)
      goto proc_failed;
   proc_info->get_info = info_read_proc;

//Hook Registration
   result = nf_register_hook(&capture_hook);
   if (result) goto hook_failed;

//Everything is ok...
   printk("Module Loaded\n");
   return 0;


hook_failed:
   printk("Asoe Capture: error registering netfilet hook (%d)", result);
   return result; /* error returned */

proc_failed:
   printk("Asoe Capture: error registering proc entry\n");
   return 1; /* error returned*/

}

static void __exit finish(void)
{


   nf_unregister_hook(&capture_hook);

   if (proc_info)
      remove_proc_entry("info", proc_capture);
   if (proc_capture)
      remove_proc_entry("asoe", &proc_root);
   printk("Module Unloaded\n");
}

module_init(init);
module_exit(finish);
