发UDP包查询时间服务器NTP

CMakeLists.txt

bash 复制代码
cmake_minimum_required(VERSION 3.13)
project(UDPDateTime C)

set(CMAKE_C_STANDARD 90)

add_executable(UDPDateTime main.c)

* main.c

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <netdb.h>
#include <netinet/in.h>

#define NTP_TIMESTAMP_DELTA 2208988800ull

/* NTP Packet structure */
typedef struct {
    uint8_t li_vn_mode;      /* Eight bits. li, vn, and mode.
                             li.   Two bits.   Leap indicator.
                             vn.   Three bits. Version number of the protocol.
                             mode. Three bits. Client will pick mode 3 for client. */

    uint8_t stratum;         /* Eight bits. Stratum level of the local clock. */
    uint8_t poll;            /* Eight bits. Maximum interval between successive messages. */
    int8_t precision;        /* Eight bits. Precision of the local clock. */

    uint32_t rootDelay;      /* 32 bits. Total round trip delay time. */
    uint32_t rootDispersion; /* 32 bits. Max error aloud from primary clock source. */
    uint32_t refId;          /* 32 bits. Reference clock identifier. */

    uint32_t refTm_s;        /* 32 bits. Reference time-stamp seconds. */
    uint32_t refTm_f;        /* 32 bits. Reference time-stamp fraction of a second. */

    uint32_t origTm_s;       /* 32 bits. Originate time-stamp seconds. */
    uint32_t origTm_f;       /* 32 bits. Originate time-stamp fraction of a second. */

    uint32_t rxTm_s;         /* 32 bits. Received time-stamp seconds. */
    uint32_t rxTm_f;         /* 32 bits. Received time-stamp fraction of a second. */

    uint32_t txTm_s;         /* 32 bits. Transmit time-stamp seconds. */
    uint32_t txTm_f;         /* 32 bits. Transmit time-stamp fraction of a second. */

} ntp_packet;                /* Total: 384 bits or 48 bytes. */

void error(const char *msg) {
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[]) {
    int sockfd, n;
    struct addrinfo hints, *res, *p;
    ntp_packet packet;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s hostname\n", argv[0]);
        exit(0);
    }

    /* Configure the hints for getaddrinfo */
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET6; /* Use IPv6 */
    hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
    hints.ai_protocol = IPPROTO_UDP; /* UDP protocol */

    /* Resolve the hostname to an address */
    if (getaddrinfo(argv[1], "123", &hints, &res) != 0) {
        error("ERROR resolving hostname");
    }

    /* Create a socket */
    sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    if (sockfd < 0) {
        error("ERROR opening socket");
    }

    /* Zero out the packet buffer */
    memset(&packet, 0, sizeof(ntp_packet));

    /* Initialize values needed for NTP request */
    packet.li_vn_mode = 0x1b; /* LI = 0, VN = 3, Mode = 3 (client) */

    /* Iterate through the results from getaddrinfo and send the packet */
    for (p = res; p != NULL; p = p->ai_next) {
        /* Send the packet to the server */
        n = sendto(sockfd, (char *)&packet, sizeof(ntp_packet), 0, p->ai_addr, p->ai_addrlen);
        if (n < 0) {
            error("ERROR sending to socket");
        }

        /* Receive the packet from the server */
        n = recv(sockfd, (char *)&packet, sizeof(ntp_packet), 0);
        if (n < 0) {
            error("ERROR receiving from socket");
        }

        break; /* Exit after successfully sending and receiving a packet */
    }

    /* Free the address info linked list */
    freeaddrinfo(res);

    /* Close the socket */
    close(sockfd);

    /* Interpret the NTP server's response */
    packet.txTm_s = ntohl(packet.txTm_s); /* Time-stamp seconds. */
    packet.txTm_f = ntohl(packet.txTm_f); /* Time-stamp fraction of a second. */

    /* Convert NTP time to UNIX time */
    time_t txTm = (time_t)(packet.txTm_s - NTP_TIMESTAMP_DELTA);

    /* Print the time */
    printf("Time: %s", ctime(&txTm));

    return 0;
}

查询 2.pool.ntp.org

nslookup 2.pool.ntp.org

bash 复制代码
Server:        108.61.10.10
Address:    108.61.10.10#53

Non-authoritative answer:
Name:    2.pool.ntp.org
Address: 162.159.200.1
Name:    2.pool.ntp.org
Address: 162.159.200.123
Name:    2.pool.ntp.org
Address: 133.243.238.243
Name:    2.pool.ntp.org
Address: 45.77.20.103
Name:    2.pool.ntp.org
Address: 2603:1040:404:3::188
Name:    2.pool.ntp.org
Address: 2606:4700:f1::1
Name:    2.pool.ntp.org
Address: 2606:4700:f1::123
Name:    2.pool.ntp.org
Address: 2406:da14:10c4:9aa0:123::

得到UTC时间 2024-06-28 02:44:46 Asia/Shanghai 时区 +8h 10点44

sudo tcpdump -i eth0 host 2.pool.ntp.org -XX

#define NTP_TIMESTAMP_DELTA 2208988800ull /* 这个数字代表1900年到1970年多少秒 */

javascript 复制代码
var lp = 0;
for (var y = 1900; y < 1970; y++) {
    if ((y%400==0) || (y%4==0 && y%100!=0)) {
        lp++;
    }
}
console.log(lp);  /* 17 */
console.log(((1970-1900)*365 + 17)*86400);  /* 2208988800 */

