Sieci komputerowe zadanie

Zadanie zaliczeniowe z Sieci Komputerowych

Oto treść:

Zadanie zaliczeniowe z Laboratorium z Sieci Komputerowych 2007

Należy napisać program filtrujacy strumień pakietów wywoływany z pięcioma argumentami:
- nazwš wej?ciowego pliku zawierajšcego pakiety (zrzut tcpdump),
- nazwš pliku wyj?ciowego, do którego należy zapisać wszystkie przepuszczone pakiety,
- nazwš pliku wyj?ciowego z informacjami na temat przepuszczanych i odrzuconych pakietów,
- nazwš pliku z "czarnš" listš adresów ip,
- nazwš pliku z "białš" listš adresów ip i portów TCP,
    nazwa_programu plik_in plik_out plik_admin plik_bad plik_good

Plik plik_bad ma następujšcy format. W kolejnych linijkach umieszczone sš:
    adres_ip niepusty_cišg_białych_znaków kierunek
gdzie kierunek jest jednym ze słów SRC lub DEST okre?lajšcymi czy chodzi o ?ródłowy czy docelowy adres ip.

Plik plik_good ma następujšcy format. W kolejnych linijkach umieszczone sš:
    adres_ip niepusty_cišg_białych_znaków kierunek niepusty_cišg_białych_znaków port_begin,port_end
gdzie:
    - kierunek jest jednym ze słów SRC lub DEST okre?lajšcymi czy chodzi o ?ródłowy czy docelowy adres ip,
    - port_begin,port_end oznaczajš zakres portów (okre?lony tylko dla protokołów TCP i UDP)
    ?ródłowych lub docelowych (w zależno?ci od parametru kierunek).

Każdy pakiet należy poddać analizie. Pakiet odrzucamy jeżeli spełniony jest przynajmniej jeden z warunków:
1) ?ródłowy lub docelowy adres ip znajduje się w plik_bad i zgadza się kierunek przesyłu danych,
2) pakiet jest wysyłany za pomocš protokołu TCP lub UDP i jego ?ródłowy lub docelowy adres ip
    znajduje się w plik_good, ale numer portu nie należy do podanego zakresu,
3) pakiet jest wysyłany za pomocš protokołu TCP, ale nie dane w nim zawarte nie pasujš do następujšcego formatu:
    pierwszym znakiem jest cyfra od 1 do 9 mówišca ile razy powinny być w danym pakiecie powtórzone dane,
    na przykład:
        2_tresc_tresc
        3_tresc_tresc_tresc
        7_tresc_tresc_tresc_tresc_tresc_tresc_tresc
W przypadku odrzucenia pakietu należy wpisać nowš linię do plik_admin w następujšcym formacie:
    ip_nadawcy ip_odbiorcy nazwa_protokołu komunikat
przy czym komunikat jest jednym spo?ród:
    - BAD SRC/DEST IP
        w przypadku niespełnienia warunku 1,
    - BAD SRC/DEST PORT
        w przypadku niespełnienia warunku 2,
    - BAD PACKET FORMAT, MISSING NUMBER
      BAD PACKET FORMAT, NOT MATCHING DATA
        w przypadku niespełnienia warunku 3 z powodu odpowiednio braku cyfry na poczštku lub braku pasujšcych danych.

Pozostałe pakiety należy przepu?cić wpisujšc do plik_out oraz wpisać nowš linię do plik_admin w następujšcym formacie:
    ip_nadawcy ip_odbiorcy nazwa_protokołu PACKET OK

Program należy przesłać na adres mailowy prowadzšcego grupę ćwiczeniowš:
    piotr.sawicki@mimuw.edu.pl
    michal.bernardelli@mimuw.edu.pl
do 2 grudnia 2007 roku do godziny 23:59.
Ocena rozwišzań wysłanych po tym terminie (wliczajšc w to sesję poprawkowš) będzie obniżona o jeden stopień.
Program powinien być skompresowany wraz z zaprojektowanym przez siebie kompletem testów.
Nazwa spakowanego pliku powinna być taka sama jak wydziałowy login.
Program ma się kompilować i działać na komputerach w laboratorium komputerowym MIM.
Za brak lub niewystarczajšcš liczbę komentarzy w kodzie ?ródłowym programu będzie obniżana ocena.
Na ostatnich ćwiczeniach należy przyj?ć i zaprezentować działanie swojego programu.

A oto rozwiazanie:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 



/* default snap length (maximum bytes per packet to capture) */
#define SNAP_LEN 1518

