Passa al contenuto principale

8. On-Wire Protocol (Protocollo su cavo)

Il cuore del protocollo NTP su cavo è il meccanismo centrale (core mechanism) che scambia valori temporali tra server, peer e client. È intrinsecamente resistente ai pacchetti persi o duplicati. L'integrità dei dati è fornita dai checksum IP e UDP. Non sono fornite né necessarie strutture di controllo di flusso o ritrasmissione. Il protocollo utilizza timestamp, che vengono estratti dalle intestazioni dei pacchetti o ottenuti dall'orologio di sistema all'arrivo o alla partenza di un pacchetto. I timestamp sono dati di precisione e devono essere riottenuti in caso di ritrasmissione a livello di collegamento e corretti per il tempo necessario a calcolare un MAC in trasmissione.

I messaggi NTP utilizzano due diverse modalità di comunicazione, uno-a-uno e uno-a-molti (one-to-one and one-to-many), comunemente chiamate unicast e broadcast. Ai fini di questo documento, il termine broadcast è interpretato come qualsiasi meccanismo uno-a-molti disponibile. Per IPv4, questo equivale a broadcast IPv4 o multicast IPv4. Per IPv6, questo equivale a multicast IPv6. A questo scopo, IANA ha allocato l'indirizzo multicast IPv4 224.0.1.1 e l'indirizzo multicast IPv6 che termina con :101, con il prefisso determinato dalle regole di ambito. Qualsiasi altro indirizzo multicast non allocato può anche essere utilizzato oltre a questi indirizzi multicast allocati.

Il protocollo su cavo utilizza quattro timestamp numerati da t1 a t4 e tre variabili di stato org, rec e xmt, come mostrato nella Figura 15. Questa figura mostra il caso più generale in cui ciascuno di due peer, A e B, misura indipendentemente l'offset e il ritardo rispetto all'altro. A scopo illustrativo, i timestamp dei pacchetti sono mostrati in minuscolo, mentre le variabili di stato sono mostrate in maiuscolo. Le variabili di stato vengono copiate dai timestamp dei pacchetti all'arrivo o alla partenza di un pacchetto.

          t2            t3           t6            t7
+---------+ +---------+ +---------+ +---------+
| 0 | | t1 | | t3 | | t5 |
+---------+ +---------+ +---------+ +---------+
| 0 | | t2 | | t4 | | t6 | Packet
+---------+ +---------+ +---------+ +---------+ Timestamps
| t1 | |t3=clock | | t5 | |t7=clock |
+---------+ +---------+ +---------+ +---------+
|t2=clock | |t6=clock |
+---------+ +---------+
Peer B
+---------+ +---------+ +---------+ +---------+
org | T1 | | T1 | | t5<>T1? | | T5 |
+---------+ +---------+ +---------+ +---------+ State
rec | T2 | | T2 | | T6 | | T6 | Variables
+---------+ +---------+ +---------+ +---------+
xmt | 0 | | T3 | | t3=T3? | | T7 |
+---------+ +---------+ +---------+ +---------+

t2 t3 t6 t7
---------------------------------------------------------
/\ \ /\ \
/ \ / \
/ \ / \
/ \/ / \/
---------------------------------------------------------
t1 t4 t5 t8

t1 t4 t5 t8
+---------+ +---------+ +---------+ +---------+
| 0 | | t1 | | t3 | | t5 |
+---------+ +---------+ +---------+ +---------+
| 0 | | t2 | | t4 | | t6 | Packet
+---------+ +---------+ +---------+ +---------+ Timestamps
|t1=clock | | t3 | |t5=clock | | t7 |
+---------+ +---------+ +---------+ +---------+
|t4=clock | |t8=clock |
+---------+ +---------+
Peer A
+---------+ +---------+ +---------+ +---------+
org | 0 | | t3<>0? | | T3 | | t7<>T3? |
+---------+ +---------+ +---------+ +---------+ State
rec | 0 | | T4 | | T4 | | T8 | Variables
+---------+ +---------+ +---------+ +---------+
xmt | T1 | | t1=T1? | | T5 | | t5=T5? |
+---------+ +---------+ +---------+ +---------+

Figura 15: Protocollo su cavo

