Skip to content

Commit

Permalink
Support cltt for IPv4, too
Browse files Browse the repository at this point in the history
Previously, the client last transaction time (cltt) was only parsed for
IPv6 despite also being defined for IPv4.

Now the corresponding last_communication public variable is assigned in
the BaseLease class instead of in Lease6.
  • Loading branch information
Aaron Sierra committed Feb 16, 2021
1 parent 6f9587f commit dcbdfe5
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 25 deletions.
53 changes: 36 additions & 17 deletions isc_dhcp_leases/iscdhcpleases.py
Expand Up @@ -166,13 +166,16 @@ def get(self, include_backups=False):

host_identifier = block['id']
block_type = block['type']
last_client_communication = parse_time(properties['cltt'])
last_client_communication = properties['cltt']

for address_block in self.regex_iaaddr.finditer(block['config']):
block = address_block.groupdict()
properties, options, sets = _extract_properties(block['config'])

lease = Lease6(block['ip'], properties, last_client_communication, host_identifier, block_type,
# Massage cltt into the IPv6 statement's properties
properties['cltt'] = last_client_communication

lease = Lease6(block['ip'], properties, host_identifier, block_type,
options=options, sets=sets, now=self.now)
leases.append(lease)

Expand All @@ -199,10 +202,11 @@ class BaseLease(object):
Base Implementation for all leases. This does most of the common work that is shared among v4 and v6 leases.
Attributes:
ip The IP address assigned by this lease as string
data Dict of all the info in the dhcpd.leases file for this lease
options Options on this lease
sets Dict of key-value set statement values from this lease
ip The IP address assigned by this lease as string
last_communication The last communication time with the host
data Dict of all the info in the dhcpd.leases file for this lease
options Options on this lease
sets Dict of key-value set statement values from this lease
"""

def __init__(self, ip, properties, options=None, sets=None, now=None):
Expand All @@ -215,6 +219,21 @@ def __init__(self, ip, properties, options=None, sets=None, now=None):
sets = {}

self.ip = ip

# FIXME: Review that this workaround for "backups" test data is really
# necessary.
#
# According to unreliable user data[*] we're expected to instantiate
# objects from incomplete lease properties, instead of ignoring them.
#
# https://github.com/MartijnBraam/python-isc-dhcp-leases/issues/20
#
# [*] - start and expiry times are identical
if 'cltt' in properties:
self.last_communication = parse_time(properties['cltt'])
else:
self.last_communication = None

self.data = properties
self.options = options
self.sets = sets
Expand Down Expand Up @@ -244,14 +263,15 @@ class Lease(BaseLease):
Representation of a IPv4 dhcp lease
Attributes:
ip The IPv4 address assigned by this lease as string
hardware The OSI physical layer used to request the lease (usually ethernet)
ethernet The ethernet address of this lease (MAC address)
start The start time of this lease as DateTime object
end The time this lease expires as DateTime object or None if this is an infinite lease
hostname The hostname for this lease if given by the client
binding_state The binding state as string ('active', 'free', 'abandoned', 'backup')
data Dict of all the info in the dhcpd.leases file for this lease
ip The IPv4 address assigned by this lease as string
last_communication The last communication time with the host
hardware The OSI physical layer used to request the lease (usually ethernet)
ethernet The ethernet address of this lease (MAC address)
start The start time of this lease as DateTime object
end The time this lease expires as DateTime object or None if this is an infinite lease
hostname The hostname for this lease if given by the client
binding_state The binding state as string ('active', 'free', 'abandoned', 'backup')
data Dict of all the info in the dhcpd.leases file for this lease
"""

def __init__(self, ip, properties, **kwargs):
Expand Down Expand Up @@ -302,11 +322,11 @@ class Lease6(BaseLease):
Attributes:
ip The IPv6 address assigned by this lease as string
last_communication The last communication time with the host
type If this is a temporary or permanent address
host_identifier The unique host identifier (replaces mac addresses in IPv6)
duid The DHCP Unique Identifier (DUID) of the host
iaid The Interface Association Identifier (IAID) of the host
last_communication The last communication time with the host
end The time this lease expires as DateTime object or None if this is an infinite lease
binding_state The binding state as string ('active', 'free', 'abandoned', 'backup')
preferred_life The preferred lifetime in seconds
Expand All @@ -316,11 +336,10 @@ class Lease6(BaseLease):

(TEMPORARY, NON_TEMPORARY, PREFIX_DELEGATION) = ('ta', 'na', 'pd')

def __init__(self, ip, properties, cltt, host_identifier, address_type, **kwargs):
def __init__(self, ip, properties, host_identifier, address_type, **kwargs):
super(Lease6, self).__init__(ip, properties=properties, **kwargs)

self.type = address_type
self.last_communication = cltt

self.host_identifier = self._iaid_duid_to_bytes(host_identifier)
self.iaid = struct.unpack('<I', self.host_identifier[0:4])[0]
Expand Down
5 changes: 3 additions & 2 deletions isc_dhcp_leases/test_lease.py
Expand Up @@ -21,12 +21,13 @@ def setUp(self):

def test_init(self):
lease = Lease("192.168.0.1", self.lease_data)
lease_start = datetime.datetime(2013, 12, 10, 12, 57, 4, tzinfo=utc)
self.assertEqual(lease.ip, "192.168.0.1")
self.assertEqual(lease.hardware, "ethernet")
self.assertEqual(lease.ethernet, "60:a4:4c:b5:6a:dd")
self.assertEqual(lease.hostname, "Satellite-C700")
self.assertEqual(
lease.start, datetime.datetime(2013, 12, 10, 12, 57, 4, tzinfo=utc))
self.assertEqual(lease.start, lease_start)
self.assertEqual(lease.last_communication, lease_start)
self.assertIsNone(lease.end)
self.assertTrue(lease.valid)
self.assertFalse(lease.active)
Expand Down
13 changes: 7 additions & 6 deletions isc_dhcp_leases/test_lease6.py
Expand Up @@ -10,14 +10,15 @@ class TestLease6(TestCase):
def setUp(self):
self.lease_time = datetime.datetime(2015, 8, 18, 16, 55, 37, tzinfo=utc)
self.lease_data = {
'cltt': '6 2015/8/18 16:55:37',
'binding': 'state active',
'ends': 'never',
'preferred-life': '375',
'max-life': '600'
}

def test_init(self):
lease = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
lease = Lease6("2001:610:600:891d::60", self.lease_data,
"4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na")
self.assertEqual(lease.ip, "2001:610:600:891d::60")

Expand All @@ -33,12 +34,12 @@ def test_init(self):
self.assertEqual(lease.type, Lease6.NON_TEMPORARY)

def test_repr(self):
lease = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
lease = Lease6("2001:610:600:891d::60", self.lease_data,
"4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na")
self.assertEqual(repr(lease), '<Lease6 2001:610:600:891d::60>')

def _test_valid(self, now=None):
lease = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
lease = Lease6("2001:610:600:891d::60", self.lease_data,
"4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na",
now=now)
self.assertTrue(lease.valid) # Lease is forever
Expand All @@ -58,9 +59,9 @@ def test_valid_historical(self):
now=datetime.datetime(2015, 7, 6, 8, 15, 0, tzinfo=utc))

def test_eq(self):
lease_a = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
lease_a = Lease6("2001:610:600:891d::60", self.lease_data,
"4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na")
lease_b = Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
lease_b = Lease6("2001:610:600:891d::60", self.lease_data,
"4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na")

self.assertEqual(lease_a, lease_b)
Expand All @@ -74,6 +75,6 @@ def test_eq(self):

def test_naive_time(self):
with self.assertRaises(ValueError):
Lease6("2001:610:600:891d::60", self.lease_data, self.lease_time,
Lease6("2001:610:600:891d::60", self.lease_data,
"4dv\\352\\000\\001\\000\\001\\035f\\037\\342\\012\\000'\\000\\000\\000", "na",
now=datetime.datetime.now())

0 comments on commit dcbdfe5

Please sign in to comment.