파도바에서 컴퓨터 네트워크 실기 시험("Reti di calcolatori")을 쉽게 통과할 수 있는 팁과 코드입니다. man
과 다양한 RFC를 통해 이 Readme에 있는 모든 내용을 찾을 수 있습니다. 빠른 참고를 위해 만들어봤습니다.
이더넷 프레임(데이터 링크 계층)에는 다음 { tcp_segment(전송 계층), icmp_packet }(이 시험의 목적상) 중 하나를 포함할 수 있는 IP 데이터그램(네트워크 계층)이 포함되어 있습니다. 이를 실현하는 쉬운 방법은 다음과 같습니다.
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바이트네트워크 전송에는 빅 엔디안이 사용됩니다. 대부분의 인텔 CPU는 리틀 엔디안입니다. 변환하려면 변환이 필요한지 자동으로 이해하는 이 두 가지 기능을 사용하십시오.
htonl(x)
또는 htons(x)
, 4바이트 변수를 변환해야 하는 경우 l 은 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바이트입니다.
//이미지 추가하기
// 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" 앞에 탭을 두도록 주의하세요(vim에서 확장 탭을 활성화한 경우 ctrl=v tab
사용). 여기서 np
생성하려는 파일(실행 파일)이고 ws18.c
컴파일할 파일입니다. 아래 줄에는 vim에 :make
작성할 때마다 호출하는 명령이 있습니다. 그런 다음 위에 제공된 .vimrc
사용하여 space
(손 떼기)와 b
( 빌드 )를 누르세요. 명령이 실행되고 코드 하단에 오류 목록이 표시됩니다. 각 항목에서 Enter 키를 누르면 올바른 줄로 빠르게 이동할 수 있습니다. 상단과 하단 분할 사이를 이동하려면 CTRL+W
W
누르세요. 하단 보기를 닫으려면(quickfix) :q
또는 :cw
.
이 Readme의 시작 부분에 있는 사이트에서 전체 시험 내용을 확인할 수 있습니다. 전체 코드는 폴더에 있습니다.
TCP 3방향 핸드셰이크(ACK+SYN)를 구현합니다.
팁 : TCP 체크섬이 올바른지 Wireshark로 확인할 수 있습니다.
특정 크기의 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 시퀀스 필드를 사용하여 2개 버퍼의 오른쪽 오프셋에 있는 contnet을 복사합니다. 코드를 중복하지 마십시오.
IP 주소 풀에서만 요청을 허용하고 텍스트 또는 HTML이 포함된 파일 전송만 허용하도록 프록시를 수정합니다.
팁 : 먼저 버퍼의 서버로부터 응답을 받은 다음 이 콘텐츠를 다른 버퍼에 복사하여 항상 그렇듯이 헤더를 추출하는 것이 좋습니다. 이는 헤더 추출 절차가 버퍼를 수정하기 때문입니다. Content-type의 조건이 가득 차면 초기 버퍼의 contnet을 전달하면 됩니다.
청크된 본문으로 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 ;
}
HTTP/1.0의 Last-Modified
헤더 구현
팁 : 기타 섹션에 몇 가지 유용한 시간 변환 기능이 있습니다. 이러한 변환이 필요 없이 수행될 수도 있습니다. HTTP 날짜 형식은 %a, %d %b %Y %H:%M:%S %Z
입니다.
1: 콘텐츠 길이(이미 구현됨) 2: 추적(??)
icmp echo를 수정하여 요청을 두 개의 IP 데이터그램(페이로드 크기가 16바이트인 데이터그램과 요청된 페이로드 크기를 가진 데이터그램)으로 분할합니다.
과정 중에 일부 숙제(필수는 아님)가 할당됩니다. 시험이 아니더라도 난이도는 거의 비슷합니다.
목적지에 도달하기 전에 패킷이 방문하는 각 노드를 추적하는 경로 추적 프로그램을 구현하십시오. 힌트: TTL(Time to Live)이 0이 되면 노드는 패킷을 폐기하고 "Time Exceeded Message"를 패킷의 소스 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>
: 지정된 URL의 IP 주소를 찾습니다( 예 : www.google.com)netstat -rn
라우팅 테이블을 표시합니다.traceroute
는 낮은 TTL(Time To Live, 모든 홉에서 감소됨) 수로 위조된 패킷을 삭제하기로 결정한 모든 게이트웨이의 IP를 인쇄하여 이동하는 경로로 IP 패킷을 라우팅합니다.