/* ethernet headers are always exactly 14 bytes [1] */
#define SIZE_ETHERNET 14

/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN	6

pcap_dumper_t *plik;

/* Ethernet header */

struct sniff_ethernet {
        u_char  ether_dhost[ETHER_ADDR_LEN];    /* destination host address */
        u_char  ether_shost[ETHER_ADDR_LEN];    /* source host address */
        u_short ether_type;                     /* IP? ARP? RARP? etc */
};

/* IP header */
struct sniff_ip {
        u_char  ip_vhl;                 /* version <> 2 */
        u_char  ip_tos;                 /* type of service */
        u_short ip_len;                 /* total length */
        u_short ip_id;                  /* identification */
        u_short ip_off;                 /* fragment offset field */
        #define IP_RF 0x8000            /* reserved fragment flag */
        #define IP_DF 0x4000            /* dont fragment flag */
        #define IP_MF 0x2000            /* more fragments flag */
        #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
        u_char  ip_ttl;                 /* time to live */
        u_char  ip_p;                   /* protocol */
        u_short ip_sum;                 /* checksum */
        struct  in_addr ip_src,ip_dst;  /* source and dest address */
};

#define IP_HL(ip)               (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip)                (((ip)->ip_vhl) >> 4)

/* TCP header */
typedef u_int tcp_seq;

struct sniff_tcp {
        u_short th_sport;               /* source port */
        u_short th_dport;               /* destination port */
        tcp_seq th_seq;                 /* sequence number */
        tcp_seq th_ack;                 /* acknowledgement number */
        u_char  th_offx2;               /* data offset, rsvd */
	#define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)
        u_char  th_flags;
        #define TH_FIN  0x01
        #define TH_SYN  0x02
        #define TH_RST  0x04
        #define TH_PUSH 0x08
        #define TH_ACK  0x10
        #define TH_URG  0x20
        #define TH_ECE  0x40
        #define TH_CWR  0x80
        #define TH_FLAGS        (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
        u_short th_win;                 /* window */
        u_short th_sum;                 /* checksum */
        u_short th_urp;                 /* urgent pointer */
};

struct sniff_udp {
        u_short uh_sport;               /* source port */
        u_short uh_dport;               /* destination port */
        u_short uh_length;				/*length header+data*/
        u_short uh_checksum;            /* chechsum */
      
};

//Struktura listy white i black

typedef struct Adresy {
	char Adres[15];
	char kierunek[4];
	int port_start;
	int port_stop;
	struct Adresy * nastepny;
};

//plik admin
FILE *admin;
struct Adresy *biala;
struct Adresy *czarna;

//funkcje operujace na listach black i white.

struct Adresy * wczytaj_adresy(char* plik,int porty)
{//wczytuje adresy z pliku i zwraca wskaznik do listy.
	FILE *f;
	struct Adresy *start;
	struct Adresy *teraz;
	int wynik;
	char ciag[128];
	char * tmp;
	char znak;

	f=fopen(plik,"r");
	wynik=fscanf(f,"%15s",ciag);



	if(wynik!=EOF)
	{
		start=malloc(sizeof(struct Adresy));
		start->nastepny=NULL;
		start->port_start=0;
		start->port_stop=0;

		strcpy(start->Adres,ciag);

		//powinno wczytac spacje:
		wynik=fscanf(f,"(space)");

		//powinno wczytac src lub dest
		wynik=fscanf(f,"%4s",ciag);

		
		if(strcmp(ciag,"SRC")||strcmp(ciag,"DEST"))
		{
			strcpy(start->kierunek,ciag);
		}
		
		//jesli mamy tez czytac numery portow.
		if (porty==1)
		{
			wynik=fscanf(f,"(space)");
			//przeczytalismy puste znaki
			wynik=fscanf(f,"%s,",ciag);
			//wczytalismy porty. Rozbijemy je.
			tmp = strtok (ciag,",");
			start->port_start=atoi(tmp);
			tmp = strtok (NULL, ",");
			start->port_stop=atoi(tmp);
		}

		while(znak!='n')
		{
			//czytamy wszystko do konca linii.
			wynik=fscanf(f,"%c",&znak);
		}

		teraz=start;
		wynik=fscanf(f,"%s",ciag);

		while(wynik!=EOF)
		{
			teraz->nastepny=malloc(sizeof(struct Adresy));
			teraz=teraz->nastepny;
			teraz->nastepny=NULL;
			teraz->port_start=0;
			teraz->port_stop=0;
			strcpy(teraz->Adres,ciag);

			//powinno wczytac spacje:
			wynik=fscanf(f,"(space)");

			//powinno wczytac src lub dest
			wynik=fscanf(f,"%s",ciag);

			if((strcmp(ciag,"SRC"))||(strcmp(ciag,"DEST")))
			{
				strcpy(teraz->kierunek,ciag);
			}
			
			//jesli mamy tez czytac numery portow.
			//jesli mamy tez czytac numery portow.
			if (porty==1)
			{
				wynik=fscanf(f,"(space)");
				//przeczytalismy puste znaki
				wynik=fscanf(f,"%s,",ciag);
				//wczytalismy porty. Rozbijemy je.
				tmp = strtok (ciag,",");
				teraz->port_start=atoi(tmp);
				tmp = strtok (NULL, ",");
				teraz->port_stop=atoi(tmp);
			}

			while(znak!='n')
			{
				//czytamy wszystko do konca linii.
				wynik=fscanf(f,"%c",&znak);
			}

			wynik=fscanf(f,"%s",ciag);
		}

		return start;
	}
	else
	{
		return NULL;
		//blad. plik pusty albo co.
	}
	fclose(f);
}


