/*
 * lsrspoof.c
 * by xeon
 *
 * Try to spoof packets using the Loose Source Option of IP headers.
 * 
*/

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

#define MAX_ERR_BUF 512
#define DEFAULT_TTL 255

#define MAX_PACKET 65535
#define WAIT_MS 10

#define false 0
#define true  1

// --------------------------------------------------------------------------
// global program variables
u_int 	optSniff  = 0,	// if == 1 sniffing IP is defined
	optBefore = 0,  // number of hosts before your machine
			// do not care, they will not receive a single packet
	optAfter  = 0,  // number of hosts after your machine
			// BEWARE! they MUST forward source routed packet
	optTarget = 0;  // if == 1 target IP is defined
// --------------------------------------------------------------------------


// --------------------------------------------------------------------------
void banner ()
{
	printf ("lsrspoof - by xeon\n");
	printf ("use: lsrspoof -s <sniff host> -t <target host>\n");
}


void exit_success (libnet_t *l, pcap_t *p)
{
	if (l) libnet_destroy (l);
	if (p) pcap_close     (p);
	exit (EXIT_SUCCESS);
}

void exit_failure (libnet_t *l, pcap_t *p)
{
	if (l) libnet_destroy (l);
	if (p) pcap_close     (p);
        exit (EXIT_SUCCESS);
}
// --------------------------------------------------------------------------


