Source code for dhcpcanon.timers

# -*- coding: utf-8 -*-
# vim:ts=4:sw=4:expandtab 2
# Copyright 2016, 2017 juga (juga at riseup dot net), MIT license.
"""Timers for the DHCP client implementation of the Anonymity Profile
([:rfc:`7844`])."""
from __future__ import absolute_import

import logging
import random
from datetime import datetime, timedelta

from .constants import (DT_PRINT_FORMAT, MAX_DELAY_SELECTING, REBIND_PERC,
                        RENEW_PERC)

logger = logging.getLogger(__name__)


[docs]def future_dt_str(dt, td): """.""" if isinstance(td, str): td = float(td) td = timedelta(seconds=td) future_dt = dt + td return future_dt.strftime(DT_PRINT_FORMAT)
[docs]def nowutc(): """.""" # NOTE: Not using UTC, as all the timers are set in reference to local time # now = datetime.utcnow().replace(tzinfo=utc) now = datetime.now() return now
[docs]def gen_delay_selecting(): """Generate the delay in seconds in which the DISCOVER will be sent. [:rfc:`2131#section-4.4.1`]:: The client SHOULD wait a random time between one and ten seconds to desynchronize the use of DHCP at startup. """ delay = float(random.randint(0, MAX_DELAY_SELECTING)) logger.debug('Delay to enter in SELECTING %s.', delay) logger.debug('SELECTING will happen on %s', future_dt_str(nowutc(), delay)) return delay
[docs]def gen_timeout_resend(attempts): """Generate the time in seconds in which DHCPDISCOVER wil be retransmited. [:rfc:`2131#section-3.1`]:: might retransmit the DHCPREQUEST message four times, for a total delay of 60 seconds [:rfc:`2131#section-4.1`]:: For example, in a 10Mb/sec Ethernet internetwork, the delay before the first retransmission SHOULD be 4 seconds randomized by the value of a uniform random number chosen from the range -1 to +1. Clients with clocks that provide resolution granularity of less than one second may choose a non-integer randomization value. The delay before the next retransmission SHOULD be 8 seconds randomized by the value of a uniform number chosen from the range -1 to +1. The retransmission delay SHOULD be doubled with subsequent retransmissions up to a maximum of 64 seconds. """ timeout = 2 ** (attempts + 1) + random.uniform(-1, +1) logger.debug('next timeout resending will happen on %s', future_dt_str(nowutc(), timeout)) return timeout
[docs]def gen_timeout_request_renew(lease): """Generate time in seconds to retransmit DHCPREQUEST. [:rfc:`2131#section-4..4.5`]:: In both RENEWING and REBINDING states, if the client receives no response to its DHCPREQUEST message, the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state) and one-half of the remaining lease time (in REBINDING state), down to a minimum of 60 seconds, before retransmitting the DHCPREQUEST message. """ time_left = (lease.rebinding_time - lease.renewing_time) * RENEW_PERC if time_left < 60: time_left = 60 logger.debug('Next request in renew will happen on %s', future_dt_str(nowutc(), time_left)) return time_left
[docs]def gen_timeout_request_rebind(lease): """.""" time_left = (lease.lease_time - lease.rebinding_time) * RENEW_PERC if time_left < 60: time_left = 60 logger.debug('Next request on rebinding will happen on %s', future_dt_str(nowutc(), time_left)) return time_left
[docs]def gen_renewing_time(lease_time, elapsed=0): """Generate RENEWING time. [:rfc:`2131#section-4.4.5`]:: T1 defaults to (0.5 * duration_of_lease). T2 defaults to (0.875 * duration_of_lease). Times T1 and T2 SHOULD be chosen with some random "fuzz" around a fixed value, to avoid synchronization of client reacquisition. """ renewing_time = int(lease_time) * RENEW_PERC - elapsed # FIXME:80 [:rfc:`2131#section-4.4.5`]: the chosen "fuzz" could fingerprint # the implementation # NOTE: here using same "fuzz" as systemd? range_fuzz = int(lease_time) * REBIND_PERC - renewing_time logger.debug('rebinding fuzz range %s', range_fuzz) fuzz = random.uniform(-(range_fuzz), +(range_fuzz)) renewing_time += fuzz logger.debug('Renewing time %s.', renewing_time) return renewing_time
[docs]def gen_rebinding_time(lease_time, elapsed=0): """.""" rebinding_time = int(lease_time) * REBIND_PERC - elapsed # FIXME:90 [:rfc:`2131#section-4.4.5`]: the chosen "fuzz" could fingerprint # the implementation # NOTE: here using same "fuzz" as systemd? range_fuzz = int(lease_time) - rebinding_time logger.debug('rebinding fuzz range %s', range_fuzz) fuzz = random.uniform(-(range_fuzz), +(range_fuzz)) rebinding_time += fuzz logger.debug('Rebinding time %s.', rebinding_time) return rebinding_time