int lista(struct Adresy * lista,char* source,char* destination, int port_zrodlo,int port_docelowy)
{
	//zwraca 1 jesli zrodlowy lub docelowy ip sa na liscie.
	//+1 jesli kierunek sie zgadza
	//+2 jesli port sie zgadza.
	//0 jesli adresu nie ma.
	int zwroc,naj_zwroc;
	struct Adresy *teraz;
	teraz=lista;
	zwroc=0;
	naj_zwroc=0;

	//szukamy
	while ((teraz!=NULL)&&(zwrocAdres,source)==0)||(strcmp(teraz->Adres,destination)==0))
		{
			if(zwroc==0)
			{
				//ip jest na liscie
				zwroc=1;
				
			}

			if((zwroc==1)&&(((strcmp(teraz->Adres,source)==0)&&(strcmp(teraz->kierunek,"SRC")==0))||((strcmp(teraz->Adres,destination)==0)&&(strcmp(teraz->kierunek,"DEST")==0))))
			{
				//odkrylismy wlasnie wpis w ktorym kierunek sie zgadza.
				zwroc=zwroc+1;
			}

			if(((port_zrodlo!=0)||(port_docelowy!=0))&&((zwroc==1)||(zwroc==2))&&(((strcmp(teraz->kierunek,"DEST")==0)&&(port_docelowy>=teraz->port_start)&&(port_docelowyport_stop))||((strcmp(teraz->kierunek,"SRC")==0)&&(port_zrodlo>=teraz->port_start)&&(port_zrodloport_stop))))
			{
				//Odkrylismy wlasnie ze i port sie zgadza.
				zwroc=zwroc+2;
			}

		}
		
		if(zwroc>naj_zwroc)
		{
			naj_zwroc=zwroc;
		}
		
		teraz=teraz->nastepny;
	}

	return naj_zwroc;
}

int posprzataj(struct Adresy * lista)
{
	struct Adresy* tmp;
	
	while(lista!=NULL)
	{
		tmp=lista;
		lista=lista->nastepny;
		free(tmp);
	}
	
	return 0;
}

//zapisuje do pliku admin.
int zapisz(char *source,char *destination,char *prot,char *komunikat)
{
	fprintf(admin,"%s %s %s %sn",source,destination,prot,komunikat);
}

//Funkcje zwiazane z wlasciwa analiza.


void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);



int check_payload(const u_char *payload, int len)
{
	int dlugosc,i,j;

	if((payload[0]'9'))
	{
		//liczba ma byc z przedzialu 0-9
		return 1;
	}
	else
	{
		dlugosc=(len-1)/(payload[0]-48);
		j=1;
		for(i=dlugosc+1;idlugosc)
			{
				j=1;
			}
		}
	}
	
	return 0;
}



/*
 * dissect/print packet
 */

