เคล็ดลับและรหัสเพื่อให้ผ่านการสอบภาคปฏิบัติเครือข่ายคอมพิวเตอร์ ("Reti di calcolatori") ในปาดัวได้อย่างง่ายดาย คุณสามารถค้นหาทุกสิ่งที่อยู่ใน readme นี้ผ่าน man
และ RFC ต่างๆ ฉันทำมันเพียงเพื่อการอ้างอิงที่รวดเร็ว
เฟรมอีเธอร์เน็ต (เลเยอร์ลิงก์ข้อมูล) มีดาตาแกรม IP (เลเยอร์เครือข่าย) ที่สามารถมีหนึ่งใน { tcp_segment (เลเยอร์การขนส่ง), icmp_packet } ต่อไปนี้ (สำหรับวัตถุประสงค์ของการสอบนี้) วิธีง่ายๆ ที่จะตระหนักได้ว่าคือ:
eth = ( struct eth_frame * ) buffer ;
ip = ( struct ip_datagram * ) eth -> payload ;
tcp = ( struct tcp_segment * ) ip -> payload ;
// or
icmp = ( struct icmp_packet * ) ip -> payload ;
(ขึ้นอยู่กับสถาปัตยกรรม แต่คุณสามารถสรุปได้ว่าสิ่งต่อไปนี้เป็นจริงสำหรับการสอบนี้)
unsigned char
: 1 ไบต์unsigned short
: 2 ไบต์unsiged int
: 4 ไบต์ในการถ่ายโอนบนเครือข่ายจะใช้ Big endian cpu ของ intel ส่วนใหญ่เป็น endian นิดหน่อย หากต้องการแปลงให้ใช้ 2 ฟังก์ชันนี้ซึ่งจะเข้าใจโดยอัตโนมัติว่าจำเป็นต้องแปลงหรือไม่:
htonl(x)
หรือ htons(x)
เพื่อแปลง x จาก H ost เป็น N etwork endianess, l หากคุณต้องแปลงตัวแปร 4 ไบต์ จะเป็น 2 ไบต์ntohl(x)
หรือ ntohs(x)
สำหรับสิ่งที่ตรงกันข้าม (คุณอาจสังเกตเห็นว่าการใช้งาน htonx และ ntohx นั้นเหมือนกัน) // Frame Ethernet
struct eth_frame {
unsigned char dst [ 6 ]; // mac address
unsigned char src [ 6 ]; // mac address
unsigned short type ; // 0x0800 = ip, 0x0806 = arp
char payload [ 1500 ]; //ARP or IP
};
ด้วย type
ที่ทำให้เราเข้าใจว่าจะส่งต่อได้ที่ไหนในระดับต่อไป (2 ตัวอย่างคือ ip หรือ arp)
ความยาวส่วนหัว: ตรวจสอบครึ่งหลังของแอตทริบิวต์ ver_ihl
ตัวอย่าง: หากเป็น '5' ความยาวของส่วนหัวจะเป็น 4 * 5 = 20 ไบต์
//todo เพิ่มรูปภาพ
// Datagramma IP
struct ip_datagram {
unsigned char ver_ihl ; // first 4 bits: version, second 4 bits: (lenght header)/8
unsigned char tos ; //type of service
unsigned short totlen ; // len header + payload
unsigned short id ; // useful in case of fragmentation
unsigned short flags_offs ; //offset/8 related to the original ip package
unsigned char ttl ;
unsigned char protocol ; // TCP = 6, ICMP = 1
unsigned short checksum ; // only header checksum (not of payload). Must be at 0 before the calculation.
unsigned int src ; // ip address
unsigned int dst ; // ip address
unsigned char payload [ 1500 ];
};
ความยาวส่วนหัว (ตามที่กำหนดไว้ที่นี่): 20
struct tcp_segment {
unsigned short s_port ;
unsigned short d_port ;
unsigned int seq ; // offset in bytes from the start of the tcp segment in the stream (from initial sequance n)
unsigned int ack ; // useful only if ACK flag is 1. Next seq that sender expect
unsigned char d_offs_res ; // first 4 bits: (header len/8)
unsigned char flags ; // check rfc
unsigned short win ; // usually initially a 0 (?)
unsigned short checksum ; // use tcp_pseudo to calculate it. Must be at 0 before the calculation.
unsigned short urgp ;
unsigned char payload [ 1000 ];
};
ในการคำนวณการตรวจสอบรวมของเซ็กเมนต์ TCP จะมีประโยชน์ในการกำหนดโครงสร้างเพิ่มเติม (ตรวจสอบ RFC สัมพัทธ์) ขนาดของมัน โดยไม่มีส่วน tcp_segment
struct tcp_pseudo {
unsigned int ip_src , ip_dst ;
unsigned char zeroes ;
unsigned char proto ; // ip datagram protocol field (tcp = 6, ip = 1)
unsigned short entire_len ; // tcp length (header + data)
unsigned char tcp_segment [ 20 /*to set appropriatly */ ]; // entire tcp packet pointer
};
หากต้องการคำนวณขนาดของส่วน TCP ทั้งหมด (หรือของ icmp) หรือมากกว่านั้นโดยทั่วไปของเพย์โหลด IP:
unsigned short ip_total_len = ntohs ( ip -> totlen );
unsigned short ip_header_dim = ( ip -> ver_ihl & 0x0F ) * 4 ;
int ip_payload_len = ip_total_len - ip_header_dim ;
เราสามารถใช้ฟังก์ชันนี้ทั้งสำหรับ IP ดาตาแกรมและเซ็กเมนต์ TCP แต่เราต้องดูแลพารามิเตอร์ len
unsigned short checksum ( unsigned char * buffer , int len ){
int i ;
unsigned short * p ;
unsigned int tot = 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 ;
}
2 กรณี คือ
ip->checksum=htons(checksum((unsigned char*) ip, 20));
- int TCP_TOTAL_LEN = 20 ;
struct tcp_pseudo pseudo ; // size of this: 12
memcpy ( 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 vary
tcp -> checksum = htons ( checksum (( unsigned char * ) & pseudo , TCP_TOTAL_LEN + 12 ));
#include <arpa/inet.h>
void print_ip ( unsigned int ip ){
struct in_addr ip_addr ;
ip_addr . s_addr = ip ;
printf ( "%sn" , inet_ntoa ( ip_addr ));
}
ฉันแนะนำ VIM และกรุณาเยื้องรหัสของคุณ
:wq
เพื่อบันทึกและออกesc
2 ครั้งถ้าคุณไม่เข้าใจว่าเกิดอะไรขึ้น/query
เพื่อค้นหา "query", n
และ N
เพื่อค้นหาผลลัพธ์ก่อนหน้า/ถัดไป " auto reformat when you pres F7
map <F7> mzgg=G`z
" F8 to save and compile creating np executable
map <F8> :w <CR> :!gcc % -o np -g <CR>
" F9 to execute
map <F9> :!./np <CR>
" make your code look nicer
set tabstop=3
set shiftwidth=3
set softtabstop=0 expandtab
set incsearch
set cindent
" Ctrl+shift+up/down to swap the line up or doen
nnoremap <C-S-Up> <Up>"add"ap<Up>
nnoremap <C-S-Down> "add"ap
" ctrl+h to hilight the last search
nnoremap <C-h> :set hlsearch!<CR>
set number
set cursorline
set mouse=a
set foldmethod=indent
set foldlevelstart=99
let mapleader="<space>"
nnoremap <leader>b :make <CR> :cw <CR>
ก่อนอื่นให้สร้าง makefile
ในไดเร็กทอรีพร้อมกับไฟล์ที่จะคอมไพล์ดังนี้:
np : ws18.c
gcc -o np ws18.c
ให้ความสนใจที่จะวางแท็บไว้ข้างหน้า "gcc" และไม่ต้องเว้นวรรค (หากคุณเปิดใช้งานส่วนขยายแท็บเป็นกลุ่มให้ใช้ ctrl=v tab
) ที่นี่ np
คือสิ่งที่คุณต้องการสร้าง (ไฟล์ปฏิบัติการ) และ ws18.c
ไฟล์ที่จะคอมไพล์ ในบรรทัดด้านล่างจะมีคำสั่งให้เรียกทุกครั้งที่คุณเขียน :make
เป็นกลุ่ม จากนั้น ด้วย .vimrc
ที่ให้ไว้ด้านบน ให้กด space
(ปล่อยมัน) และ b
( b uild) คำสั่งจะถูกดำเนินการ และคุณจะเห็นรายการข้อผิดพลาดที่ด้านล่างของโค้ด คุณสามารถข้ามไปในบรรทัดที่ถูกต้องได้อย่างรวดเร็วโดยกด Enter ในแต่ละรายการ หากต้องการย้ายระหว่างการแยกบนและล่าง ให้กด CTRL+W
W
หากต้องการปิดมุมมองด้านล่าง (แก้ไขด่วน) :q
หรือ :cw
คุณสามารถดูข้อสอบฉบับสมบูรณ์ได้ในเว็บไซต์ตอนต้นของ readme นี้ รหัสทั้งหมดอยู่ในโฟลเดอร์
ใช้ TCP จับมือสามทาง (ACK+SYN)
เคล็ดลับ : คุณสามารถตรวจสอบด้วย wireshark ว่าการตรวจสอบ TCP ของคุณถูกต้องหรือไม่
ใช้การตอบกลับเสียงสะท้อนเฉพาะกับคำขอ icmp ในขนาดที่กำหนดเท่านั้น
เคล็ดลับ : คุณสามารถคำนวณขนาดของข้อความ icmp ได้ดังนี้:
unsigned short dimension = ntohs ( ip -> totlen );
unsigned short header_dim = ( ip -> ver_ihl & 0x0F ) * 4 ;
int icmp_dimension = dimension - header_dim ;
ใช้เซิร์ฟเวอร์ HTTP ที่:
เคล็ดลับ : เว็บเบราว์เซอร์ส่วนใหญ่ละเว้นส่วนหัว Retry-After
ดังนั้นการเปลี่ยนเส้นทางจะไม่เกิดขึ้นหลังจาก 10 วินาที แต่เกิดขึ้นทันที ในโซลูชันจะมีอาร์เรย์ที่เก็บสถานะการเชื่อมต่อสำหรับแต่ละ IP
ใช้ ICMP "ปลายทางที่ไม่สามารถเข้าถึงได้" ที่ระบุว่าพอร์ตไม่พร้อมใช้งาน
เคล็ดลับ : คุณต้องส่งแพ็คเกจเพื่อตอบสนองต่อการเชื่อมต่อ TCP icmp->type = 3
, icmp->code=3
และอย่าลืมคัดลอกเนื้อหาของเพย์โหลดดั้งเดิมของ icmp ลงในเพย์โหลด
สกัดกั้นการเชื่อมต่อที่ได้รับครั้งแรก และพิมพ์ลำดับและรับทราบหมายเลขของพวกเขา จากนั้นสร้างสตรีม 2 รายการขึ้นมาใหม่ในบัฟเฟอร์ 2 แบบ และพิมพ์เนื้อหา
เคล็ดลับ : หากต้องการสกัดกั้นการสิ้นสุดการเชื่อมต่อ เพียงตรวจสอบว่าแพ็คเกจมีบิต FIN ที่ 1 หรือไม่ (หลังจากกรองแพ็คเกจทั้งหมดแล้ว โดยคงเฉพาะแพ็คเกจที่เป็นของการเชื่อมต่อครั้งแรก) ใช้ฟิลด์ลำดับ TCP เพื่อคัดลอก contnet ที่ออฟเซ็ตด้านขวาในบัฟเฟอร์ 2 ตัว อย่าทำซ้ำรหัส
แก้ไขพร็อกซีเพื่ออนุญาตคำขอจากกลุ่มที่อยู่ IP เท่านั้น และอนุญาตเฉพาะการถ่ายโอนไฟล์ที่มีข้อความหรือ html
เคล็ดลับ : เป็นการดีกว่าถ้าได้รับการตอบสนองจากเซิร์ฟเวอร์ในบัฟเฟอร์ก่อน จากนั้นคัดลอกเนื้อหานี้ไปยังบัฟเฟอร์อื่นเพื่อแยกส่วนหัวเช่นเคย เนื่องจากขั้นตอนการแยกส่วนหัวปรับเปลี่ยนบัฟเฟอร์ หากเงื่อนไขของประเภทเนื้อหาเต็มแล้ว ให้ส่งต่อ connet ของบัฟเฟอร์เริ่มต้น
ส่งการตอบสนอง HTTP ด้วยเนื้อหาที่เป็นก้อน
เคล็ดลับ : เพิ่ม Content-Type: text/plainrnTransfer-Encoding: chunkedrn
ไปยังส่วนหัว HTTP จากนั้น หากต้องการสร้างแต่ละก้อนที่จะส่ง คุณสามารถใช้สิ่งที่ต้องการ:
int build_chunk ( char * s , int len ){
sprintf ( chunk_buffer , "%xrn" , len ); // size in hex
// debug printf("%d in hex: %s",len,chunk_buffer);
int from = strlen ( chunk_buffer );
int i = 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 ;
return i + from ;
}
ใช้ส่วนหัว Last-Modified
ของ HTTP/1.0
เคล็ดลับ : ฟังก์ชันการแปลงเวลาที่มีประโยชน์บางส่วนในส่วนเบ็ดเตล็ด สามารถทำได้โดยไม่ต้องมีการแปลงเหล่านี้ รูปแบบวันที่ HTTP คือ %a, %d %b %Y %H:%M:%S %Z
1: ความยาวเนื้อหา (ถูกนำไปใช้แล้ว) 2: ติดตาม (??)
แก้ไข icmp echo เพื่อแบ่งคำขอออกเป็นสองดาตาแกรม IP โดยอันหนึ่งมีขนาดเพย์โหลด 16 ไบต์ และอีกอันมีขนาดเพย์โหลดที่ร้องขอ
ในระหว่างหลักสูตรมีการมอบหมายการบ้านบางส่วน (ไม่บังคับ) แม้จะไม่ใช่ข้อสอบ แต่ก็มีระดับความยากไม่มากก็น้อย
ใช้โปรแกรม Traceroute ติดตามแต่ละโหนดที่แพ็กเก็ตเข้าชมก่อนที่จะค้นหาปลายทางอีกครั้ง คำแนะนำ: เมื่อ time to live กลายเป็น 0 โหนดจะทิ้งแพ็กเก็ตและส่ง "ข้อความที่เกินเวลา" ไปยังที่อยู่ IP ต้นทางของแพ็กเก็ต (ดู RFC793)
ใช้ส่วนหัว HTTP WWW-Authenticate
เพื่อต้องการข้อมูลรับรองการเข้าถึงไปยังไคลเอนต์
ใช้ไคลเอนต์ที่ยอมรับเนื้อหาที่เป็นก้อน
รูปแบบวันที่ HTTP คือ %a, %d %b %Y %H:%M:%S %Z
char date_buf [ 1000 ];
char * getNowHttpDate (){
time_t now = time ( 0 );
struct tm tm = * gmtime ( & now );
strftime ( date_buf , sizeof date_buf , "%a, %d %b %Y %H:%M:%S %Z" , & tm );
printf ( "Time is: [%s]n" , date_buf );
return date_buf ;
}
// parse time and convert it to millisecond from epoch
time_t httpTimeToEpoch ( char * time ){
struct tm tm ;
char buf [ 255 ];
memset ( & tm , 0 , sizeof ( struct tm ));
strptime ( time , "%a, %d %b %Y %H:%M:%S %Z" , & tm );
return mktime ( & tm );
}
// returns 1 if d1 < d2
unsigned char compareHttpDates ( char * d1 , char * d2 ){
return httpTimeToEpoch ( d1 ) < httpTimeToEpoch ( d2 );
}
unsigned char expired ( char * uri , char * last_modified ){
char * complete_name = uriToCachedFile ( uri );
FILE * fp = fopen ( complete_name , "r" );
if ( fp == NULL ) return 1 ;
//read the first line
char * line = 0 ; size_t len = 0 ;
getline ( & line , & len , fp );
if ( compareHttpDates ( last_modified , line )) return 0 ;
return 1 ;
//todo read First line and compare
}
rewind(FILE*)
ตั้งเคอร์เซอร์ไว้ที่จุดเริ่มต้น
FILE * fin ;
if (( fin = fopen ( uri + 1 , "rt" )) == NULL ) { // the t is useless
printf ( "File %s non aperton" , uri + 1 );
sprintf ( response , "HTTP/1.1 404 File not foundrnrn<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 lenght
sprintf ( response , "HTTP/1.1 200 OKrnConnection: keep-alivernContent-Length: %drnrn" , content_length );
printf ( "Response: %sn" , response );
//send header
t = write ( s2 , response , strlen ( response ));
//rewind the file
rewind ( fin );
//re-read the file, char per char
while (( c = fgetc ( fin )) != EOF ) {
//printf("%c", c);
//sending the file, char per char
if ( write ( s2 , ( unsigned char * ) & c , 1 ) != 1 ) {
perror ( "Write fallita" );
}
}
fclose ( fin );
}
char car ;
while ( read ( s3 , & car , 1 )) {
write ( s2 , & car , 1 );
// printf("%c",car);
}
unsigned char targetip [ 4 ] = { 147 , 162 , 2 , 100 };
unsigned int netmask = 0x00FFFFFF ;
if (( * (( unsigned int * ) targetip ) & netmask ) == ( * (( unsigned int * ) myip ) & netmask ))
nexthop = targetip ;
else
nexthop = gateway ;
จากชื่อโฮสต์ (เช่น www.google.it) ไปจนถึงที่อยู่ IP
/**
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
*/
struct hostent * he ;
he = gethostbyname ( hostname );
printf ( "Indirizzo di %s : %d.%d.%d.%dn" , hostname ,
( unsigned char )( he -> h_addr [ 0 ]), ( unsigned char )( he -> h_addr [ 1 ]),
( unsigned char )( he -> h_addr [ 2 ]), ( unsigned char )( he -> h_addr [ 3 ]));
สำหรับการฟัง:
int s = 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: stream
0 ); // protocol (0=ip), check /etc/protocols
if ( s == -1 ) {
perror ( "Socket Fallita" );
return 1 ;
}
// 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.
int yes = 1 ;
if ( setsockopt ( s , SOL_SOCKET , SO_REUSEADDR , & yes , sizeof ( int )) == -1 ) {
perror ( "setsockopt" );
return 1 ;
}
struct sockaddr_in indirizzo ;
indirizzo . sin_family = AF_INET ;
indirizzo . sin_port = htons ( 8987 );
indirizzo . sin_addr . s_addr = 0 ;
t = bind ( s , ( struct sockaddr * ) & indirizzo , sizeof ( struct sockaddr_in ));
if ( t == -1 ) {
perror ( "Bind fallita" );
return 1 ;
}
t = listen ( s ,
// backlog defines the maximum length for the queue of pending connections.
10 );
if ( t == -1 ) {
perror ( "Listen Fallita" );
return 1 ;
}
int lunghezza = sizeof ( struct sockaddr_in );
// the remote address will be placed in indirizzo_remoto
s2 = accept ( s , ( struct sockaddr * ) & indirizzo_remoto , & lunghezza );
if ( s2 == -1 ) {
perror ( "Accept Fallita" );
return 1 ;
}
// now we can read in this way:
char buffer [ 10000 ];
int i ;
for ( i = 0 ; ( t = read ( s2 , buffer + i , 1 )) > 0 ; i ++ ); // ps. it's not a good way
// if the previous read returned -1
if ( t == -1 ) {
perror ( "Read Fallita" );
return 1 ;
}
ในตอนท้าย อย่าลืมปิดซ็อกเก็ตทั้งหมดโดย close(s)
(ซึ่งอยู่ในซ็อกเก็ตที่คุณต้องการปิด)
int s = 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 ));
unsigned char buffer [ 1500 ];
bzero ( & sll , sizeof ( struct sockaddr_ll ));
struct sockaddr_ll sll ;
sll . sll_ifindex = if_nametoindex ( "eth0" );
len = sizeof ( sll );
int t = sendto ( s , //socket
buffer , //things to send
14 + 20 + 28 , // len datagram
0 , //flags
( struct sockaddr * ) & sll , // destination addr
len // dest addr len
);
// to receive
t = recvfrom ( s , buffer , 1500 , 0 , ( struct sockaddr * ) & sll , & len );
if ( t == -1 ) {
perror ( "recvfrom fallita" );
return 1 ;
}
void stampa_eth ( struct eth_frame * e ){
printf ( "nn ***** PACCHETTO Ethernet *****n" );
printf ( "Mac destinazione: %x:%x:%x:%x:%x:%xn" , 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:%xn" , e -> src [ 0 ], e -> src [ 1 ], e -> src [ 2 ], e -> src [ 3 ], e -> src [ 4 ], e -> src [ 5 ] );
printf ( "EtherType: 0x%xn" , htons ( e -> type ) );
}
void stampa_ip ( struct ip_datagram * i ){
unsigned int ihl = ( i -> ver_ihl & 0x0F ) * 4 ; // Lunghezza header IP
unsigned int totlen = htons ( i -> totlen ); // Lunghezza totale pacchetto
unsigned int opt_len = ihl - 20 ; // Lunghezza campo opzioni
printf ( "nn ***** PACCHETTO IP *****n" );
printf ( "Version: %dn" , i -> ver_ihl & 0xF0 );
printf ( "IHL (bytes 60max): %dn" , ihl );
printf ( "TOS: %dn" , i -> tos );
printf ( "Lunghezza totale: %dn" , totlen );
printf ( "ID: %xn" , htons ( i -> id ) );
unsigned char flags = ( unsigned char )( htons ( i -> flag_offs ) >> 13 );
printf ( "Flags: %d | %d | %d n" , flags & 4 , flags & 2 , flags & 1 );
printf ( "Fragment Offset: %dn" , htons ( i -> flag_offs ) & 0x1FFF );
printf ( "TTL: %dn" , i -> ttl );
printf ( "Protocol: %dn" , i -> proto );
printf ( "Checksum: %xn" , htons ( i -> checksum ) );
unsigned char * saddr = ( unsigned char * ) & i -> saddr ;
unsigned char * daddr = ( unsigned char * ) & i -> daddr ;
printf ( "IP Source: %d.%d.%d.%dn" , saddr [ 0 ], saddr [ 1 ], saddr [ 2 ], saddr [ 3 ] );
printf ( "IP Destination: %d.%d.%d.%dn" , daddr [ 0 ], daddr [ 1 ], daddr [ 2 ], daddr [ 3 ] );
if ( ihl > 20 ){
// Stampa opzioni
printf ( "Options: " );
for ( int j = 0 ; j < opt_len ; j ++ ){
printf ( "%.3d(%.2x) " , i -> payload [ j ], i -> payload [ j ]);
}
printf ( "n" );
}
}
void stampa_arp ( struct arp_packet * a ){
printf ( "nn ***** PACCHETTO ARP *****n" );
printf ( "Hardware type: %dn" , htons ( a -> htype ) );
printf ( "Protocol type: %xn" , htons ( a -> ptype ) );
printf ( "Hardware Addr len: %dn" , a -> hlen );
printf ( "Protocol Addr len: %dn" , a -> plen );
printf ( "Operation: %dn" , htons ( a -> op ) );
printf ( "HW Addr sorgente: %x:%x:%x:%x:%x:%xn" , a -> hsrc [ 0 ], a -> hsrc [ 1 ], a -> hsrc [ 2 ], a -> hsrc [ 3 ], a -> hsrc [ 4 ], a -> hsrc [ 5 ] );
printf ( "IP Source: %d.%d.%d.%dn" , a -> psrc [ 0 ], a -> psrc [ 1 ], a -> psrc [ 2 ], a -> psrc [ 3 ] );
printf ( "HW Addr Destinazione: %x:%x:%x:%x:%x:%xn" , a -> hdst [ 0 ], a -> hdst [ 1 ], a -> hdst [ 2 ], a -> hdst [ 3 ], a -> hdst [ 4 ], a -> hdst [ 5 ] );
printf ( "IP Dest: %d.%d.%d.%dn" , a -> pdst [ 0 ], a -> pdst [ 1 ], a -> pdst [ 2 ], a -> pdst [ 3 ] );
}
void stampa_icmp ( struct icmp_packet * i ){
printf ( "nn ***** PACCHETTO ICMP *****n" );
printf ( "Type: %dn" , i -> type );
printf ( "Code: %dn" , i -> code );
printf ( "Code: 0x%xn" , htons ( i -> checksum ) );
printf ( "ID: %dn" , htons ( i -> id ) );
printf ( "Sequence: %dn" , htons ( i -> seq ) );
}
void stampa_tcp ( struct tcp_segment * t ){
printf ( "nn ***** PACCHETTO TCP *****n" );
printf ( "Source Port: %dn" , htons ( t -> s_port ) );
printf ( "Source Port: %dn" , htons ( t -> d_port ) );
printf ( "Sequence N: %dn" , ntohl ( t -> seq ) );
printf ( "ACK: %dn" , ntohl ( t -> ack ) );
printf ( "Data offset (bytes): %dn" , ( 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=%dn" , ( t -> flags & 0x01 ) );
printf ( "Windows size: %dn" , htons ( t -> win ) );
printf ( "Checksum: 0x%xn" , htons ( t -> checksum ) );
printf ( "Urgent pointer: %dn" , htons ( t -> urgp ) );
}
ไม่มีประโยชน์จริงๆ แต่..
// es. tcp.c
printf ( "%.4d. // delta_sec (unsigned int)
% .6d // delta_usec
% .5d -> % .5d // ports (unsigned short)
% .2 x // 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
: เพื่อทราบพอร์ต TCP ทั้งหมดที่มีในระดับแอปพลิเคชัน/etc/protocols
nslookup <URL>
: ค้นหาที่อยู่ IP ของ URL ที่ระบุ ( ตัวอย่าง : www.google.com)netstat -rn
แสดงตารางเส้นทางtraceroute
กำหนดเส้นทางแพ็กเก็ต IP ในเส้นทางที่มันเดินทางโดยการพิมพ์ IP ของทุกเกตเวย์ที่ตัดสินใจทิ้งแพ็กเก็ตที่ถูกปลอมแปลงด้วย TTL ต่ำ (time to live, ลดลงในทุก ๆ ฮอป)