21.11. SNTP: простой синхронизирующий сетевой протокол

21.11. SNTP: простой синхронизирующий сетевой протокол

Синхронизирующий сетевой протокол (Network Time Protocol, NTP) — это сложный протокол синхронизации часов в глобальной или локальной сети. Его точность часто может достигать миллисекунд. В RFC 1305 [76] этот протокол подробно описан, а в RFC 2030 [77] рассматривается протокол SNTP — упрощенная версия NTP, предназначенная для узлов, которым не требуется функциональность полной реализации NTP. Типичной является ситуация, когда несколько узлов в локальной сети синхронизируют свои часы через Интернет с другими узлами NTP, а затем распространяют полученное значение времени в локальной сети с использованием либо широковещательной, либо многоадресной передачи.

В этом разделе мы создадим клиент SNTP, который прослушивает широковещательные или групповые сообщения NTP на всех присоединенных сетях, а затем выводит разницу во времени между пакетом NTP и текущим истинным временем узла. Мы не пытаемся изменить это время, поскольку для этого необходимы права привилегированного пользователя.

Файл ntp.h, показанный в листинге 21.11, содержит некоторые из основных определений формата пакета NTP.

Листинг 21.11. Заголовок ntp.h: формат пакета NTP и определения

//ssntp/ntp.h

 1 #define JAN_1970 2208988800UL /* 1970 - 1900 в секундах */

 2 struct l_fixedpt { /* 64-разрядное число с фиксированной точкой */

 3  uint32_t int_part;

 4  uint32_t fraction;

 5 };

 6 struct s_fixedpt { /* 32-разрядное число с фиксированной точкой */

 7  u_short int_part;

 8  u_short fraction;

 9 };

10 struct ntpdata { /* заголовок NTP */

11  u_char status;

12  u_char stratum;

13  u_char ppoll;

14  int    precision:8;

15  struct s_fixedpt distance;

16  struct s_fixedpt dispersion;

17  uint32_t refid;

18  struct l_fixedpt reftime;

19  struct l_fixedpt org;

20  struct 1_fixedpt rec;

21  struct l_fixedpt xmt;

22 };

23 #define VERSION_MASK 0x38

24 #define MODE_MASK 0x07

25 #define MODE CLIENT 3

26 #define MODE_SERVER 4

27 #define MODE_BROADCAST 5

2-22 l_fixedpt задает 64-разрядные числа с фиксированной точкой, используемые NTP для отметок времени, a s_fixedpt — 32-разрядные значения с фиксированной точкой, также используемые NTP. Структура ntpdata представляет 48-байтовый формат пакета NTP.

В листинге 21.12 пpeдcтaвлeнa функция main.

Листинг 21.12. Функция main

//ssntp/main.c

 1 #include "sntp.h"

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int sockfd;

 6  char buf[MAXLINE];

 7  ssize_t n;

 8  socklen_t salen, len;

 9  struct ifi_info *ifi;

10  struct sockaddr *mcastsa, *wild, *from;

11  struct timeval now;

12  if (argc != 2)

13   err_quit("usage: ssntp <Ipaddress>");

14  sockfd = Udp_client(argv[1], "ntp", (void**)&mcastsa, &salen);

15  wild = Malloc(salen);

16  memcpy(wild, mcastsa. salen); /* копируем семейство и порт */

17  sock_set_wild(wild, salen);

18  Bind(sockfd, wild, salen); /* связываем сокет с универсальным[3]

                                  адресом */

19 #ifdef MCAST

20  /* получаем список интерфейсов и обрабатываем каждый интерфейс */

21  for (ifi = Get_ifi_info(mcastsa->sa_family, 1); ifi != NULL;

22   ifi = ifi->ifi_next) {

23   if (ifi->ifi_flags & IFF_MULTICAST) {

24    Mcast_join(sockfd, mcastsa, salen, ifi->ififname, 0);

25    printf("joined %s on %s ",

26     Sock_ntop(mcastsa, salen), ifi->ifi_name);

27   }

28  }

29 #endif

30  from = Malloc(salen);

31  for (;;) {

32   len = salen;

33   n = Recvfrom(sockfd, buf, sizeof(buf), 0, from, &len);

34   Gettimeofday(&now, NULL);

35   sntp_proc(buf, n, &now);

36  }

37 }

Получение IP-адреса многоадресной передачи