Here's a breakdown of the relevant portions of the tcpdump output:

Packet 1: Sent from telaviv172.xyz to the NTP server (2.pool.ntp.org)

  • Timestamp: 02:44:46.233051
  • Source: telaviv172.xyz (IPv6 address 2a05:f480:2c00:17ff:5400:4ff:fee9:7f7f) on port 58492
  • Destination: any.time.nl.ntp on the NTP port (default 123)
Packet Breakdown:
  • Ethernet Frame:
    • 0x0000: fe00 04e9 7f7f 5600 04e9 7f7f 86dd
  • IPv6 Header:
    • 0x0010: 6000 0000 0038 1140 2a05 f480 2c00 17ff 5400 04ff fee9 7f7f
      • This part includes the source IPv6 address: 2a05:f480:2c00:17ff:5400:4ff:fee9:7f7f
    • 0x0020: 2001 0678 0008 0000 0000 0000 0000 0000 0123 e47c 007b 0038 61db 1b00
      • This part includes the destination IPv6 address and the payload (NTP data).
  • NTP Payload:
    • 0x0030: 0123 e47c 007b 0038 61db 1b00
    • The payload includes NTP data specific to the request.

Packet 2: Response from the NTP server to telaviv172.xyz

  • Timestamp: 02:44:46.233263
  • Source: any.time.nl.ntp on port 123
  • Destination: telaviv172.xyz (IPv6 address 2a05:f480:2c00:17ff:5400:4ff:fee9:7f7f) on port 58492
Packet Breakdown:
  • Ethernet Frame:
    • 0x0000: 5600 04e9 7f7f fe00 04e9 7f7f 86dd
  • IPv6 Header:
    • 0x0010: 6001 4c84 0038 113b 2001 0678 0008 0000 0000 0000 0000 0000 0123
      • This part includes the destination IPv6 address.
    • 0x0020: 2a05 f480 2c00 17ff 5400 04ff fee9 7f7f
      • This part includes the source IPv6 address.
  • NTP Payload:
    • 0x0030: 007b e47c 0038 e542 1c02 00e7 0000 0f8e 0000 0074 1e14 233d ea28
    • The payload includes NTP data specific to the response.

Relevant IPv6 Address Information:

In the first packet, from 0x0016 to 0x0026 byte positions, the IPv6 address 2a05:f480:2c00:17ff:5400:4ff:fee9:7f7f is located as follows:

  • 0x0016: 2a05 f480 2c00 17ff 5400 04ff fee9 7f7f

This matches the IPv6 address of telaviv172.xyz. This part of the packet shows the address in its full form, confirming it as the source address for this packet.

In summary, the tcpdump output confirms a successful NTP query and response transaction between telaviv172.xyz and the NTP server, with the correct IPv6 addresses included in the packets.

Let's break down the Ethernet frame information in more detail:

Ethernet Frame Breakdown:

The Ethernet frame starts from 0x0000 and includes the following information:

  • Destination MAC Address: The first 6 bytes
  • Source MAC Address: The next 6 bytes
  • Type/Length: The following 2 bytes
Ethernet Frame:
  • 0x0000: fe00 04e9 7f7f 5600 04e9 7f7f 86dd
  1. Destination MAC Address:
    • fe:00:04:e9:7f:7f
  2. Source MAC Address:
    • 56:00:04:e9:7f:7f
  3. Type/Length:
    • 0x86dd

Analysis of 0x86dd

  • 0x86dd is the EtherType field in the Ethernet frame.
  • The value 0x86dd indicates that the payload of the Ethernet frame is an IPv6 packet. This is specified by the EtherType for IPv6, which is 0x86dd.

So, the correct interpretation of the Ethernet frame details is:

  • Destination MAC Address: fe:00:04:e9:7f:7f
  • Source MAC Address: 56:00:04:e9:7f:7f
  • Type: 0x86dd (indicating an IPv6 packet)

This means your original interpretation of the MAC addresses and the following two bytes being the EtherType field for IPv6 is correct.

相关推荐
藥瓿亭10 分钟前
K8S认证|CKS题库+答案| 10. Trivy 扫描镜像安全漏洞
linux·运维·服务器·云原生·容器·kubernetes·cks
leo__52039 分钟前
在Ubuntu中设置开机自动运行(sudo)指令的指南
服务器·ubuntu·postgresql
不像程序员的程序媛1 小时前
http接口莫名奇妙返回body空白
网络·网络协议·http
rui锐rui2 小时前
大模型模型部署和暴露接口
linux·运维·服务器
Clownseven2 小时前
云防火墙(安全组)配置指南:从入门到精通端口开放 (2025)
服务器·安全
码农101号12 小时前
Linux中shell编程表达式和数组讲解
linux·运维·服务器
是小满满满满吗12 小时前
传输层:udp与tcp协议
linux·服务器·网络
CryptoPP13 小时前
使用WebSocket实时获取印度股票数据源(无调用次数限制)实战
后端·python·websocket·网络协议·区块链
Mintimate13 小时前
云服务器 Linux 手动 DD 安装第三方 Linux 发行版:原理与实战
linux·运维·服务器
gadiaola13 小时前
【计算机网络】第3章:传输层—TCP 拥塞控制
网络·网络协议·tcp/ip·计算机网络