+/*
+ * Copyright (C) 2008 Johannes Maximilian Kühn
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
#include "crypto.h"
+struct key *key_ptr;
int key_cnt = 0;
+/* Generates a md5 digest of the ntp packet (exluding the MAC) concatinated
+ * with the key specified in keyid and compares this digest to the digest in
+ * the packet's MAC. If they're equal this function returns 1 (packet is
+ * authentic) or else 0 (not authentic).
+ */
int
auth_md5 (
- void *pkt_data,
+ char *pkt_data,
int mac_size,
- char *cmp_key,
- int cmp_size
+ struct key *cmp_key
)
{
register int a;
- MD5Context ctx;
char digest[16];
+ MD5_CTX ctx;
+
+ if(cmp_key->type != 'M')
+ return -1;
MD5Init(&ctx);
- unsigned char *digest_data = (unsigned char *) malloc(sizeof(char) * (LEN_PKT_NOMAC + cmp_size));
- for(a=0; a<LEN_PKT_NOMAC; a++)
- digest_data[a] = (unsigned char) pkt_data[a];
+ char *digest_data = (char *) malloc(sizeof(char) * (LEN_PKT_NOMAC + cmp_size));
- for(a=0; a<cmp_size; a++)
- digest_data[LEN_PKT_NOMAC + a] = (unsigned char) cmp_key[a];
+ for(a=0; a<LEN_PKT_NOMAC; a++)
+ digest_data[a] = pkt_data[a];
+ for(a=0; a<cmp_key->key_len; a++)
+ digest_data[LEN_PKT_NOMAC + a] = cmp_key->key_seq[a];
- MD5Update(&ctx, digest_data, LEN_PKT_NOMAC + cmp_size);
- MD5Final(digest, &ctx);
+ MD5Update(&ctx, (unsigned char *)digest_data, LEN_PKT_NOMAC + cmp_key->key_len);
+ MD5Final((unsigned char *)digest, &ctx);
free(digest_data);
- if(strncmp(cmp_key, digest, cmp_size) != 0) {
- return 0;
- }
- else {
- return 1;
- }
+ for(a=0; a<16; a++)
+ if(digest[a] != pkt_data[LEN_PKT_MAC + a])
+ return 0;
+
+ return 1;
}
+/* Load keys from the specified keyfile into the key structures.
+ * Returns -1 if the reading failed, otherwise it returns the
+ * number of keys it read
+ */
int
auth_init (
char *keyfile,
- struct key *keys
+ struct key **keys
)
{
+ printf("auth_init: %s\n", keyfile);
char kbuf[96];
FILE *keyf = fopen(keyfile, "r");
- register int a, line_cnt;
+ register int a, line_cnt, line_limit;
struct key *prev;
if(keyf == NULL) {
- /* Do something about it */
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
+
+ return -1;
}
line_cnt = 0;
+
+ if(feof(keyf)) {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp auth_init: Key file %s is empty!\n", keyfile);
+
+ return -1;
+ }
+
while(!feof(keyf)) {
struct key *act = (struct key *) malloc(sizeof(struct key));
+ line_limit = 0;
fgets(kbuf, 96, keyf);
- sscanf(fbuf, "%i %c %16s", act->key_id, act->type, act->key_seq);
+ for(a=0; a<strlen(kbuf) && a < 96; a++) {
+ if(kbuf[a] == '#') {
+ line_limit = a;
+ a = 96;
+ }
+ }
+
+ if(line_limit != 0)
+ kbuf[line_limit] = '\0';
#ifdef DEBUG
- printf("auth_init: key_id %i type %c with key %s\n", act->key_id, act->type, act->key_seq);
+ printf("sntp auth_init: fgets: %s", kbuf);
#endif
- if(line_cnt == 0) {
- keys = act;
- prev = act;
- }
- else {
- prev->next = act;
- prev = act;
- }
+ sscanf(kbuf, "%i %c %16s", &act->key_id, &act->type, act->key_seq);
+ act->key_len = strlen(key_seq);
+
+#ifdef DEBUG
+ printf("sntp auth_init: key_id %i type %c with key %s\n", act->key_id, act->type, act->key_seq);
+#endif
- line_cnt++;
+ if(act->type != 0) {
+ if(line_cnt == 0) {
+ *keys = act;
+ prev = act;
+ }
+ else {
+ prev->next = act;
+ act->next = NULL;
+ prev = act;
+ }
+
+ line_cnt++;
+ }
}
fclose(keyf);
+
+#ifdef DEBUG
+ STDLINE
+ printf("sntp auth_init: Read %i keys from file %s:\n", line_cnt, keyfile);
+
+ struct key *kptr = *keys;
+ for(a=0; a<line_cnt; a++) {
+ printf("key_id %i type %c with key %s (key length: %i)\n", kptr->key_id,
+ kptr->type, kptr->key_seq, kptr->key_len);
+ kptr = kptr->next;
+ }
+ STDLINE
+#endif
key_cnt = line_cnt;
+ key_ptr = *keys;
return line_cnt;
}
+/* Looks for the key with keyid key_id and sets the d_key pointer to the
+ * address of the key. If no matching key is found the pointer is not touched.
+ */
+void
+get_key (
+ int key_id,
+ struct key **d_key
+ )
+{
+ register int a;
+ struct key *itr_key = key_ptr;
-
-
-
-
+ if(key_cnt == 0)
+ return;
+
+ for(a=0; a<key_cnt && itr_key != NULL; a++) {
+ if(itr_key->key_id == key_id) {
+ *d_key = itr_key;
+ return;
+ }
}
- rewind(keyf);
-
-
-
+ return;
+}
-#include "sntp-opts.h"
+/*
+ * Copyright (C) 2008 Johannes Maximilian Kühn
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
#include "networking.h"
-#include "header.h"
-#include "utilities.h"
-#include "log.h"
char adr_buf[INET6_ADDRSTRLEN];
tres[a] = (struct addrinfo **) malloc(sizeof(struct addrinfo));
#ifdef DEBUG
- printf("Starting host resolution for %s...\n", hosts[a]);
+ printf("sntp resolve_hosts: Starting host resolution for %s...\n", hosts[a]);
#endif
struct addrinfo hints, *dres;
memset(&hints, 0, sizeof(hints));
- if(pref_family == NULL)
+ if(pref_family == 0)
hints.ai_family = PF_UNSPEC;
else
hints.ai_family = pref_family;
{
*rsock = socket(dest->ss_family, SOCK_DGRAM, 0);
-#ifdef DEBUG
if(*rsock == -1)
- printf("Failed to create UDP socket with family %i\n", dest->ss_family);
-#endif
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("Failed to create UDP socket with family %i\n", dest->ss_family);
}
-/* If there's nothing more to do here we might need this function */
+/* If there's nothing more to do here we might need this function
+ * Originally I thought about doing some broad-/multicast related
+ * cleaning up here.
+ */
void
close_socket (
SOCKET rsock
)
{
#ifdef DEBUG
+ printf("sntp sendpkt: Packet data:\n");
pkt_output(pkt, len, stdout);
- getnameinfo((struct sockaddr *) dest, dest->ss_len, adr_buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
-
- printf("\nSending packet to %s...\n", adr_buf);
#endif
- int cc = sendto(rsock, (char *)pkt, len, 0, (struct sockaddr *)dest, dest->ss_len);
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ getnameinfo((struct sockaddr *) dest, SOCKLEN(dest), adr_buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
+
+ printf("sntp sendpkt: Sending packet to %s...\n", adr_buf);
+ }
+
+ int cc = sendto(rsock, (char *)pkt, len, 0, (struct sockaddr *)dest, SOCKLEN(dest));
if (cc == SOCKET_ERROR) {
#ifdef DEBUG
- printf("Socket error: %i. Couldn't send packet!\n", cc);
+ printf("sntp sendpkt: Socket error: %i. Couldn't send packet!\n", cc);
#endif
if (errno != EWOULDBLOCK && errno != ENOBUFS) {
}
}
-#ifdef DEBUG
else {
- printf("Packet sent.\n");
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("Packet sent.\n");
}
-#endif
}
/* Receive raw data */
SOCKET rsock,
struct sockaddr_storage *sender,
char *rdata,
- size_t rdata_length
+ int rdata_length
)
{
socklen_t slen = SOCKLEN(&rsock);
#ifdef DEBUG
- printf("Trying to receive data from...\n");
+ printf("sntp recvdata: Trying to receive data from...\n");
#endif
int recvc = recvfrom(rsock, rdata, rdata_length, 0,
(struct sockaddr *) sender, &slen);
#ifdef DEBUG
- printf("recvfrom returned...\n");
+ printf("sntp recvdata: recvfrom returned...\n");
#endif
#ifdef DEBUG
if(recvc > 0) {
- getnameinfo((struct sockaddr *)sender, sender->ss_len, adr_buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
+ getnameinfo((struct sockaddr *)sender, SOCKLEN(sender), adr_buf, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
printf("Received %i bytes from %s:\n", recvc, adr_buf);
/* Receive data from broadcast. Couldn't finish that. Need to do some digging
* here, especially for protocol independence and IPv6 multicast */
int
-recvbcst (
+recv_bcst_data (
+ SOCKET rsock,
+ char *rdata,
+ int rdata_len,
+ struct sockaddr_storage *sas,
+ struct sockaddr_storage *ras
+ )
+{
+ struct timeval timeout_tv;
+ fd_set bcst_fd;
+
+ int btrue = 1;
+ int recv_bytes = 0;
+
+
+ setsockopt(rsock, SOL_SOCKET, SO_REUSEADDR, &btrue, sizeof(btrue));
+
+ if(sas->ss_family == AF_INET) {
+ struct sockaddr_in sin;
+ struct ip_mreq mdevadr;
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ sin.sin_port = htons(123);
+
+ if(bind(rsock, (struct sockaddr *) sas, SOCKLEN(sas)) < 0) {}
+
+
+ if(setsockopt(rsock, IPPROTO_IP, IP_MULTICAST_LOOP, &btrue, sizeof(btrue)) < 0) {
+ /* some error message regarding setting up multicast loop */
+ return BROADCAST_FAILED;
+ }
+
+ char *buf = ss_to_str(sas);
+
+ mdevadr.imr_multiaddr.s_addr = inet_addr(buf);
+ mdevadr.imr_interface.s_addr = htonl(INADDR_ANY);
+
+ if(mdevadr.imr_multiaddr.s_addr == -1) {
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf);
+ }
+
+ return BROADCAST_FAILED;
+ }
+
+ free(buf);
+
+ if (setsockopt(rsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mdevadr, sizeof(mdevadr)) < 0) {
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ char *buf = ss_to_str(sas);
+
+ printf("sntp recv_bcst_data: Couldn't add IP membership for %s\n", buf);
+
+ free(buf);
+
+ return BROADCAST_FAILED;
+ }
+ }
+ }
+ else if(sas->ss_family == AF_INET6) {
+ struct sockaddr_in6 sin6;
+ struct ipv6_mreq mdevadr;
+
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = in6addr_any;
+ sin6.sin6_port = htons(123);
+
+ if(bind(rsock, (struct sockaddr *) sas, sizeof(sas)) < 0) {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recv_bcst_data: Couldn't bind() address.\n");
+ }
+
+ if(setsockopt(rsock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &btrue, sizeof (btrue)) < 0) {
+ /* some error message regarding setting up multicast loop */
+ return BROADCAST_FAILED;
+ }
+
+ mdevadr.ipv6mr_multiaddr = *((struct in6_addr *) sas);
+ /* FIXME hat value for ipv6mr_interface? Use utilities for sock to char op*/
+ /* mdevadr.ipv6mr_interface = in6addr_any; */
+
+ if(!IN6_IS_ADDR_MULTICAST((struct in6_addr *) &mdevadr.ipv6mr_multiaddr)) {
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ char *buf = ss_to_str(sas);
+
+ printf("sntp recv_bcst_data: %s is not a broad-/multicast address, aborting...\n", buf);
+
+ free(buf);
+ }
+
+ return BROADCAST_FAILED;
+ }
+
+ if (setsockopt(rsock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mdevadr, sizeof(mdevadr)) < 0) {
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ char *buf = ss_to_str(sas);
+
+ printf("sntp recv_bcst_data: Couldn't join group for %s\n", buf);
+
+ free(buf);
+
+ return BROADCAST_FAILED;
+ }
+ }
+ }
+
+ FD_ZERO(&bcst_fd);
+ FD_SET(rsock, &bcst_fd);
+
+ if(ENABLED_OPT(TIMEOUT))
+ timeout_tv.tv_sec = (int) OPT_ARG(TIMEOUT);
+ else
+ timeout_tv.tv_sec = 60;
+
+ switch(select(rsock + 1, &bcst_fd, 0, 0, &timeout_tv)) {
+ FD_CLR(rsock, &bcst_fd);
+
+ case -1:
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recv_bcst_data: select() returned -1, an error occured, aborting.\n");
+
+ return BROADCAST_FAILED;
+ break;
+
+ case 0:
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recv_bcst_data: select() reached timeout (%i sec), aborting.\n", timeout_tv.tv_sec);
+
+ return BROADCAST_FAILED;
+ break;
+
+ default:
+ socklen_t ss_len = SOCKLEN(ras);
+ recv_bytes = recvfrom(rsock, rdata, rdata_len, 0, (struct sockaddr *) ras, (socklen_t *) &ss_len);
+ }
+
+ if(recv_bytes == -1) {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recv_bcst_data: Failed to receive from broad-/multicast\n");
+
+ return BROADCAST_FAILED;
+ }
+
+ if(sas->ss_family == AF_INET)
+ setsockopt(rsock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &btrue, sizeof(btrue));
+ else if(sas->ss_family == AF_INET6)
+ setsockopt(rsock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &btrue, sizeof(btrue));
+
+ return recv_bytes;
+}
+
+int
+recv_bcst_pkt (
SOCKET rsock,
struct pkt *rpkt,
struct sockaddr_storage *sas
- )
+ )
{
+ struct sockaddr_storage sender;
+ register int a;
+ int is_authentic, has_mac, orig_pkt_len;
+
+ char *rdata = (char *) malloc(sizeof(char) * 256);
+
+ int pkt_len = recv_bcst_data(rsock, rdata, 256, sas, &sender);
+
+
+ if(pkt_len < 0)
+ return BROADCAST_FAILED;
- return 0;
+ /* No MAC, no authentication */
+ if(pkt_len == LEN_PKT_NOMAC)
+ has_mac = 0;
+
+ /* If there's more than just the NTP packet it should be a MAC */
+ else if(pkt_len > LEN_PKT_NOMAC)
+ has_mac = pkt_len - LEN_PKT_NOMAC;
+ else
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ printf("sntp recv_bcst_pkt: Funny packet length: %i. Discarding package.\n", pkt_len);
+ return PACKET_UNUSEABLE;
+ }
+
+ /* Packet too big */
+ if(pkt_len > LEN_PKT_NOMAC + MAX_MAC_LEN) {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recv_bcst_pkt: Received packet is too big (%i bytes), trying again to get a useable packet\n",
+ pkt_len);
+
+ return PACKET_UNUSEABLE;
+ }
+
+ orig_pkt_len = pkt_len;
+ pkt_len = min(pkt_len, sizeof(struct pkt));
+
+ /* Let's copy the received data to the packet structure */
+ for(a=0; a<pkt_len; a++)
+ if(a < orig_pkt_len)
+ ((char *)rpkt)[a] = rdata[a];
+ else
+ ((char *)rpkt)[a] = 0;
+
+ free(rdata);
+
+ /* 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 {
+ if(has_mac == MAX_MAC_LEN) {
+ struct key *pkt_key = NULL;
+
+ /* Look for the key used by the server in the specified keyfile
+ * and if existent, fetch it or else leave the pointer untouched */
+ get_key(rpkt->mac[0], &pkt_key);
+
+ /* Seems like we've got a key with matching keyid */
+ if(pkt_key != NULL) {
+ /* Generate a md5sum of the packet with the key from our keyfile
+ * and compare those md5sums */
+ if(!auth_md5((char *) rpkt, has_mac, pkt_key)) {
+ if(ENABLED_OPT(AUTHENTICATION)) {
+ /* We want a authenticated packet */
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ char *hostname = ss_to_str(sas);
+ printf("sntp recv_bcst_pkt: Broadcast packet received from %s is not authentic. Will discard this packet.\n",
+ hostname);
+
+ free(hostname);
+ }
+ return SERVER_AUTH_FAIL;
+ }
+ else {
+ /* We don't know if the user wanted authentication so let's
+ * use it anyways */
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ char *hostname = ss_to_str(sas);
+ printf("sntp recv_bcst_pkt: Broadcast packet received from %s is not authentic. Authentication not enforced.\n",
+ hostname);
+
+ free(hostname);
+ }
+
+ is_authentic = 0;
+ }
+ }
+ else {
+ /* Yay! Things worked out! */
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ char *hostname = ss_to_str(sas);
+ printf("sntp recv_bcst_pkt: Broadcast packet received from %s successfully authenticated using key id %i.\n",
+ hostname, rpkt->mac[0]);
+
+ free(hostname);
+ }
+
+ is_authentic = 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* Check for server's ntp version */
+ if(PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
+ PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recv_bcst_pkt: Packet shows wrong version (%i)\n",
+ PKT_VERSION(rpkt->li_vn_mode));
+
+ return SERVER_UNUSEABLE;
+ }
+
+ /* We want a server to sync with */
+ if(PKT_MODE(rpkt->li_vn_mode) != MODE_BROADCAST
+ && PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recv_bcst_pkt: mode %d stratum %i\n",
+ PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
+
+ return SERVER_UNUSEABLE;
+ }
+
+ if(rpkt->stratum == STRATUM_PKT_UNSPEC) {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recv_bcst_pkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt->stratum);
+
+ char *ref_char = (char *) &rpkt->refid;
+
+ /* 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("recv_bcst_pkt: Server not in sync, skipping this server\n");
+
+ return SERVER_UNUSEABLE;
+ }
+
+ return pkt_len;
}
struct pkt *spkt
)
{
+ struct sockaddr_storage sender;
+ char *rdata, done;
+
register int a;
- int has_mac, is_authentic;
+ int has_mac, is_authentic, orig_pkt_len;
l_fp org;
- struct sockaddr_storage sender;
- char *rdata, done;
-
/* Much space, just to be sure */
rdata = (char *) malloc(sizeof(char) * 512);
- int pkt_length = recvdata(rsock, &sender, rdata, 512);
+ int pkt_len = 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)
+ if(pkt_len == 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(pkt_len > LEN_PKT_NOMAC)
+ has_mac = pkt_len - LEN_PKT_NOMAC;
- else
- if(debug) {
- fprintf(stderr, "recvpkt: Funny packet length: %i. Discarding package.\n", pkt_length);
+ else {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recvpkt: Funny packet length: %i. Discarding package.\n", pkt_len);
+
return PACKET_UNUSEABLE;
- }
+ }
/* Packet too big */
- if(pkt_length > LEN_PKT_MAC) {
+ if(pkt_len > 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);
+ pkt_len);
return PACKET_UNUSEABLE;
}
+ orig_pkt_len = pkt_len;
+ pkt_len = min(pkt_len, sizeof(struct pkt));
+
+ for(a=0; a<pkt_len; a++)
+ /* FIXME! */
+ if(a < orig_pkt_len)
+ ((char *) rpkt)[a] = rdata[a];
+ else
+ ((char *) rpkt)[a] = 0;
+
/* MAC could be useable for us */
if(has_mac) {
/* Two more things that the MAC must conform to */
is_authentic = 0; /* Or should we discard this packet? */
}
else {
- /* Do auth stuff */
+ if(has_mac == MAX_MAC_LEN) {
+ struct key *pkt_key = NULL;
+
+ /*
+ * Look for the key used by the server in the specified keyfile
+ * and if existent, fetch it or else leave the pointer untouched
+ */
+ get_key(rpkt->mac[0], &pkt_key);
+
+ /* Seems like we've got a key with matching keyid */
+ if(pkt_key != NULL) {
+ /*
+ * Generate a md5sum of the packet with the key from our keyfile
+ * and compare those md5sums
+ */
+ if(!auth_md5((char *) rpkt, has_mac, pkt_key)) {
+ if(ENABLED_OPT(AUTHENTICATION)) {
+ /* We want a authenticated packet */
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ char *hostname = ss_to_str(sas);
+ printf("sntp recvpkt: Broadcast packet received from %s is not authentic. Will discard this packet.\n",
+ hostname);
+
+ free(hostname);
+ }
+ return SERVER_AUTH_FAIL;
+ }
+ else {
+ /*
+ * We don't know if the user wanted authentication so let's
+ * use it anyways
+ */
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ char *hostname = ss_to_str(sas);
+ printf("sntp recvpkt: Broadcast packet received from %s is not authentic. Authentication not enforced.\n",
+ hostname);
+
+ free(hostname);
+ }
+
+ is_authentic = 0;
+ }
+ }
+ else {
+ /* Yay! Things worked out! */
+ if(ENABLED_OPT(NORMALVERBOSE)) {
+ char *hostname = ss_to_str(sas);
+ printf("sntp recvpkt: Broadcast packet received from %s successfully authenticated using key id %i.\n",
+ hostname, rpkt->mac[0]);
+
+ free(hostname);
+ }
+
+ is_authentic = 1;
+ }
+ }
+ }
}
}
/* Check for server's ntp version */
if(PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recvpkt: Packet got wrong version (%i)\n", PKT_VERSION(rpkt->li_vn_mode));
+
return SERVER_UNUSEABLE;
}
/* 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
+ if(ENABLED_OPT(NORMALVERBOSE))
printf("sntp recvpkt: mode %d stratum %i\n",
PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
-#endif
+
return SERVER_UNUSEABLE;
}
+ /* Stratum is unspecified (0) check what's going on */
if(rpkt->stratum == STRATUM_PKT_UNSPEC) {
if(ENABLED_OPT(NORMALVERBOSE))
printf("sntp recvpkt: Stratum unspecified, going to check for KOD (stratum: %i)\n", rpkt->stratum);
char *ref_char = (char *) &rpkt->refid;
+
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recvpkt: Packet refid: %c%c%c%c\n", ref_char[0], ref_char[1], ref_char[2], ref_char[3]);
/* If it's a KOD packet we'll just use the KOD information */
if(ref_char[0] != 'X') {
- if(strncmp(ref_char, "DENY", 4))
+ if(!strncmp(ref_char, "DENY", 4))
return KOD_DEMOBILIZE;
- if(strncmp(ref_char, "RSTR", 4))
+ if(!strncmp(ref_char, "RSTR", 4))
return KOD_DEMOBILIZE;
- if(strncmp(ref_char, "RATE", 4))
+ if(!strncmp(ref_char, "RATE", 4))
return KOD_RATE;
/* There are other interesting kiss codes which might be interesting for authentication */
return SERVER_UNUSEABLE;
}
-
/*
* Decode the org timestamp and make sure we're getting a response
* to our last request.
*/
- NTOHL_FP(&rpkt->org, &org);
- if (!L_ISEQU(&org, &spkt->xmt)) {
- if (debug)
- printf("receive: pkt.org and peer.xmt differ\n");
+
+#ifdef DEBUG
+ printf("rpkt->org:\n");
+ l_fp_output(&rpkt->org, stdout);
+ printf("spkt->xmt:\n");
+ l_fp_output(&spkt->xmt, stdout);
+#endif
+
+ if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
+ if(ENABLED_OPT(NORMALVERBOSE))
+ printf("sntp recvpkt: pkt.org and peer.xmt differ\n");
return PACKET_UNUSEABLE;
}
- return pkt_length;
+ return pkt_len;
}
/*
closesocket(sockfd);
return 1;
}
-
-int
-filter_reachable (
- struct addrinfo **res,
- int resc
- )
-{
- register int a, b;
- int filter_elements = 0;
-
- int *index = (int *) malloc(sizeof(int) * resc);
-
- for(a=0, b=0; a<resc; a++) {
- if(is_reachable(res[a])) {
- index[b] = a;
- b++;
- }
- }
-
- struct addrinfo **cpyres = (struct addrinfo **) malloc(sizeof(struct addrinfo *) * b);
-
- filter_elements = b+1;
-
- for(a=0; a<filter_elements; a++)
- cpyres[a] = res[index[a]];
-
-
- for(a=0, b=0; a<resc; a++) {
- if(a == index[b])
- b++;
- else
- freeaddrinfo(res[a]);
- }
-
- res = cpyres;
-
- return filter_elements;
-}