/**************************************************************************************	
Port 80 Basic Visual Packet Sniffer

for Linux using OpenGL, Glut, and the Berkley Sockets API

by robotcowboy (www.robotcowboy.com) over one night

for a Net Art Seminar at the Art & Tech Program at IT University in Goteborg, Sweden
October 19th, 2005

compile with (with opengl and glut installed):
g++ -O2 -Wall  -L/usr/X11R6/lib -lX11 -lXmu -lXi -lm -lGL -lGLU -lglut port80.cpp -o port80

switch to root and set your ethernet adapter to promiscuous mode, otherwise you wont
get any data :| $ su - 		 
 	      | Password: *****
	      | $ ifconfig eth0 promisc
	      
you must run port80 in root, otherwise the SOCKET_RAW type is not allowed and only NULL data will be read

run: | $ ./port80 -md -h500 -w500
	 	   
command line options: -m : display mode -> d (dots), l (lines), p (polygons - default) 
		      -h : height of display window (in pixels) (default - 500)
		      -w : width  of display widonw (in pixels) (defualt - 500)
		      
I didn't build any exit code into this, although ESC kinda works so use CTRL+C :P
		      
you can freely use this code; much of the socket usage comes from this guide:

http://packetstormsecurity.org/sniffers/Sniffer_construction.txt

***************************************************************************************/

#include <stdio.h>
#include <stdlib.h> 
#include <iostream>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <GL/glut.h>

#define ESCAPE 27
#define FALSE 0
#define TRUE 1

GLint winx = 500;
GLint winy = 500;

int sock;
char buffer[65535];
int bytes_recieved;
char mode = 'p';

/* set background color and shader */
void init(void)
{
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glShadeModel(GL_SMOOTH);
}
				
/* idle() get called periodicaly */
void idle()
{
  glutPostRedisplay(); /* redraw the screen */
}			

/* reshape() gets called when the window is resized */ 
void reshape(int w, int h)
{
  glViewport((w-winx)/2,(h-winy)/2, -1, -1);
  glMatrixMode(GL_PROJECTION);
  gluOrtho2D(0, w, 0, h);
  
  winx = w;
  winy = h;
  
}

/* keyboard() gets called when a key is pressed */
void keyboard(unsigned char key, int x, int y)
{
  switch(key){
  case ESCAPE:
    exit(0);
  }   
}

/* grad a packet and stuff it into buffer, block otherwise */
void grabPacket()
{

	int fromlen;
	struct sockaddr_in from;
	fromlen = sizeof from;
	
	glutPostRedisplay();
	
	// read datagram
	bytes_recieved = recvfrom(sock, buffer, sizeof buffer, 0,
					(struct sockaddr *)&from, 
					(socklen_t*) &fromlen);
		
	printf("Bytes received --> %5d\n",bytes_recieved);
	printf("Source address --> %s\n",inet_ntoa(from.sin_addr));
}

/* grabs packets and displays their contents from buffer 
   each char's data is used to generate x,y postions and color */
void draw()
{
	glClear(GL_COLOR_BUFFER_BIT);
	
	grabPacket();
	
	// remove 11 from odd length to make even
	if(bytes_recieved%2 == 1)
	bytes_recieved--;
	
	if(mode == 'p')
	glBegin(GL_POLYGON);
	
	if(mode == 'd')
	{
		glPointSize(10);
		glBegin(GL_POINTS);		
	}
	
	if(mode == 'l')
	glBegin(GL_LINES);
	
	for(int c = 0;  c < bytes_recieved-4; c+=4)
	{
		double 	R = abs((unsigned int) buffer[c]/127),
			G = abs((unsigned int) buffer[c+1]/127),
			B = abs((unsigned int) buffer[c+2]/127),
			A = abs((unsigned int) buffer[c+3]/127),
			x1 = abs( buffer[c] * (winx/100)),
			x2 = abs( buffer[c+1] * (winx/100)),
			y1 = abs( buffer[c+2] * (winy/100)),
			y2 = abs( buffer[c+3] * (winy/100));
			
		glColor4f(R, G, B, A);
		glVertex2i((GLint) x1, (GLint) y1); 
		glVertex2i((GLint) x2, (GLint) y2);
		
	}
	glEnd();
	
	glutSwapBuffers();
}
	
int main(int argc, char **argv)
{	
	if(argc > 1)
	{
		for(int c = 1; c < argc; c++)
		{
			if(strncmp(argv[c], "-m", 2) == 0)
			mode = argv[c][2];
			
			else if(strncmp(argv[c], "-h", 2) == 0)
			{
				winy = atoi(argv[c+1]);
				c++;
			}
			
			else if(strncmp(argv[c], "-w", 2) == 0)
			{
				winx = atoi(argv[c+1]);
				c++;
			}
			else
			{
				fprintf(stderr,
				"Usage: -md(dot) -ml(line) -mp(poly) [DEFAULT] -h winy(int) -w winx(int)\n");
      				exit(0);
			}
		} 

	}
	
	// create socket
	sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
	
	printf("PORT 80 BEGIN\n");
	
	glutInit(&argc, argv);                        /* Initialize */
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); /* Double buffering */
	glutInitWindowSize(winx, winy);             /* Set window size */ 
	glutInitWindowPosition(0, 0);                 /* Set initial pos */
	glutCreateWindow("PORT80");                    /* Make it visible */
	init();                                       /* Run our own init */
	glutDisplayFunc(draw);                     /* connect display function */
	glutReshapeFunc(reshape);                     /* connect reshape function */
	glutKeyboardFunc(keyboard);                   /* connect keyboard function */
	glutIdleFunc(idle);                           /* connect idle function */
	glutMainLoop();                               /* Start glutMainloop */ 
	
	return 0;
}