12-14 При выполнении программы пользователь должен задать в качестве аргумента командной строки адрес многоадресной передачи, к которому он будет присоединяться. В случае IPv4 это будет 224.0.1.1 или имя ntp.mcast.net. В случае IPv6 это будет ff05::101 для области действия NTP, локальной в пределах сайта. Наша функция udp_client выделяет в памяти пространство для структуры адреса сокета корректного типа (либо IPv4, либо IPv6) и записывает адрес многоадресной передачи и порт в эту структуру. Если эта программа выполняется на узле, не поддерживающем многоадресную передачу, может быть задан любой IP-адрес, так как в этой структуре задействуются только семейство адресов и порт. Обратите внимание, что наша функция udp_client не связывает адрес с сокетом (то есть не вызывает функцию bind) — она лишь создает сокет и заполняет структуру адреса сокета.

Связывание универсального адреса с сокетом

15-18 Мы выделяем в памяти пространство для другой структуры адреса сокета и заполняем ее, копируя структуру, заполненную функцией udp_client. При этом задаются семейство адреса и порт. Мы вызываем нашу функцию sock_set_wild, чтобы присвоить IP-адресу универсальный адрес, а затем вызываем функцию bind.

Получение списка интерфейсов

20-22 Наша функция get_ifi_info возвращает информацию обо всех интерфейсах и адресах. Запрашиваемое нами семейство адреса берется из структуры адреса сокета, заполненной функцией udp_client на основе аргумента командной строки.

Присоединение к группе

23-27 Мы вызываем нашу функцию mcast_join, чтобы присоединиться к группе, заданной аргументом командной строки для каждого интерфейса, поддерживающего многоадресную передачу. Все эти присоединения происходят на одном сокете, который использует эта программа. Как отмечалось ранее, количество присоединений на одном сокете ограничено константой IP_MAX_MEMBERSHIPS (которая обычно имеет значение 20), но лишь немногие многоинтерфейсные узлы используют столько интерфейсов.

Чтение и обработка всех пакетов NTP

30-36 В памяти размещается другая структура адреса сокета для хранения адреса, возвращаемого функцией recvfrom, и программа входит в бесконечный цикл, считывая все пакеты NTP, которые получает узел, и вызывая нашу функцию sntp_proc (описывается далее) для обработки пакета. Поскольку сокет был связан с универсальным адресом и присоединение к группе произошло на всех интерфейсах, поддерживающих многоадресную передачу, сокет должен получить любой пакет NTP направленной, широковещательной или многоадресной передачи, получаемый узлом. Перед вызовом функции sntp_proc мы вызываем функцию gettimeofday, чтобы получить текущее время, потому что функция sntp_proc вычисляет разницу между временем пакета и текущим временем.

Наша функция sntp_proc, показанная в листинге 21.13, обрабатывает пакет NTP.

Листинг 21.13. Функция sntp_proc: обработка пакета NTР

//ssntp/sntp_proc.c

 1 #include "sntp.h"

 2 void

 3 sntp proc(char *buf, ssize_t n, struct timeval *nowptr)

 4 {

 5  int version, mode;

 6  uint32_t nsec, useci;

 7  double usecf;

 8  struct timeval diff;

 9  struct ntpdata *ntp;

10  if (n < (ssize_t)sizeof(struct ntpdata)) {

11   printf(" packet too small: %d bytes ", n);

12   return;

13  }

14  ntp = (struct ntpdata*)buf;

15  version = (ntp->status & VERSION_MASK) >> 3;

16  mode = ntp->status & MODE_MASK;

17  printf(" v%d, mode %d, strat %d, ", version, mode, ntp->stratum);

18  if (mode == MODE_CLIENT) {

19   printf("client ");

20   return;

21  }

22  nsec = ntohl(ntp->xmt.int_part) - JAN_1970;

23  useci = ntohl(ntp->xmt.fraction); /* 32-разрядная дробь */

24  usecf = useci; /* дробь в double */

25  usecf /= 4294967296.0; /* деление на 2**32 -> [0, 1.0) */

26  useci = usecf * 1000000.0; /* дробь в миллионную часть */

27  diff.tv_sec = nowptr->tv_sec - nsec;

28  if ((diff.tv_usec = nowptr->tv_usec - useci) < 0) {

29   diff.tv_usec += 1000000;

30   diff.tv_sec--;

31  }

32  useci = (diff.tv_sec * 1000000) + diff.tv_usec; /* diff в мс */

33  printf("clock difference = %d usec ", useci);

34 }

Ратификация пакета

10-21 Сначала мы проверяем размер пакета, затем выводим его версию, режим и слой (stratum) сервера. Если режимом является MODE_CLIENT, пакет является запросом клиента, а не ответом сервера, и мы игнорируем его.

Получение времени передачи из пакета NTP

