From c55140f8bbd8e8f0e7c112a419027b65d479add6 Mon Sep 17 00:00:00 2001 From: sarthurdev <965089+sarthurdev@users.noreply.github.com> Date: Wed, 6 Mar 2024 21:53:46 +0100 Subject: dhcp: T6102: Fix clear DHCP lease op-mode * Add `clear dhcpv6-server lease` * Standardize using vyos.opmode --- op-mode-definitions/clear-dhcp-server-lease.xml.in | 20 ----- op-mode-definitions/dhcp.xml.in | 30 ++++++++ python/vyos/kea.py | 12 +++ src/op_mode/clear_dhcp_lease.py | 88 ---------------------- src/op_mode/dhcp.py | 23 ++++++ 5 files changed, 65 insertions(+), 108 deletions(-) delete mode 100644 op-mode-definitions/clear-dhcp-server-lease.xml.in delete mode 100755 src/op_mode/clear_dhcp_lease.py diff --git a/op-mode-definitions/clear-dhcp-server-lease.xml.in b/op-mode-definitions/clear-dhcp-server-lease.xml.in deleted file mode 100644 index aef0eb22a..000000000 --- a/op-mode-definitions/clear-dhcp-server-lease.xml.in +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - Clear DHCP server lease - - - - - DHCP server lease - - sudo ${vyos_op_scripts_dir}/clear_dhcp_lease.py --ip $4 - - - - - - diff --git a/op-mode-definitions/dhcp.xml.in b/op-mode-definitions/dhcp.xml.in index 0db7471e5..3c42c8e8f 100644 --- a/op-mode-definitions/dhcp.xml.in +++ b/op-mode-definitions/dhcp.xml.in @@ -1,5 +1,35 @@ + + + + + Clear DHCP server lease + + + + + DHCP server lease + + ${vyos_op_scripts_dir}/dhcp.py clear_dhcp_server_lease --family inet --address $4 + + + + + + Clear DHCPv6 server lease + + + + + DHCPv6 server lease + + ${vyos_op_scripts_dir}/dhcp.py clear_dhcp_server_lease --family inet6 --address $4 + + + + + diff --git a/python/vyos/kea.py b/python/vyos/kea.py index 2328d0b00..5aa91e652 100644 --- a/python/vyos/kea.py +++ b/python/vyos/kea.py @@ -328,6 +328,18 @@ def kea_get_leases(inet): return leases['arguments']['leases'] +def kea_delete_lease(inet, ip_address): + ctrl_socket = f'/run/kea/dhcp{inet}-ctrl-socket' + + args = {'ip-address': ip_address} + + result = _ctrl_socket_command(ctrl_socket, f'lease{inet}-del', args) + + if result and 'result' in result: + return result['result'] == 0 + + return False + def kea_get_active_config(inet): ctrl_socket = f'/run/kea/dhcp{inet}-ctrl-socket' diff --git a/src/op_mode/clear_dhcp_lease.py b/src/op_mode/clear_dhcp_lease.py deleted file mode 100755 index 7d4b47104..000000000 --- a/src/op_mode/clear_dhcp_lease.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2023 VyOS maintainers and contributors -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library. If not, see . - -import argparse -import re - -from vyos.configquery import ConfigTreeQuery -from vyos.kea import kea_parse_leases -from vyos.utils.io import ask_yes_no -from vyos.utils.process import call -from vyos.utils.commit import commit_in_progress - -# TODO: Update to use Kea control socket command "lease4-del" - -config = ConfigTreeQuery() -base = ['service', 'dhcp-server'] -lease_file = '/config/dhcp/dhcp4-leases.csv' - - -def del_lease_ip(address): - """ - Read lease_file and write data to this file - without specific section "lease ip" - Delete section "lease x.x.x.x { x;x;x; }" - """ - with open(lease_file, encoding='utf-8') as f: - data = f.read().rstrip() - pattern = rf"^{address},[^\n]+\n" - # Delete lease for ip block - data = re.sub(pattern, '', data) - - # Write new data to original lease_file - with open(lease_file, 'w', encoding='utf-8') as f: - f.write(data) - -def is_ip_in_leases(address): - """ - Return True if address found in the lease file - """ - leases = kea_parse_leases(lease_file) - for lease in leases: - if address == lease['address']: - return True - print(f'Address "{address}" not found in "{lease_file}"') - return False - -if not config.exists(base): - print('DHCP-server not configured!') - exit(0) - -if config.exists(base + ['failover']): - print('Lease cannot be reset in failover mode!') - exit(0) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser() - parser.add_argument('--ip', help='IPv4 address', action='store', required=True) - - args = parser.parse_args() - address = args.ip - - if not is_ip_in_leases(address): - exit(1) - - if commit_in_progress(): - print('Cannot clear DHCP lease while a commit is in progress') - exit(1) - - if not ask_yes_no(f'This will restart DHCP server.\nContinue?'): - exit(1) - else: - del_lease_ip(address) - call('systemctl restart kea-dhcp4-server.service') diff --git a/src/op_mode/dhcp.py b/src/op_mode/dhcp.py index 1d9ad0e76..d27e1baf7 100755 --- a/src/op_mode/dhcp.py +++ b/src/op_mode/dhcp.py @@ -31,6 +31,7 @@ from vyos.configquery import ConfigTreeQuery from vyos.kea import kea_get_active_config from vyos.kea import kea_get_leases from vyos.kea import kea_get_pool_from_subnet_id +from vyos.kea import kea_delete_lease from vyos.utils.process import is_systemd_service_running time_string = "%a %b %d %H:%M:%S %Z %Y" @@ -360,6 +361,28 @@ def show_server_static_mappings(raw: bool, family: ArgFamily, pool: typing.Optio else: return _get_formatted_server_static_mappings(static_mappings, family=family) +def _lease_valid(inet, address): + leases = kea_get_leases(inet) + for lease in leases: + if address == lease['ip-address']: + return True + return False + +@_verify +def clear_dhcp_server_lease(family: ArgFamily, address: str): + v = 'v6' if family == 'inet6' else '' + inet = '6' if family == 'inet6' else '4' + + if not _lease_valid(inet, address): + print(f'Lease not found on DHCP{v} server') + return None + + if not kea_delete_lease(inet, address): + print(f'Failed to clear lease for "{address}"') + return None + + print(f'Lease "{address}" has been cleared') + def _get_raw_client_leases(family='inet', interface=None): from time import mktime from datetime import datetime -- cgit v1.2.3