首页 > 解决方案 > 使用 UDP 传输格式化 SOCK_RAW 以查询 NTP

问题描述

我想使用专门的原始套接字查询 NTP 服务器。这是我一段时间后得到的,但我的回复被解码为 12/31/1899。我认为我的结构是正确的,但我搞砸了我传递记忆的方式。(我在 Windows 上的 Ubuntu VM 中运行它。我确实在 VM 中以 root 身份运行该程序)。

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include <errno.h>
#include <netinet/udp.h>
#include <netinet/ip.h>


#define LI(packet)   (uint8_t) ((packet.li_vn_mode & 0xC0) >> 6)
#define VN(packet)   (uint8_t) ((packet.li_vn_mode & 0x38) >> 3)
#define MODE(packet) (uint8_t) ((packet.li_vn_mode & 0x07) >> 0)

void goFail( char* msg ) {
    perror(msg);
    exit(1);
}

unsigned short checkSum(unsigned short *buf, int nwords) {
        unsigned long sum;
        for(sum=0; nwords>0; nwords--) {
             sum += *buf++;
        }
        sum = (sum >> 16) + (sum &0xffff);
        sum += (sum >> 16);

        return (unsigned short)(~sum);
}

struct ipheader {
 unsigned char      iph_ihl:5, iph_ver:4;
 unsigned char      iph_tos;
 unsigned short int iph_len;
 unsigned short int iph_ident;
 unsigned char      iph_flag;
 unsigned short int iph_offset;
 unsigned char      iph_ttl;
 unsigned char      iph_protocol;
 unsigned short int iph_chksum;
 unsigned int       iph_sourceip;
 unsigned int       iph_destip;
};

struct udpheader {
 unsigned short int udph_srcport;
 unsigned short int udph_destport;
 unsigned short int udph_len;
 unsigned short int udph_chksum;

};

int main()   {
  printf("\nStarted...");
  fflush(stdout);

  char* host_name = "pool.ntp.org";
  char* source_name = "174.44.196.123";


  typedef struct {
    uint8_t li_vn_mode;
    uint8_t stratum;
    uint8_t poll;
    uint8_t precision;

    uint32_t rootDelay;
    uint32_t rootDispersion;
    uint32_t refId;

    uint32_t refTm_s;
    uint32_t refTm_f;
    uint32_t origTm_s;
    uint32_t origTm_f;

    uint32_t rxTm_s;
    uint32_t rxTm_f;
    uint32_t txTm_s;
    uint32_t txTm_f;
  } ntp_packet;


//  ntp_packet ntp_data_packet;// = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
//  memset( &ntp_data_packet, 0, sizeof( ntp_packet ) );
//  *( ( char * ) &ntp_data_packet + 0 ) = 0x1b;

  int raw_sock;

  //TODO what buffer size??
  char buffer[sizeof(ntp_packet) + sizeof(struct ipheader) + sizeof(struct udpheader)];
  memset(&buffer, 0, sizeof(buffer));


  struct ipheader *ip = (struct ipheader *) &buffer[0];
  struct udpheader *udp = (struct udpheader *)  (&buffer[0] + sizeof(struct ipheader));
  ntp_packet *ntp_data_packet = (ntp_packet*)&buffer + sizeof (struct ipheader) + sizeof(struct udpheader);

    printf("\nsizeof ip %d",sizeof(*ip));
    printf("\nsizeof ud %d",sizeof(*udp));
    printf("\nsizeof nt %d",sizeof(*ntp_data_packet));
    printf("\nsizeof buf %d\n",sizeof(buffer));

  ntp_data_packet->li_vn_mode = 0x1b;




  struct sockaddr_in sin, din;
  int one = 1;
  const int *val = &one;

  //TODO another size
//  memset(&buffer, 0, sizeof (sizeof(ntp_packet)));

  // Create a raw socket with UDP protocol

  raw_sock = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);

  if(raw_sock < 0) {
      goFail("Socket() error");
  }

  sin.sin_family = AF_INET;
  din.sin_family = AF_INET;

  sin.sin_port = htons(613);
  din.sin_port = htons(123);

  sin.sin_addr.s_addr = inet_addr(source_name);
  din.sin_addr.s_addr = inet_addr(host_name);

  ip->iph_ihl = 5;
  ip->iph_ver = 4;
  ip->iph_tos = 16; // Low delay
  ip->iph_len = sizeof(struct ipheader) + sizeof(struct udpheader) +sizeof(ntp_packet) ;
  ip->iph_ident = htons(6130);
  ip->iph_ttl = 255; // hops
  ip->iph_protocol = 17; // UDP
  ip->iph_sourceip = inet_addr(source_name);
  ip->iph_destip = inet_addr(gethostbyname(host_name));

  udp->udph_srcport = htons(613);
  udp->udph_destport = htons(123);
  udp->udph_len = htons(sizeof(struct udpheader) + sizeof(ntp_packet));

  ip->iph_chksum = checkSum((unsigned short *)&ntp_data_packet, sizeof(struct ipheader) + sizeof(struct udpheader));

