Passa al contenuto principale

3. Protocollo di Tempo di Rete

Questa sezione consiste in una definizione formale del Protocollo di Tempo di Rete, inclusi i suoi formati di dati, entità, variabili di stato, eventi e procedure di elaborazione degli eventi. La specifica si basa sul modello di implementazione illustrato nella Figura 1, ma non è inteso che questo modello sia l'unico su cui può essere basata una specifica. In particolare, la specifica è destinata a illustrare e chiarire le operazioni intrinseche di NTP, nonché a servire come fondamento per una specifica più rigorosa, completa e verificabile.

3.1. Formati dei Dati

Tutte le operazioni matematiche espresse o implicite qui sono in aritmetica a virgola fissa in complemento a due. I dati sono specificati come quantità intere o a virgola fissa, con bit numerati in modo big-endian da zero partendo dalla posizione sinistra o di ordine superiore. Poiché varie implementazioni possono scalare quantità derivate esternamente per uso interno, né la precisione né il posizionamento del punto decimale per quantità a virgola fissa sono specificati. Salvo diversa indicazione, tutte le quantità sono senza segno e possono occupare l'intera larghezza del campo con uno zero implicito che precede il bit zero. I pacchetti hardware e software progettati per funzionare con quantità con segno produrranno quindi risultati sorprendenti quando il bit più significativo (segno) è impostato. Si suggerisce che le quantità a virgola fissa senza segno derivate esternamente come i timestamp vengano spostate di un bit a destra per uso interno, poiché la precisione rappresentata dall'intera larghezza del campo è raramente giustificata.

Poiché i timestamp NTP sono dati preziosi e, di fatto, rappresentano il prodotto principale del protocollo, è stato stabilito un formato di timestamp speciale. I timestamp NTP sono rappresentati come un numero a virgola fissa senza segno a 64 bit, in secondi relativi alle 0h del 1 gennaio 1900. La parte intera è nei primi 32 bit e la parte frazionaria negli ultimi 32 bit. Questo formato consente un'aritmetica multi-precisione conveniente e la conversione in rappresentazione del Protocollo di Tempo (secondi), ma complica la conversione in rappresentazione del messaggio di timestamp ICMP (millisecondi). La precisione di questa rappresentazione è di circa 200 picosecondi, che dovrebbe essere adeguata anche per i requisiti più esotici.

I timestamp sono determinati copiando il valore corrente dell'orologio locale in un timestamp quando si verifica un evento significativo, come l'arrivo di un messaggio. Per mantenere la massima accuratezza, è importante che questo sia fatto il più vicino possibile al driver hardware o software associato all'evento. In particolare, i timestamp di partenza dovrebbero essere rideterminati per ogni ritrasmissione a livello di collegamento. In alcuni casi un particolare timestamp potrebbe non essere disponibile, ad esempio quando l'host viene riavviato o il protocollo si avvia per la prima volta. In questi casi il campo a 64 bit è impostato su zero, indicando che il valore è non valido o non definito.

Si noti che da un certo momento nel 1968 il bit più significativo (bit 0 della parte intera) è stato impostato e che il campo a 64 bit traboccherà in un certo momento nel 2036. Se NTP sarà in uso nel 2036, saranno necessari mezzi esterni per qualificare il tempo relativo al 1900 e il tempo relativo al 2036 (e altri multipli di 136 anni). I dati con timestamp che richiedono tale qualificazione saranno così preziosi che mezzi appropriati dovrebbero essere facilmente disponibili. Esisterà un intervallo di 200 picosecondi, d'ora in poi ignorato, ogni 136 anni quando il campo a 64 bit sarà zero e quindi considerato non valido.

3.2. Variabili di Stato e Parametri

Quello che segue è un riepilogo delle varie variabili di stato e parametri utilizzati dal protocollo. Sono separati in classi di variabili di sistema, che si riferiscono all'ambiente del sistema operativo e al meccanismo dell'orologio locale; variabili di peer, che rappresentano lo stato della macchina di protocollo specifica per ciascun peer; variabili di pacchetto, che rappresentano il contenuto del messaggio NTP; e parametri, che rappresentano costanti di configurazione fisse per tutte le implementazioni della versione corrente. Per ciascuna classe, la descrizione della variabile è seguita dal suo nome e dalla procedura o valore che la controlla. Si noti che le variabili sono in minuscolo, mentre i parametri sono in maiuscolo. Ulteriori dettagli sui formati e sull'uso sono presentati nelle sezioni e appendici successive.

3.2.1. Variabili Comuni

Le seguenti variabili sono comuni a due o più delle classi sistema, peer e pacchetto. Variabili aggiuntive sono specifiche per il meccanismo di autenticazione opzionale descritto nell'Appendice C. Quando è necessario distinguere tra variabili comuni con lo stesso nome, verrà utilizzato l'identificatore della variabile.

Indirizzo del Peer (Peer Address,peer.peeraddr, pkt.peeraddr), Porta del Peer (Peer Port,peer.peerport, pkt.peerport): Questi sono l'indirizzo Internet a 32 bit e il numero di porta a 16 bit del peer.

Indirizzo dell'Host (Host Address,peer.hostaddr, pkt.hostaddr), Porta dell'Host (Host Port,peer.hostport, pkt.hostport): Questi sono l'indirizzo Internet a 32 bit e il numero di porta a 16 bit dell'host. Sono inclusi tra le variabili di stato per supportare il multi-homing.

Indicatore di Salto (Leap Indicator,sys.leap, peer.leap, pkt.leap): Questo è un codice a due bit che avverte di un imminente secondo intercalare da inserire nella scala temporale NTP. I bit vengono impostati prima delle 23:59 del giorno di inserimento e reimpostati dopo le 00:00 del giorno seguente. Ciò fa sì che il numero di secondi (intervallo di rollover) nel giorno di inserimento venga aumentato o diminuito di uno. Nel caso dei server primari i bit vengono impostati dall'intervento dell'operatore, mentre nel caso dei server secondari i bit vengono impostati dal protocollo. I due bit, bit 0 e bit 1, rispettivamente, sono codificati come segue:

ValoreSignificato
00nessun avviso
01l'ultimo minuto ha 61 secondi
10l'ultimo minuto ha 59 secondi
11condizione di allarme (orologio non sincronizzato)

In tutti i casi tranne la condizione di allarme (11₂), NTP stesso non fa nulla con questi bit, tranne passarli alle routine di conversione del tempo che non fanno parte di NTP. La condizione di allarme si verifica quando, per qualsiasi motivo, l'orologio locale non è sincronizzato, ad esempio durante il primo avvio o dopo un periodo prolungato in cui nessuna fonte di riferimento primaria è disponibile.

