/*
 *  $Id$
 *
 *  libnet example code
 *  example 2:  link-layer api / ICMP hostmask packet
 *
 *  Copyright (c) 1998, 1999 Mike D. Schiffman <mike@infonexus.com>
 *  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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.
 *
 */
#define LIBNET_LIL_ENDIAN 1

#include <libnet.h>
#include <pcap.h>

void usage(char *);

// sec2 (inside packet must match ncp address)
//u_char enet_src[6] = {0x00, 0xe0, 0xbb, 0x0d, 0x00, 0x01};
//u_char enet_dst[6] = {0x00, 0xe0, 0xbb, 0x0d, 0x00, 0x02};
//u_char enet_src[6] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff}; // 0:e0:bb:b:d8:be nbx
u_char enet_src[6] = { 0x00,0x48,0x54,0x3B,0x3A,0x07 }; // ws35 but wont write
//u_char enet_src[6] = { 0x00, 0xe0, 0xbb, 0x0c, 0x0, 0x54 };	// fake  nbx phone
u_char enet_dst[6] = { 0x00, 0xe0, 0xbb, 0x0b, 0xd8, 0xbe };	// 0:e0:bb:b:d8:be nbx

struct libnet_link_int *network;	/* pointer to link interface struct */
u_char *device;			/* pointer to the device to use */

struct link_int *libnet;

void fn(u_char * u, const struct pcap_pkthdr *pcap, const u_char * data);
void xsend_packet(const u_char * pkt, short proto, int len, u_char * src,
		  u_char * dest);