// --------------------------------------------------------------------------
int main (int argc, char **argv)
{
	u_int count = 0;
	u_int hopNumber = 1;
	u_char errbuf[MAX_ERR_BUF];
	u_char optLSR[64];
	u_long sniffIP, targetIP;
	u_long srcIP;
	
	libnet_t *l = NULL;
	libnet_ptag_t ip_tag = 0, ip_opt_tag = 0, ip_icmp_tag = 0;
	struct libnet_stats ls;
	
	pcap_t *p = NULL;
	struct bpf_program pcap_filter; 
	bpf_u_int32 pcap_sniffDevIP, pcap_sniffDev_netmask;
	u_char pcap_filterexp[512] = "ip[20]==131";	// 131=lsrr option code
	struct pcap_pkthdr pkthdr;
	u_char *sniffDev = NULL;
	u_char *readPacket = NULL;

	// ------------------------------------------------------------------

	if (argc == 1) {
		banner ();
		exit_success (l, p);
	}

	if (NULL == (l = libnet_init (LIBNET_RAW4, NULL,  errbuf))) {
		fprintf (stderr, "libnet_init() failed: %s", errbuf);
		exit_failure (l, p);
        }

	// ------------------------------------------------------------------
	
	while ((count = getopt(argc, argv, "s:b:a:t:")) != EOF) {
		switch (count) {
			case 's': if (0 == optSniff) {
					  if (-1 == (sniffIP = libnet_name2addr4 (l, optarg, LIBNET_RESOLVE))) {
						fprintf (stderr, "libnet_name2addr4() failed: bad address %s\n", optarg);
						exit_failure (l, p);
					  }
					  ++optSniff;
				  }
				  else {
					  fprintf (stderr, "error: source IP already specified!\n");
					  exit_failure (l, p);
				  }
				  break;
			case 't': if (0 == optTarget) {
					  if (-1 == (targetIP = libnet_name2addr4 (l, optarg, LIBNET_RESOLVE))) {
						fprintf (stderr, "libnet_name2addr4() failed: bad address %s\n", optarg);
						exit_failure (l, p);
					  }
					  ++optTarget;
				  }
				  else {
					   fprintf (stderr, "error: destination IP already specified!\n");
                                           exit_failure (l, p);
				  }
				  break;
			default: fprintf (stderr, "warning: option -%c non supported\n", count);
		}
	}
	if ((optSniff == 0) || (optTarget == 0)) {
		fprintf (stderr, "error: sniffing IP or target IP not specified!\n"
				 "sniffing IP -> the IP where you forge LSRR, probably your current host)\n"
				 "target   IP -> the IP of the enemy host\n");
		exit_failure (l, p);
	}
		
	// ------------------------------------------------------------------

	// creating ICMP echo request payload
	if (-1 == (ip_icmp_tag = libnet_build_icmpv4_echo (
			ICMP_ECHO,                            // type
	                0,                                    // code
			0,                                    // checksum
			libnet_get_prand (LIBNET_PRu16),      // id
			libnet_get_prand (LIBNET_PRu16),      // sequence number
			NULL,                                 // payload
			0,                                    // payload size
			l,                                    // libnet handle
			0
	))) {
		fprintf (stderr, "libnet_build_icmpv4_echo() failed: %s\n", libnet_geterror (l));
		exit_failure (l, p);
	}
	
	// creating fake source IP
	srcIP = libnet_get_prand (LIBNET_PRu32);

	// adding source route option, 4 byte alignet with a leading IPOPT_NOP
	optLSR[0] = IPOPT_LSRR;
	optLSR[1] = 3 + hopNumber*4;
	optLSR[2] = 8;
	memcpy (optLSR+3, &sniffIP, sizeof (sniffIP));
	optLSR[optLSR[1]] = IPOPT_EOL;
	
	if (-1 == (ip_opt_tag = libnet_build_ipv4_options (
		 	optLSR,
			4 + 4*hopNumber,
			l,
			0))) {
		fprintf (stderr, "libnet_build_ipv4_options() failed: %s\n", libnet_geterror (l));
		exit_failure (l, p);
	}
	
	// creating packet
	if (-1 == (ip_tag = libnet_build_ipv4 (
			LIBNET_IPV4_H,		// entire packet length		
			0,			// tos
			getpid(),		// ID
			0,			// fragmentation flags and offset
			DEFAULT_TTL,		// TTL
			IPPROTO_ICMP,		// protocol, default ICMP (ping)
			0,			// checksum, lets libnet take care of it
			libnet_get_prand (LIBNET_PRu32),
						// source IP
			targetIP,		// dest IP
			NULL,			// packet data
			0,			// payload length
			l,
			0))) {
		fprintf (stderr, "libnet_build_ipv4() failed: %s\n", libnet_geterror (l));
		exit_failure (l, p);
	}

	// -----------------------------------------------------------------

	// finding sniffing device
	while (NULL == (sniffDev = pcap_lookupdev (errbuf))) {
		fprintf (stderr, "pcap_lookupdev() failed: %s\n", errbuf);
		exit_failure (l, p);
	}
	if (NULL == (p = pcap_open_live (sniffDev, MAX_PACKET, false, WAIT_MS, errbuf))) {
		fprintf (stderr, "pcap_open_live() failed: %s\n", errbuf);
                exit_failure (l, p);
        }
	
	// finding sniff device netmask, used next in pcap filter creation
	if (-1 == pcap_lookupnet (sniffDev, &pcap_sniffDevIP, &pcap_sniffDev_netmask, errbuf)) {
		fprintf (stderr, "pcap_lookupnet() failed: %s\n", errbuf);
                exit_failure (l, p);
        }
	
	//if (NULL == inet_ntop (AF_INET, &pcap_sniffDev_netmask, errbuf, MAX_ERR_BUF))
	//	fprintf (stderr, "inet_ntop() failed: %s\n", strerror (errno));
	//else
	//	printf ("sniffing device netmask = %s\n", errbuf);
		
	// creating pcap sniffing filter
	if (-1 == pcap_compile (p, &pcap_filter, pcap_filterexp, false, pcap_sniffDev_netmask)) {
		fprintf (stderr, "pcap_compile() failed: %s\n", pcap_geterr (p));
		exit_failure (l, p);
	}
	if (-1 == pcap_setfilter (p, &pcap_filter)) {
		fprintf (stderr, "pcap_setfilter() failed: %s\n", pcap_geterr (p));
                exit_failure (l, p);
        }
	
	// ------------------------------------------------------------------
	
	// writing packet to the wire
	if (-1 == (count = libnet_write (l))) {
		fprintf(stderr, "Write error: %s\n", libnet_geterror(l));
		exit_failure (l, p);
	}
	else {
		printf ("Wrote %d byte packet; check the wire.\n", count);
	//	libnet_stats(l, &ls);
	//	printf ("Packets sent:  %lld\n"
        //		"Packet errors: %lld\n"
	//		"Bytes written: %lld\n",
	//		ls.packets_sent, ls.packet_errors, ls.bytes_written);
        }

	// getting (an hope) response packet
	readPacket = pcap_next (p, &pkthdr);
	
	//bpf_u_int32 caplen; /* length of portion present */
	//bpf_u_int32 len; /* length this packet (off wire) */ 

	printf ("packet portion: %d\n", pkthdr.caplen);
	printf ("packet length:  %d\n", pkthdr.len);
	/*if ( == readPacket)
		printf ("Sorry, %s doesn't seems to support LSRR.\n", libnet_addr2name4 (targetIP, LIBNET_DONT_RESOLVE));
	else
		printf ("%s support LSRR.\n", libnet_addr2name4 (targetIP, LIBNET_DONT_RESOLVE));
	*/
	// ------------------------------------------------------------------

	exit_success (l, p);

	// ------------------------------------------------------------------
}
// --------------------------------------------------------------------------