Modalità (Mode,peer.mode, pkt.mode): Questo è un intero che indica la modalità di associazione, con valori codificati come segue:

ValoreModalità
0non specificato
1simmetrico attivo
2simmetrico passivo
3client
4server
5broadcast
6riservato per messaggi di controllo NTP
7riservato per uso privato

Strato (Stratum,sys.stratum, peer.stratum, pkt.stratum): Questo è un intero che indica lo strato dell'orologio locale, con valori definiti come segue:

ValoreSignificato
0non specificato
1riferimento primario (es. orologio atomico calibrato, orologio radio)
2-255riferimento secondario (via NTP)

Ai fini del confronto, un valore di zero è considerato maggiore di qualsiasi altro valore. Si noti che il valore massimo dell'intero codificato come variabile di pacchetto è limitato dal parametro NTP.MAXSTRATUM.

3.2.2. Variabili di Sistema

La Tabella 1 mostra l'insieme completo delle variabili di sistema. Oltre alle variabili comuni descritte in precedenza, le seguenti variabili sono utilizzate dal sistema operativo per sincronizzare l'orologio locale.

Orologio Locale (Local Clock,sys.clock): Questo è il tempo locale corrente, in formato timestamp. Il tempo locale è derivato dall'orologio hardware della macchina particolare e si incrementa a intervalli a seconda del design utilizzato. Un design appropriato, inclusi meccanismi di regolazione e compensazione dello skew, è descritto nella Sezione 5.

Fonte dell'Orologio (Clock Source,sys.peer): Questo è un selettore che identifica la fonte di sincronizzazione corrente. Di solito questo sarà un puntatore a una struttura contenente le variabili del peer. Il valore speciale NULL indica che non c'è attualmente una fonte di sincronizzazione valida.

3.2.3. Variabili del Peer

La Tabella 2 mostra l'insieme completo delle variabili del peer. Oltre alle variabili comuni descritte in precedenza, le seguenti variabili sono utilizzate dalle funzioni di gestione e misurazione del peer.

Bit Configurato (Configured Bit,peer.config): Questo è un bit che indica che l'associazione è stata creata da informazioni di configurazione e non dovrebbe essere smobilitata se il peer diventa irraggiungibile.

Timestamp di Aggiornamento (Update Timestamp,peer.update): Questo è il tempo locale, in formato timestamp, quando è stato ricevuto il messaggio NTP più recente. Viene utilizzato nel calcolo della dispersione dello skew.

Registro di Raggiungibilità (Reachability Register,peer.reach): Questo è un registro a scorrimento di bit NTP.WINDOW utilizzato per determinare lo stato di raggiungibilità del peer, con bit che entrano dall'estremità meno significativa (più a destra). Un peer è considerato raggiungibile se almeno un bit in questo registro è impostato a uno.

Timer del Peer (Peer Timer,peer.timer): Questo è un contatore intero utilizzato per controllare l'intervallo tra i messaggi NTP trasmessi. Una volta impostato su un valore diverso da zero, il contatore decrementa a intervalli di un secondo fino a raggiungere zero, momento in cui viene chiamata la procedura di trasmissione. Si noti che il funzionamento di questo timer è indipendente dagli aggiornamenti dell'orologio locale, il che implica che il sistema di cronometraggio e l'architettura del sistema timer a intervalli devono essere indipendenti l'uno dall'altro.

3.2.4. Variabili di Pacchetto

La tabella 3 mostra l'insieme completo delle variabili di pacchetto. Oltre alle variabili comuni descritte in precedenza, sono definite le seguenti variabili.

Numero di Versione (Version Number,pkt.version): Questo è un intero che indica il numero di versione del mittente. I messaggi NTP saranno sempre inviati con il numero di versione corrente NTP.VERSION e saranno sempre accettati se il numero di versione corrisponde a NTP.VERSION. Eccezioni possono essere consigliate caso per caso quando il numero di versione viene modificato. Le linee guida specifiche per l'interoperabilità tra questa versione e le versioni precedenti di NTP sono riassunte nell'appendice D.

3.2.5. Variabili del Filtro di Clock

Quando si utilizzano gli algoritmi di filtraggio e selezione suggeriti nella sezione 4, sono definite le seguenti variabili di stato oltre alle variabili descritte in precedenza.

Registro del Filtro (Filter Register,peer.filter): Questo è un registro a scorrimento di NTP.SHIFT stadi, dove ogni stadio memorizza una tripla costituita dal ritardo misurato, dallo scostamento misurato e dalla dispersione calcolata associati a una singola osservazione. Queste triple entrano dall'estremità più significativa (più a sinistra) e vengono spostate verso l'estremità meno significativa (più a destra) e infine scartate all'arrivo di nuove osservazioni.

Contatore di Dati Validi (Valid Data Counter,peer.valid): Questo è un contatore intero che indica i campioni validi rimanenti nel registro del filtro. Viene utilizzato per determinare lo stato di raggiungibilità e quando l'intervallo di polling dovrebbe essere aumentato o diminuito.

Scostamento (Offset,peer.offset): Questo è un numero con segno a virgola fissa che indica lo scostamento dell'orologio del peer rispetto all'orologio locale, in secondi.

Ritardo (Delay,peer.delay): Questo è un numero con segno a virgola fissa che indica il ritardo di andata e ritorno dell'orologio del peer rispetto all'orologio locale sul percorso di rete tra di essi, in secondi. Si noti che questa variabile può assumere valori sia positivi che negativi, a seconda della precisione dell'orologio e dell'accumulo di errori di deriva.

Dispersione (Dispersion,peer.dispersion): Questo è un numero con segno a virgola fissa che indica l'errore massimo dell'orologio del peer rispetto all'orologio locale sul percorso di rete tra di essi, in secondi. Sono possibili solo valori positivi maggiori di zero.

3.2.6. Variabili di Autenticazione

Quando si utilizza il meccanismo di autenticazione suggerito nell'appendice C, sono definite le seguenti variabili di stato oltre alle variabili descritte in precedenza. Queste variabili vengono utilizzate solo se è implementato il meccanismo di autenticazione opzionale descritto nell'appendice C.

Bit di Abilitazione dell'Autenticazione (Authentication Enabled Bit,peer.authenable): Questo è un bit che indica che l'associazione deve operare in modalità autenticata.

