#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include "packet.h"

#define TIME_TARGET_MAX		30
#define MSGSTRING_MAX		240
#define TARGET_LOGNAME_MAX	160

int rotate_flag;
int exitloop;

char target_logname[TARGET_LOGNAME_MAX];
char current_logfile[TARGET_LOGNAME_MAX];
char current_eth[25];
char acmp1[25];
char acmp2[25];

extern char *optarg;
int addr_cmp=0;

int flags;
struct ifreq ifr;
int fd;

void outprs(nsig);
int opentlog(FILE **fd, char *logfilename)
{
    *fd = fopen(logfilename, "a");
    if (*fd == NULL) return -1;
    return 0;
}

void genatime(time_t now, char *atime)
{
    bzero(atime, TIME_TARGET_MAX);
    strncpy(atime, ctime(&now), 26);
    atime[strlen(atime) - 1] = '\0';
}

void writelog(FILE *fd, char *msg)
{
    char atime[TIME_TARGET_MAX];

    genatime(time((time_t *) NULL), atime);
    fprintf(fd, "%s; %s\n", atime, msg);
    fflush(fd);
}


int iface_up(char *iface)
{
    int fd;
    int ir;
    struct ifreq ifr;

    fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);

    strcpy(ifr.ifr_name, iface);
    ir = ioctl(fd, SIOCGIFFLAGS, &ifr);

    close(fd);

    if ((ir != 0) || (!(ifr.ifr_flags & IFF_UP)))
	return 0;

    return 1;
}


void detstats(char *iface)
{
    char buf[MAX_PACKET_SIZE];
    char *packet;
    struct iphdr *ipacket = NULL;
    char *tpacket;
    unsigned int iphlen;
    unsigned int sport, dport;

    char ifname[8];
    struct sockaddr_ll fromaddr;
    unsigned short linktype;
    
    int br;
    int framelen = 0;
    int pkt_result = 0;
    FILE *logfile = NULL;
    unsigned int iplen = 0;
    int ch;
    struct timeval tv;
    unsigned long updtime = 0;
    unsigned long long updtime_usec = 0;
    unsigned long starttime, now;
    unsigned long statbegin, startlog;
    unsigned long long unow;
    char *tmp1,*tmp2;


    char unitstring[7];

    struct promisc_states *promisc_list;
    char err_msg[80];
    char *tmpstr;

    open_socket(&fd);
    if (fd < 0) exit(1);

    printf(" Try to set and unset promisc mode for %s \n",(char *) iface);

    //if((s = socket(PF_PACKET,SOCK_RAW, PROTO))<0) printf("Error open the  socket \n");
  
    ifr.ifr_ifindex = 0;
    strcpy(ifr.ifr_name, iface);
    if(ioctl(fd, SIOCGIFFLAGS,&ifr) < 0)  printf("===Error in ioctl \n");
    printf("Device had flags  %x\n",ifr.ifr_flags);
    flags = ifr.ifr_flags;
    ifr.ifr_flags |= IFF_PROMISC;
    if(ioctl(fd, SIOCSIFFLAGS,&ifr) < 0)  printf("===Error in ioctl \n");
    printf("Now device has flags %x\nhit any key...",ifr.ifr_flags);


    if(opentlog(&logfile, current_logfile)<0) exit(1);
    if (!iface_up(iface)) exit(1);

    while (!exitloop) {
	getpacket(fd, buf, &fromaddr, &ch, &br, ifname);

	if (br > 0) {
	    framelen = br;
            pkt_result = processpacket(buf, &packet, &br, NULL,&sport, &dport, &fromaddr, &linktype,ifname, iface);
            
            if (pkt_result == INVALID_PACKET)   continue;
                                 
	    if (fromaddr.sll_protocol == ETH_P_IP) {
                ipacket = (struct iphdr *) packet;
		
		tmp1=prnaddrX((char *)(packet+12)); //src
		tmp2=prnaddrX((char *)(packet+16)); //dst				

		if(addr_cmp==2){
			if((strstr(tmp1,acmp1)&&strstr(tmp2,acmp2))||(strstr(tmp2,acmp1)&&strstr(tmp1,acmp2))){
				tmpstr = pr_iph((struct iphdr*)packet,(char *)packet);
			        writelog(logfile,tmpstr);
				printf("%s",tmpstr);
				if(tmpstr!=NULL) free(tmpstr);		
			};
		} else {
			tmpstr = pr_iph((struct iphdr*)packet,(char *)packet);
		        writelog(logfile,tmpstr);
			printf("%s",tmpstr);
			if(tmpstr!=NULL) free(tmpstr);		
		};
		if(tmp1 != NULL) free(tmp1);
		if(tmp2 != NULL) free(tmp2);
	    };
	};
    };

    ifr.ifr_flags = flags;
    if(ioctl(fd, SIOCSIFFLAGS,&ifr) < 0)  printf("===Error in ioctl \n");
    printf("We restore devices flags %x\n",ifr.ifr_flags);

    close(fd);
    fclose(logfile);
}



int main(int argc, char **argv){
    char opt;
    char *defaultlog="./iplog.log";
    char *defaulteth="eth0";
    char *defauls="127.0.0.1";    
    char *defauld="127.0.0.1";        

    signal (SIGTERM, outprs);
    signal (SIGINT, outprs);    

    printf("---------------%d\n",argc);
    if (argc > 4){
	do {
	    opterr = 0;
	    opt = getopt(argc, argv,"i:l:h:s:d:v");

	    if (opt == 'h') {
		printf("%s\n","iplog -i <interface> -l <logfile>");
		exit(0);
	    } else if (opt == 'l') {
	        if ( (char*)optarg != NULL)
	            strncpy(current_logfile, (char*)optarg, strlen((char*)optarg));
	        else
	            strncpy(current_logfile,defaultlog,strlen(defaultlog));
	    } else if (opt == 'i') {
	        if ( (char*)optarg != NULL)
	            strncpy(current_eth, (char*)optarg, strlen((char*)optarg));
	        else
	            strncpy(current_eth,defaulteth,strlen(defaulteth));
	    } else if (opt == 's') {
		addr_cmp++;
	        if ( (char*)optarg != NULL)
	            strncpy(acmp1,  (char*)optarg, strlen( (char*)optarg));
	        else
	            strncpy(acmp1,defauls,strlen(defauls));
		    
	    } else if (opt == 'd') {

		addr_cmp++;	    
	        if ( (char*)optarg != NULL)
	            strncpy(acmp2,  (char*)optarg, strlen( (char*)optarg));
	        else
	            strncpy(acmp2,defauld,strlen(defauld));
		    
	    } else if (opt == '?') {
		fprintf(stderr,"\nInvalid option or missing parameter, use iptraf -h for help\n\n");
		exit(1);
	    } 
	} while ((opt != '?') && (opt != -1));
	
	printf("Start monitoring for %s to %s \n",current_eth,current_logfile);
	if(addr_cmp==2){
	    printf("-s %s -d %s \n",acmp1,acmp2);	
	};
	
	//exit(0);	
	detstats(current_eth);	
    } else {
	printf("%s\n","iplog -i <interface> -l <logfile> [-s xxx.xxx.xxx.xxx -d yyy.yyy.yyy.yyy]");
	exit(0);
    };
    exit(0);
}


void outprs(nsig){

    ifr.ifr_flags = flags;
    if(ioctl(fd, SIOCSIFFLAGS,&ifr) < 0)  printf("===Error in ioctl \n");
    printf("We restore devices flags %x\n",ifr.ifr_flags);
    exit(0);
};
