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; }