1 /* ntp.c - Network Timxe Protocol module for sendip
2 * Author: Mike Ricketts <mike@earth.li>
3 * ChangeLog since 2.1 release:
10 #include <netinet/in.h>
11 #include <arpa/inet.h>
12 #include <sys/socket.h>
13 #include "sendip_module.h"
16 /* Character that identifies our options
18 const char opt_char='n';
20 u_int32_t make_fixed_point(double n, bool issigned, int totbits, int intbits) {
25 double intpartd, fracpartd;
28 if(issigned) totbits--;
30 fracbits=totbits-intbits;
36 } /* else, signbit is unused */
41 fracpartd=floor(ldexp(modf(n,&intpartd),ldexp(2.0,fracbits)));
43 fracpartd=floor(ldexp(modf(n,&intpartd),32));
44 intpart=(u_int32_t)intpartd;
45 fracpart=(u_int32_t)fracpartd;
48 if(issigned&&signbit) {
55 intpart&=(1<<intbits)-1;
56 intpart<<=(totbits-intbits);
59 if(intbits!=totbits) {
61 fracpart&=((1<<fracbits)-1)<<intbits;
69 bool make_ts(ntp_ts *dest, char *src) {
70 char *intpart, *fracpart;
72 fracpart=strchr(intpart,'.');
75 dest->intpart=(u_int32_t)strtoul(intpart,&fracpart,0);
79 fracpart++; // skip the .
80 if(fracpart && *fracpart) {
82 d = strtod(fracpart-1,(char **)NULL);
83 dest->fracpart=make_fixed_point(d,FALSE,32,0);
88 sendip_data *initialize(void) {
89 sendip_data *ret = malloc(sizeof(sendip_data));
90 ntp_header *ntp = malloc(sizeof(ntp_header));
91 memset(ntp,0,sizeof(ntp_header));
92 ret->alloc_len = sizeof(ntp_header);
93 ret->data = (void *)ntp;
98 bool do_opt(char *opt, char *arg, sendip_data *pack) {
99 ntp_header *ntp = (ntp_header *)pack->data;
101 case 'l': /* Leap Indicator (2 bits) */
102 ntp->leap=(u_int8_t)strtoul(arg,(char **)NULL,0)&3;
103 pack->modified|=NTP_MOD_LEAP;
105 case 's': /* Status (6 bits, values 0-4 defined */
106 ntp->status=(u_int8_t)strtoul(arg,(char **)NULL,0)&0x3F;
107 pack->modified|=NTP_MOD_STATUS;
109 case 't': /* Type (8 bits, values 0-4 defined */
110 ntp->type=(u_int8_t)strtoul(arg,(char **)NULL,0)&0xFF;
111 pack->modified|=NTP_MOD_TYPE;
113 case 'p': /* precision (16 bits, range +32 to -32) */
114 ntp->precision=htons((int8_t)strtol(arg,(char **)NULL,0));
115 pack->modified|=NTP_MOD_PRECISION;
117 case 'e': /* esitmated error (32 bits, fixed point between bits 15/16) */
118 ntp->error=make_fixed_point(strtod(arg,(char **)NULL),FALSE,32,16);
119 pack->modified|=NTP_MOD_ERROR;
121 case 'd': /* estimated drift rate (32 bits, signed fixed point left of
123 ntp->drift=make_fixed_point(strtod(arg,(char **)NULL),TRUE,32,0);
124 pack->modified|=NTP_MOD_DRIFT;
126 case 'r': /* reference clock id (32 bits or a 4 byte string). Can be:
127 If type==1: "WWVB", "GOES", "WWV\0"
128 If type==2: IP address
131 if('0'<=*arg&&*arg<='9') {
132 /* either a number or an IP */
133 if((ntp->reference.ipaddr=inet_addr(arg))==-1) {
134 /* Not a valid IP, or really want 255.255.255.255 */
135 if(strcmp(arg,"255.255.255.255")) {
136 ntp->reference.ipaddr=htonl(strtol(arg,(char **)NULL,0));
140 /* Hopefully a 4 byte or less string */
141 ntp->reference.ipaddr = 0;
143 memcpy(ntp->reference.id,arg,strlen(arg));
145 usage_error("NTP reference clock ID must be IP addr, 32 bit integer, or 4 byte string\n");
149 pack->modified|=NTP_MOD_REF;
151 case 'f': /* reference timestamp (64 bits) */
152 if(make_ts(&(ntp->reference_ts),arg)) {
153 pack->modified|=NTP_MOD_REFERENCE;
155 usage_error("Couldn't parse NTP reference timestamp\n");
159 case 'o': /* originate timestamp (64 bits) */
160 if(make_ts(&(ntp->originate_ts),arg)) {
161 pack->modified|=NTP_MOD_ORIGINATE;
163 usage_error("Couldn't parse NTP originate timestamp\n");
167 case 'a': /* receive timestamp (64 bits) */
168 if(make_ts(&(ntp->receive_ts),arg)) {
169 pack->modified|=NTP_MOD_RECEIVE;
171 usage_error("Couldn't parse NTP receive timestamp\n");
175 case 'x': /* transmit timestamp (64 bits) */
176 if(make_ts(&(ntp->transmit_ts),arg)) {
177 pack->modified|=NTP_MOD_TRANSMIT;
179 usage_error("Couldn't parse NTP transmit timestamp\n");
188 bool finalize(char *hdrs, sendip_data *headers[], sendip_data *data,
190 if(hdrs[strlen(hdrs)-1] != 'u') {
191 usage_error("Warning: NTP should be contained in a UDP packet\n");
197 return sizeof(ntp_opts)/sizeof(sendip_option);
199 sendip_option *get_opts() {