/*
  ______      _            _   ___   ___               
 (_____ \    | |          (_) / __) / __)              
  _____) )    \ \   ____   _ | |__ | |__   ____   ____ 
 (_____ (      \ \ |  _ \ | ||  __)|  __) / _  ) / ___)
       | | _____) )| | | || || |   | |   ( (/ / | |    
       |_|(______/ |_| |_||_||_|   |_|    \____)|_|                                                      


                      - Version 0.1 -
                                             RedKod Team
                                           www.redkod.com
Coder: R-e-D
Mail : r-e-d@redkod.com

Sniffer designed for NT System.
Copyright (C) 2002 R-e-D

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

*/

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)

typedef struct ip_hdr
{
    unsigned char verlen;  
    unsigned char  tos;           
    unsigned short tot_len;       
    unsigned short id;            
    unsigned short offset;        
    unsigned char  ttl;           
    unsigned char  protocol;      
    unsigned short checksum;      
    unsigned int   saddr;         
    unsigned int   daddr;         

} IP_HDR;

typedef struct tcp_hdr
{
	unsigned short	sport;
	unsigned short	dport;
	unsigned int	seqnum;
	unsigned int	acknum;
	unsigned char	DataOffset;
	unsigned char	Flags;
	unsigned short	Windows;
	unsigned short	Checksum;
	unsigned short	UrgPointer;
} TCP_HDR;

typedef struct icmp_hdr
{
 unsigned char  type;
 unsigned char  code;
 unsigned short checksum; 
 unsigned short id;
 unsigned short sequence;
 unsigned long  timestamp;
} ICMP_HDR; 

char *DisplayError(void);
int InitWinsock(void);
SOCKET Create_Raw_Socket(void);
int Launch_Sniffing(SOCKET sock);
int parsepacket(char *packet);
void icmp_display(struct ip_hdr *ip, struct icmp_hdr *icmp);
void tcp_display(struct ip_hdr *ip, struct tcp_hdr *tcp);

char *DisplayError(void)
{
	LPVOID error;
	char *buffer=NULL;

	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
    GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&error, 0, NULL);
	
	buffer = (char *)GlobalAlloc(GPTR, strlen(error)+1);
	sprintf(buffer, "%s", error);

	return(buffer);
}

int parsepacket(char *packet)
{
	struct ip_hdr *ip;
	struct icmp_hdr *icmp;
	struct tcp_hdr *tcp;

	ip = (struct ip_hdr *)packet;
	icmp = (struct icmp_hdr *)(packet + sizeof(struct ip_hdr));
	tcp = (struct tcp_hdr *)(packet + sizeof(struct tcp_hdr));

	switch(ip->protocol)
	{
	case 6: /* TCP PROTOCOL */
		tcp_display(ip, tcp);
		break;
	case 1: /* ICMP PROTOCOL */
		icmp_display(ip, icmp);
		break;
	default: /* OTHERS PROTOCOLS */	
		break;
	}

	return(0);
}

void icmp_display(struct ip_hdr *ip, struct icmp_hdr *icmp)
{  	

	fprintf(stdout, "ICMP: [%d] %s", ntohs(ip->tot_len), inet_ntoa(*(struct in_addr *)&ip->saddr));
	fprintf(stdout, " > %s type %d code %d ttl %d seq %x\n", inet_ntoa(*(struct in_addr *)&ip->daddr), 
													  icmp->type, icmp->code, ip->ttl, ntohs(icmp->sequence));
}

void tcp_display(struct ip_hdr *ip, struct tcp_hdr *tcp) 
{
   
	fprintf(stdout, "TCP: [%d] %s:%d", ntohs(ip->tot_len), inet_ntoa(*(struct in_addr *)&ip->saddr), ntohs(tcp->sport));
	fprintf(stdout, " > %s:%d ttl %d win %d checksum %d flag %d\n", inet_ntoa(*(struct in_addr *)&ip->daddr), 
		ntohs(tcp->dport), ip->ttl, ntohs(tcp->Windows), tcp->Checksum, tcp->Flags);

}

int InitWinsock(void)
{
    WSADATA wsaData;

	if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
    {
	    fprintf(stderr, "WSAStartup() failed: %s", DisplayError());
	    exit(-1);
    }

	return(0);
}

SOCKET Create_Raw_Socket(void) 
{
   int sock;
   BOOL optval = TRUE;
   
   sock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
   if (sock == INVALID_SOCKET)
   {
      fprintf(stderr, "WSASocket() failed: %s", DisplayError());
      exit(-1);
   }

   return(sock);
}

int Launch_Sniffing(SOCKET sock)
{
	DWORD dwBufferLen[10], dwBufferInLen = 1, dwBytesReturned = 0, dwSize;
	struct sockaddr_in dest, from;
	struct hostent *hp;  
	int sread, i, fromlen = sizeof(from);  
	char *packet=NULL, *Hostname=NULL;

	Hostname = (char *)malloc(32 * sizeof(char *));
	dwSize = 32 * sizeof(char *);
	
	if (GetComputerName(Hostname, &dwSize) == 0)
	{
	    fprintf(stderr, "GetComputerName(), %s", DisplayError());
		return(-1);
	}

	if((hp = gethostbyname(Hostname)) == NULL)  
	{
		fprintf(stderr, "gethostbyname(), %s", DisplayError());
		return(-1);  
	}
	
	free(Hostname);

	i = 0;
    while((hp->h_addr_list[i+1]) != NULL)
    {
       i++;
    }

    memcpy(&from.sin_addr.s_addr, hp->h_addr_list[i], hp->h_length);

	if((hp = gethostbyname(inet_ntoa(from.sin_addr))) == NULL)  
	{
		fprintf(stderr, "gethostbyname(), %s", DisplayError());
		return(-1); 
	}

	memset(&dest, 0, sizeof(dest));  
	memcpy(&dest.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
	dest.sin_family = AF_INET;  
	dest.sin_port = htons(8000);

	if(bind(sock, (PSOCKADDR)&dest, sizeof(dest)) == SOCKET_ERROR)
	{
		fprintf(stderr, "bind(), %s", DisplayError());
		return(-1);
	}

	if(WSAIoctl(sock, SIO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen), &dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL) == SOCKET_ERROR)
	{
		fprintf(stderr, "WSAIoctl(), %s", DisplayError());
		return(-1);
	}

	packet = (char *)malloc(2048 * sizeof(char *));
	
	while(1)  
	{  
		sread = recvfrom(sock, packet, 8191, 0, (struct sockaddr*)&from, &fromlen);  

		if (sread == SOCKET_ERROR || sread < 0)  
		{  
			if (WSAGetLastError() == WSAETIMEDOUT)  
			continue;  

		printf("recvfrom failed: %d\n", WSAGetLastError());  
		return(-1);  
		} 

        parsepacket(packet);
	}

	free(packet);

	return(0);
}

int main(int argc, char **argv)
{	

	SOCKET socksniffer; 
	char *version = "\nSniffer for NT System By R-e-D\n"
		            "         - Version 0.1 -\n"
					"      http://www.redkod.com/\n"
					"         r-e-d@redkod.com\n"
					"    Save the raw packet mode :)\n\n";  

	fprintf(stdout, "%s", version);
	fprintf(stdout, "Now, Sniff !!\n\n");

	/* Init Winsock */
	InitWinsock();	

	/* Create raw socket for sniffing */
	socksniffer = Create_Raw_Socket();

	/* Launch sniffing */
	Launch_Sniffing(socksniffer);

	return(0);
}
