miniupnpd: use monotonic clock for timeouts, etc.

fixes #288

also changed set_startup_time()
This commit is contained in:
Thomas Bernard 2018-03-13 11:43:07 +01:00
parent 2d783f6e69
commit dd2aa84204
12 changed files with 112 additions and 65 deletions

View File

@ -1,4 +1,7 @@
$Id: Changelog.txt,v 1.432 2017/05/24 22:47:53 nanard Exp $
$Id: Changelog.txt,v 1.437 2018/03/12 22:45:13 nanard Exp $
2018/03/13:
Use monotonic clock for timeouts, etc.
2018/02/22:
Add option force_igd_desc_v1 to force devices and services versions

View File

@ -1,4 +1,4 @@
/* $Id: miniupnpd.c,v 1.221 2017/05/27 07:47:55 nanard Exp $ */
/* $Id: miniupnpd.c,v 1.226 2018/03/13 10:35:55 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -794,43 +794,39 @@ sigusr1(int sig)
/* record the startup time, for returning uptime */
static void
set_startup_time(int sysuptime)
set_startup_time(void)
{
startup_time = time(NULL);
startup_time = upnp_time();
#ifdef USE_TIME_AS_BOOTID
if(startup_time > 60*60*24 && upnp_bootid == 1) {
/* We know we are not January the 1st 1970 */
upnp_bootid = (unsigned int)startup_time;
if(upnp_bootid == 1) {
upnp_bootid = (unsigned int)time(NULL);
/* from UDA v1.1 :
* A convenient mechanism is to set this field value to the time
* that the device sends its initial announcement, expressed as
* seconds elapsed since midnight January 1, 1970; */
}
#endif /* USE_TIME_AS_BOOTID */
if(sysuptime)
if(GETFLAG(SYSUPTIMEMASK))
{
/* use system uptime instead of daemon uptime */
#if defined(__linux__)
char buff[64];
int uptime = 0, fd;
fd = open("/proc/uptime", O_RDONLY);
if(fd < 0)
unsigned long uptime = 0;
FILE * f = fopen("/proc/uptime", "r");
if(f == NULL)
{
syslog(LOG_ERR, "open(\"/proc/uptime\" : %m");
syslog(LOG_ERR, "fopen(\"/proc/uptime\") : %m");
}
else
{
memset(buff, 0, sizeof(buff));
if(read(fd, buff, sizeof(buff) - 1) < 0)
if(fscanf(f, "%lu", &uptime) != 1)
{
syslog(LOG_ERR, "read(\"/proc/uptime\" : %m");
syslog(LOG_ERR, "fscanf(\"/proc/uptime\") : %m");
}
else
{
uptime = atoi(buff);
syslog(LOG_INFO, "system uptime is %d seconds", uptime);
syslog(LOG_INFO, "system uptime is %lu seconds", uptime);
}
close(fd);
fclose(f);
startup_time -= uptime;
}
#elif defined(SOLARIS_KSTATS)
@ -1632,7 +1628,7 @@ init(int argc, char * * argv, struct runtime_vars * v)
syslog(LOG_NOTICE, "version " MINIUPNPD_VERSION " started");
#endif /* TOMATO */
set_startup_time(GETFLAG(SYSUPTIMEMASK));
set_startup_time();
/* presentation url */
if(presurl)
@ -2063,11 +2059,13 @@ main(int argc, char * * argv)
/* main loop */
while(!quitting)
{
#ifdef USE_TIME_AS_BOOTID
/* Correct startup_time if it was set with a RTC close to 0 */
if((startup_time<60*60*24) && (time(NULL)>60*60*24))
if((upnp_bootid<60*60*24) && (time(NULL)>60*60*24))
{
set_startup_time(GETFLAG(SYSUPTIMEMASK));
upnp_bootid = time(NULL);
}
#endif
/* send public address change notifications if needed */
if(should_send_public_address_change_notif)
{

View File

@ -1,4 +1,4 @@
/* $Id: natpmp.c,v 1.52 2015/05/27 12:43:14 nanard Exp $ */
/* $Id: natpmp.c,v 1.55 2018/03/12 22:41:54 nanard Exp $ */
/* MiniUPnP project
* (c) 2007-2017 Thomas Bernard
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
@ -247,7 +247,7 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
if(epoch_origin == 0) {
epoch_origin = startup_time;
}
WRITENU32(resp+4, time(NULL) - epoch_origin);
WRITENU32(resp+4, upnp_time() - epoch_origin);
if(req[0] > 0) {
/* invalid version */
syslog(LOG_WARNING, "unsupported NAT-PMP version : %u",
@ -382,15 +382,9 @@ void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
}
}
/* do the redirection */
#if 0
timestamp = (unsigned)(time(NULL) - startup_time)
+ lifetime;
snprintf(desc, sizeof(desc), "NAT-PMP %u", timestamp);
#else
timestamp = time(NULL) + lifetime;
timestamp = upnp_time() + lifetime;
snprintf(desc, sizeof(desc), "NAT-PMP %hu %s",
eport, (proto==IPPROTO_TCP)?"tcp":"udp");
#endif
/* TODO : check return code */
if(upnp_redirect_internal(NULL, eport, senderaddrstr,
iport, proto, desc,
@ -439,7 +433,7 @@ void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
if(epoch_origin == 0) {
epoch_origin = startup_time;
}
WRITENU32(notif+4, time(NULL) - epoch_origin);
WRITENU32(notif+4, upnp_time() - epoch_origin);
#ifndef MULTIPLE_EXTERNAL_IP
FillPublicAddressResponse(notif, 0);
if(notif[3])

View File

@ -1,4 +1,4 @@
/* $Id: pcpserver.c,v 1.39 2015/06/22 07:28:21 nanard Exp $ */
/* $Id: pcpserver.c,v 1.47 2018/03/13 10:21:19 nanard Exp $ */
/* MiniUPnP project
* Website : http://miniupnp.free.fr/
* Author : Peter Tatrai
@ -684,7 +684,7 @@ static int CreatePCPPeer_NAT(pcp_info_t *pcp_msg_info)
uint16_t eport = pcp_msg_info->ext_port; /* public port */
char peerip_s[INET6_ADDRSTRLEN], extip_s[INET6_ADDRSTRLEN];
time_t timestamp = time(NULL) + pcp_msg_info->lifetime;
time_t timestamp = upnp_time() + pcp_msg_info->lifetime;
int r;
FillSA((struct sockaddr*)&intip, pcp_msg_info->mapped_ip,
@ -890,7 +890,7 @@ static int CreatePCPMap_NAT(pcp_info_t *pcp_msg_info)
char iaddr_old[INET6_ADDRSTRLEN];
uint16_t iport_old, eport_first = 0;
int any_eport_allowed = 0;
unsigned int timestamp = time(NULL) + pcp_msg_info->lifetime;
unsigned int timestamp = upnp_time() + pcp_msg_info->lifetime;
if (pcp_msg_info->ext_port == 0) {
pcp_msg_info->ext_port = pcp_msg_info->int_port;
@ -1450,7 +1450,7 @@ static void createPCPResponse(unsigned char *response, pcp_info_t *pcp_msg_info)
if(epoch_origin == 0) {
epoch_origin = startup_time;
}
WRITENU32(response + 8, time(NULL) - epoch_origin); /* epochtime */
WRITENU32(response + 8, upnp_time() - epoch_origin); /* epochtime */
switch (pcp_msg_info->result_code) {
/*long lifetime errors*/
case PCP_ERR_UNSUPP_VERSION:
@ -1690,7 +1690,7 @@ void PCPPublicAddressChanged(int * sockets, int n_sockets)
/* according to RFC 6887 8.5 :
* if the external IP address(es) of the NAT (controlled by
* the PCP server) changes, the Epoch time MUST be reset. */
epoch_origin = time(NULL);
epoch_origin = upnp_time();
#ifdef ENABLE_IPV6
PCPSendUnsolicitedAnnounce(sockets, n_sockets, socket6);
#else /* IPv4 Only */

View File

@ -1,4 +1,4 @@
/* $Id: testasyncsendto.c,v 1.4 2018/01/16 00:50:49 nanard Exp $ */
/* $Id: testasyncsendto.c,v 1.5 2018/03/13 10:25:52 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* MiniUPnP project
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
@ -21,6 +21,8 @@
#include "asyncsendto.h"
struct lan_addr_list lan_addrs;
int runtime_flags = 0;
time_t startup_time = 0;
#define DEST_IP "239.255.255.250"
#define DEST_PORT 1900

View File

@ -1,7 +1,7 @@
/* $Id: testgetroute.c,v 1.5 2013/02/06 12:07:36 nanard Exp $ */
/* $Id: testgetroute.c,v 1.7 2018/03/13 10:25:52 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2015 Thomas Bernard
* (c) 2006-2018 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -23,6 +23,8 @@
#endif
struct lan_addr_list lan_addrs;
int runtime_flags = 0;
time_t startup_time = 0;
int
main(int argc, char ** argv)

View File

@ -1,8 +1,8 @@
/* $Id: upnpevents.c,v 1.38 2017/11/02 15:50:35 nanard Exp $ */
/* $Id: upnpevents.c,v 1.39 2018/03/12 22:41:54 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2008-2017 Thomas Bernard
* (c) 2008-2018 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -182,7 +182,7 @@ upnpevents_addSubscriber(const char * eventurl,
if(!tmp)
return NULL;
if(timeout)
tmp->timeout = time(NULL) + timeout;
tmp->timeout = upnp_time() + timeout;
LIST_INSERT_HEAD(&subscriberlist, tmp, entries);
upnp_event_create_notify(tmp);
return tmp->uuid;
@ -197,10 +197,10 @@ upnpevents_renewSubscription(const char * sid, int sidlen, int timeout)
if((sidlen == 41) && (memcmp(sid, sub->uuid, 41) == 0)) {
#ifdef UPNP_STRICT
/* check if the subscription already timeouted */
if(sub->timeout && time(NULL) > sub->timeout)
if(sub->timeout && upnp_time() > sub->timeout)
continue;
#endif
sub->timeout = (timeout ? time(NULL) + timeout : 0);
sub->timeout = (timeout ? upnp_time() + timeout : 0);
return sub->uuid;
}
}
@ -624,7 +624,7 @@ void upnpevents_processfds(fd_set *readset, fd_set *writeset)
obj = next;
}
/* remove timeouted subscribers */
curtime = time(NULL);
curtime = upnp_time();
for(sub = subscriberlist.lh_first; sub != NULL; ) {
subnext = sub->entries.le_next;
if(sub->timeout && curtime > sub->timeout && sub->notify == NULL) {

View File

@ -1,7 +1,7 @@
/* $Id: upnppinhole.c,v 1.7 2014/12/09 09:13:53 nanard Exp $ */
/* $Id: upnppinhole.c,v 1.12 2018/03/13 10:24:55 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2017 Thomas Bernard
* (c) 2006-2018 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -130,7 +130,7 @@ upnp_add_inboundpinhole(const char * raddr,
AF_INET6, iaddr, &address);
return -4;
}
current = time(NULL);
current = upnp_time();
timestamp = current + leasetime;
r = 0;
@ -252,7 +252,7 @@ upnp_get_pinhole_info(unsigned short uid,
if(r >= 0) {
if(leasetime) {
time_t current_time;
current_time = time(NULL);
current_time = upnp_time();
if(timestamp > (unsigned int)current_time)
*leasetime = timestamp - current_time;
else
@ -289,7 +289,7 @@ upnp_update_inboundpinhole(unsigned short uid, unsigned int leasetime)
#if defined(USE_PF) || defined(USE_NETFILTER)
unsigned int timestamp;
timestamp = time(NULL) + leasetime;
timestamp = upnp_time() + leasetime;
return update_pinhole(uid, timestamp);
#else
UNUSED(uid); UNUSED(leasetime);
@ -331,7 +331,7 @@ upnp_check_pinhole_working(const char * uid,
/* TODO : to be implemented */
#if 0
FILE * fd;
time_t expire = time(NULL);
time_t expire = upnp_time();
char buf[1024], filename[] = "/var/log/kern.log", expire_time[32]="";
int res = -4, str_len;

View File

@ -1,4 +1,4 @@
/* $Id: upnpredirect.c,v 1.92 2018/01/16 00:50:49 nanard Exp $ */
/* $Id: upnpredirect.c,v 1.93 2018/03/12 22:41:53 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* MiniUPnP project
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
@ -25,6 +25,7 @@
#include "upnpglobalvars.h"
#include "upnpevents.h"
#include "portinuse.h"
#include "upnputils.h"
#if defined(USE_NETFILTER)
#include "netfilter/iptcrdr.h"
#endif
@ -202,7 +203,7 @@ int reload_from_lease_file()
syslog(LOG_WARNING, "could not unlink file %s : %m", lease_file);
}
current_time = time(NULL);
current_time = upnp_time();
while(fgets(line, sizeof(line), fd)) {
syslog(LOG_DEBUG, "parsing lease file line '%s'", line);
proto = line;
@ -353,7 +354,7 @@ upnp_redirect(const char * rhost, unsigned short eport,
(rhost && (strcmp(rhost, rhost_old) == 0)))) {
syslog(LOG_INFO, "updating existing port mapping %hu %s (rhost '%s') => %s:%hu",
eport, protocol, rhost_old, iaddr_old, iport_old);
timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
timestamp = (leaseduration > 0) ? upnp_time() + leaseduration : 0;
if(iport != iport_old) {
r = update_portmapping(ext_if_name, eport, proto, iport, desc, timestamp);
} else {
@ -378,7 +379,7 @@ upnp_redirect(const char * rhost, unsigned short eport,
return -4;
#endif /* CHECK_PORTINUSE */
} else {
timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
timestamp = (leaseduration > 0) ? upnp_time() + leaseduration : 0;
syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
eport, iaddr, iport, protocol, desc);
return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
@ -448,7 +449,7 @@ upnp_get_redirection_infos(unsigned short eport, const char * protocol,
0, 0);
if(r == 0 &&
timestamp > 0 &&
timestamp > (unsigned int)(current_time = time(NULL))) {
timestamp > (unsigned int)(current_time = upnp_time())) {
*leaseduration = timestamp - current_time;
} else {
*leaseduration = 0;
@ -481,7 +482,7 @@ upnp_get_redirection_infos_by_index(int index,
return -1;
else
{
current_time = time(NULL);
current_time = upnp_time();
*leaseduration = (timestamp > (unsigned int)current_time)
? (timestamp - current_time)
: 0;
@ -567,7 +568,7 @@ get_upnp_rules_state_list(int max_rules_number_target)
tmp = malloc(sizeof(struct rule_state));
if(!tmp)
return 0;
current_time = time(NULL);
current_time = upnp_time();
nextruletoclean_timestamp = 0;
while(get_redirect_rule_by_index(i, /*ifname*/0, &tmp->eport, 0, 0,
&iport, &proto, 0, 0, 0,0, &timestamp,

View File

@ -1,4 +1,4 @@
/* $Id: upnpsoap.c,v 1.149 2018/01/16 00:50:49 nanard Exp $ */
/* $Id: upnpsoap.c,v 1.151 2018/03/13 10:32:53 nanard Exp $ */
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* MiniUPnP project
* http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
@ -32,6 +32,7 @@
#include "getifstats.h"
#include "getconnstatus.h"
#include "upnpurns.h"
#include "upnputils.h"
/* utility function */
static int is_numeric(const char * s)
@ -274,7 +275,7 @@ GetStatusInfo(struct upnphttp * h, const char * action, const char * ns)
* Disconnecting, Disconnected */
status = get_wan_connection_status_str(ext_if_name);
uptime = (time(NULL) - startup_time);
uptime = upnp_get_uptime();
bodylen = snprintf(body, sizeof(body), resp,
action, ns, /*SERVICE_TYPE_WANIPC,*/
status, (long)uptime, action);

View File

@ -1,7 +1,7 @@
/* $Id: upnputils.c,v 1.10 2014/11/07 11:53:39 nanard Exp $ */
/* $Id: upnputils.c,v 1.12 2018/03/13 10:25:20 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2006-2014 Thomas Bernard
* (c) 2006-2018 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -12,6 +12,7 @@
#include <syslog.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
@ -184,3 +185,38 @@ get_lan_for_peer(const struct sockaddr * peer)
return lan_addr;
}
time_t upnp_time(void)
{
#if defined(CLOCK_MONOTONIC_FAST) || defined(CLOCK_MONOTONIC)
#if defined(CLOCK_MONOTONIC_FAST)
#define UPNP_CLOCKID CLOCK_MONOTONIC_FAST
#else
#define UPNP_CLOCKID CLOCK_MONOTONIC
#endif
struct timespec ts;
if (clock_gettime(UPNP_CLOCKID, &ts) < 0)
return time(NULL);
else
return ts.tv_sec;
#else
return time(NULL);
#endif
}
time_t upnp_get_uptime(void)
{
#if defined(CLOCK_UPTIME_FAST) || defined(CLOCK_UPTIME)
#if defined(CLOCK_UPTIME_FAST)
#define UPNP_CLOCKID_UPTIME CLOCK_UPTIME_FAST
#else
#define UPNP_CLOCKID_UPTIME CLOCK_UPTIME
#endif
if(GETFLAG(SYSUPTIMEMASK))
{
struct timespec ts;
if (clock_gettime(UPNP_CLOCKID_UPTIME, &ts) >= 0)
return ts.tv_sec;
}
#endif
return upnp_time() - startup_time;
}

View File

@ -1,7 +1,7 @@
/* $Id: upnputils.h,v 1.6 2014/03/31 12:32:57 nanard Exp $ */
/* $Id: upnputils.h,v 1.9 2018/03/13 10:25:20 nanard Exp $ */
/* MiniUPnP project
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
* (c) 2011-2013 Thomas Bernard
* (c) 2011-2018 Thomas Bernard
* This software is subject to the conditions detailed
* in the LICENCE file provided within the distribution */
@ -29,6 +29,16 @@ set_non_blocking(int fd);
struct lan_addr_s *
get_lan_for_peer(const struct sockaddr * peer);
/**
* get the time for upnp (release expiration, etc.)
* Similar to a monotonic time(NULL)
*/
time_t upnp_time(void);
/**
* return either the machine or the daemon uptime
*/
time_t upnp_get_uptime(void);
/**
* define portability macros