Nella figura, il primo pacchetto trasmesso da A contiene solo il timestamp di origine (origin timestamp) t1, che viene quindi copiato in T1. B riceve il pacchetto a t2 e copia t1 in T1 e il timestamp di ricezione t2 in T2. In questo momento o in qualche momento successivo a t3, B invia un pacchetto ad A contenente t1 e t2 e il timestamp di trasmissione t3. Tutti e tre i timestamp vengono copiati nelle corrispondenti variabili di stato. A riceve il pacchetto a t4 contenente i tre timestamp t1, t2 e t3 e il timestamp di destinazione t4. Questi quattro timestamp vengono utilizzati per calcolare l'offset e il ritardo di B rispetto ad A, come descritto di seguito.

Prima che le variabili di stato xmt e org vengano aggiornate, vengono eseguiti due controlli di integrità (sanity checks) per proteggersi da pacchetti duplicati, falsi o riprodotti. Nello scambio sopra, un pacchetto è duplicato o riprodotto se il timestamp di trasmissione t3 nel pacchetto corrisponde alla variabile di stato org T3. Un pacchetto è falso se il timestamp di origine t1 nel pacchetto non corrisponde alla variabile di stato xmt T1. In entrambi questi casi, le variabili di stato vengono aggiornate, quindi il pacchetto viene scartato. Per proteggersi dalla riproduzione dell'ultimo pacchetto trasmesso, la variabile di stato xmt viene impostata a zero immediatamente dopo un controllo di falsità riuscito.

I quattro timestamp più recenti, da T1 a T4, vengono utilizzati per calcolare l'offset di B rispetto ad A

theta = T(B) - T(A) = 1/2 * [(T2-T1) + (T3-T4)]

e il ritardo di andata e ritorno (round-trip delay)

delta = T(ABA) = (T4-T1) - (T3-T2).

Si noti che le quantità tra parentesi sono calcolate da timestamp senza segno a 64 bit e risultano in valori con segno con 63 bit significativi più segno. Questi valori possono rappresentare date da 68 anni nel passato a 68 anni nel futuro. Tuttavia, l'offset e il ritardo sono calcolati come somme e differenze di questi valori, che contengono 62 bit significativi e due bit di segno, quindi possono rappresentare valori non ambigui da 34 anni nel passato a 34 anni nel futuro. In altre parole, il tempo del client deve essere impostato entro 34 anni del server prima dell'avvio del servizio. Questa è una limitazione fondamentale con l'aritmetica intera a 64 bit.

Nelle implementazioni in cui è disponibile l'aritmetica a virgola mobile doppia (floating double arithmetic), le differenze di primo ordine possono essere convertite in virgola mobile doppia e le somme e differenze di secondo ordine calcolate in tale aritmetica. Poiché i termini di secondo ordine sono tipicamente molto piccoli rispetto alle magnitudini dei timestamp, non vi è perdita di significatività, ma l'intervallo non ambiguo viene ripristinato da 34 anni a 68 anni.

In alcuni scenari in cui l'offset di frequenza iniziale del client è relativamente grande e il tempo di propagazione effettivo piccolo, è possibile che il calcolo del ritardo diventi negativo. Ad esempio, se la differenza di frequenza è 100 ppm e l'intervallo T4-T1 è 64 s, il ritardo apparente è -6,4 ms. Poiché i valori negativi sono fuorvianti nei calcoli successivi, il valore di delta deve essere limitato a non meno di s.rho, dove s.rho è la precisione del sistema descritta nella Sezione 11.1, espressa in secondi.

La discussione sopra assume il caso più generale in cui due peer simmetrici misurano indipendentemente gli offset e i ritardi tra loro. Nel caso di un server senza stato (stateless server), il protocollo può essere semplificato. Un server senza stato copia T3 e T4 dal pacchetto del client a T1 e T2 del pacchetto del server e aggiunge il timestamp di trasmissione T3 prima di inviarlo al client. Ulteriori dettagli per compilare i campi del protocollo rimanenti sono forniti nella Sezione 9 e nelle sezioni successive e nell'appendice.

Si noti che il protocollo su cavo come descritto resiste alla riproduzione di un pacchetto di risposta del server. Tuttavia, non resiste alla riproduzione del pacchetto di richiesta del client, che risulterebbe in un pacchetto di risposta del server con nuovi valori di T2 e T3 e risulterebbe in offset e ritardo errati. Questa vulnerabilità può essere evitata impostando la variabile di stato xmt a zero dopo aver calcolato l'offset e il ritardo.