Bit Autenticato (Authenticated Bit,peer.authentic): Questo è un bit che indica che l'ultimo messaggio ricevuto dal peer è stato autenticato correttamente.

Identificatore di Chiave (Key Identifier,peer.hostkeyid,peer.peerkeyid,pkt.keyid): Questo è un intero che identifica la chiave crittografica utilizzata per generare il codice di autenticazione del messaggio.

Chiavi Crittografiche (Cryptographic Keys,sys.key): Questo è un insieme di chiavi DES a 64 bit. Ogni chiave è costruita come nelle distribuzioni Berkeley Unix, che consiste di otto ottetti, dove i sette bit di ordine inferiore di ciascun ottetto corrispondono ai bit DES 1-7 e il bit di ordine superiore corrisponde al bit di parità dispari DES 8.

Checksum Crittografico (Crypto-Checksum,pkt.check): Questo è un checksum crittografico calcolato dalla procedura di cifratura.

3.2.7. Parametri

La tabella 4 mostra i parametri assunti per tutte le implementazioni operanti nel sistema Internet. È necessario concordare i valori di questi parametri al fine di evitare inutili sovraccarichi di rete e mantenere associazioni di peer stabili. I seguenti parametri sono assunti fissi e applicabili a tutte le associazioni.

Numero di Versione (NTP.VERSION): Questo è il numero di versione NTP corrente (3).

Porta NTP (NTP.PORT): Questo è il numero di porta (123) assegnato a NTP dall'Internet Assigned Numbers Authority.

Stratum Massimo (NTP.MAXSTRATUM): Questo è il valore massimo di stratum che può essere codificato come variabile di pacchetto, interpretato anche come "infinito" o irraggiungibile dall'algoritmo di routing della sottorete.

Età Massima dell'Orologio (NTP.MAXAGE): Questo è l'intervallo massimo per cui un orologio di riferimento sarà considerato valido dopo il suo ultimo aggiornamento, in secondi.

Deriva Massima (NTP.MAXSKEW): Questo è l'errore di scostamento massimo dovuto alla deriva dell'orologio locale sull'intervallo determinato da NTP.MAXAGE, in secondi. Il rapporto φ = NTP.MAXSKEW / NTP.MAXAGE è interpretato come il tasso di deriva massimo possibile dovuto a tutte le cause.

Distanza Massima (NTP.MAXDISTANCE): Quando si utilizza l'algoritmo di selezione suggerito nella sezione 4, questa è la distanza di sincronizzazione massima per i peer accettabili per la sincronizzazione.

Intervallo di Polling Minimo (NTP.MINPOLL): Questo è l'intervallo di polling minimo consentito da qualsiasi peer del sistema Internet, in secondi come potenza di due.

Intervallo di Polling Massimo (NTP.MAXPOLL): Questo è l'intervallo di polling massimo consentito da qualsiasi peer del sistema Internet, in secondi come potenza di due.

Numero Minimo di Orologi Selezionati (NTP.MINCLOCK): Quando si utilizza l'algoritmo di selezione suggerito nella sezione 4, questo è il numero minimo di peer accettabili per la sincronizzazione.

Numero Massimo di Orologi Selezionati (NTP.MAXCLOCK): Quando si utilizza l'algoritmo di selezione suggerito nella sezione 4, questo è il numero massimo di peer considerati per la selezione.

Dispersione Minima (NTP.MINDISPERSE): Quando si utilizza l'algoritmo di filtraggio suggerito nella sezione 4, questo è l'incremento di dispersione minimo per ciascun livello di stratum, in secondi.

Dispersione Massima (NTP.MAXDISPERSE): Quando si utilizza l'algoritmo di filtraggio suggerito nella sezione 4, questa è la dispersione massima del peer e la dispersione assunta per i dati mancanti, in secondi.

Dimensione del Registro di Raggiungibilità (NTP.WINDOW): Questa è la dimensione del registro di raggiungibilità (peer.reach), in bit.

Dimensione del Filtro (NTP.SHIFT): Quando si utilizza l'algoritmo di filtraggio suggerito nella sezione 4, questa è la dimensione del registro a scorrimento del filtro di clock (peer.filter), in stadi.

Peso del Filtro (NTP.FILTER): Quando si utilizza l'algoritmo di filtraggio suggerito nella sezione 4, questo è il peso utilizzato per calcolare la dispersione del filtro.

Peso di Selezione (NTP.SELECT): Quando si utilizza l'algoritmo di selezione suggerito nella sezione 4, questo è il peso utilizzato per calcolare la dispersione di selezione.

3.3. Modalità di Operazione

Tranne che in modalità broadcast, un'associazione NTP si forma quando due peer scambiano messaggi e uno o entrambi creano e mantengono un'istanziazione della macchina di protocollo, chiamata associazione. L'associazione può operare in una delle cinque modalità indicate dalla variabile di modalità host (peer.mode): simmetrico attivo, simmetrico passivo, client, server e broadcast, che sono definite come segue:

Simmetrico Attivo (Symmetric Active,1): Un host che opera in questa modalità invia messaggi periodici indipendentemente dallo stato di raggiungibilità o dallo strato del suo peer. Operando in questa modalità, l'host annuncia la sua disponibilità a sincronizzare ed essere sincronizzato dal peer.

Simmetrico Passivo (Symmetric Passive,2): Questo tipo di associazione viene normalmente creato all'arrivo di un messaggio da un peer che opera in modalità simmetrica attiva e persiste solo finché il peer è raggiungibile e opera a un livello di strato inferiore o uguale all'host; altrimenti, l'associazione viene sciolta. Tuttavia, l'associazione persisterà sempre fino a quando almeno un messaggio è stato inviato in risposta. Operando in questa modalità, l'host annuncia la sua disponibilità a sincronizzare ed essere sincronizzato dal peer.

Client (Client,3): Un host che opera in questa modalità invia messaggi periodici indipendentemente dallo stato di raggiungibilità o dallo strato del suo peer. Operando in questa modalità, l'host, solitamente una workstation LAN, annuncia la sua disponibilità ad essere sincronizzato da, ma non a sincronizzare il peer.

Server (Server,4): Questo tipo di associazione viene normalmente creato all'arrivo di un messaggio di richiesta client ed esiste solo per rispondere a quella richiesta, dopo di che l'associazione viene sciolta. Operando in questa modalità, l'host, solitamente un server di tempo LAN, annuncia la sua disponibilità a sincronizzare, ma non ad essere sincronizzato dal peer.

