File: openvpn.py

package info (click to toggle)
python-asusrouter 1.21.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,856 kB
  • sloc: python: 20,497; makefile: 3
file content (118 lines) | stat: -rw-r--r-- 2,989 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""OpenVPN module for AsusRouter."""

from __future__ import annotations

from collections.abc import Awaitable, Callable
from enum import IntEnum
import logging
from typing import Any

from asusrouter.modules.firmware import Firmware
from asusrouter.tools.converters import get_arguments

_LOGGER = logging.getLogger(__name__)

REQUIRE_IDENTITY = True


class AsusOVPNClient(IntEnum):
    """Asus OpenVPN client state."""

    UNKNOWN = -999
    ERROR = -1
    DISCONNECTED = 0
    CONNECTING = 1
    CONNECTED = 2

    OFF = DISCONNECTED
    ON = CONNECTING


class AsusOVPNServer(IntEnum):
    """Asus OpenVPN server state."""

    UNKNOWN = -999
    ERROR = -1
    DISCONNECTED = 0
    CONNECTING = 1
    CONNECTED = 2

    OFF = DISCONNECTED
    ON = CONNECTING


async def set_state(
    callback: Callable[..., Awaitable[bool]],
    state: AsusOVPNClient | AsusOVPNServer,
    **kwargs: Any,
) -> bool:
    """Set the OpenVPN state."""

    # Check if state is available
    if not isinstance(
        state, AsusOVPNClient | AsusOVPNServer
    ) or state.value not in (
        0,
        1,
    ):
        _LOGGER.debug("No state found in arguments")
        return False

    # Get the arguments
    vpn_id, identity = get_arguments(("id", "identity"), **kwargs)

    if not vpn_id:
        _LOGGER.debug("No VPN id found in arguments")
        return False

    service_arguments = {"id": vpn_id}

    service_map: dict[Any, str]

    # Get the correct service call
    # This will be firmware dependent
    if (
        not identity
        or identity.merlin
        or identity.firmware < Firmware(major="3.0.0.4", minor=388, build=0)
    ):
        service_map = {
            (AsusOVPNClient, AsusOVPNClient.ON): f"start_vpnclient{vpn_id}",
            (AsusOVPNClient, AsusOVPNClient.OFF): f"stop_vpnclient{vpn_id}",
            (AsusOVPNServer, AsusOVPNServer.ON): f"start_vpnserver{vpn_id}",
            (AsusOVPNServer, AsusOVPNServer.OFF): f"stop_vpnserver{vpn_id}",
        }
        service = service_map.get((type(state), state))
    else:
        service_map = {
            AsusOVPNServer.ON: (
                "restart_openvpnd;restart_chpass;restart_samba;restart_dnsmasq;"
            ),
            AsusOVPNServer.OFF: "stop_openvpnd;restart_samba;restart_dnsmasq;",
        }
        service = (
            service_map.get(state)
            if isinstance(state, AsusOVPNServer)
            else None
        )
        service_arguments["VPNServer_enable"] = (
            "1" if state == AsusOVPNServer.ON else "0"
        )

    if not service:
        _LOGGER.debug("Unknown state %s", state)
        return False

    _LOGGER.debug(
        "Triggering state set with parameters: service=%s, arguments=%s",
        service,
        service_arguments,
    )

    # Run the service
    return await callback(
        service=service,
        arguments=service_arguments,
        apply=True,
        expect_modify=kwargs.get("expect_modify", False),
    )