发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.

相关推荐
yaoxin5211234 分钟前
第三十二章 UDP 客户端 服务器通信
服务器·网络协议·udp
筱小虾米2 小时前
解决SSL VPN客户端一直提示无法连接服务器的问题
运维·服务器
杨充5 小时前
16.迭代器模式设计思想
网络协议·rpc·迭代器模式
wanhengwangluo7 小时前
裸金属服务器能够帮助企业解决哪些问题?
运维·服务器
titxixYY7 小时前
SElinux
linux·运维·服务器
Tony聊跨境8 小时前
反向代理服务器的用途是什么?
网络·网络协议·tcp/ip·智能路由器·ip
聚名网8 小时前
手机无法连接服务器1302什么意思?
运维·服务器·智能手机
代码欢乐豆9 小时前
软件工程第13章小测
服务器·前端·数据库·软件工程
望获linux10 小时前
在 ARM 平台上如何实现Linux系统的1秒启动
linux·服务器·开发语言·数据库·操作系统·嵌入式操作系统·arm平台
先天打工圣体的男人10 小时前
Linux中安装InfluxDB
linux·运维·服务器