void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
	/* declare pointers to packet headers */
	const struct sniff_ethernet *ethernet;  /* The ethernet header [1] */
	const struct sniff_ip *ip;              /* The IP header */
	const struct sniff_tcp *tcp;            /* The TCP header */
	//const struct sniff_udp *udp;			/* The UDP header */
	const char *payload;                    /* Packet payload */
	char *source,*destination;
	char prot[10];						//nazwa protokolu

	int size_ip;
	int size_tcp;
	int size_payload;
	int wynik_biala,wynik_czarna,port_zrodlowy,port_docelowy,wynik_payload;
	
	/* define ethernet header */
	ethernet = (struct sniff_ethernet*)(packet);
	/* define/compute ip header offset */
	ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
	size_ip = IP_HL(ip)*4;
	if (size_ip ip_p) {
		case IPPROTO_TCP:
			strncpy(prot,"TCP",4);
			break;
		case IPPROTO_UDP:
			strncpy(prot,"UDP",4);
			break;
		case IPPROTO_ICMP:
			strncpy(prot,"ICMP",5);
			break;
		case IPPROTO_IP:
			strncpy(prot,"IP",3);
			break;
		default:
			strncpy(prot,"OTHER",6);
			break;
	}


	//Rozpoznajemy adresy zrodlowy i docelowy
	destination=inet_ntoa(ip->ip_src);
	source=(char*)malloc(sizeof(char)*strlen(destination));
	strncpy(source,destination,strlen(destination));
	source[strlen(destination)]='';
	destination=inet_ntoa(ip->ip_dst);
	
	//testujemy.
	wynik_czarna=lista(czarna,source,destination,0,0);
	
	if(wynik_czarna>1)
	{
		//odrzucamy z powodu warunku 1 - jest w pliku_bad
		zapisz(source,destination,prot,"BAD SRC/DEST IP");
	}
	else
	{
		if (ip->ip_p==IPPROTO_TCP || ip->ip_p==IPPROTO_UDP) //tcp lub udp
		{
			tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
			port_zrodlowy=ntohs(tcp->th_sport);
			port_docelowy=ntohs(tcp->th_dport);
			//testujemy.
			wynik_biala=lista(biala,source,destination,port_zrodlowy,port_docelowy);
			
			if((wynik_biala==1)||(wynik_biala==2)) //jest na liscie, ale nie zgadza sie port. (jesli by sie zgadzal byloby 3 albo 4)
			{
				//odrzucamy z powodu niespelnienia warunku 2.
				zapisz(source,destination,prot,"BAD SRC/DEST PORT");
			}
			else
			{
				//ok. przeszlismy pierwsze dwa testy. teraz czy format pliku sie zgadza.
				wynik_payload=0;
				
				if (ip->ip_p==IPPROTO_TCP)
				{
					size_tcp = TH_OFF(tcp)*4;
					if (size_tcp ip_len) - (size_ip + size_tcp);
					
					if (size_payload > 0) 
					{
						wynik_payload=check_payload(payload,size_payload);
						//if(wynik_payload==2)
						//	printf("%snnnn---------n",payload);
						
					}
				}
				
				if(wynik_payload==1)
				{
					zapisz(source,destination,prot,"BAD PACKET FORMAT, MISSING NUMBER");
				}
				else if (wynik_payload==2)
				{
					zapisz(source,destination,prot,"BAD PACKET FORMAT, NOT MATCHING DATA");
				}
				else
				{
					//PAKIET OK!!
					pcap_dump(plik, header, packet);//przepuszaczamy
					zapisz(source,destination,prot,"PACKET OK");
				}
			}
		}
		
	}
	
	return;
}




/*main-----------------------------------------------------------------*/
/*main-----------------------------------------------------------------*/
/*main-----------------------------------------------------------------*/
int main(int argc, char **argv)
{
	//char *dev = NULL;			/* capture device name */
	char errbuf[PCAP_ERRBUF_SIZE];		/* error buffer */
	pcap_t *handle;				/* packet capture handle */

	if(argc==6)
	{

		//wczytujemy dane z odpowiednich list.
		czarna=wczytaj_adresy(argv[4],0);
		biala=wczytaj_adresy(argv[5],1);

	  	if (!(handle=pcap_open_offline(argv[1], errbuf)))
		 {
			perror(errbuf);
			exit(1);
		 }

	  	if (!(plik=pcap_dump_open(handle, argv[2])))
		 {
			printf("BLADn");
			exit(1);
		 }
		
		admin=fopen(argv[3],"w");

		if (pcap_dispatch(handle, -1/*num_packets*/, got_packet,(u_char *) admin));

		fclose(admin);
		pcap_dump_close(plik);
		pcap_close(handle);
		//sprzatamy pamiec:
		posprzataj(biala);
		posprzataj(czarna);
		
	}
	else
	{
		printf("Podaj 5 parametrow!!n");
		return 1;
	}
	return 0;
}

Leave a Reply