22-34 В пакете NTP нас интересует поле xmt — отметка времени. Это 64-разрядное значение с фиксированной точкой, определяющее момент отправки пакета сервером. Поскольку отметки времени NTP отсчитывают секунды начиная с 1 января 1900 года, а отметки времени Unix — с 1 января 1970 года, сначала мы вычитаем JAN_1970 (число секунд в 70 годах) из целой части.

Дробная часть — это 32-разрядное целое без знака, которое может принимать значение от 0 до 4 294 967 295 включительно. Оно копируется из 32-разрядного целого (usecf) в переменную с плавающей точкой двойной точности (usecf) и делится на 4 294 967 296 (232). Результат больше либо равен 0.0 и меньше 1.0. Мы умножаем это число на 1 000 000 — число микросекунд в секунде, записывая результат в переменную useci как 32-разрядное целое без знака.

Число микросекунд лежит в интервале от 0 до 999 999 (см. упражнение 21.5). Мы преобразуем значение в микросекунды, поскольку отметка времени Unix, возвращаемая функцией gettimeofday, возвращается как два целых числа: число секунд и число микросекунд, прошедшее с 1 января 1970 года (UTC). Затем мы вычисляем и выводим разницу между истинным временем узла и истинным временем сервера NTP в микросекундах.

Один из факторов, не учитываемых нашей программой, — это задержка в сети между клиентом и сервером. Но мы считаем, что пакеты NTP обычно приходят как широковещательные или многоадресные пакеты в локальной сети, а в этом случае задержка в сети составит всего несколько миллисекунд.

Если мы запустим эту программу на узле macosx с сервером NTP на узле freebsd4, который с помощью многоадресной передачи отправляет пакеты NTP в сеть Ethernet каждые 64 с, то получим следующий результат:

macosx # ssntp 224.0.1.1

joined 224.0.1.1.123 on lo0

joined 224.0.1.1.123 on en1

v4, mode 5, strat 3, clock difference = 661 usec

v4, mode 5, strat 3, clock difference = -1789 usec

v4, mode 5, strat 3, clock difference = -2945 usec

v4, mode 5, strat 3, clock difference = -3689 usec

v4, mode 5, strat 3, clock difference = -5425 usec

v4, mode 5, strat 3, clock difference = -6700 usec

v4, mode 5, strat 3, clock difference = -8520 usec

Перед запуском нашей программы мы завершили на узле работу NTP-сервера, поэтому когда наша программа запускается, время очень близко к времени сервера. Мы видим, что этот узел отстал на 9181 мс за 384 с работы программы, то есть за 24 ч он отстанет на 2 с.

Поделитесь на страничке

Следующая глава >

Похожие главы из других книг

Сетевой адаптер

Из книги Домашние и офисные сети под Vista и XP автора Ватаманюк Александр Иванович

Сетевой адаптер Чтобы пользователь мог подключить свой компьютер к локальной сети, в его компьютере должно быть установлено специальное устройство – сетевой контроллер.Сетевой адаптер выполняет множество заданий, самые главные из которых – кодирование/ декодирование


5.3.1. Учебный пример: SMTP, простой протокол передачи почты

Из книги Искусство программирования для Unix автора Реймонд Эрик Стивен

5.3.1. Учебный пример: SMTP, простой протокол передачи почты В примере 5.7. иллюстрируется транзакция SMTP (Simple Mail Transfer Protocol — простой протокол передачи почты), который описан в спецификации RFC 2821. В данном примере строки, начинающиеся с С:, отправляются почтовым транспортным


Сетевой этикет

Из книги Популярный самоучитель работы в Интернете автора Кондратьев Геннадий Геннадьевич

Сетевой этикет Интернет обладает гигантскими возможностями для переписки и других видов удаленного общения. Однако необходимо иметь в виду, что общение посредством текстовых сообщений, в отличие от живого, имеет одну неприятную особенность. При обычном разговоре


Сетевой этикет

Из книги Интернет. Новые возможности. Трюки и эффекты [litres] автора Баловсяк Надежда Васильевна

