-/* Check for isc/binds logging facility, probably interesting, probably worth adapting */
+/* Add timestamps to file logging!!! */
#include "log.h"
#include "sntp-opts.h"
void log_msg(char *message, char type) {
if(init) {
- printf("log!\n");
- printf(log_file, message);
+ fprintf(log_file, message);
}
else {
- printf("ELSEZWEIG!!!!! HAAAAAARRRRRRRRRRRRRRRRRG!\n");
switch(type) {
case 0:
type = LOG_CONS;
#define DEBUG
-int ai_fam_templ;
+int ai_fam_pref;
volatile int debug;
char adr_buf[INET6_ADDRSTRLEN];
)
{
register int c;
+ struct kod_entry **reason = NULL;
+ /* IPv6 available? */
if (isc_net_probeipv6() != ISC_R_SUCCESS) {
- ai_fam_templ = AF_INET;
+ ai_fam_pref = AF_INET;
#ifdef DEBUG
printf("No ipv6 support available, forcing ipv4\n");
#endif
}
+ else {
+ /* Check for options -4 and -6 */
+ if(ENABLED_OPT(IPV4))
+ ai_fam_pref = AF_INET;
+ else if(ENABLED_OPT(IPV6))
+ ai_fam_pref = AF_INET6;
+ else
+ ai_fam_pref = NULL;
+ }
-#ifndef NO_DISK
-#endif
log_msg("Started sntp", 0);
int optct = optionProcess(&sntpOptions, argc, argv);
/* Initialize logging system */
if(HAVE_OPT(FILELOG)) {
- init_log((char *) OPT_ARG(FILELOG));
+ init_log((char *)OPT_ARG(FILELOG));
}
+ /* If there's a specified KOD file init KOD system.
+ * If not and system may save to HD use default file.
+ */
if(HAVE_OPT(KOD)) {
- kod_init_kod_db(OPT_ARG(KOD));
+ kod_init_kod_db((char *)OPT_ARG(KOD));
+ }
+ else {
+ kod_init_kod_db("sntp.kod");
}
-
/* Considering employing a variable that prevents functions of doing anything until
* everything is initialized properly
*/
struct addrinfo **resh = (struct addrinfo **) malloc(sizeof(struct addrinfo **));
- int resc = resolve_hosts(argv, argc, resh);
+ int resc = resolve_hosts(argv, argc, resh, ai_fam_pref);
if(resc < 1) {
/* Error! Network down? */
getnameinfo(resh[c]->ai_addr, resh[c]->ai_addrlen, adr_buf,
INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
- if(!kod_entry_exists(adr_buf) &&
+ int kodc;
+ char *hostname = addrinfo_to_str(resh[c]);
+
+ if((kodc = search_entry(hostname, reason)) == 0 &&
is_reachable(resh[c])) {
int ow_ret = on_wire(resh[c]);
if(ow_ret < 0) {
- printf("on_wire failed!\n");
+ printf("on_wire failed for server %s!\n", hostname);
}
else {
sync_data_suc = 1;
}
}
else {
- struct kod_entry **reason;
- int kodc = search_entry(resh[c], reason);
-
- printf("KoD package exists for %s, stopping any further communication.\n",
- adr_buf);
+ printf("KoD %i packages exists for %s, stopping any further communication.\n",
+ kodc, adr_buf);
}
freeaddrinfo(resh[c]);
+ free(hostname);
}
return 0;
}
+/* The heart of (S)NTP, exchange NTP packets and compute values to correct the local clock */
int
on_wire (
struct addrinfo *host
double t21, t34, delta, offset;
- int error, rsock, rpktl;
+ int error, rpktl, sw_case;
+
+ char *hostname;
- l_fp p_rec, p_xmt, p_ref, p_org, xmt, org, tmp, dst, theta;
+ l_fp p_rec, p_xmt, p_ref, p_org, xmt, tmp, dst;
error = GETTIMEOFDAY(&tv_xmt, (struct timezone *)NULL);
/* FIXME! Modus broadcast + adr. check -> bdr. pkt */
set_li_vn_mode(x_pkt, LEAP_NOTINSYNC, 4, 3);
-
-
create_socket(&sock, (struct sockaddr_storage *)host->ai_addr);
- rsock = sendpkt(sock, host->ai_addr, x_pkt, LEN_PKT_NOMAC);
+ sendpkt(sock, (struct sockaddr_storage *)host->ai_addr, x_pkt, LEN_PKT_NOMAC);
rpktl = recvpkt(sock, r_pkt, x_pkt);
close_socket(sock);
-/* if(rpktl == -1)
- return -1; */
-
- /* -2 would indicate that we should try to get a packet
- * from this server again
- */
- if(rpktl != -2) {
+ if(rpktl > 0)
+ sw_case = 1;
+ else
+ sw_case = rpktl;
+
+ switch(sw_case) {
+ case SERVER_UNUSEABLE:
+ return -1;
+ break;
+
+ case PACKET_UNUSEABLE:
+ break;
+
+ case SERVER_AUTH_FAIL:
+ break;
+
+ case KOD_DEMOBILIZE:
+ /* Received a DENY or RESTR KOD packet */
+ hostname = addrinfo_to_str(host);
+ add_entry(hostname, (char *) &r_pkt->refid);
+
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("on_wire: Received KOD packet with code: %s from %s, demobilizing all connections\n",
+ (char *) r_pkt->refid, hostname);
+
+ char *log_str = (char *) malloc(sizeof(char) * (INET6_ADDRSTRLEN + 72));
+ snprintf(log_str, (INET6_ADDRSTRLEN + 72),
+ "Received a KOD packet with code %s from %s, demobilizing all connections",
+ (char *) &r_pkt->refid, hostname);
+
+ log_msg(log_str, 2);
+
+ free(log_msg);
+ break;
+
+ case KOD_RATE:
+ /* Hmm... probably we should sleep a bit here */
+ break;
+
+ case 1:
+
+ /* Convert timestamps from network to host byte order */
NTOHL_FP(&r_pkt->reftime, &p_ref);
NTOHL_FP(&r_pkt->org, &p_org);
NTOHL_FP(&r_pkt->rec, &p_rec);
#ifdef DEBUG
pkt_output(r_pkt, rpktl, stdout);
-
+
printf("on_wire: rpkt->reftime:\n");
l_fp_output(&(r_pkt->reftime), stdout);
printf("on_wire: rpkt->org:\n");
l_fp_output(&(r_pkt->xmt), stdout);
#endif
+ /* Compute offset etc. */
GETTIMEOFDAY(&tv_dst, (struct timezone *)NULL);
tv_dst.tv_sec += JAN_1970;
-
+
tmp = p_rec;
L_SUB(&tmp, &p_org);
if(ENABLED_OPT(NORMALVERBOSE))
printf("on_wire: t21: %.6f\t t34: %.6f\ndelta: %.6f\t offset: %.6f\n",
- t21, t34, delta, offset);
+ t21, t34, delta, offset);
-/* set_time(offset); */
+ set_time(offset);
return 0;
}
return -1;
}
+/* Compute the 8 bits for li_vn_mode */
void
set_li_vn_mode (
struct pkt *spkt,
spkt->li_vn_mode |= mode;
}
+/* set_time corrects the local clock by offset with either settimeofday() or by default
+ * with adjtime()/adjusttimeofday().
+ */
int
set_time (
double offset
struct timeval tp;
if(ENABLED_OPT(SETTOD)) {
-
GETTIMEOFDAY(&tp, (struct timezone *)NULL);
tp.tv_sec += (int) offset;
return 0;
}
}
-
-
}
-
-#include <config.h>
-#include <unistd.h>
-
#include "sntp-opts.h"
#include "networking.h"
#include "header.h"
char adr_buf[INET6_ADDRSTRLEN];
+/* resolve_hosts consumes an arry of hostnames/addresses and its length, stores a pointer
+ * to the array with the resolved hosts in res and returns the size of the array res.
+ * pref_family enforces IPv4 or IPv6 depending on commandline options and system
+ * capability. If pref_family is NULL or PF_UNSPEC any compatible family will be accepted.
+ * Check here: Probably getaddrinfo() can do without ISC's IPv6 availability check?
+ */
int
resolve_hosts (
char **hosts,
int hostc,
- struct addrinfo **res
+ struct addrinfo **res,
+ int pref_family
)
{
register unsigned int a, b;
int error;
memset(&hints, 0, sizeof(hints));
- hints.ai_family = PF_UNSPEC;
- hints.ai_socktype = SOCK_DGRAM;
-/* hints.ai_protocol = IPPROTO_UDP; */
+ if(pref_family == NULL)
+ hints.ai_family = PF_UNSPEC;
+ else
+ hints.ai_family = pref_family;
+
+ hints.ai_socktype = SOCK_DGRAM;
error = getaddrinfo(hosts[a], "123", &hints, tres[a]);
return entryc;
}
+/* Creates a socket and returns. */
void
create_socket (
SOCKET *rsock,
}
+/* If there's nothing more to do here we might need this function */
void
close_socket (
SOCKET rsock
#endif
}
+/* Receive raw data */
int
recvdata (
SOCKET rsock,
struct sockaddr_storage *sender,
char *rdata,
- size_t rdata_length,
- char *done
+ size_t rdata_length
)
{
socklen_t slen = SOCKLEN(&rsock);
printf("Failure, recvc: %i\n", recvc);
}
#endif
- /* Remove this when found a reasonable max. size. For now
- * notify when there's data left to fetch
- */
- if(recvc >= 511)
- *done = 0;
- else
- *done = 1;
return recvc;
}
-/* Fetch data, check if it's data for us and whether it's useable or not. If not, return -1
- * so we can delete this server from our list and continue with another one.
+/* Receive data from broadcast. Couldn't finish that. Need to do some digging
+ * here, especially for protocol independence and IPv6 multicast */
+int
+recvbcst (
+ SOCKET rsock,
+ struct pkt *rpkt,
+ struct sockaddr_storage *sas
+ )
+{
+
+ return 0;
+}
+
+
+
+/* Fetch data, check if it's data for us and whether it's useable or not. If not, return
+ * a failure code so we can delete this server from our list and continue with another one.
*/
int
recvpkt (
)
{
register int a;
- int has_mac;
- int is_authentic;
+ int has_mac, is_authentic;
- l_fp tmp;
l_fp org;
- l_fp rec;
struct sockaddr_storage sender;
/* Much space, just to be sure */
rdata = (char *) malloc(sizeof(char) * 512);
- int pkt_length = recvdata(rsock, &sender, rdata, 512, &done);
+ int pkt_length = recvdata(rsock, &sender, rdata, 512);
if(!done) {
/* Do something about it, first check for a maximum length of ntp packets,
*/
}
+ pkt_length = min(pkt_length, sizeof(struct pkt));
+
+ for(a=0; a<pkt_length; a++)
+ ((unsigned char *) rpkt)[a] = rdata[a];
+
/* Some checks to see if that packet is intended for us */
+ /* No MAC, no authentication */
if(pkt_length == LEN_PKT_NOMAC)
has_mac = 0;
+ /* If there's more than just the NTP packet it should be a MAC */
else if(pkt_length > LEN_PKT_NOMAC)
has_mac = pkt_length - LEN_PKT_NOMAC;
else
if(debug) {
fprintf(stderr, "recvpkt: Funny packet length: %i. Discarding package.\n", pkt_length);
- return -1;
+ return PACKET_UNUSEABLE;
}
- if(has_mac) {
- if(has_mac > MAX_MAC_LEN || has_mac % 4 != 0) {
- return -1;
- }
- /* Do auth stuff */
- }
-
- /*struct pkt *tmp_rpkt = (struct pkt *)rdata;
- rpkt->li_vn_mode = tmp_rpkt->li_vn_mode;
- rpkt->stratum = tmp_rpkt->stratum;
- rpkt->ppoll = tmp_rpkt->ppoll;
- rpkt->precision = tmp_rpkt->precision;
- rpkt->rootdelay = tmp_rpkt->rootdelay;
- rpkt->rootdisp = tmp_rpkt->rootdisp;
- rpkt->refid = tmp_rpkt->refid;
- rpkt->reftime = tmp_rpkt->reftime;
- rpkt->org = tmp_rpkt->org;
- rpkt->rec = tmp_rpkt->rec;
- rpkt->xmt = tmp_rpkt->xmt; */
-
+ /* Packet too big */
if(pkt_length > LEN_PKT_MAC) {
if(ENABLED_OPT(NORMALVERBOSE))
printf("sntp recvpkt: Received packet is too big (%i bytes), trying again to get a useable packet\n",
pkt_length);
- return -2;
+ return PACKET_UNUSEABLE;
}
-
- for(a=0; a<pkt_length; a++)
- ((unsigned char *) rpkt)[a] = rdata[a];
- printf("%x %x\n", PKT_VERSION(rpkt->li_vn_mode), NTP_OLDVERSION);
- if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
+ /* MAC could be useable for us */
+ if(has_mac) {
+ /* Two more things that the MAC must conform to */
+ if(has_mac > MAX_MAC_LEN || has_mac % 4 != 0) {
+ is_authentic = 0; /* Or should we discard this packet? */
+ }
+ else {
+ /* Do auth stuff */
+ }
+ }
+
+ /* Check for server's ntp version */
+ if(PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
- return -1;
+ return SERVER_UNUSEABLE;
}
- if (PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
+ /* We want a server to sync with */
+ if(PKT_MODE(rpkt->li_vn_mode) != MODE_SERVER
&& PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
#ifdef DEBUG
printf("sntp recvpkt: mode %d stratum %i\n",
PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
#endif
- return -1;
+ return SERVER_UNUSEABLE;
}
if(rpkt->stratum == STRATUM_PKT_UNSPEC) {
if(ENABLED_OPT(NORMALVERBOSE))
- printf("sntp recvpkt: Unusable packet, discarding. (stratum: %i)\n", rpkt->stratum);
+ printf("sntp recvpkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt->stratum);
+
+
+ char *ref_char = (char *) &rpkt->refid;
- return -1;
+ /* If it's a KOD packet we'll just use the KOD information */
+ if(ref_char[0] != 'X') {
+ if(strncmp(ref_char, "DENY", 4))
+ return KOD_DEMOBILIZE;
+
+ if(strncmp(ref_char, "RSTR", 4))
+ return KOD_DEMOBILIZE;
+
+ if(strncmp(ref_char, "RATE", 4))
+ return KOD_RATE;
+
+ /* There are other interesting kiss codes which might be interesting for authentication */
+ }
}
+ /* If the server is not synced it's not really useable for us */
if(PKT_LEAP(rpkt->li_vn_mode) == LEAP_NOTINSYNC) {
if(ENABLED_OPT(NORMALVERBOSE))
printf("sntp recvpkt: Server not in sync, skipping this server\n");
- return -1;
+ return SERVER_UNUSEABLE;
}
if (!L_ISEQU(&org, &spkt->xmt)) {
if (debug)
printf("receive: pkt.org and peer.xmt differ\n");
- return -1;
+
+ return PACKET_UNUSEABLE;
}
-
- /* Left for now, finishin other stuff. I think I might want that somewhere else,
- * don't want this function to do on-wire tasks. Sanity checks are right here I think
- *
- server->leap = PKT_LEAP(rpkt->li_vn_mode);
- server->stratum = PKT_TO_STRATUM(rpkt->stratum);
- server->precision = rpkt->precision;
- server->rootdelay = ntohl(rpkt->rootdelay);
- server->rootdisp = ntohl(rpkt->rootdisp);
- server->refid = rpkt->refid;
- NTOHL_FP(&rpkt->reftime, &server->reftime);
- NTOHL_FP(&rpkt->rec, &rec);
- NTOHL_FP(&rpkt->xmt, &server->org);
-
- if (L_ISZERO(&rec) || !L_ISHIS(&server->org, &rec))
- return -1; */
-
return pkt_length;
}
/*
* is_reachable - check to see if we have a route to given destination
- * (non-blocking).
*/
int
is_reachable (
-#ifndef NETWORK_H
-#define NETWORK_H
+#ifndef NETWORKING_H
+#define NETWORKING_H
#include <strings.h>
#include <errno.h>
+#include <config.h>
+#include <unistd.h>
+
#include <ntp_stdlib.h>
+#include <ntp_machine.h>
+#include <ntp_fp.h>
+#include <ntp.h>
-#include "data_formats.h"
-/* FIXME, see portability issue 1 */ /* irrelevant for now */
-#ifndef SYS_WINNT
-#define SOCKET int
-#define INVALID_SOCKET -1
-#define SOCKET_ERROR -1
-#define closesocket close
-#endif
+#define SERVER_UNUSEABLE -1 /* Skip server */
+#define PACKET_UNUSEABLE -2 /* Discard packet and try to get a useable packet again if not tried too often */
+#define SERVER_AUTH_FAIL -3 /* Authentication failed, act upon settings */
+#define KOD_DEMOBILIZE -4 /* KOD packet with code DENY or RSTR, stop all communication and save KOD information */
+#define KOD_RATE -5 /* KOD packet with code RATE, reduce poll intervall */
/* From ntpdate.c */
int is_reachable (struct addrinfo *dst);
-int resolve_hosts (char **hosts, int hostc, struct addrinfo **res);
+int resolve_hosts (char **hosts, int hostc, struct addrinfo **res, int pref_family);
void create_socket (SOCKET *rsock, struct sockaddr_storage *dest);
void close_socket (SOCKET rsock);
-void send_pkt (SOCKET rsock, struct sockaddr_storage *dest, struct pkt *pkt, int len);
+void sendpkt (SOCKET rsock, struct sockaddr_storage *dest, struct pkt *pkt, int len);
-int recvdata (SOCKET rsock, struct sockaddr_storage *sender, char *rdata, size_t rdata_length, char *done);
+int recvdata (SOCKET rsock, struct sockaddr_storage *sender, char *rdata, size_t rdata_length);
int recvpkt (SOCKET rsock, struct pkt *rpkt, struct pkt *spkt);
+int recvbcst (SOCKET rsock, struct pkt *rpkt, struct sockaddr_storage *sas);
+
+/* Shortened peer structure. Not absolutely necessary yet */
+struct speer {
+ struct speer *next;
+ struct sockaddr_storage srcadr;
+ u_char version;
+ u_char hmode;
+ u_char hpoll;
+ u_char minpoll;
+ u_char maxpoll;
+ u_int flags;
+ u_char num_events;
+ u_char ttl;
+ u_char leap;
+ u_char pmode;
+ u_char stratum;
+ u_char ppoll;
+ u_char precision;
+ u_int32 refid;
+ l_fp reftime;
+ keyid_t keyid;
+
+#ifdef OPENSSL
+#define clear_to_zero opcode
+ u_int32 opcode; /* last request opcode */
+ associd_t assoc; /* peer association ID */
+ u_int32 crypto; /* peer status word */
+ EVP_PKEY *pkey; /* public key */
+ const EVP_MD *digest; /* message digest algorithm */
+ char *subject; /* certificate subject name */
+ char *issuer; /* certificate issuer name */
+ struct cert_info *xinfo; /* issuer certificate */
+ keyid_t pkeyid; /* previous key ID */
+ keyid_t hcookie; /* host cookie */
+ keyid_t pcookie; /* peer cookie */
+ const struct pkey_info *ident_pkey; /* identity key */
+ BIGNUM *iffval; /* identity challenge (IFF, GQ, MV) */
+ const BIGNUM *grpkey; /* identity challenge key (GQ) */
+ struct value cookval; /* receive cookie values */
+ struct value recval; /* receive autokey values */
+ struct exten *cmmd; /* extension pointer */
+ u_long refresh; /* next refresh epoch */
+
+ /*
+ * Variables used by authenticated server
+ */
+ keyid_t *keylist; /* session key ID list */
+ int keynumber; /* current key number */
+ struct value encrypt; /* send encrypt values */
+ struct value sndval; /* send autokey values */
+#else /* OPENSSL */
+#define clear_to_zero status
+#endif /* OPENSSL */
+
+ l_fp rec; /* receive time stamp */
+ l_fp xmt; /* transmit time stamp */
+ l_fp dst; /* destination timestamp */
+ l_fp aorg; /* origin timestamp */
+ l_fp borg; /* alternate origin timestamp */
+ double offset; /* peer clock offset */
+ double delay; /* peer roundtrip delay */
+};
+
+
+
+
+
#endif
_EndOfDoc_;
};
+flag = {
+ name = broadcast;
+ value = b;
+ descrip = "Use broadcast packages for synchronisation";
+ doc = <<- _EndOfDoc_
+ If specified SNTP will wait 5 minutes for broadcast packets
+ for synchronisation. The amount of time SNTP waits can be
+ specified by option -t.
+ _EndOfDoc_;
+};
+
+flag = {
+ name = timeout;
+ value = t;
+ descrip = "Specify the number of seconds until SNTP times out when waiting for broadcast packets";
+ arg-type = number;
+ doc = <<- _EndOfDoc_
+ When waiting for a broadcast packet SNTP will wait the number
+ of seconds specified and times out.
+ _EndOfDoc_;
+};
+
+
detail = <<- _END_DETAIL
.I sntp
can be used as a SNTP client to query a NTP or SNTP server and either display
}
+char *
+addrinfo_to_str (
+ struct addrinfo *addr
+ )
+{
+ char *buf = (char *) malloc(sizeof(char) * INET6_ADDRSTRLEN);
+
+ getnameinfo(addr->ai_addr, addr->ai_addrlen, buf,
+ INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
+
+ return buf;
+}
void l_fp_output_bin (l_fp *ts, FILE *output);
void l_fp_output_dec (l_fp *ts, FILE *output);
+char *addrinfo_to_str (struct addrinfo *addr);
#endif