From: Johannes Maximilian Kuehn Date: Wed, 10 Sep 2008 22:58:04 +0000 (+0000) Subject: log.h: X-Git-Tag: NTP_4_2_5P142~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8855d523d78aeaf2937996071bc81c2aad8f32c1;p=thirdparty%2Fntp.git log.h: fixed missing timestamp for file logging kod_management.c: Fixed the core dump when no kod file is specified networking.c: Some fixes for broadcast mode remove filter reachable (no use for this function) utilities.c: Added a function to convert a struct sockaddr_storage to a string containing its hostname crypto.c: Completeted auth md5 functions bk: 48c850fcVp8qWyVmdYrAax-y6KW9mQ --- diff --git a/gsoc_sntp/crypto.c b/gsoc_sntp/crypto.c index 9fba3de87..f3aea7fe9 100644 --- a/gsoc_sntp/crypto.c +++ b/gsoc_sntp/crypto.c @@ -1,97 +1,183 @@ +/* + * 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; akey_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; akey_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; akey_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; akey_id == key_id) { + *d_key = itr_key; + return; + } } - rewind(keyf); - - - + return; +} diff --git a/gsoc_sntp/crypto.h b/gsoc_sntp/crypto.h index 126071893..ff223c9b4 100644 --- a/gsoc_sntp/crypto.h +++ b/gsoc_sntp/crypto.h @@ -1,19 +1,49 @@ +/* + * 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. + */ + #ifndef CRYPTO_H #define CRYPTO_H -#include #include +#include +#include -/* #include "sntp-opts.h" */ +#include +#include +#include +#include + +#include "utilities.h" +#include "sntp-opts.h" -int auth_md5(void *pkt_data, int mac_size, char *cmp_key, int cmp_size); -int auth_init(char *keyfile, struct key *keys); + +/* #include "sntp-opts.h" */ struct key { - unsigned int key_id; + int key_id; + int key_len; char type; char key_seq[16]; struct key *next; }; +int auth_md5(char *pkt_data, int mac_size, char *cmp_key, int cmp_size); +int auth_init(char *keyfile, struct key **keys); +void get_key(int key_id, struct key **d_key); + + #endif diff --git a/gsoc_sntp/header.h b/gsoc_sntp/header.h index 1a4b85dc0..4e3fa9661 100644 --- a/gsoc_sntp/header.h +++ b/gsoc_sntp/header.h @@ -24,6 +24,8 @@ No changes should be needed for any system that is even remotely like Unix. */ # define SAVENAME "/etc/sntp.state" /* Stores the recovery state */ #endif +#define DEBUG + /* Defined in main.c */ @@ -31,7 +33,7 @@ No changes should be needed for any system that is even remotely like Unix. */ #define op_client 1 /* Behave as a challenge client */ #define op_listen 2 /* Behave as a listening client */ -extern const char *argv0; +/* extern const char *argv0; extern int verbose, operation; @@ -41,7 +43,7 @@ extern void fatal (int syserr, const char *message, const char *insert); -/* Defined in unix.c */ + Defined in unix.c */ extern void do_nothing (int seconds); @@ -73,7 +75,7 @@ extern int read_socket (int which, void *packet, int length, int waiting); extern int flush_socket (int which); -extern void close_socket (int which); +/* extern void close_socket (int which); */ diff --git a/gsoc_sntp/kod_management.c b/gsoc_sntp/kod_management.c index 685a4c75c..022d97093 100644 --- a/gsoc_sntp/kod_management.c +++ b/gsoc_sntp/kod_management.c @@ -1,3 +1,20 @@ +/* + * 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. + */ + /* TODO check for memory leaks */ #include @@ -12,6 +29,9 @@ struct kod_entry *kod_db; FILE *db_s; +/* + * Search for a KOD entry + */ int search_entry ( char *hostname, @@ -22,7 +42,7 @@ search_entry ( struct kod_entry *sptr = kod_db; for(a=0; ahostname, hostname)) + if(!strcmp(sptr->hostname, hostname)) resc++; sptr = sptr->next; @@ -32,7 +52,7 @@ search_entry ( b=0; for(a=0; ahostname, hostname)) { + if(!strcmp(sptr->hostname, hostname)) { dst[b] = sptr; b++; } @@ -162,7 +182,7 @@ kod_init_kod_db ( db_s = fopen(db_file, "r"); - if(db_file == NULL) { + if(db_s == NULL) { char msg[80]; snprintf(msg, 80, "kod_init_kod_db(): Cannot open KOD db file %s", db_file); @@ -175,7 +195,8 @@ kod_init_kod_db ( log_msg(msg, 2); } - printf("Starting to read KOD file %s...\n", db_file); + if(ENABLED_OPT(NORMALVERBOSE)) + printf("Starting to read KOD file %s...\n", db_file); /* First let's see how many entries there are and check for right syntax */ while(!feof(db_s)) { diff --git a/gsoc_sntp/kod_management.h b/gsoc_sntp/kod_management.h index fcb22d048..e1c6cc71d 100644 --- a/gsoc_sntp/kod_management.h +++ b/gsoc_sntp/kod_management.h @@ -1,3 +1,20 @@ +/* + * 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. + */ + #ifndef KOD_MANAGEMENT_H #define KOD_MANAGEMENT_H @@ -13,7 +30,7 @@ int kod_entry_exists (char *search_str); void add_entry (char *hostname, char *type); void delete_entry (char *hostname, char *type); -void init_kod_db (char *db_file); +void kod_init_kod_db (char *db_file); void write_kod_db (void); void kod_atexit (void); diff --git a/gsoc_sntp/log.c b/gsoc_sntp/log.c index e511b986f..ed62b67a7 100644 --- a/gsoc_sntp/log.c +++ b/gsoc_sntp/log.c @@ -1,4 +1,20 @@ -/* Add timestamps to file logging!!! */ +/* + * 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 "log.h" #include "sntp-opts.h" @@ -10,7 +26,11 @@ FILE *log_file; void log_msg(char *message, char type) { if(init) { - fprintf(log_file, message); + time_t cur_time = time(NULL); + char *timestamp = ctime(&cur_time); + + fprintf(log_file, "%s: %s\n", timestamp, message); + fflush(log_file); } else { switch(type) { @@ -33,8 +53,10 @@ void log_msg(char *message, char type) { void debug_msg(char *message) { if(HAVE_OPT(FILELOG)) { - fprintf(stderr, message); - fprintf(stderr, "\n"); + time_t cur_time = time(NULL); + char *timestamp = ctime(&cur_time); + + fprintf(stderr, "%s: %s\n", timestamp, message); } else { syslog(LOG_DEBUG | LOG_PERROR | LOG_CONS, message); @@ -42,7 +64,6 @@ void debug_msg(char *message) { } void init_log(char *logfile) { - printf("INIT IST KRIEEEEEG %s!!!\n", logfile); log_file = fopen(logfile, "a"); if(log_file == NULL) { diff --git a/gsoc_sntp/log.h b/gsoc_sntp/log.h index a17a5227b..0a8026297 100644 --- a/gsoc_sntp/log.h +++ b/gsoc_sntp/log.h @@ -1,3 +1,20 @@ +/* + * 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. + */ + #ifndef LOG_H #define LOG_H @@ -5,9 +22,10 @@ #include #include - -#include #include +#include +#include + void log_msg(char *message, char type); void debug_msg(char *message); diff --git a/gsoc_sntp/main.c b/gsoc_sntp/main.c index d0be5f873..6c18d5fa6 100644 --- a/gsoc_sntp/main.c +++ b/gsoc_sntp/main.c @@ -1,33 +1,32 @@ -#include +#include +#include #include +#include #include #include -#include -#include #include #include +#include "crypto.h" #include "kod_management.h" #include "networking.h" #include "utilities.h" #include "log.h" -#define DEBUG int ai_fam_pref; volatile int debug; char adr_buf[INET6_ADDRSTRLEN]; +struct key *keys = NULL; void set_li_vn_mode (struct pkt *spkt, char leap, char version, char mode); int sntp_main (int argc, char **argv); int on_wire (struct addrinfo *host); -void set_li_vn_mode (struct pkt *spkt, char leap, char version, char mode); int set_time (double offset); - int main ( int argc, @@ -37,6 +36,9 @@ main ( return sntp_main(argc, argv); } +/* + * The actual main function. + */ int sntp_main ( int argc, @@ -60,7 +62,7 @@ sntp_main ( else if(ENABLED_OPT(IPV6)) ai_fam_pref = AF_INET6; else - ai_fam_pref = NULL; + ai_fam_pref = 0; } log_msg("Started sntp", 0); @@ -82,10 +84,12 @@ sntp_main ( if(HAVE_OPT(KOD)) { kod_init_kod_db((char *)OPT_ARG(KOD)); } - else { - kod_init_kod_db("sntp.kod"); + + if(HAVE_OPT(KEYFILE)) { + auth_init((char *)OPT_ARG(KEYFILE), keys); } + /* Considering employing a variable that prevents functions of doing anything until * everything is initialized properly */ @@ -157,12 +161,13 @@ on_wire ( error = GETTIMEOFDAY(&tv_xmt, (struct timezone *)NULL); + tv_xmt.tv_sec += JAN_1970; + #ifdef DEBUG - printf("Current time sec: %i msec: %i\n\n", (unsigned int) tv_xmt.tv_sec, + printf("sntp on_wire: Current time sec: %i msec: %i\n", (unsigned int) tv_xmt.tv_sec, (unsigned int) tv_xmt.tv_usec); #endif - tv_xmt.tv_sec += JAN_1970; TVTOTS(&tv_xmt, &xmt); HTONL_FP(&xmt, &(x_pkt->xmt)); @@ -183,6 +188,8 @@ on_wire ( else sw_case = rpktl; + printf("sw_case: %i\n", sw_case); + switch(sw_case) { case SERVER_UNUSEABLE: return -1; diff --git a/gsoc_sntp/networking.c b/gsoc_sntp/networking.c index f0841c60f..c76d37bbb 100644 --- a/gsoc_sntp/networking.c +++ b/gsoc_sntp/networking.c @@ -1,8 +1,21 @@ -#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]; @@ -33,7 +46,7 @@ resolve_hosts ( 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; @@ -41,7 +54,7 @@ resolve_hosts ( memset(&hints, 0, sizeof(hints)); - if(pref_family == NULL) + if(pref_family == 0) hints.ai_family = PF_UNSPEC; else hints.ai_family = pref_family; @@ -125,14 +138,16 @@ create_socket ( { *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 @@ -151,28 +166,31 @@ sendpkt ( ) { #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 */ @@ -181,25 +199,25 @@ recvdata ( 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); @@ -216,14 +234,322 @@ recvdata ( /* 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 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; } @@ -238,19 +564,19 @@ recvpkt ( 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, @@ -258,36 +584,42 @@ recvpkt ( */ } - pkt_length = min(pkt_length, sizeof(struct pkt)); - - for(a=0; a 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; amac[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 */ @@ -345,20 +740,26 @@ recvpkt ( 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; } /* @@ -388,41 +789,3 @@ is_reachable ( 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 +#include + #include #include #include #include - +#include +#include #include #include +#include #include #include +#include "log.h" +#include "sntp-opts.h" +#include "utilities.h" + +/* FIXME To be replaced by the constants in ntp.h */ #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 */ +#define BROADCAST_FAILED -6 /* From ntpdate.c */ @@ -30,11 +58,13 @@ void close_socket (SOCKET rsock); 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); +int recvdata (SOCKET rsock, struct sockaddr_storage *sender, char *rdata, int rdata_len); int recvpkt (SOCKET rsock, struct pkt *rpkt, struct pkt *spkt); -int recvbcst (SOCKET rsock, struct pkt *rpkt, struct sockaddr_storage *sas); +int recv_bcst_data (SOCKET rsock, char *rdata, int rdata_len, struct sockaddr_storage *sas, struct sockaddr_storage *ras); + +int recv_bcst_pkt (SOCKET rsock, struct pkt *rpkt, struct sockaddr_storage *sas); /* Shortened peer structure. Not absolutely necessary yet */ struct speer { diff --git a/gsoc_sntp/utilities.c b/gsoc_sntp/utilities.c index d6e712243..722f397c9 100644 --- a/gsoc_sntp/utilities.c +++ b/gsoc_sntp/utilities.c @@ -1,5 +1,25 @@ +/* + * 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 "utilities.h" +/* Display a NTP packet in hex with leading address offset + * e.g. offset: value, 0: ff 1: fe ... 255: 00 + */ void pkt_output ( struct pkt *dpkg, @@ -28,6 +48,8 @@ pkt_output ( fprintf(output, HLINE); } +/* Output a long floating point value in hex in the style described above + */ void l_fp_output ( l_fp *ts, @@ -46,6 +68,8 @@ l_fp_output ( } +/* Output a long floating point value in binary in the style described above + */ void l_fp_output_bin ( l_fp *ts, @@ -81,6 +105,8 @@ l_fp_output_bin ( fprintf(output, HLINE); } +/* Output a long floating point value in decimal in the style described above + */ void l_fp_output_dec ( l_fp *ts, @@ -99,6 +125,9 @@ l_fp_output_dec ( } +/* Convert a struct addrinfo to a string containing the address in style + * of inet_ntoa + */ char * addrinfo_to_str ( struct addrinfo *addr @@ -111,3 +140,20 @@ addrinfo_to_str ( return buf; } + +/* Convert a struct sockaddr_storage to a string containing the address in + * style of inet_ntoa + */ +char * +ss_to_str ( + struct sockaddr_storage *saddr + ) +{ + char *buf = (char *) malloc(sizeof(char) * INET6_ADDRSTRLEN); + + getnameinfo((struct sockaddr *) saddr, SOCKLEN(saddr), buf, + INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); + + + return buf; +} diff --git a/gsoc_sntp/utilities.h b/gsoc_sntp/utilities.h index c943f121e..db26db83e 100644 --- a/gsoc_sntp/utilities.h +++ b/gsoc_sntp/utilities.h @@ -1,3 +1,37 @@ +/* + * 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. + */ + +/* + * 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. + */ + #ifndef UTILITIES_H #define UTILITIES_H @@ -18,5 +52,6 @@ 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); +char *ss_to_str (struct sockaddr_storage *saddr); #endif