Сетевой этикет Чтобы чувствовать себя комфортно в любом обществе, не вызывать удивления и негодования старожилов и понимать слова и поступки других людей, необходимо знать как минимум две вещи: язык, на котором здесь общаются, и принятые правила поведения (это применимо


5.3.1. Учебный пример: SMTP, простой протокол передачи почты

Из книги Искусство программирования для Unix автора Реймонд Эрик Стивен

5.3.1. Учебный пример: SMTP, простой протокол передачи почты В примере 5.7. иллюстрируется транзакция SMTP (Simple Mail Transfer Protocol — простой протокол передачи почты), который описан в спецификации RFC 2821. В данном примере строки, начинающиеся с C:, отправляются почтовым транспортным


3.2 Сетевой стек Windows NT

Из книги Серверные технологии хранения данных в среде Windows® 2000 Windows® Server 2003 автора Дайлип Наик

3.2 Сетевой стек Windows NT Разобраться в особенностях стека сетевого ввода-вывода Windows NT важно по нескольким причинам. Клиент Windows NT использует стек сетевого ввода-вывода для получения доступа к ресурсам, которые находятся под управлением сервера, а также для передачи данных.


3.2.3 Сетевой уровень

Из книги TCP/IP Архитектура, протоколы, реализация (включая IP версии 6 и IP Security) автора Фейт Сидни М

3.2.3 Сетевой уровень Функции сетевого уровня (network layer) выполняет протокол IP, который осуществляет, маршрутизацию данных между системами. Данные могут следовать по одному пути или использовать несколько различных путей при перемещении в интернете. Данные пересылаются в


Простой протокол валидации сертификатов

Из книги Инфраструктуры открытых ключей автора Полянская Ольга Юрьевна

Простой протокол валидации сертификатов Простой протокол валидации сертификатов (Simple Certificate Validation Protocol - SCVP) разрабатывался рабочей группой PKIX для обеспечения делегирования процессов валидации и обнаружения пути сертификации доверенным сторонам в среде Интернет [91].


Сетевой маркетинг

Из книги Интернет – легко и просто! автора Александров Егор

Сетевой маркетинг В Интернете предложения заработать деньги с помощью механизмов сетевого маркетинга (Multi-Level Marketing, MLM) встречаются на каждом углу.Теоретически все выглядит просто шикарно, однако на практике работает с чудовищным скрипом, стуком и пробуксовкой. Причем


Что такое сетевой адрес

Из книги Бесплатные разговоры через Интернет автора Фрузоров Сергей

Что такое сетевой адрес Для того чтобы можно было различать компьютеры в сети, каждому из них присваивается свой уникальный адрес. Так мы всегда сможем идентифицировать компьютер нашего друга и подключиться именно к нему, чтобы начать общение. Мы уже решили, что общаться


Сетевой роман

Из книги Киберпанк: повести и рассказы автора

Сетевой роман mindw0rkОпубликовано: dl, 07.11.06 00:12Вы наверняка читали заметки журналистов о том, что любовь по сети – искусственна по своей природе, что настоящие чувства можно испытать только когда смотришь предмету своего обожания в глаза. Может, господа журналисты в чем-то и


Сетевой протокол

Из книги Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ автора Борри Хелен

Сетевой протокол Предполагается, что вы будете использовать рекомендованный протокол TCP/IP для вашей сети клиент-сервер, чтобы получить все преимущества независимой от платформы сети.! ! !СОВЕТ. Чтобы получить информацию об использовании протокола NetBEUI (Named Pipes, Именованные


Сетевой этикет

Из книги Работа в Интернете. Энциклопедия автора Ташков Петр Андреевич

Сетевой этикет Чтобы чувствовать себя комфортно в любом обществе, не вызывать удивления и негодования старожилов и понимать слова и поступки других людей, необходимо знать как минимум две вещи: язык, на котором здесь общаются, и принятые правила поведения (это применимо


Сетевой вход в систему

Из книги Недокументированные и малоизвестные возможности Windows XP автора Клименко Роман Александрович

Сетевой вход в систему Служба поддерживает возможность входа в систему данного компьютера с помощью сетевого компьютера, входящего в домен, как будто пользователь входит локально. Если данный компьютер не входит в домен, не подключен к сети или сетевой вход в оболочку


4.10. Сетевой экран

Из книги Linux глазами хакера автора Флёнов Михаил Евгеньевич

4.10. Сетевой экран Мы достаточно подробно рассмотрели управление доступом к файлам, но на этом распределение прав не закапчивается. Сейчас уже невозможно работать без соединения с локальной сетью или Интернетом, поэтому, прежде чем наш сервер начнет функционировать, нам


Сетевой адаптер

Из книги Ноутбук [секреты эффективного использования] автора Пташинский Владимир

Сетевой адаптер Адаптер для подключения к локальной сети присутствует в любом ноутбуке. В большинстве случаев это Ethernet 10/100, но сегодня появляются портативные компьютеры, оснащенные Ethernet-картами, поддерживающими скорость соединения 1 Гбит/с. Значимых для пользователя