- Notifications
You must be signed in to change notification settings - Fork8
nicomazz/ComputerNetworks-unipd2018
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Tips and code to easily pass the computer networks practical exam ("Reti di calcolatori") in Padua.You can find everything that is in this readme throughman, and the various RFCs. I've done it just for a fast reference.
TOC
- Useful RFCs
- Useful links
- Something to understand before trying the past exams
- Editor for the exam
- Past exams
- Misc
- HTTP-date
- rewind
- Read a file and forward it
- Read from a socket and forward to another socket (like a proxy)
- Check if the target ip is in our network
- gethostbyname
- socket creation, binding for listening and writing (like http requests)
- RAW socket creation, binding for listening and writing (to deal with tcp/icmp/arp requests directly)
- Useful utils to print packet contents
- How to printf the various things
- Useful info
- Here you can find a summary of the most important things to know to pass the exam.Anyway, maybe is better to study more in depth every topic.
- C socket programming online book. There is more than needed, but still interesting.
An Ethernet frame (data link layer) contains an IP datagram (network layer) that can contains one of the following { tcp_segment (transport layer), icmp_packet } (for the purpose of this exam). An easy way to realize that is:
eth= (structeth_frame*)buffer;ip= (structip_datagram*)eth->payload;tcp= (structtcp_segment*)ip->payload;// oricmp= (structicmp_packet*)ip->payload;
Data types and endianess
(depends on the architecture, but you can assume that the following is true for this exam)
unsigned char: 1 byteunsigned short: 2 bytesunsiged int: 4 bytes
To transfer on the network is used Big endian. Most of the intel's cpus are little endian. To convert use this 2 functions that automatically understand if a conversion is needed:
htonl(x)orhtons(x)to convert x fromHosttoNetwork endianess,l if you have to convert a 4 bytes variable,s a 2 bytes one.ntohl(x)orntohs(x)for the opposite. (You may notice that the implementation of htonx and ntohx is the same)- if a variable is 1 byte long we don't have endianess problems (obviously)
Ethernet frame
// Frame Ethernetstructeth_frame {unsignedchardst[6];// mac addressunsignedcharsrc[6];// mac addressunsigned shorttype;// 0x0800 = ip, 0x0806 = arpcharpayload[1500];//ARP or IP };
Thanks to thetype we can understand where to forward it on the next level (2 examples are ip or arp)
IP datagram
Header length: check second half ofver_ihl attribute. Example: if it's '5', then the header length is4 * 5 = 20 bytes.
//todo add image
// Datagramma IPstructip_datagram{unsignedcharver_ihl;// first 4 bits: version, second 4 bits: (lenght header)/8unsignedchartos;//type of serviceunsigned shorttotlen;// len header + payloadunsigned shortid;// useful in case of fragmentationunsigned shortflags_offs;//offset/8 related to the original ip packageunsignedcharttl;unsignedcharprotocol;// TCP = 6, ICMP = 1unsigned shortchecksum;// only header checksum (not of payload). Must be at 0 before the calculation.unsignedintsrc;// ip addressunsignedintdst;// ip addressunsignedcharpayload[1500];};
TCP segment
Header (as defined here) length:20
structtcp_segment {unsigned shorts_port;unsigned shortd_port;unsignedintseq;// offset in bytes from the start of the tcp segment in the stream (from initial sequance n)unsignedintack;// useful only if ACK flag is 1. Next seq that sender expectunsignedchard_offs_res;// first 4 bits: (header len/8)unsignedcharflags;// check rfcunsigned shortwin;// usually initially a 0 (?)unsigned shortchecksum;// use tcp_pseudo to calculate it. Must be at 0 before the calculation.unsigned shorturgp;unsignedcharpayload[1000];};
To calculate the checksum of a TCP segment is useful to define an additional structure (check on the relative RFC). Size of it, without the tcp_segment part
structtcp_pseudo{unsignedintip_src,ip_dst;unsignedcharzeroes;unsignedcharproto;// ip datagram protocol field (tcp = 6, ip = 1)unsigned shortentire_len;// tcp length (header + data)unsignedchartcp_segment[20/*to set appropriatly */];// entire tcp packet pointer};
To calculate the size of the entire tcp segment (or of the icmp), or more in general of the ip payload:
unsigned shortip_total_len=ntohs(ip->totlen);unsigned shortip_header_dim= (ip->ver_ihl&0x0F)*4;intip_payload_len=ip_total_len-ip_header_dim;
Checksum calculation
We can use this function both for the IP datagram and the TCP segment,but we must take care about thelen parameter.
- todo: take care about minimum size for tcp, and odd/even corner case
unsigned shortchecksum(unsignedchar*buffer,intlen){inti;unsigned short*p;unsignedinttot=0;p= (unsigned short*)buffer;for(i=0;i<len/2;i++){tot=tot+htons(p[i]);if (tot&0x10000)tot= (tot&0xFFFF)+1; }return (unsigned short)0xFFFF-tot;}
The 2 cases are:
- IP:
ip->checksum=htons(checksum((unsigned char*) ip, 20));` - TCP:
intTCP_TOTAL_LEN=20;structtcp_pseudopseudo;// size of this: 12memcpy(pseudo.tcp_segment,tcp,TCP_TOTAL_LEN);pseudo.zeroes=0;pseudo.ip_src=ip->src;pseudo.ip_dst=ip->dst;pseudo.proto=6;pseudo.entire_len=htons(TCP_TOTAL_LEN);// may varytcp->checksum=htons(checksum((unsignedchar*)&pseudo,TCP_TOTAL_LEN+12));
Convert int IP address in string
#include<arpa/inet.h>voidprint_ip(unsignedintip){structin_addrip_addr;ip_addr.s_addr=ip;printf("%s\n",inet_ntoa(ip_addr));}
I advice VIM. And please, indent your code.
:wqto save and quit.- Press
esc2 times if you don't understand what is happening /queryto search for "query",nandNto search prev/next result
Put this in ~/.vimrc to save time:
" auto reformat when you pres F7map <F7> mzgg=G`z" F8 to save and compile creating np executablemap <F8> :w <CR> :!gcc % -o np -g <CR>" F9 to executemap <F9> :!./np <CR>" make your code look nicerset tabstop=3set shiftwidth=3set softtabstop=0 expandtabset incsearchset cindent" Ctrl+shift+up/down to swap the line up or doennnoremap <C-S-Up> <Up>"add"ap<Up>nnoremap <C-S-Down> "add"ap" ctrl+h to hilight the last searchnnoremap <C-h> :set hlsearch!<CR>set numberset cursorlineset mouse=aset foldmethod=indent set foldlevelstart=99let mapleader="\<space>"nnoremap <leader>b :make <CR> :cw <CR>First of all create amakefile in the directory with the files to compile, like this:
np : ws18.c gcc -o np ws18.cPay attention to put a tab before "gcc", and not spaces (if you have expandtab enabled in vim, usectrl=v tab).Herenp is what you want generate (the executable), andws18.c the file to compile. In the line below there is the command to call each time you write:make in vim.Then, with the.vimrc provided above, pressspace (release it) andb (build).The command will be excuted, and you will see in the bottom of your code the list of errors.You can fastly jump in the correct line by pressing enter in each entry.To move between the top and bottom split pressCTRL+WW. To close the bottom view (quickfix):q, or:cw.
You can find the complete exam statement in the site at the beginning of this readme.The complete code is in the folders.
Past exams
Implement TCP three way handshake (ACK+SYN).
Tips:You can check with wireshark if your TCP checksum is correct or not.
- Is the option field to include?
Implement echo reply only for icmp requests of a certain size
Tips:You can calculate the size of an icmp message in this way:
unsigned shortdimension=ntohs(ip->totlen);unsigned shortheader_dim= (ip->ver_ihl&0x0F)*4;inticmp_dimension=dimension-header_dim;
Implement an HTTP server that:
- redirect to a default page if the target resource is not available
- Send a temporary unavailable response if the resource is available, and after a second request gives the output.
Tips:The headerRetry-After is ignored by most web browser, so the redirect will not take place after 10 seconds, but immediately.In the solution there is an array that keeps the state of the connection for each ip.
Implement an ICMP "Destination unreachable" that say that the port is unavailable
Tips:you have to send the package in response to a tcp connection.icmp->type = 3,icmp->code=3.And remember to copy in the payload the content of the icmp original payload.
Intercept the first received connection, and print sequence and acknowledge numbers of them. Then reconstruct the 2 streams in 2 different buffers, and print their content.
Tips:To intercept the end of the connection, just check if a package contains the FIN bit at 1 (after having filtered all the packages, maintaining only the ones belonging to the first connection).Use the tcp sequence field to copy the contnet at the right offset in the 2 buffers.DON'T DUPLICATE CODE.
Modify the proxy to allow the request only from a pool of IP addresses, and allow only the transfer of files with text or html.
Tips:Is better to first receive the response from the server in a buffer, then copy this content to another buffer to extract headers as always.This because the header extraction procedure modifies the buffer.If the condition of the Content-type is fullfilled then just forward the contnet of the initial buffer.
Send HTTP response with a chunked body.
Tips:AddContent-Type: text/plain\r\nTransfer-Encoding: chunked\r\n to HTTP headers.Then, to build each chunk to send, you can use something like:
Code to build a chunk
intbuild_chunk(char*s,intlen){sprintf(chunk_buffer,"%x\r\n",len);// size in hex// debug printf("%d in hex: %s",len,chunk_buffer);intfrom=strlen(chunk_buffer);inti=0;for (;i<len;i++)chunk_buffer[from+i]=s[i];chunk_buffer[from+(i++)]='\r';chunk_buffer[from+(i++)]='\n';chunk_buffer[i+from]=0;returni+from;}
Implement theLast-Modified header of HTTP/1.0
Tips:Some useful time conversion functions in the misc section. It could also have been done without the need of these conversions.The HTTP date format is%a, %d %b %Y %H:%M:%S %Z
1: content length (was already implemented)2: trace (??)
- How doeswww.webtrace.com work?
Modify icmp echo to split the request into two IP datagrams, one with a payloadsize of 16 bytes and the other one with the requested payload size.
During the course some homeworks (not mandatory) are assigned. Even if they are not exams they have more or less the same level of difficulty.
Homeworks
Implement a traceroute program, tracking each node the packets visits before reching the destination.Hint: when the time to live becomes 0 a node discards the packet and send a "Time Exceeded Message" to the source IP address of the packet (see RFC793).
use the HTTP headerWWW-Authenticate to require the access credentials to the client.
implement a client that accepts chunked content.
The HTTP date format is%a, %d %b %Y %H:%M:%S %Z
Some useful functions to deal with HTTP time
chardate_buf[1000];char*getNowHttpDate(){time_tnow=time(0);structtmtm=*gmtime(&now);strftime(date_buf,sizeofdate_buf,"%a, %d %b %Y %H:%M:%S %Z",&tm);printf("Time is: [%s]\n",date_buf);returndate_buf;}// parse time and convert it to millisecond from epochtime_thttpTimeToEpoch(char*time){structtmtm;charbuf[255];memset(&tm,0,sizeof(structtm));strptime(time,"%a, %d %b %Y %H:%M:%S %Z",&tm);returnmktime(&tm);}// returns 1 if d1 < d2unsignedcharcompareHttpDates(char*d1,char*d2){returnhttpTimeToEpoch(d1)<httpTimeToEpoch(d2);}unsignedcharexpired(char*uri,char*last_modified){char*complete_name=uriToCachedFile(uri);FILE*fp=fopen(complete_name,"r");if (fp==NULL)return1;//read the first linechar*line=0;size_tlen=0;getline(&line,&len,fp);if (compareHttpDates(last_modified,line))return0;return1;//todo read First line and compare}
rewind(FILE*) set the cursor at the beginning
Read a file and forward it
FILE*fin;if ((fin=fopen(uri+1,"rt"))==NULL) {// the t is uselessprintf("File %s non aperto\n",uri+1);sprintf(response,"HTTP/1.1 404 File not found\r\n\r\n<html>File non trovato</html>");t=write(s2,response,strlen(response));if (t==-1) {perror("write fallita");return-1; }}else {content_length=0;while ((c=fgetc(fin))!=EOF)content_length++;// get file lenghtsprintf(response,"HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Length: %d\r\n\r\n",content_length);printf("Response: %s\n",response);//send headert=write(s2,response,strlen(response));//rewind the filerewind(fin);//re-read the file, char per charwhile ((c=fgetc(fin))!=EOF) {//printf("%c", c);//sending the file, char per charif (write(s2, (unsignedchar*)&c,1)!=1) {perror("Write fallita"); } }fclose(fin);}
charcar;while (read(s3,&car,1)) {write(s2,&car,1);// printf("%c",car);}
unsignedchartargetip[4]= {147,162,2,100};unsignedintnetmask=0x00FFFFFF;if ((*((unsignedint*)targetip)&netmask)== (*((unsignedint*)myip)&netmask))nexthop=targetip;elsenexthop=gateway;
from hostname (likewww.google.it) to ip address
/**struct hostent { char *h_name; // official name of host char **h_aliases; // alias list int h_addrtype; // host address type int h_length; // length of address char **h_addr_list; // list of addresses}#define h_addr h_addr_list[0] // for backward compatibility*/structhostent*he;he=gethostbyname(hostname);printf("Indirizzo di %s : %d.%d.%d.%d\n",hostname, (unsignedchar)(he->h_addr[0]), (unsignedchar)(he->h_addr[1]), (unsignedchar)(he->h_addr[2]), (unsignedchar)(he->h_addr[3]));
For listening:
Socket creation and options setting
ints=socket(AF_INET,// domain: ipv4/*SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mechanism may be supported.SOCK_DGRAM Supports datagrams (connectionless, unreliable messages of a fixed maximum length).SOCK_RAW Provides raw network protocol access.*/SOCK_STREAM,// type: stream0);// protocol (0=ip), check /etc/protocolsif (s==-1) {perror("Socket Fallita");return1;}// https://stackoverflow.com/questions/3229860/what-is-the-meaning-of-so-reuseaddr-setsockopt-option-linux// SO_REUSEADDR allows your server to bind to an address which is in a TIME_WAIT state.intyes=1;if (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))==-1) {perror("setsockopt");return1;}
Binding to a local port
structsockaddr_inindirizzo;indirizzo.sin_family=AF_INET;indirizzo.sin_port=htons(8987);indirizzo.sin_addr.s_addr=0;t=bind(s, (structsockaddr*)&indirizzo,sizeof(structsockaddr_in));if (t==-1) {perror("Bind fallita");return1;}t=listen(s,// backlog defines the maximum length for the queue of pending connections.10);if (t==-1) {perror("Listen Fallita");return1;}
Accepting a connection, and reading the actual content of the buffer
intlunghezza=sizeof(structsockaddr_in);// the remote address will be placed in indirizzo_remotos2=accept(s, (structsockaddr*)&indirizzo_remoto,&lunghezza);if (s2==-1) {perror("Accept Fallita");return1;}// now we can read in this way:charbuffer[10000];inti;for (i=0; (t=read(s2,buffer+i,1))>0;i++);// ps. it's not a good way// if the previous read returned -1if (t==-1) {perror("Read Fallita");return1;}
At the end, remember to close all the sockets withclose(s) (where s in the socket you want to close)
RAW socket creation, binding for listening and writing (to deal with tcp/icmp/arp requests directly)
ints=socket(//AF_PACKET Low level packet interface packet(7)AF_PACKET,//SOCK_RAW Provides raw network protocol access.SOCK_RAW,// When protocol is set to htons(ETH_P_ALL), then all protocols are received.htons(ETH_P_ALL));unsignedcharbuffer[1500];bzero(&sll,sizeof(structsockaddr_ll));structsockaddr_llsll;sll.sll_ifindex=if_nametoindex("eth0");len=sizeof(sll);intt=sendto(s,//socketbuffer,//things to send14+20+28,// len datagram0,//flags (structsockaddr*)&sll,// destination addrlen// dest addr len);// to receivet=recvfrom(s,buffer,1500,0, (structsockaddr*)&sll,&len);if (t==-1) {perror("recvfrom fallita");return1;}
Ethernet packet
voidstampa_eth(structeth_frame*e ){printf("\n\n ***** PACCHETTO Ethernet *****\n" );printf("Mac destinazione: %x:%x:%x:%x:%x:%x\n",e->dst[0],e->dst[1],e->dst[2],e->dst[3],e->dst[4],e->dst[5] );printf("Mac sorgente: %x:%x:%x:%x:%x:%x\n",e->src[0],e->src[1],e->src[2],e->src[3],e->src[4],e->src[5] );printf("EtherType: 0x%x\n",htons(e->type ) );}
IP datagram
voidstampa_ip(structip_datagram*i ){unsignedintihl= (i->ver_ihl&0x0F)*4;// Lunghezza header IPunsignedinttotlen=htons(i->totlen );// Lunghezza totale pacchettounsignedintopt_len=ihl-20;// Lunghezza campo opzioniprintf("\n\n ***** PACCHETTO IP *****\n" );printf("Version: %d\n",i->ver_ihl&0xF0 );printf("IHL (bytes 60max): %d\n",ihl );printf("TOS: %d\n",i->tos );printf("Lunghezza totale: %d\n",totlen );printf("ID: %x\n",htons(i->id ) );unsignedcharflags= (unsignedchar)(htons(i->flag_offs) >>13);printf("Flags: %d | %d | %d \n",flags&4,flags&2,flags&1 );printf("Fragment Offset: %d\n",htons(i->flag_offs)&0x1FFF );printf("TTL: %d\n",i->ttl );printf("Protocol: %d\n",i->proto );printf("Checksum: %x\n",htons(i->checksum ) );unsignedchar*saddr= (unsignedchar* )&i->saddr;unsignedchar*daddr= (unsignedchar* )&i->daddr;printf("IP Source: %d.%d.%d.%d\n",saddr[0],saddr[1],saddr[2],saddr[3] );printf("IP Destination: %d.%d.%d.%d\n",daddr[0],daddr[1],daddr[2],daddr[3] );if(ihl>20 ){// Stampa opzioniprintf("Options: " );for(intj=0;j<opt_len ;j++ ){printf("%.3d(%.2x) ",i->payload[j],i->payload[j]);}printf("\n" );}}
ARP
voidstampa_arp(structarp_packet*a ){printf("\n\n ***** PACCHETTO ARP *****\n" );printf("Hardware type: %d\n",htons(a->htype ) );printf("Protocol type: %x\n",htons(a->ptype ) );printf("Hardware Addr len: %d\n",a->hlen );printf("Protocol Addr len: %d\n",a->plen );printf("Operation: %d\n",htons(a->op ) );printf("HW Addr sorgente: %x:%x:%x:%x:%x:%x\n",a->hsrc[0],a->hsrc[1],a->hsrc[2],a->hsrc[3],a->hsrc[4],a->hsrc[5] );printf("IP Source: %d.%d.%d.%d\n",a->psrc[0],a->psrc[1],a->psrc[2],a->psrc[3] );printf("HW Addr Destinazione: %x:%x:%x:%x:%x:%x\n",a->hdst[0],a->hdst[1],a->hdst[2],a->hdst[3],a->hdst[4],a->hdst[5] );printf("IP Dest: %d.%d.%d.%d\n",a->pdst[0],a->pdst[1],a->pdst[2],a->pdst[3] );}
ICMP content
voidstampa_icmp(structicmp_packet*i ){printf("\n\n ***** PACCHETTO ICMP *****\n" );printf("Type: %d\n",i->type );printf("Code: %d\n",i->code );printf("Code: 0x%x\n",htons(i->checksum ) );printf("ID: %d\n",htons(i->id) );printf("Sequence: %d\n",htons(i->seq) );}
TCP
voidstampa_tcp(structtcp_segment*t ){printf("\n\n ***** PACCHETTO TCP *****\n" );printf("Source Port: %d\n",htons(t->s_port ) );printf("Source Port: %d\n",htons(t->d_port ) );printf("Sequence N: %d\n",ntohl(t->seq ) );printf("ACK: %d\n",ntohl(t->ack ) );printf("Data offset (bytes): %d\n", (t->d_offs_res >>4 )*4 );printf("Flags: " );printf("CWR=%d | ", (t->flags&0x80) >>7 );printf("ECE=%d | ", (t->flags&0x40) >>6 );printf("URG=%d | ", (t->flags&0x20) >>5 );printf("ACK=%d | ", (t->flags&0x10) >>4 );printf("PSH=%d | ", (t->flags&0x08) >>3 );printf("RST=%d | ", (t->flags&0x04) >>2 );printf("SYN=%d | ", (t->flags&0x02) >>1 );printf("FIN=%d\n", (t->flags&0x01) );printf("Windows size: %d\n",htons(t->win ) );printf("Checksum: 0x%x\n",htons(t->checksum ) );printf("Urgent pointer: %d\n",htons(t->urgp ) );}
Not really useful, but..
// es. tcp.cprintf("%.4d. // delta_sec (unsigned int) %.6d// delta_usec %.5d->%.5d// ports (unsigned short) %.2x// tcp flags (unsigned char) in hex: es: "12" %.10u// seq (unsigned int) %.10u// ack %.5u//tcp win %4.2f\n",delta_sec,delta_usec,htons(tcp->s_port),htons(tcp->d_port),tcp->flags,htonl(tcp->seq)-seqzero,htonl(tcp->ack)-ackzero,htons(tcp->win), (htonl(tcp->ack)-ackzero) / (double)(delta_sec*1000000+delta_usec));
/etc/services: To know all the TCP ports available at the application level./etc/protocolsnslookup <URL>: finds the ip address of the specified URL (example:www.google.com)netstat -rnshows routing tabletracerouteroutes an ip packet in which path it travels by printing the IP of every gateway that decidesto drop the packet that was forged with low TTL (time to live, decremented on every hop) count.
About
Tips and resources to easily pass the "Computer Networks" practical exam ("Reti di calcolatori") in Padua
Topics
Resources
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Contributors3
Uh oh!
There was an error while loading.Please reload this page.