Broadcast (Broadcast,5): Un host che opera in questa modalità invia messaggi periodici indipendentemente dallo stato di raggiungibilità o dallo strato dei peer. Operando in questa modalità, l'host, solitamente un server di tempo LAN che opera su un mezzo broadcast ad alta velocità, annuncia la sua disponibilità a sincronizzare tutti i peer, ma non ad essere sincronizzato da nessuno di essi.

Un host che opera in modalità client invia occasionalmente un messaggio NTP a un host che opera in modalità server, forse immediatamente dopo il riavvio e successivamente a intervalli periodici. Il server risponde semplicemente scambiando gli indirizzi e le porte, compilando le informazioni richieste e restituendo il messaggio al client. I server non hanno bisogno di conservare informazioni di stato tra le richieste dei client, mentre i client sono liberi di gestire l'intervallo di invio dei messaggi NTP per adattarsi alle condizioni locali. In queste modalità, la macchina di protocollo descritta in questo documento può essere notevolmente semplificata in un semplice meccanismo di chiamata di procedura remota, senza perdite significative di accuratezza o robustezza, specialmente quando opera su una LAN ad alta velocità.

Nelle modalità simmetriche la distinzione client/server (quasi) scompare. La modalità simmetrica passiva è destinata all'uso da parte di time server che operano vicino ai nodi radice (stratum più basso) della sottorete di sincronizzazione e con un numero relativamente elevato di peer su base intermittente. In questa modalità l'identità del peer non deve essere nota in anticipo, poiché l'associazione con le sue variabili di stato viene creata solo all'arrivo di un messaggio NTP. Inoltre, la memoria di stato può essere riutilizzata quando il peer diventa irraggiungibile o opera a un livello di stratum superiore e quindi non idoneo come fonte di sincronizzazione.

La modalità simmetrica attiva è destinata all'uso da parte di time server che operano vicino ai nodi terminali (stratum più alto) della sottorete di sincronizzazione. Un servizio orario affidabile può solitamente essere mantenuto con due peer al livello di stratum immediatamente inferiore e un peer allo stesso livello di stratum, quindi la frequenza del polling continuo non è normalmente significativa, anche quando la connettività viene persa e ogni polling restituisce un messaggio di errore.

Normalmente un peer opera in modalità attiva (modalità simmetrica attiva, client o broadcast), come configurato da un file di avvio, mentre l'altro opera in modalità passiva (modalità simmetrica passiva o server), spesso senza configurazione preventiva. Tuttavia, entrambi i peer possono essere configurati per operare in modalità simmetrica attiva. Si verifica una condizione di errore quando entrambi i peer operano nella stessa modalità, ma non in modalità simmetrica attiva. In tal caso ciascun peer ignorerà i messaggi dell'altro, per cui le associazioni precedenti, se presenti, verranno smobilitate a causa del fallimento della raggiungibilità.

La modalità broadcast è destinata alle operazioni su LAN ad alta velocità con numerose workstation e dove non è richiesta la massima accuratezza. Nello scenario tipico, uno o più time server sulla LAN inviano trasmissioni periodiche alle workstation, le quali determinano quindi l'ora sulla base di un ritardo preconfigurato dell'ordine di pochi millisecondi. Come nelle modalità client/server, la macchina di protocollo può essere notevolmente semplificata in questa modalità; tuttavia, una forma modificata dell'algoritmo di selezione dell'orologio può essere utile nei casi in cui vengono utilizzati più time server per una maggiore affidabilità.

3.4. Elaborazione degli Eventi

Gli eventi significativi di interesse in NTP si verificano alla scadenza di un timer del peer (peer.timer), di cui uno è dedicato a ciascun peer con un'associazione attiva, e all'arrivo di un messaggio NTP dai vari peer. Un evento può verificarsi anche come risultato di un comando dell'operatore o di un guasto di sistema rilevato, come un guasto della fonte di riferimento primaria. Questa sezione descrive le procedure invocate quando si verificano questi eventi.

3.4.1. Convenzioni di Notazione

Gli algoritmi di filtraggio e selezione NTP operano su un insieme di variabili: scostamento dell'orologio (θ, THETA), ritardo di andata e ritorno (δ, DELTA) e dispersione (ε, EPSILON). Quando è necessario distinguerle, le lettere greche minuscole sono utilizzate per le variabili relative a un peer, mentre le lettere greche maiuscole sono utilizzate per le variabili relative alla fonte di riferimento primaria, cioè attraverso il peer fino alla radice della sottorete di sincronizzazione. I pedici verranno utilizzati per identificare un particolare peer quando il contesto non è chiaro. Questi algoritmi si basano su una quantità chiamata distanza di sincronizzazione (λ, LAMBDA), calcolata dal ritardo di andata e ritorno e dalla dispersione come descritto di seguito.

Come descritto nell'appendice H, la dispersione del peer ε include i seguenti contributi: errore di misurazione ρ = 1 << sys.precision, accumulo dell'errore di deriva φτ (dove φ = NTP.MAXSKEW / NTP.MAXAGE è il tasso di deriva massimo e τ = sys.clock - peer.update è l'intervallo dall'ultimo aggiornamento) e la dispersione del filtro (campione) ε_σ calcolata dall'algoritmo del filtro di clock. La dispersione radice EPSILON include i contributi della dispersione del peer selezionato ε e dell'accumulo dell'errore di deriva φτ, oltre alla dispersione radice del peer stesso. La dispersione di sistema include la dispersione di selezione (campione) ε_ξ calcolata dall'algoritmo di selezione dell'orologio e lo scostamento iniziale assoluto dell'orologio |THETA| fornito all'algoritmo dell'orologio locale. Sia ε che EPSILON sono quantità dinamiche, poiché dipendono dal tempo τ trascorso dall'ultimo aggiornamento, nonché dalle dispersioni dei campioni calcolate dagli algoritmi.

Ogni volta che le variabili del peer pertinenti vengono aggiornate, tutte le dispersioni associate a quel peer vengono aggiornate per riflettere l'accumulo dell'errore di deriva. I calcoli possono essere riassunti come segue:

  • θ = peer.offset
  • δ = peer.delay
  • ε = peer.dispersion = ρ + φτ + ε_σ
  • λ = ε + |δ| / 2

