	/* 	
	**	vecna - vecna@s0ftpj.org
	**	simple packet forwarder from datalink level
	**	using libvsk - unique file "spf.c"
	*/

#include "libvsk.h"
#include <errno.h>

extern int errno;

#define fatal(M)	{	   \
			perror(M); \
			exit(0);   \
			}

int check_dup(struct ipkt *);
void setport(char *, char *, int[]); 

int main(int argc, char **argv)
	{
	int dlsfd, rsfd, opt, proto, forward, hdrincl =1, offset =0, x,
	port[4]={0, 0xFFFF, 0, 0xFFFF};
	/* 
	**	datalink sockfd, raw sockfd, options index, proto 
	**	listened, offset is size datalink protocol header 
	**	port[4] array for puts source/dest/high/low port
	*/
	char *iface;
	/* 	
	**	interface name.
	*/
	char *ipsrc, *ipdst;
	/* 
	**	ipsrc =fucked host, ipdst =bnc ip
	*/
	unsigned int real;
	/*
	**	real ip of attacker where forward packets
	*/
	char *rcvd =malloc(sizeof(struct ipkt));
	/*
	**	memory area where put packet, packet is readed with
	**	datalink header, offset is size of this header and
	**	is used on main cicle, *rcvd is delclared here for
	**	make only one allocation.
	*/

	printf("\t simple packet forwarded for multiple pourpose\n");
	printf("\t by vecna - vecna@s0ftpj.org - www.s0ftpj.org\n\n");

	if(argc != 11)
		{
		printf( "\t usage %s -t -n -p -i -s"
			"\n\t -t source of packet"
			"\n\t -n new destination"
			"\n\t -s service (UDP/TCP) type (ICMP) 0 if any"
			"\n\t -p protocol"
			"\n\t -i interface"
		        "\n",argv[0]);
		exit(0);
		}

	while(( opt = getopt(argc, argv, "t:n:i:p:s:")) != -1)
		{
		struct protoent *pe;	
		switch(opt)
			{
			case 't':
				ipsrc =optarg;
				break;
			case 'n':
				if(( real =inet_addr(optarg)) == -1)
					{
					errno =EINVAL;
					fatal("-r option required IP");
					}
				break;
			case 'p':
				if ((pe = getprotobyname(optarg)) == NULL)
					fatal("getprotobyname");
				proto = pe->p_proto;
				break;
			case 'i':
				iface =optarg;
				break;
			case 's':
                                if(!atoi(optarg))
                                        break;
				port[2] =port[3] =atoi(optarg);
				break;
			default:
				if(optarg)
					fprintf(stderr,"%s on",optarg);
				errno =EINVAL;
				fatal(" getopt()");
				break;
			}
		}

	ipdst =NULL;

	if(( dlsfd =set_vsk_param(ipsrc, ipdst, port,
				iface, proto, IO_IN, IP_FW_INSERT, 0, 0))<0)
	 	fatal("set_vsk: IP_FW_INSERT");

	/* 
	**	IP_FW_DELETE must be used on signal(SIGCLOSE, unset_vsk()); 
	**	or use "ipchains -F", as in this example where filtering 
	**	rules is not clean after end of program.
	*/

	if((offset =get_offset(dlsfd, iface)) <0)
		fatal("get device offset");

	if((forward = socket(AF_INET, SOCK_RAW, proto)) == -1)
		fatal("forward socket - SOCK_RAW");

	if((x = setsockopt(forward, IPPROTO_IP, IP_HDRINCL, 
					&hdrincl, sizeof(hdrincl))) == -1)
		fatal("setsockopt - IP_HDRINCL");

	while(1)
		{
		struct ipkt *packet;
                static int last_id;

		read(dlsfd, rcvd, sizeof(struct ipkt));

		(char *)packet = rcvd + offset; 

		if(check_dup(packet))
			continue;

/* 	questo e` il ciclo principale, in ordine:
leggo sul socket a datalink quello che mi arriva, faccio un cast in una
struttura ipkt che contiene ip header + buffer dati (in questo momento non
conosco ancora il protocollo di livello inferiore) dopo aver sommato l'offset
per levare l'header di livello 2, poi con check_dup controllo se e` il 
pacchetto che ho appena ristrasmesso o se e` un altro pacchetto, poi con
check_packet controllo se e` uno dei pacchetti filtrati, poi ... vediamo il
codice ... 	*/ 

		if(check_packet(packet, packet->ip.protocol))
			{
			struct sockaddr_in sin;

			struct udphdr *udp;
			struct tcphdr *tcp;
			struct icmphdr *icmp;

	/** other manipulation on iphdr can applied here **/
			packet->ip.daddr = real;
			packet->ip.check = 0x00;

/* 	bhe, e` abbastanza semplice, qui ho il pacchetto in una struttura 
ipkt, a seconda del campo "protocol" riesco a fare degli opportuni cast e 
lavorare anche su quell'header, dopo aver letto o cambiato o fatto qualunque
cosa al pacchetto...	*/

			switch(packet->ip.protocol)
				{
				case IPPROTO_ICMP:
					(char *)icmp =(char *)packet 
						+sizeof(struct iphdr);
					sin.sin_port =htons(0);
					break;				
				case IPPROTO_TCP:
					(char *)tcp =(char *)packet 
						+sizeof(struct iphdr);
					sin.sin_port =tcp->dest;
					break;
				case IPPROTO_UDP:
					(char *)udp =(char *)packet 
						+sizeof(struct iphdr);
					sin.sin_port =udp->dest;
					break;
				default:
					printf(" PROTOCOL NOT SUPP\n");
					break;
	/* 
	**	other manipulation at icmp/udp/tcp header 
	**	can applied on switch() 
	*/
				}

			sin.sin_family = AF_INET;
			sin.sin_addr.s_addr = packet->ip.daddr;

			x =resend(forward, packet, sin, 
					ntohs(packet->ip.tot_len), NULL, 0);
			if(x < 0)
				fatal("sendto on forwarding packet");
			}
		}
	free(rcvd);	
	/* never used :) */
	}

int check_dup(struct ipkt *packet)
	{
	static int last_id;
	int id =htons(packet->ip.id);

	if(id ==htons(last_id))
		return 1;

	last_id =packet->ip.id;

	return 0;
	}
