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