dove τ è l'intervallo tra il momento in cui è stato inviato il timestamp originale (dal quale sono stati determinati θ e δ) e il presente, ed ε_σ è la dispersione del filtro (vedere la procedura del filtro di clock di seguito). Le variabili relative alla radice della sottorete di sincronizzazione tramite il peer i sono determinate come segue:

  • THETA_i = θ_i
  • DELTA_i = peer.rootdelay + δ_i
  • EPSILON_i = peer.rootdispersion + ε_i + φτ_i
  • LAMBDA_i = EPSILON_i + |DELTA_i| / 2

dove tutte le variabili si intendono appartenenti all'i-esimo peer. Infine, supponendo che l'i-esimo peer sia selezionato per la sincronizzazione, le variabili di sistema sono determinate come segue:

  • THETA = scostamento finale combinato
  • DELTA = DELTA_i
  • EPSILON = EPSILON_i + ε_ξ + |THETA|
  • LAMBDA = LAMBDA_i

dove ε_ξ è la dispersione di selezione (vedere la procedura di selezione dell'orologio di seguito).

Di seguito è riportato uno pseudocodice informale che esegue questi calcoli. Si noti che lo pseudocodice non è espresso in alcun linguaggio particolare, sebbene presenti molte somiglianze con il linguaggio C. I dettagli specifici degli algoritmi importanti sono ulteriormente illustrati dalle routine in linguaggio C nell'appendice I.

3.4.2. Procedura di Trasmissione

La procedura di trasmissione viene eseguita quando il timer del peer decrementa fino a zero per tutte le modalità tranne la modalità client con un server broadcast e la modalità server in tutti i casi. Nella modalità client con un server broadcast i messaggi non vengono mai inviati. Nella modalità server i messaggi vengono inviati solo in risposta ai messaggi ricevuti. Questa procedura viene chiamata anche dalla procedura di ricezione quando arriva un messaggio NTP che non genera un'associazione persistente.

begin transmit procedure

pkt.peeraddr <- peer.hostaddr; /* copy system and peer variables */
pkt.peerport <- peer.hostport;
pkt.hostaddr <- peer.peeraddr;
pkt.hostport <- peer.peerport;
pkt.leap <- sys.leap;
pkt.version <- NTP.VERSION;
pkt.mode <- peer.mode;
pkt.stratum <- sys.stratum;
pkt.poll <- peer.hostpoll;
pkt.precision <- sys.precision;
pkt.rootdelay <- sys.rootdelay;
if (sys.leap = 11₂ or (sys.clock - sys.reftime) > NTP.MAXAGE)
skew <- NTP.MAXSKEW;
else
skew <- φ(sys.clock - sys.reftime);
pkt.rootdispersion <- sys.rootdispersion + (1 << sys.precision) + skew;
pkt.refid <- sys.refid;
pkt.reftime <- sys.reftime;

pkt.org <- peer.org; /* copy timestamps */
pkt.rec <- peer.rec;
pkt.xmt <- sys.clock;
peer.xmt <- pkt.xmt;

#ifdef (authentication implemented) /* see Appendix C */
call encrypt;
#endef
send packet;

peer.reach <- peer.reach << 1; /* update reachability */
if (peer.reach = 0 and peer.config = 0)
begin
demobilize association;
exit;
endif

if (peer.reach & 6 != 0) /* test two low-order bits */
if (peer.valid < NTP.SHIFT) /* valid data received */
peer.valid <- peer.valid + 1;
else peer.hostpoll <- peer.hostpoll + 1;
else begin
peer.valid <- peer.valid - 1; /* nothing heard */
peer.hostpoll <- peer.hostpoll - 1;
call clock-filter(0, 0, NTP.MAXDISPERSE);
call clock-select; /* select clock source */
endif
call poll-update;
end transmit procedure;

3.4.3. Procedura di Ricezione

La procedura di ricezione viene eseguita all'arrivo di un messaggio NTP. Convalida il messaggio, interpreta le varie modalità e chiama altre procedure per filtrare i dati e selezionare la fonte di sincronizzazione. Se il numero di versione nel pacchetto non corrisponde alla versione corrente, il messaggio può essere scartato; tuttavia, eccezioni consigliate possono essere concesse caso per caso in occasione dei cambi di versione. Se i messaggi di controllo NTP descritti nell'appendice B sono implementati e la modalità del pacchetto è 6 (controllo), viene chiamata la procedura dei messaggi di controllo. Gli indirizzi Internet e le porte di origine e destinazione negli header IP e UDP vengono associati al peer corretto. Se non vi è corrispondenza, viene creata una nuova istanza della macchina di protocollo e l'associazione viene mobilitata.

begin receive procedure
if (pkt.version != NTP.VERSION) exit;
#ifdef (control messages implemented)
if (pkt.mode = 6) call control-message;
#endef
for (all associations) /* access control goes here */
match addresses and ports to associations;
if (no matching association)
call receive-instantiation procedure; /* create association */

#ifdef (authentication implemented) /* see Appendix C */
call decrypt;
#endef

if (pkt.mode = 0) /* for compatibility */
mode <- (see Section 3.3);
else
mode <- pkt.mode;

case (mode, peer.hostmode) /* see Table 5 */

error: if (peer.config = 0) demobilize association;
break;

recv: call packet; /* process packet */
if (valid header) begin
peer.reach <- peer.reach | 1;
if (valid data) call clock-update;
endif
else
if (peer.config = 0) demobilize association;
break;

xmit: call packet; /* process packet */
peer.hostpoll <- peer.peerpoll;
call poll-update;
call transmit;
if (peer.config = 0) demobilize association;
break;

pkt: call packet; /* process packet */
if (valid header) begin
peer.reach <- peer.reach | 1;
if (valid data) call clock-update;
endif
else if (peer.config = 0) begin
peer.hostpoll <- peer.peerpoll;
call poll-update;
call transmit;
demobilize association;
endif
endcase
end receive procedure;

3.4.4. Procedura del Pacchetto

La procedura del pacchetto controlla la validità del messaggio, calcola i campioni di ritardo/scostamento e chiama altre procedure per filtrare i dati e selezionare la fonte di sincronizzazione. Il test 1 richiede che il timestamp di trasmissione non corrisponda all'ultimo ricevuto dallo stesso peer; in caso contrario, il messaggio potrebbe essere un vecchio duplicato. Il test 2 richiede che il timestamp di origine corrisponda all'ultimo inviato allo stesso peer; in caso contrario, il messaggio potrebbe essere fuori sequenza, falsificato o peggio. Nel caso della modalità broadcast (5), il ritardo apparente di andata e ritorno sarà zero e la piena accuratezza dell'operazione di trasferimento dell'ora potrebbe non essere raggiunta. Tuttavia, l'accuratezza ottenuta potrebbe essere sufficiente per la maggior parte degli scopi. La procedura di aggiornamento del polling viene chiamata con l'argomento peer.hostpoll (peer.peerpoll potrebbe essere cambiato).

begin packet procedure
peer.rec <- sys.clock; /* capture receive timestamp */
if (pkt.mode != 5) begin
test1 <- (pkt.xmt != peer.org); /* test 1 */
test2 <- (pkt.org = peer.xmt); /* test 2 */
endif
else begin
pkt.org <- peer.rec; /* fudge missing timestamps */
pkt.rec <- pkt.xmt;
test1 <- true; /* fake tests */
test2 <- true;
endif
peer.org <- pkt.xmt; /* update originate timestamp */
peer.peerpoll <- pkt.poll; /* adjust poll interval */
call poll-update(peer.hostpoll);

test3 <- (pkt.org != 0 and pkt.rec != 0); /* test 3 */

δ <- (T_i - T_(i-3)) - (T_(i-1) - T_(i-2))
θ <- ((T_(i-2) - T_(i-3)) + (T_(i-1) - T_i)) / 2
ε <- (1 << sys.precision) + φ(T_i - T_(i-3))

test4 <- (|δ| < NTP.MAXDISPERSE and ε < NTP.MAXDISPERSE); /* test 4 */

#ifdef (authentication implemented) /* test 5 */
test5 <- ((peer.config = 1 and peer.authenable = 0) or peer.authentic = 1);
#endef

test6 <- (pkt.leap != 11₂ and /* test 6 */
pkt.reftime <= pkt.xmt < pkt.reftime + NTP.MAXAGE)
test7 <- (pkt.stratum <= sys.stratum and /* test 7 */
pkt.stratum < NTP.MAXSTRATUM);
test8 <- (|pkt.rootdelay| < NTP.MAXDISPERSE and /* test 8 */
pkt.rootdispersion < NTP.MAXDISPERSE);

if (not valid header) exit;
peer.leap <- pkt.leap; /* copy packet variables */
peer.stratum <- pkt.stratum;
peer.precision <- pkt.precision;
peer.rootdelay <- pkt.rootdelay;
peer.rootdispersion <- pkt.rootdispersion;
peer.refid <- pkt.refid;
peer.reftime <- pkt.reftime;
if (valid data) call clock-filter(θ, δ, ε); /* process sample */
end packet procedure;

3.4.5. Procedura di Aggiornamento dell'Orologio

La procedura di aggiornamento dell'orologio viene chiamata dalla procedura di ricezione quando sono stati determinati dati validi di scostamento dell'orologio, ritardo e dispersione dalla procedura del filtro di clock per il peer corrente. Il risultato delle procedure di selezione e combinazione dell'orologio è il valore finale di correzione dell'orologio THETA, che viene utilizzato dalla procedura dell'orologio locale per aggiornare l'orologio locale. Se nessun candidato sopravvive a queste procedure, la procedura di aggiornamento dell'orologio termina senza ulteriori azioni.

begin clock-update procedure
call clock-select; /* select clock source */
if (sys.peer != peer) exit;

LAMBDA <- distance(peer); /* update system variables */
if (LAMBDA >= NTP.MAXDISTANCE) exit;
sys.leap <- peer.leap;
sys.stratum <- peer.stratum + 1;
sys.refid <- peer.peeraddr;
call local-clock;
if (local clock reset) begin /* if reset, clear state variables */
sys.leap <- 11₂;
for (all peers) call clear;
endif
else begin
sys.peer <- peer; /* if not, adjust local clock */
sys.rootdelay <- DELTA;
sys.rootdispersion <- EPSILON + max(ε_ξ + |THETA|, NTP.MINDISPERSE);
endif
sys.reftime <- sys.clock;
end clock-update procedure;

In alcune configurazioni di sistema è disponibile una fonte precisa di informazioni di temporizzazione sotto forma di un treno di impulsi di temporizzazione distanziati di un secondo. Solitamente questo viene fornito in aggiunta a una fonte di informazioni di codice orario, come un orologio radio o persino NTP stesso, per numerare i secondi, i minuti, le ore e i giorni. In queste configurazioni le variabili di sistema sono impostate per fare riferimento alla fonte da cui derivano gli impulsi. Per le configurazioni che supportano una fonte di riferimento primaria, come un orologio radio o un orologio atomico calibrato, lo stratum è impostato a 1 finché questa è l'effettiva fonte di sincronizzazione, indipendentemente dal fatto che la procedura dell'orologio primario venga utilizzata o meno.

Le specifiche degli algoritmi di selezione dell'orologio e dell'orologio locale non sono parte integrante della specifica NTP, poiché potrebbero esistere altri algoritmi che offrono prestazioni equivalenti. Tuttavia, un algoritmo di selezione dell'orologio che si è dimostrato efficace nell'ambiente Internet è descritto nella sezione 4 e un algoritmo dell'orologio locale è descritto nella sezione 5, e il loro utilizzo è raccomandato. L'algoritmo di selezione dell'orologio descritto nella sezione 4 seleziona generalmente il peer con lo stratum più basso e la distanza di sincronizzazione minima tra tutti i peer disponibili, a meno che quel peer non sembri essere un falsificatore (falseticker). Il risultato è che tutti gli algoritmi operano insieme per costruire un albero di copertura di peso minimo rispetto ai time server di riferimento primari, producendo una sottorete di sincronizzazione master-slave gerarchica.

3.4.6. Procedura dell'Orologio Primario

Quando una fonte di riferimento primaria, come un orologio radio, è collegata all'host, è conveniente incorporare le sue informazioni nel database come se l'orologio fosse rappresentato come un peer ordinario. Nella procedura dell'orologio primario, l'orologio viene interrogato circa una volta al minuto e il codice orario restituito viene utilizzato per produrre un nuovo aggiornamento per l'orologio locale. Quando il peer.timer del peer dell'orologio primario decrementa fino a zero, la procedura di trasmissione non viene chiamata; invece, viene interrogato l'orologio radio, di solito utilizzando una stringa ASCII specificata a tale scopo. Quando viene ricevuto un codice orario valido dall'orologio radio, viene convertito nel formato timestamp NTP e le variabili del peer vengono aggiornate. Il valore di peer.leap viene impostato in base allo stato dei bit di avviso del secondo intercalare nel codice orario, se disponibili, o manualmente dall'operatore. Il valore di peer.peeraddr, che diventerà il valore di sys.refid quando viene chiamata la procedura di aggiornamento dell'orologio, viene impostato su una stringa ASCII che descrive il tipo di orologio (vedere l'appendice A).

begin primary-clock-update procedure
peer.leap <- "from" radio or operator; /* copy variables */
peer.peeraddr <- ASCII identifier;
peer.rec <- radio timestamp;
peer.reach <- 1;
call clock-filter(sys.clock - peer.rec, 0, 1 << peer.precision);
call clock-update; /* update local clock */
end primary-clock-update procedure;

3.4.7. Procedure di Inizializzazione

Le procedure di inizializzazione vengono utilizzate per configurare e inizializzare il sistema, i suoi peer e le associazioni.

3.4.7.1. Procedura di Inizializzazione

La procedura di inizializzazione viene chiamata al riavvio o al riavvio del daemon NTP. L'orologio locale è presumibilmente indefinito al riavvio; tuttavia, in alcune apparecchiature è disponibile una stima dall'ambiente di riavvio, come un orologio/calendario con backup a batteria. La variabile di precisione è determinata dall'architettura intrinseca dell'orologio hardware locale. Le variabili di autenticazione vengono utilizzate solo se è implementato il meccanismo di autenticazione descritto nell'appendice C. I valori di queste variabili sono determinati utilizzando procedure che esulano dall'ambito di NTP stesso.

begin initialization procedure
#ifdef (authentication implemented) /* see Appendix C */
sys.keys <- as required;
#endef;
sys.leap <- 11₂; /* copy variables */
sys.stratum <- 0 (undefined);
sys.precision <- host precision;
sys.rootdelay <- 0 (undefined);
sys.rootdispersion <- 0 (undefined);
sys.refid <- 0 (undefined);
sys.reftime <- 0 (undefined);
sys.clock <- external reference;
sys.peer <- NULL;
sys.poll <- NTP.MINPOLL;
for (all configured peers) /* create configured associations */
call initialization-instantiation procedure;
end initialization procedure;

3.4.7.2. Procedura di Istanziazione dell'Inizializzazione

Questa procedura specifica dell'implementazione viene chiamata dalla procedura di inizializzazione al fine di definire un'associazione. L'indirizzo e la modalità del peer sono determinati dalle informazioni lette durante la procedura di riavvio o come risultato dei comandi dell'operatore. Le variabili di autenticazione vengono utilizzate solo se è implementato il meccanismo di autenticazione descritto nell'appendice C. I valori di queste variabili sono determinati utilizzando procedure che esulano dall'ambito di NTP stesso. Con il bit di autenticazione impostato come suggerito, solo i peer correttamente autenticati possono diventare la fonte di sincronizzazione.

begin initialization-instantiation procedure
peer.config <- 1;
#ifdef (authentication implemented) /* see Appendix C */
peer.authenable <- 1 (suggested);
peer.authentic <- 0;
peer.hostkeyid <- as required;
peer.peerkeyid <- 0;
#endef;
peer.peeraddr <- peer IP address; /* copy variables */
peer.peerport <- NTP.PORT;
peer.hostaddr <- host IP address;
peer.hostport <- NTP.PORT;
peer.mode <- host mode;
peer.peerpoll <- 0 (undefined);
peer.timer <- 0;
peer.delay <- 0 (undefined);
peer.offset <- 0 (undefined);
call clear; /* initialize association */
end initialization-instantiation procedure;

3.4.7.3. Procedura di Istanziazione della Ricezione

La procedura di istanziazione della ricezione viene chiamata dalla procedura di ricezione quando viene scoperto un nuovo peer. Inizializza le variabili del peer e mobilita l'associazione. Se il messaggio proviene da un peer che opera in modalità client (3), la modalità host viene impostata sulla modalità server (4); in caso contrario, viene impostata sulla modalità simmetrica passiva (2). Le variabili di autenticazione vengono utilizzate solo se è implementato il meccanismo di autenticazione descritto nell'appendice C. Se implementato, solo i peer non configurati correttamente autenticati possono diventare la fonte di sincronizzazione.

begin receive-instantiation procedure
#ifdef (authentication implemented) /* see Appendix C */
peer.authenable <- 0;
peer.authentic <- 0;
peer.hostkeyid <- as required;
peer.peerkeyid <- 0;
#endef
peer.config <- 0; /* copy variables */
peer.peeraddr <- pkt.peeraddr;
peer.peerport <- pkt.peerport;
peer.hostaddr <- pkt.hostaddr;
peer.hostport <- pkt.hostport;
if (pkt.mode = 3) /* determine mode */
peer.mode <- 4;
else
peer.mode <- 2;
peer.peerpoll <- 0 (undefined);
peer.timer <- 0;
peer.delay <- 0 (undefined);
peer.offset <- 0 (undefined);
call clear; /* initialize association */
end receive-instantiation procedure;

3.4.7.4. Procedura di Istanziazione dell'Orologio Primario

Questa procedura viene chiamata dalla procedura di inizializzazione al fine di configurare le variabili di stato per l'orologio primario. Il valore di peer.precision è determinato dalle specifiche dell'orologio radio e dell'interfaccia hardware. Il valore di peer.rootdispersion è nominalmente dieci volte l'errore massimo intrinseco dell'orologio radio; ad esempio, 10 μs per un orologio atomico calibrato, 10 ms per un orologio radio WWVB o GOES e 100 ms per un orologio radio WWV meno preciso.

begin clock-instantiation procedure
peer.config <- 1; /* copy variables */
peer.peeraddr <- 0 undefined;
peer.peerport <- 0 (not used);
peer.hostaddr <- 0 (not used);
peer.hostport <- 0 (not used);
peer.leap <- 11₂;
peer.mode <- 0 (not used);
peer.stratum <- 0;
peer.peerpoll <- 0 (undefined);
peer.precision <- clock precision;
peer.rootdelay <- 0;
peer.rootdispersion <- clock dispersion;
peer.refid <- 0 (not used);
peer.reftime <- 0 (undefined);
peer.timer <- 0;
peer.delay <- 0 (undefined);
peer.offset <- 0 (undefined);
call clear; /* initialize association */
end clock-instantiation procedure;

In alcune configurazioni che coinvolgono un orologio atomico calibrato o un ricevitore LORAN-C, la fonte di riferimento primaria potrebbe fornire solo impulsi al secondo e mancare di un codice orario completo da cui derivare la numerazione dei secondi, ecc. In queste configurazioni la numerazione dei secondi può essere derivata da altre fonti, come un orologio radio o persino altri peer NTP. In queste configurazioni le variabili dell'orologio primario dovrebbero riflettere la fonte di riferimento primaria, non la fonte di numerazione dei secondi; tuttavia, se la fonte di numerazione dei secondi si guasta o è noto che funziona in modo non corretto, gli aggiornamenti dalla fonte di riferimento primaria dovrebbero essere soppressi come se essa stessa si fosse guastata.

3.4.8. Procedura di Azzeramento

La procedura di azzeramento viene chiamata quando si verifica un evento che comporta un cambiamento significativo dello stato di raggiungibilità o una potenziale interruzione dell'orologio locale.

begin clear procedure
peer.org <- 0 (undefined); /* mark timestamps undefined */
peer.rec <- 0 (undefined);
peer.xmt <- 0 (undefined);
peer.reach <- 0; /* reset state variables */
peer.filter <- [0, 0, NTP.MAXDISPERSE]; /* all stages */
peer.valid <- 0;
peer.dispersion <- NTP.MAXDISPERSE;
peer.hostpoll <- NTP.MINPOLL; /* reset poll interval */
call poll-update;
call clock-select; /* select clock source */
end clear procedure;

3.4.9. Procedura di Aggiornamento del Polling

La procedura di aggiornamento del polling viene chiamata quando si verifica un evento significativo che può comportare una modifica dell'intervallo di polling o del timer del peer. Controlla i valori dell'intervallo di polling dell'host (peer.hostpoll) e dell'intervallo di polling del peer (peer.peerpoll) e limita ciascuno al suo intervallo valido. Se il peer è selezionato per la sincronizzazione, il valore viene ulteriormente limitato in funzione della conformità calcolata (vedere la sezione 5).

begin poll-update procedure
temp <- peer.hostpoll; /* determine host poll interval */
if (peer = sys.peer)
temp <- min(temp, sys.poll, NTP.MAXPOLL);
else
temp <- min(temp, NTP.MAXPOLL);
peer.hostpoll <- max(temp, NTP.MINPOLL);
temp <- 1 << min(peer.hostpoll, max(peer.peerpoll, NTP.MINPOLL));

if (peer.timer = 0) /* reset peer timer */
peer.timer <- temp;
else if (peer.timer > temp)
peer.timer <- (sys.clock & (temp - 1)) + 1;
end poll-update procedure;

3.5. Procedura di Distanza di Sincronizzazione

La procedura di distanza calcola la distanza di sincronizzazione dalle variabili del peer per il peer peer.

begin distance(peer) procedure;
DELTA &lt;- peer.rootdelay + |peer.delay|;
EPSILON &lt;- peer.rootdispersion + peer.dispersion + φ(sys.clock - peer.update);
LAMBDA &lt;- EPSILON + |DELTA| / 2;
end distance procedure;

Si noti che, mentre DELTA può essere negativo in alcuni casi, sia EPSILON che LAMBDA sono sempre positivi.

3.6. Problemi di Controllo degli Accessi

Il design NTP è tale che la modifica accidentale o dolosa dei dati (manomissione, tampering) o la distruzione (interferenza, jamming) presso un server di tempo non dovrebbe in generale risultare in errori di cronometraggio altrove nella sottorete di sincronizzazione. Tuttavia, il successo di questo approccio dipende da server di tempo ridondanti e percorsi di rete diversificati, insieme all'assunzione che la manomissione o l'interferenza non si verifichino contemporaneamente presso molti server di tempo in tutta la sottorete di sincronizzazione. In linea di principio, la vulnerabilità della sottorete può essere ingegnerizzata attraverso la selezione di server di tempo noti per essere affidabili e consentendo solo a quei server di tempo di diventare la fonte di sincronizzazione. Le procedure di autenticazione descritte nell'Appendice C rappresentano un meccanismo per far rispettare questo; tuttavia, gli algoritmi di crittografia possono essere molto intensivi per la CPU e possono degradare seriamente l'accuratezza, a meno che non vengano prese precauzioni come quelle menzionate nella descrizione della procedura di trasmissione.

Sebbene non sia una caratteristica richiesta di NTP stesso, alcune implementazioni possono includere una funzionalità di controllo degli accessi che impedisce l'accesso non autorizzato e controlla quali peer sono autorizzati ad aggiornare l'orologio locale. A questo scopo è utile distinguere tra tre categorie di accesso: quelli che sono preautorizzati come affidabili, preautorizzati come amichevoli e tutti gli altri accessi (non preautorizzati). Presumibilmente, la preautorizzazione viene realizzata tramite voci nel file di configurazione o un qualche tipo di sistema di gestione dei biglietti come Kerberos [STE88]. In questo modello, solo gli accessi affidabili possono risultare nel peer che diventa la fonte di sincronizzazione. Mentre gli accessi amichevoli non possono risultare nel peer che diventa la fonte di sincronizzazione, i messaggi NTP e i timestamp vengono restituiti come specificato.

Non sembra utile mantenere un orologio segreto, come risulterebbe dalla restrizione degli accessi non preautorizzati, a meno che l'intento non sia quello di nascondere l'esistenza del server di tempo stesso. Gli host Internet ben comportati sono tenuti a restituire un messaggio di errore ICMP servizio-non-disponibile se un servizio non è implementato o le risorse non sono disponibili; tuttavia, nel caso di NTP le risorse richieste sono minime, quindi c'è poco bisogno di restringere le richieste destinate solo a leggere l'orologio. Un meccanismo di controllo degli accessi semplice ma efficace consiste quindi nel considerare tutte le associazioni preconfigurate in modalità simmetrica o modalità client (modalità 1, 2 e 3) come affidabili e tutte le altre associazioni, preconfigurate o meno, come amichevoli.

Se è richiesto un modello di fiducia più completo, il design può essere basato su una lista di controllo degli accessi con ogni voce costituita da un indirizzo Internet a 32 bit, una maschera a 32 bit e una modalità a 3 bit. Se l'AND logico dell'indirizzo sorgente (pkt.peeraddr) e della maschera in una voce corrisponde all'indirizzo corrispondente nella voce e la modalità (pkt.mode) corrisponde alla modalità nella voce, l'accesso è consentito; altrimenti viene restituito un messaggio di errore ICMP al richiedente. Attraverso una scelta appropriata della maschera, è possibile restringere le richieste per modalità a indirizzi individuali, un particolare sottorete o indirizzi di rete, o non avere alcuna restrizione. La lista di controllo degli accessi fungerebbe quindi da filtro che controlla quali peer potrebbero creare associazioni.