int main(int argc, char *argv[])
{
    int packet_size,		/* size of our packet */
     c;				/* misc */
    u_long src_ip, dst_ip;	/* source ip, dest ip */
    u_char *packet;		/* pointer to our packet buffer */
    char err_buf[LIBNET_ERRBUF_SIZE];	/* error buffer */
    char buf[20];
    int x;

    unsigned char pkt[] = {
	0x48, 0x52, 0x00, 0xe0, 0xbb, 0x0b, 0xd8, 0xbe, 0xd7, 0x27, 0x00,
	0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x05, 0x02, 0x02, 0x80,
	0xb3, 0x00, 0x27, 0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0xff,
	0xff, 0x11, 0x07, 0x00, 0xff, 0x00, 0x07, 0x00, 0x07, 0x00,
	0x07, 0xff, 0xff, 0x12, 0x07, 0x00, 0xff, 0x00, 0x07, 0x55,
	0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x0f, 0xff,
	0xf0, 0x02, 0x20, 0x33, 0x39, 0x32, 0x20, 0x20, 0x20, 0x20,
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
	0x20, 0x20, 0x20, 0x20, 0x20, 0x54, 0x69, 0x6d, 0x20, 0x48,
	0x6f, 0x67, 0x61, 0x72, 0x64, 0x20, 0x20, 0x20, 0x20, 0x20,
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00,
	0x00,

    };



    char errbuf[256];
    pcap_t *pd;

	int lt=0;
    int snaplen = 1536;
    unsigned short seq = 0x0;
    struct bpf_program filter;

    printf("libnet example code:\tmodule 2\n\n");
    printf("packet injection interface:\tlink layer\n");
    printf("packet type:\t\t\tICMP net mask [no payload]\n");

    device = NULL;
    src_ip = 0;
    dst_ip = 0;


    while ((c = getopt(argc, argv, "i:d:s:")) != EOF) {
	switch (c) {
	case 'd':
	    if (!(dst_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
		libnet_error(LIBNET_ERR_FATAL,
			     "Bad destination IP address: %s\n", optarg);

	    break;
	case 'i':
	    device = optarg;
	    break;
	case 's':
	    if (!(src_ip = libnet_name_resolve(optarg, LIBNET_RESOLVE)))
		libnet_error(LIBNET_ERR_FATAL,
			     "Bad source IP address: %s\n", optarg);
	    break;
	default:
	    exit(EXIT_FAILURE);
	}
    }



/*
 * open lib pcap
 */


    if (device == NULL)
	device = pcap_lookupdev(errbuf);
    if (device == NULL)
	printf("%s", errbuf);

    pd = pcap_open_live(device, snaplen, 1, 500, errbuf);
    // pcap_setnonblock(pd,1,errbuf); if timeouts don't work



    /*
     *  Step 1: Network Initialization (interchangable with step 2).
     */
    if (device == NULL) {
	struct sockaddr_in sin;
	/*
	 *  Try to locate a device.
	 */
	if (libnet_select_device(&sin, (char **) &device, err_buf) == -1) {
	    libnet_error(LIBNET_ERR_FATAL,
			 "libnet_select_device failed: %s\n", err_buf);
	}
	printf("device:\t\t\t\t%s\n", device);
    }
    if ((network = libnet_open_link_interface(device, err_buf)) == NULL) {
	libnet_error(LIBNET_ERR_FATAL, "libnet_open_link_interface: %s\n",
		     err_buf);
    }


    /*
     *  We're going to build an ICMP packet with no payload using the
     *  link-layer API, so this time we need memory for a ethernet header
     *  as well as memory for the ICMP and IP headers.
     */
    packet_size = LIBNET_IP_H + LIBNET_ETH_H + LIBNET_ICMP_MASK_H;
    packet_size = 2000;


    /*
     *  Step 2: Memory Initialization (interchangable with step 1).
     */
    if (libnet_init_packet(packet_size, &packet) == -1) {
	libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
    }
    //for (seq = 0; seq < 65535; seq++) {

    /*
     *  Step 3: Packet construction (ethernet header).
     */
    //bcopy(enet_src2, &pkt[2], 6);
    //bcopy(&seq, &pkt[8], sizeof(seq));
    //sprintf(buf, " %05d ", seq);
    ////bcopy(buf,&pkt[68],7);        // add seq no to display

    //xsend_packet(pkt, 0x8868, sizeof(pkt), enet_src, enet_dst);
    x = pcap_compile(pd, &filter, "port not 22", 1, 0xffffff00);
    fprintf(stderr, "x=%d\n", x);
    x = pcap_setfilter(pd, &filter);


    while (1) {
	int now=time(0);
	x = pcap_dispatch(pd, -1, &fn, 0);
	//x=pcap_dispatch(pd,1,&fn,0);
	//printf("x=%d\n",x);
	if(now>=lt+2) {	// every 2 seconds
		printf("Server rerun %d %d \n" ,lt, now);
		lt=now;
		send_whatever();
	}
    }

#if 0
    libnet_build_ethernet(enet_dst, enet_src, 0x8868,	//ETHERTYPE_IP,
			  pkt,	//"This is a test", //NULL,
			  sizeof(pkt),	//14, //0,
			  packet);

    if (seq % 1000 == 1)
	printf("sizeof:%d\n", seq);
    //printf("sizeof:%d\n",sizeof(pkt));
    /*
     *  Step 3: Packet construction (IP header).
     */
#endif				//0

    //}

    /*
     *  Shut down the interface.
     */
    if (libnet_close_link_interface(network) == -1) {
	libnet_error(LN_ERR_WARNING,
		     "libnet_close_link_interface couldn't close the interface");
    }


    /*
     *  Free packet memory.
     */
    libnet_destroy_packet(&packet);

    return (c == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
}

send_whatever() {
// broadcast this  ....
// 01e0bb000009 00e0bb0bd8be 0012 aaaa0300e0bb444c0002000600e0bb0bd8bebebebebebebebebebebebebebebebebebebebebebebebebebebebebe
		//u_char pkt[]="XXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAAAAAAAAAAAAAAAAAAAAa";
		u_char pkt[]= {
//0x01, 0xe0, 0xbb, 0x00, 0x00, 0x09, 0x00, 0xe0, 0xbb, 0x0b, 0xd8, 0xbe,
//0x00, 0x12,
 0xaa, 0xaa, 0x03, 0x00, 0xe0, 0xbb, 0x44, 0x4c, 0x00, 0x02,
0x00, 0x06, 0x00, 0xe0, 0xbb, 0x0b, 0xd8, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,

		};
	u_char enet_dst[6] = { 0x01, 0xe0, 0xbb, 0x00, 0xd0, 0x09 };	// nbx boot broadcast
	//u_char enet_dst[6] = { 0x01, 0xe0, 0xbb, 0x00, 0xd0, 0x99 };	// nbx boot broadcast

	xsend_packet(pkt, 0x0012, sizeof(pkt), enet_src, enet_dst);
}



// rename this send_packet when the api is clean
void xsend_packet(const u_char * pkt, short proto, int len, u_char * src,
		  u_char * dest)
{
    /*
     *  Step 2: Memory Initialization (interchangable with step 1).
     */
    int packet_size = len;	// max 1536 but this is only for malloc
    //u_char *packet;                     /* pointer to our packet buffer */
    u_char packet[1538];
    int x;
	
//printf("%d\n",packet_size);
	
    //if (libnet_init_packet(packet_size, &packet) == -1)
    //libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
	
    packet_size += 12 + 2;
    libnet_build_ethernet(dest, src, proto,	//ETHERTYPE_IP,
			  pkt,	//"This is a test", //NULL,
			  packet_size, packet);
	
errno=0;
//if(packet_size>1000)
//packet_size=500;
    if ((x =
	 libnet_write_link_layer(network, device, packet,
				 packet_size)) < packet_size)
	libnet_error(LN_ERR_WARNING,
		     "qlibnet_write_link_layer only wrote %d bytes of %d  (%d)\n", x,packet_size,errno);
    else;			//-tim    printf("construction and injection completed, wrote all %d bytes\n", x);
	
}


void usage(char *name)
{
    fprintf(stderr, "usage: %s [-i interface] -s s_ip -d d_ip\n", name);
}

/* EOF */
// ether_addr return static buffer ascii version of 6 byte ehter address
// note this can be called 4 times before it starts reusing buffer space
char *ether_addr(const u_char * x)
{
    static u_char buf[100];
    static count;
    u_char *b;

    count++;
    b = buf;
    b += (count & 3) * 25;
    sprintf(b, "%02x:%02x:%02x:%02x:%02x:%02x", x[0], x[1], x[2], x[3],
	    x[4], x[5]);
    return b;
}

void fn(u_char * u, const struct pcap_pkthdr *pcap, const u_char * data)
{
    int S = pcap->caplen; // - (12 + 2);
    int i;
    u_char *dat = (u_char *) data;
//return;
//printf("Got packet\n");
    if (data[0] == 1)
	printf("*");
    else if (data[5] == 'T')
	printf(">");
    else
	printf(" ");
    for (i = 0; i < 40; i++) {
	printf("%02x", data[i]);
	if (i == 5 || i == 11 || i == 13)
	    printf(" ");
    }
    printf("\n");
    if (data[5 + 6] == 'T') {
	printf("My pkt\n");
	return;
    }
    // download packet (IPX format?)
    //if (data[12] == 0x00 && data[13] == 0x12 && data[14] == 0xaa) { }
    //if (data[1]==0xe0 && data[2]==0xbb  && data[14] == 0xaa && data[15] == 0xaa && data[16] == 3) {
    if (data[14] == 0xaa && data[15] == 0xaa && data[16] == 3) {


	int type = data[23];	// ack 22 iff 0x80
	static file_size = 0;

	//aaaa 0300 e0bb 444c 0001 001a 00e0 bb04
	//27c5 0203 1813 55a1 0200 0500 c401 0000
	//0000 0000 0000 0000 0000 0000 0000
    printf("some download pkt type %d\n", type);
return;
	switch (type) {
	FILE *out;
	int siz;
	case 2:
	    {			// download server broadcast

		u_char pkt[] =
		    { 0xaa, 0xaa, 0x03, 0x00, 0xe0, 0xbb, 0x44, 0x4c,
		    0x00, 0x01, 0x00, 0x1a, 0x00, 0xe0, 0xbb, 0x04, 0x27,
			0xc5,
		    0x02, 0x03, 0x18, 0x13, 0x55, 0xa1, 0x02, 0x00, 0x05,
			0x00,
		    0xc4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
			0x00,
		    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		};

		bcopy(enet_src, &pkt[12], 6);

		printf("Download server at %s %s\n", ether_addr(data + 6),
		       ether_addr(&data[18 + 6 + 2]));
		xsend_packet(pkt, 0x0012, sizeof(pkt), enet_src, enet_dst);
		printf("\n");

	    }
		out=fopen("Download","wb");
	    break;
	case 4:		// data pakcets
	    file_size++;
		//siz=(int *)((u_char *)(dat+23+3));
		siz=(data[26]<<24)+(data[27]<<16)+(data[28]<<8)+data[29];
		fprintf(stderr,"Add %x %d ",siz,S-30);
		if(out)
			fwrite(&data[30],S-30,1,out);
	case 5:		// eof
	    fprintf(stderr,"File size %d\n", file_size);
	case 1:		// what we send back so we shouldn't get them
	default:
	    printf("some download pkt type %d\n", type);
	    dat[22] = 0x80;
	    xsend_packet(data + 14, 0x0012, S, enet_src, enet_dst);
		break;

		
	}
	if(type==5)
		exit(0);
    }				// end download packets

}
