I comandi Linux: la rete ( 4 ) | OTHER chapters | |||||||
Pacchetti, segmenti e datagramma Una precisazione: in questo testo i tre termini vengono usati in modo indifferenziato. In realtà, solitamente, il termine " pacchetto di dati " viene riferito ad un pacchetto di dati IP, il termine " datagramma " viene riferito ad un pacchetto di dati UDP, il termine " segmento " viene riferito ad un pacchetto di dati TCP. Il comando
L'output di
Oppure, per rendere leggibili gli stessi dati, visualizzandoli sia in ASCII, sia in sequenze di valori esadecimali, eseguire
Per avere maggiori informazioni, estratte dagli header del singolo pacchetto di dati, utilizzare l'opzione
In particolare, la prima
La scheda di rete può anche essere indicata con il numero ad essa associato, così come risultante dall'esecuzione dell'opzione
che stampa la lista delle interfacce di rete disponibili, alle quali
Intercettare tutto il traffico TCP/IP, magari mettendosi in ascolto su tutte le interfacce di rete, può rivelarsi un lavoro molto oneroso e potrebbe comportare la perdita di tutti quei pacchetti di dati che
Tcpdump stampa il contenuto dei pacchetti di dati che transitano nella scheda di rete e che soddisfano le condizioni presenti nell'espressione booleana. La descrizione del contenuto del singolo pacchetto è preceduta dalla notazione temporale, espressa in ore, minuti, secondi, frazione di secondo a partire dalla mezzanotte:
Per escludere il timestamp:
Per visualizzare un timestamp non formattato:
che stampa il numero dei secondi trascorsi dal 1 gennaio 1970, alle ore 00:00:00, UTC, e le frazioni di secondo trascorse da quel momento. Per stampare solo la differenza in millisecondi tra la transazione corrente e quella precedente:
Per stampare, oltre all'orario, anche la data:
Per stampare solo la differenza in millisecondi tra la transazione corrente e la prima transazione (la prima riga dell'output):
Il comando
chiuderà il programma
specificando il numero di byte desiderato. Il comando:
imposta il valore al valore di default: 65535 byte. Ricorda che una grandezza eccessiva aumenta il tempo impiegato da tcpdump per elaborare i pacchetti di dati, diminuendo, di fatto, la quantità di pacchetti catturati. È consigliabile, quindi, limitare il numero dei byte al valore minimo che permetta di catturare le informazioni che stiamo cercando, sapendo che
Quindi, per selezionare i pacchetti di dati che abbiano impostato a 1 i valori SYN e ACK, bisognerà catturare i primi 13 byte dei datagramma, salvarli in un file (vedremo poi come) e far leggere il file a
che è pari al valore decimale 18. Una volta salvato l'output nel file dumpfile, quindi, dovremo eseguire il comando:
Lo stesso principio vale per tutte le altre flag:
Un'altra accortezza che potrebbe ridurre i tempi di risposta di
Per disabilitare la risoluzione dei nomi, utilizziamo l'opzione
È possibile selezionare anche quali pacchetti di dati scaricare (dump), indicandoli nella sezione espressione:
Questo è tra gli esempi più semplici, e chiede a tcpdump di scaricare i pacchetti di dati in arrivo da o in partenza per l'host sundown. Le espressioni TCPDUMP sono anche note come BPF, o Berkeley Packet Filters. Sulla riga di comando sono da scrivere tra virgolette singole, così da evitare confusioni ed errori di interpretazione. L'espressione è fatta da uno o più primitivi (primitives). I primitivi, normalmente, sono composti da un identificativo (nome o numero: sundown, nel nostro esempio), preceduto da uno o più qualificatori (qualifiers: host, nel nostro esempio). Esistono tre differenti tipi di qualifier:
Per catturare pacchetti di dati HTTP (port 80), provenienti o dall'indirizzo IP 192.168.122.98 oppure dall'indirizzo IP 54.204.39.132, eseguite:
Per selezionare i pacchetti in basi ai protocolli che li hanno generati:
I protocolli ARP ( Address Resolution Protocol ) e RARP ( Reverse Address Resolution Protocol ) sono due protocolli che fanno da ponte tra la rete fisica sottostante ( normalmente, Ethernet ) e la rete internet. Una rete fisica sottostante, quale Ethernet, parla un suo proprio linguaggio ( protocollo ) e si serve dell'indirizzo fisico delle macchine, per connettere una macchina all'altra. L'indirizzo fisico delle macchine è l'indirizzo fisico della singola scheda di rete e viene assegnato direttamente dal produttore della scheda. Un indirizzo fisico di una scheda di rete, quindi, può avere un formato variabile, a seconda del protocollo che gestirà quella scheda. Il protocollo Ethernet utilizza il cosiddetto MAC address, o indirizzo MAC ( Media Access Control ), un indirizzo composto da 48 bit. Il protocollo IP, invece, utilizza indirizzi numerici a 32 ( IPv4 ) oppure 128 bit ( IPv6 ), che non hanno alcuna relazione con gli indirizzi MAC. Ogni volta in cui un pacchetto IP di dati deve essere trasmesso dal computer host al router, o viceversa, quel pacchetto deve attraversare un pezzo di rete fisica, gestita da un protocollo diverso da IP, Ethernet nel nostro caso, un protocollo che non è in grado di gestire gli indirizzi IP. Quindi, deve esistere un software che esegua la risoluzione ( conversione ) tra l'indirizzo IP del computer host o del router ed il corrispondente indirizzo fisico, o MAC address. I software, fondati sul protocollo ARP, eseguono la risoluzione tra indirizzo IP ed indirizzo MAC, mentre i software, fondati sul protocollo RARP eseguono l'operazione inversa, risolvendo gli indirizzi MAC nei corrispondenti indirizzi IP. Il meccanismo utilizzato da ARP è semplicissimo: quando un router o un host di una rete riceve un pacchetto di dati, contenente un indirizzo IP di destinazione e quell'indirizzo IP appartiene alla stessa rete fisica del router o della macchina che lo ha ricevuto, il router o la macchina che ha ricevuto il pacchetto di dati prepara un datagramma ARP e lo invia a tutte le macchine collegate alla medesima rete ( messaggio Broadcast ): La macchina host alla quale era stato assegnato l'indirizzo IP ricercato, invierà, al mittente, e solo al mittente ( messaggio Unicast ), un datagramma di risposta. Il datagramma di richiesta contiene una sola domanda: chi ha questo indirizzo IP? Il datagramma di risposta, ovviamente, contiene la risposta: questo indirizzo IP è mio, ed io ho un indirizzo MAC pari a XYZ. Un datagramma ARP contiene i seguenti dati:
Naturalmente, quando un host o un router invia una richesta ARP, deve lasciare in bianco il campo dell'indirizzo fisico di destinazione, Target Hardware Address, visto che è proprio il pezzo di informazione che sta richiedendo. Nel caso del protocollo ARP ( Address Resolution Protocol ), che restituisce la corrispondenza tra l'indirizzo IP e l'indirizzo fisico di rete ( MAC address, nel caso di reti Ethernet ) di un computer, il formato dell'output è molto semplice:
La prima riga, inviata, alle ore 23:40:03 e 449919 microsecondi ( un milionesimo di secondo ), dice che la macchina di nome " rtsg " ha inviato un pacchetto ARP, chiedendo l'indirizzo fisico Ethernet della macchina di nome " csam ". La macchina di nome " csam " risponde ( Reply ), inviando il suo indirizzo Ethernet ( in questo esempio, l'indirizzo fisico viene nascosto e sostituito con il nome della macchina in lettere maiuscole ). Per chiedere a
dove:
è l'indirizzo IP di " csam ",
è l'indirizzo IP di " rtsg ",
è il MAC address di " csam " e
è la maschera di rete che indica una comunicazione broadcast. I pacchetti ARP Request vengono inviati a tutte le macchine appartenenti alla rete locale ( Broadcast ), mentre i pacchetti di risposta ( Reply ) vengono inviati, dalla macchina detentrice dell'indirizzo IP contenuto nella richiesta, alla macchina che aveva inviato la richiesta. Questo risulta ancora più chiaro, se chiediamo a
dove i nomi delle macchine, CSAM e RTSG, sono, in realtà, rappresentati dai loro indirizzi fisici MAC, nella forma:
L'opzione Un frame Ethernet è composto da tre sezioni:
In realtà, esitono due differenti formati per il frame Ethernet:
La differenza tra i due formati è l'uso di un campo di due byte che per Ethernet contiene un numero di protocollo in azione, mentre per IEEE 802.3 contiene la lunghezza del campo data nella frame. La lunghezza massima di un frame Ethernet è di 1526 byte. Quindi, il campo dei dati trasportati può arrivare a 1500 byte. Questo vale anche per 802.3, ma solo per velocità fino a 10 Mbps, mentre può variare per velocità superiori. In all specifications, the type values contained within this field are simply known as Ethertypes. This field, as described in IEEE Std 802.3 Clause 3.2.6, is two-octets long and takes one of two meanings depending on its numeric value. For numeric evaluation, the first octet is the most significant octet of this field. When the values of this field is greater than or equal to 1536 decimal (equal to 0600hexadecimal) the Length/Type field indicates the nature of the MAC client protocol (type interpretation). The length and type interpretations of this field are mutually exclusive. (ieee.org) TCP ( Transfer Control Protocol ) è il protocollo che gestisce le comunicazioni tra un host e l'altro, mettendo in atto una serie di strategie che rendano quelle comunicazioni affidabili. Affinchè una comunicazione possa essere considerata affidabile, TCP tiene traccia di tutti i pacchetti di dati inviati, si preoccupa di verificare che ogni singolo pacchetto di dati sia arrivato a destinazione, che vi sia arrivato integro, reinviandolo, nel caso non fosse stato consegnato, e che il computer di destinazione sia in grado di riassemblare tutti i pacchetti di dati ricevuti, nello stesso ordine in cui erano stati inviati. TCP prende in consegna i dati da spedire dall'applicazione utente, li impacchetta in un datagramma e consegna il suo datagramma, completo di header ( intestazioni ) e dati dell'applicazione, al protocollo di livello inferiore, che si occuperà del trasporto vero e proprio: il protocollo IP. I molti campi presenti nell'header TCP rispecchiano la complessità e la vastità dei compiti assegnati a questo protocollo. I campi presenti in un header TCP sono i seguenti:
Per le transazioni TCP, per comprendere l'output restituito dal comando
dove:
rappresentano, rispettivamente, il nome o l'indirizzo IP, completo di nome o numero di porta, del computer di origine ( src: source ) del datagramma e del computer di destinazione ( dst: destination ). Se si desidera che la coppia indirizzo IP.portaTCP venga scritta con gli indirizzi numerici, senza che venga fatta la risoluzione dei nomi, utilizzare l'opzione
FLAGS è un campo in cui possono apparire uno o più dei seguenti simboli:
che indicano il tipo di datagramma in transito ed esprimono il valore degli 8 bit di controllo, contenuti nell'header TCP. I campi SRC, DST e FLAGS sono sempre presenti, mentre la presenza o meno di ciascuno degli altri campi dipende dal contenuto dell'header del datagramma TCP. Il campo " Data-seqno " descrive la porzione occupata dai dati, contenuti nel datagramma corrente, nello spazio dell'intera sequenza:
ACK, come abbiamo già visto, è il numero di sequenza iniziale che il computer corrente si aspetta per il prossimo datagramma proveniente dal computer all'altro capo della connessione:
Il campo WINDOW è il numero di byte dedicati allo spazio di buffer, nel computer all'altro capo della connessione:
Del campo URG, abbiamo già parlato. Le opzioni sono le eventuali opzioni TCP attive. Per esempio:
Vediamo, come esempio, una porzione di un accesso ( rlogin ) al server " csam ", dal computer ( host ) " rtsg ":
La prima riga dice che il computer chiamato " rtsg " ha inviato, dalla porta 1023, un pacchetto di dati al computer di nome " csam ", con porta di nome " login ". Il datagramma aveva la flag S attiva ( SYN message ). Il valore del numero di sequenza iniziale e finale era 768512: questo significa che il pacchetto non conteneva dati ( 0 ). Non era presente alcun ACK, la finestra dati ( window ) accettava 4096 byte e c'era un'opzione attiva che chiedeva di impostare il valore del MSS ( max-segment-size ) a 1024 byte:
Il computer " csam " risponde con un suo messaggio SYN, inviando un ACK, relativo al messaggio SYN di " rtsg ".
Il computer " rtsg ", quindi, conferma la ricezione ( ACK ) del messaggio SYN di " csam ":
Il punto (
Alla sesta riga, " rtsg " invia, a " csam ", 19 byte ( dal byte 2 al byte 20, " rtsg " → " csam " ). La flag PUSH è impostata:
Alla settima riga, " csam " conferma di aver ricevuto i dati inviati da " rtsg ", fino al byte 21 ( escluso ):
La gran parte di quei dati sembrano essere ancora nel buffer del socket, visto che la finestra dati di " csam " è più piccola di 19 byte ( 4096 - 4077 ). Nello stesso datagramma, " csam " ha inviato, a " rtsg ", 1 byte di dati. Alla ottava e nona riga, " csam " invia, a " rtsg ", due byte, in modalità URGENT e PUSH:
UDP ( User Datagram Protocol ), come TCP ( Transmission Control Protocol ), è l'altro protocollo che gestisce le comunicazioni tra un host e l'altro, ma, a differenza di TCP, non si preoccupa affatto di rendere quelle comunicazioni affidabili. Intanto, una premessa doverosa: qualsiasi applicazione, utente o di sistema, dovesse comunicare con un host remoto, utilizzando TCP/IP, deve, prima di inviare i dati a IP, inviarli ad uno, ed uno solo, dei due protocolli di trasporto: TCP o UDP. La scelta tra i due è dettata dalle esigenze di trasporto: volete una consegna affidabile, tracciata in ogni suo componente e garantita? Scegliete TCP. Desiderate inviare i vostri pacchetti di dati, in modo che arrivino a destinazione il più presto possibile, senza perdere tempo in inutili controlli e verifiche continue? Scegliete UDP. Il meccanismo di trasporto UDP, ottimale per applicazioni di videoconferenza, giochi, chat, nelle quali la consegna tempestiva è il requisito più importante, viene definito " consegna con il massimo sforzo ": UDP invia i dati: se arrivano, bene! Se non arrivano, va bene lo stesso. Se arrivano in ritardo o danneggiati, va bene ugualmente! I dati persi vengono semplicemente dimenticati, mentre i dati danneggiati vengono eliminati. Nessuna sessione di comunicazione, nessuna ritrasmissione dei pacchetti di dati persi. Questa semplificazione del processo di invio si riflette, ovviamente, anche nelle dimensioni del datagramma UDP, che è composto, oltre che dai dati dell'applicazione, da pochi ed essenziali header:
Tutto qui! UDP non prevede alcun handshake a tre vie ne' altri meccanismi per l'apertura di una sessione. La mancanza di un qualsiasi meccanismo per l'apertura e la gestione di una sessione porta molte persone a definire UDP un protocollo senza connessione. Uno dei servizi che utilizzano il protocollo UDP è il Domain Name service requests ( RFC-1034 e RFC 1035 ), che permette ad un host di chiedere ad un server DNS la risoluzione di un nome a dominio. Le richieste al Name server hanno il seguente formato:
dove:
Tutti gli altri campi sono campi delle intestazioni DNS:
Un esempio di richiesta DNS:
dove l'host
dove, oltre ai campi che già conosciamo, troviamo:
In questa risposta, i campi
In questo secondo esempio di risposta, con ID 2, vediamo una risposta che indica un non-existent domain ( NXDomain ), o dominio inesistente, una risposta che è da considerarsi autorevole, vista la presenza dell'asterisco, nessuna risposta ( 0 ), un Name Server ( 1 ) e nessun record " authority " ( 0 ).
TCP e UDP hanno la responsabilità di prelevare i dati da una applicazione ( utente o di sistema ) e di preparare l'ambiente di spedizione. Entrambi questi protocolli, però, non conoscono nulla della rete e di come permettere ai dati di attraversarla e di raggiungere la loro destinazione finale. TCP e UDP nemmeno conoscono il metodo di indirizzamento dei pacchetti di dati. Questo accade perchè la responsabilità del trasporto vero e proprio dei dati cade sul protocollo di livello inferiore: IP ( Internet Protocol ). IP è il protocollo che crea una rete virtuale che funziona e opera indipendentemente dalla reale rete sottostante, rappresentata dal livello hardware (LLC, Logical Link Control e MAC, Media Access Control). IP è un protocollo per la trasmissione di pacchetti di dati, ed è un protocollo inaffidabile, best-effort, connectionless: questo significa che IP non si preoccupa di sapere se un pacchetto di dati è arrivato a destinazione o se è stato spedito o ricevuto nell'ordine corretto o se è stato spedito più volte (duplicato). Queste verifiche sono di competenza dei protocolli del livello superiore: il transport layer (TCP/UDP). Il protocollo IP riceve il segmento ( datagramma ) TCP, oppure UDP, oppure, in casi particolari, anche ICMP, segmento che comprende sia i dati dell'applicazione, sia le intestazioni ( header ) TCP, oppure UDP, oppure ICMP, e crea un nuovo pacchetto, aggiungendo, al segmento ricevuto, le sue intestazioni ( header ), tra le quali troveremo le informazioni utili all'indirizzamento ed all'instradamento del nuovo pacchetto di dati:
Abbiamo già visto, nel paragrafo precedente, i record IP pubblicati da
ICMP ( Internet Control Message Protocol ) è il protocollo, introdotto con la RFC 792, che ha il compito di trasportare i messaggi di sistema ( di errore, di feedback e di test ). Un datagramma ICMP è estremamente complesso, poichè cambia struttura, a seconda del tipo di messaggio che trasporta. I messaggi ICMP utilizzano gli stessi header IP di base ed occupano, di un pacchetto IP, l'area destinata ai dati:
In questo pacchetto di dati IP, i primi 20 byte (in neretto) contengono l'header IP. Dal 21esimo byte inizia il payload del pacchetto IP e, quindi, l'header ICMP. Il primo ottetto dell'header ICMP è il campo type che determina il formato dei dati successivi. Un type offre una descrizione generica del tipo di messaggio trasportato, mentre il campo ICMP successivo, Code, ne offre una descrizione più dettagliata. Anche il campo Code occupa 8 bit:
Nel messaggio di Destinazione irraggiungibile, i Code 0, 1, 4, 5 arrivano da un gateway, mentre i Code 2 e 3 arrivano da un host. Il terzo campo dell'header ICMP Destinazione irraggiungibile è la checksum (16 bit), che si calcola a partire dal campo Type, seguito da un campo a zero (unused), di 16 o 32 bit, seguito, a sua volta, dall'l'intero header IP del pacchetto di dati per il quale si è verificato l'errore, seguito dai 64 bit della sua area dati ( payload ).
Nel messaggio di echo request e nel messaggio conseguente, echo reply, Type che hanno un solo Code, la struttura della frame comprende due nuovi campi:
Il Campo Identifier ( 16 bit ) può essere usato come TCP o UDP utilizzano i numeri di porta, per identificare una sessione, mentre il campo Sequence Number può essere incrementato per ogni richiesta echo inviata. La risposta echo, invece, dovrà contenere gli stessi valori contenuti nella richiesta. I dati ricevuti nell'echo message, infatti, devono essere ritrasmessi nell'echo reply message. I dati del payload di un ICMP Echo Request packet sono usati come padding. ICMP Echo Reply packet deve contenere gli stessi dati contenuti nella ICMP Echo request. Filtri per selezionare il traffico da intercettare E' possibile chiedere a
oppure destinato ( dst, destination ) ad un determinato host ( computer ):
oppure originato da o destinato a un determinato host:
E' possibile, anche, specificare il nome dell'host, piuttosto che l'indirizzo IP: l'importante è che non sia stata impostata l'opzione
Come per gli host, è possibile specificare una porta di origine, oppure una porta di destinazione oppure entrambe:
oppure, ancora, un range di porte:
E' possibile specificare una intera rete da intercettare, sia come origine del traffico da catturare, sia come destinazione, sia per entrambi, specificando la rete con la notazione CIDR ( Classless Inter-Domain Routing ):
E' possibile specificare un protocollo di cui intercettare il traffico:
E' possibile specificare un indirizzo di rete Ethernet ( MAC address ), sia come origine del traffico da catturare, sia come destinazione, sia per entrambi:
Del traffico Ethernet, così come del traffico IP, è possibile intercettare solo quello di tipo Broadcast, oppure Multicast:
E' possibile utilizzare gli operatori booleani per combinare più espressioni. Gli operatori booleani disponibili sono:
Per esempio:
E' possibile, infine, catturare i pacchetti di dati TCP, che abbiano attivati uno o più bit di flag ( SYN-ACK, URG-ACK, etc. ). Come abbiamo visto in precedenza, gli otto bit di FLAG sono contenuti nel 14esimo byte dell'header TCP. Questo significa che, all'interno dell'array composto dai byte compresi nell'header TCP, gli otto bit delle FLAG sono rappresentabili, come byte:
All'interno dell'array con indice 13 ( un byte ), poi, troviamo i singoli bit, cioè le singole FLAG:
numerate come segue:
E' facile comprendere, a questo punto, come sia possibile rappresentare le varie configurazioni che l'intero byte può assumere, a seconda dell'attivazione di uno o più bit, interpretando l'intero byte come un numero intero senza segno a 8 bit ( 8-bit unsigned integer ), nell'ordine network byte. Per esempio, quando avessimo:
sarebbe chiaro che il solo bit attivo sarebbe il bit FIN:
Quando invece avessimo:
sarebbe chiaro che il solo bit attivo sarebbe il bit SYN:
E così via. Anche le eventuali combinazioni di bit verrebbero identificate nello stesso modo. Per esempio, un bit ACK ed un bit SYN attivi, come avviene nella risposta SYN-ACK, darebbe come risultato:
Quindi, per chiedere a
oppure, per i pacchetti di dati di tipo SYN-ACK, dovremo eseguire:
E se dovessimo rappresentare l'ipotesi del bit SYN attivo, a prescindere che siano, o meno, attivi altri bit? Come possiamo chiedere a
Come è facilmente intuibile, l'AND logico restituisce il solo bit SYN attivo. Questa operazione può essere data in pasto a
Questo comando restituirà tutti i pacchetti di dati con il bit SYN attivo, sia abbinato a qualche altro bit attivo, sia come unico bit attivo. Alcuni campi possono essere espressi con i loro nomi, piuttosto che con il loro numero di indice. Per esempio:
Ricordarsi di eseguire l'escape sul carattere AND (
selezionerà tutti i pacchetti di dati TCP che nei primi due byte dell'header ( da offset 0
Il comando
contiene i 2 byte dell'header IP, che hanno inizio dal byte 2 ( in un array, il conteggio dell'indice parte sempre da zero ). Sappiamo che il terzo ed il quarto byte dell'header IP contengono la lunghezza totale del datagramma IP, misurata in ottetti e comprendente l'intestazione IP ed il payload ( che comprende, a sua volta, l'intestazione, o header, TCP oppure UDP ). Quindi, se volessimo catturare i pacchetti di dati IP, la cui lunghezza fosse superiore ai 52 byte, per esempio, dovremmo eseguire il seguente comando:
L'opzione
che, come è evidente, da, come risultato, i due gruppi, di 4 bit ciascuno, seguenti:
Quello che a noi interessa è il valore contenuto nel primo gruppo: 4, che è la versione IP, ma è chiaro che l'intera sequenza di bit ( byte ) da, come risultato:
Ecco perchè, per verificare la sola versione IP, la sintassi del comando dovrà essere:
per la versione 4, e:
per la versione 6. Alla pagina Guida all’uso di TCPDUMP, trovate l'ottima guida a Per salvare i dati catturati da
Attenzione: l'attività TCP, nel vostro computer, potrebbe essere molto frenetica. In questo caso, potreste, nel giro di pochi minuti, generare un file enorme. Utilizzate, eventualmente, anche l'opzione
In questo esempio, stiamo chiedendo a
con le eventuali opzioni di cui abbiamo bisogno. Per esempio:
per stampare a video l'output in formato ASCII. La possibilità di un'analisi a posteriore dell'output, attraverso la creazione di un file, è molto utile, soprattutto, se abbinata al comando
oppure, abbinata al comando
E' anche possibile selezionare il traffico da catturare, prima di salvarlo nel file:
Un altro modo per salvare l'output in un file, pur facendolo scorrere a video, è utilizzare l'opzione
Attenzione: l'opzione
Questo significa che le opzioni di selezione del traffico e di visualizzazione devono essere scelte prima della creazione del file. Per esempio:
E' anche possibile abbinare le opzioni di salvataggio e le opzioni di visualizzazione dei dati. Per esempio, la riga di comando:
cattura tutto il traffico in transito, lo scrive, in formato ASCII ( A ) nel file
|
||||||||
I comandi Linux: la rete ( 4 ) | The .bit guides: original contents |