//  if(setsockopt(raw_sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) {
//      goFail("setSockOpt() error");
//  }

  printf("...Using raw socket and UDP protocol...");

//  int wrresponse = write( sd, ( char* ) &packet, sizeof( ntp_packet ) );
//  int read_response = read( sd, ( char* ) &packet, sizeof( ntp_packet ) );

  printf("\nBefore send\n");
  for(int i =0; i<sizeof (buffer);i++) {
      if (i%16==0) {
          printf("\n");
      }
          printf("%x ",buffer[i] & 0xff);

  }



  if( sendto(raw_sock, &buffer, sizeof(buffer), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
    goFail("sendto() error");
  }



  printf("\nBefore read: %d",ntp_data_packet->txTm_s);



  printf("...Sendto() is OK...");
//  int n = read( raw_sock, ( char* ) buffer, sizeof(buffer) );
  int n = recv(raw_sock,buffer,sizeof(buffer),0);
  printf("\nAfter read with result %d\n",n);
  for(int i =0; i<sizeof (buffer);i++) {
      if (i%16==0) {
          printf("\n");
      }
          printf("%x ",buffer[i] & 0xff);

  }
  printf("...Got a packet!...");
  fflush(stdout);

  if ( n <= 0 ) {
    goFail( "couldnt read from socket" );
  }

    printf("\nAfter read: %d\n",ntp_data_packet->txTm_s);

  ntp_data_packet->txTm_s = ntohl( ntp_data_packet->txTm_s );
  ntp_data_packet->txTm_f = ntohl( ntp_data_packet->txTm_f );

      printf("\nAfter format: %d\n",ntp_data_packet->txTm_s);

  time_t txTm = ( time_t ) ( ntp_data_packet->txTm_s - 2208988800ull );
  printf( "DECODED RAW: The time is: %s", ctime( ( const time_t* ) &txTm ) );

  close(raw_sock);

  return 0;
}

(我知道我可以只使用 SOCK_DGRAM,但这个练习是探索原始套接字)。

输出

Program output:
Started...
sizeof ip 24
sizeof ud 8
sizeof nt 48
sizeof buf 80
...Using raw socket and UDP protocol...
Before send

5 4 10 0 50 0 17 f2 0 0 0 0 ff 11 a6 d5
ae 2c c4 7b ff ff ff ff 2 65 0 7b 0 38 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Before read: 3681606...Sendto() is OK...
After read with result 69

45 0 0 45 4a 5f 40 0 40 11 f2 12 7f 0 0 1
7f 0 0 35 94 ec 0 35 0 31 fe 78 6d 6 1 0
0 1 0 0 0 0 0 1 4 70 6f 6f 6c 3 6e 74
70 3 6f 72 67 0 0 1 0 1 0 0 29 4 b0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...Got a packet!...
After read: 3681606

After format: 1177368576
DECODED RAW: The time is: Fri Apr 23 17:49:36 1937

标签: csocketsntp

解决方案


推荐阅读