File: adding_deleting_port_mapping.py

package info (click to toggle)
async-upnp-client 0.44.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,072 kB
  • sloc: python: 11,921; xml: 2,826; sh: 32; makefile: 6
file content (107 lines) | stat: -rw-r--r-- 3,307 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
#!/usr/bin/env python3
"""Example of adding and deleting a port mapping."""

import asyncio
import ipaddress
import sys
from datetime import timedelta
from typing import cast

from async_upnp_client.aiohttp import AiohttpRequester
from async_upnp_client.client_factory import UpnpFactory
from async_upnp_client.profiles.igd import IgdDevice
from async_upnp_client.utils import CaseInsensitiveDict, get_local_ip

SOURCE = ("0.0.0.0", 0)


async def discover_igd_devices() -> set[CaseInsensitiveDict]:
    """Discover IGD devices."""
    # Do the search, this blocks for timeout (4 seconds, default).
    discoveries = await IgdDevice.async_search(source=SOURCE)
    if not discoveries:
        print("Could not find device")
        sys.exit(1)

    return discoveries


async def build_igd_device(discovery: CaseInsensitiveDict) -> IgdDevice:
    """Find and construct device."""
    location = discovery["location"]
    requester = AiohttpRequester()
    factory = UpnpFactory(requester, non_strict=True)
    device = await factory.async_create_device(description_url=location)
    return IgdDevice(device, None)


async def async_add_port_mapping(igd_device: IgdDevice) -> None:
    """Add port mapping."""
    external_ip_address = await igd_device.async_get_external_ip_address()
    if not external_ip_address:
        print("Could not get external IP address")
        sys.exit(1)

    remote_host = ipaddress.ip_address(external_ip_address)
    remote_host_ipv4 = cast(ipaddress.IPv4Address, remote_host)
    local_ip = ipaddress.ip_address(get_local_ip())
    local_ip_ipv4 = cast(ipaddress.IPv4Address, local_ip)
    # Change `enabled` to False to disable port mapping.
    # NB: This does not delete the port mapping.
    enabled = True
    mapping_name = "Bombsquad"
    await igd_device.async_add_port_mapping(
        remote_host=remote_host_ipv4,
        external_port=43210,
        internal_client=local_ip_ipv4,
        internal_port=43210,
        protocol="UDP",
        enabled=enabled,
        description=mapping_name,
        lease_duration=timedelta(seconds=7200),
    )  # Time in secs


async def async_del_port_mapping(igd_device: IgdDevice) -> None:
    """Delete port mapping."""
    external_ip_address = await igd_device.async_get_external_ip_address()
    if not external_ip_address:
        print("Could not get external IP address")
        sys.exit(1)

    remote_host = ipaddress.ip_address(external_ip_address)
    remote_host_ipv4 = cast(ipaddress.IPv4Address, remote_host)
    await igd_device.async_delete_port_mapping(
        remote_host=remote_host_ipv4,
        external_port=43210,
        protocol="UDP",
    )


async def async_main() -> None:
    """Async main."""
    discoveries = await discover_igd_devices()
    print(f"Discoveries: {discoveries}")
    discovery = list(discoveries)[0]
    print(f"Using device at location: {discovery['location']}")
    igd_device = await build_igd_device(discovery)

    print("Creating port mapping")
    await async_add_port_mapping(igd_device)

    await asyncio.sleep(5)

    print("Deleting port mapping")
    await async_del_port_mapping(igd_device)


def main() -> None:
    """Main."""
    try:
        asyncio.run(async_main())
    except KeyboardInterrupt:
        pass


if __name__ == "__main__":
    main()