/*
    FilenameSnarf
    -------------
     Utility to sniff filenames & paths of file being transfered through the machine.
     Currently supports: FTP
     
     Largely based on other *snarf stuff from Dsniff so credits to Dug Song!
*/

#include "config.h"

#include <sys/types.h>
#include <sys/queue.h>
#include <netinet/in.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
#include <err.h>
#include <libnet.h>
#include <nids.h>
#include <pcap.h>
#include <pcaputil.h>

#include "version.h"     

static int      pcap_off;
static u_char   buf[BUFSIZ];

libnet_t *l;
libnet_ptag_t   ip_id;
libnet_ptag_t  tcp_id;

static void
usage(void)
{
        fprintf(stderr, "Version: " VERSION "\n"
                "Usage: filenamesnarf [-i interface] expression\n");
        exit(1);
}

static void
ftp_parse(struct libnet_ipv4_hdr *ip, struct libnet_tcp_hdr *tcp, int pkt_len) {
    int data_len;
    char tmp[6];
    char command[1024];
    unsigned int port_no;
    data_len = pkt_len - (ip->ip_hl + tcp->th_off)*4; 
     unsigned int a1, a2, a3, a4, p1, p2;
    
        if (data_len > 5) {
	//we are only interested in commands
	//now we memcpy part of buf into tmp and add \0
	memcpy(tmp,buf,5);
	tmp[5] = 0x00;
	//and we compare strings
	if ((strcmp("RETR ",tmp) == 0) || (strcmp("STORE",tmp) == 0) ||(strcmp("226 T",tmp) == 0) ||(strcmp("450 ",tmp) 
== 0)) {
	    //now we want the whole command printed out
	    memcpy(command,buf,data_len -1);
	    command[data_len -1] = 0x00;
	    printf("FTP [%s:%d] > [%s:%d] - %s\n",
	    libnet_addr2name4(ip->ip_src.s_addr, 0), ntohs(tcp->th_sport),
	    libnet_addr2name4(ip->ip_dst.s_addr, 0), ntohs(tcp->th_dport),
	    command);
	} else if (strcmp("PORT ",tmp) == 0) {
	    //we parse the command properly
	    memcpy(command, buf + 5,data_len - 6);
	    command[data_len - 6] = 0x00;
	    sscanf(command, "%u,%u,%u,%u,%u,%u",
                    &a1, &a2, &a3, &a4, &p1, &p2);
	    port_no = (p1 << 8) | p2;
	    printf("Conversion done\n");
	    printf("FTP [%s:%d] > [%s:%d] - PORT %u.%u.%u.%u:%u\n",
	    libnet_addr2name4(ip->ip_src.s_addr, 0), ntohs(tcp->th_sport),
	    libnet_addr2name4(ip->ip_dst.s_addr, 0), ntohs(tcp->th_dport),
	    a1, a2, a3, a4, port_no);
	}    
    }

}

static void
sniff_filename(u_char *user,const struct pcap_pkthdr *pcap, const u_char *pkt)
{
        struct libnet_ipv4_hdr *ip;
        struct libnet_tcp_hdr *tcp;
        int  len;
        pkt += pcap_off;
        len = pcap->caplen - pcap_off;
	//we split TCP and UDP traffic
        ip = (struct libnet_ipv4_hdr *)pkt;
        
	if (ip->ip_p == IPPROTO_TCP) {
	    //TCP protocols here
    	    tcp = (struct libnet_tcp_hdr *)(pkt + ip->ip_hl * 4);

	    if (!(tcp->th_flags & TH_PUSH))
		return;	
	    memset(buf,0x00,BUFSIZ);	
	    memcpy(buf, pkt + ip->ip_hl*4 + tcp->th_off*4,len - ip->ip_hl*4 + tcp->th_off*4);
	    //now calling all the protocol parsers
	    ftp_parse(ip,tcp,len);
		
	} else if (ip->ip_p == IPPROTO_UDP) {
	    //UDP protocols here
	
	}




}     

int
main(int argc, char *argv[])
{
        extern char *optarg;
        extern int optind;
        int c;
        char *intf, *filter, ebuf[PCAP_ERRBUF_SIZE];
        pcap_t *pd;
        u_char *user;

        intf = NULL;

          char errbuf[LIBNET_ERRBUF_SIZE];

            l = libnet_init(
                    LIBNET_RAW4,    /* or LIBNET_LINK or LIBNET_RAW6 */
                    NULL,           /* or device if you using LIBNET_LINK */
                    errbuf);
        ip_id = LIBNET_PTAG_INITIALIZER;

        while ((c = getopt(argc, argv, "i:")) != -1) {
                switch (c) {
                case 'i':
                        intf = optarg;
                        break;
                default:
                        usage();
                        break;
                }
        }
        if (intf == NULL && (intf = pcap_lookupdev(ebuf)) == NULL)
                errx(1, "%s", ebuf);

        argc -= optind;
        argv += optind;
/*
        if (argc == 0)
                usage();
*/
        filter = copy_argv(argv);

        if ((pd = pcap_init(intf, filter, 128)) == NULL)
                errx(1, "couldn't initialize sniffing");

        if ((pcap_off = pcap_dloff(pd)) < 0)
                errx(1, "couldn't determine link layer offset");

        libnet_seed_prand(l);

        warnx("listening on %s [%s]", intf, filter);

        pcap_loop(pd, -1, sniff_filename,user);

        /* NOTREACHED */

        exit(0);
}

