flyte / upnpclient

uPnP client library for Python 3.
MIT License
202 stars 37 forks source link

Can't follow typical usage examples from readme #42

Open R0CKH0PP3R opened 1 year ago

R0CKH0PP3R commented 1 year ago

After installing with pip as user, I get the following when trying the usage examples:


Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import upnpclient
>>> devices = upnpclient.discover()
>>> devices
[<Device 'PiFi (UpMpd AV)'>, <Device 'Focal UpMpd AV'>, <Device 'Plex Media Server: odroid'>, <Device 'PiFi (UpMpd OH)'>, <Device 'WFADevice'>, <Device 'BT Home Hub 6.0A'>, <Device 'Focal UpMpd OH'>]
>>> d = devices[0]
>>> d.WANIPConn1.GetStatusInfo()
Traceback (most recent call last):
  File "/home/ahaslam/.local/lib/python3.10/site-packages/upnpclient/upnp.py", line 148, in __getattr__
    return self.service_map[name]
KeyError: 'WANIPConn1'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ahaslam/.local/lib/python3.10/site-packages/upnpclient/upnp.py", line 150, in __getattr__
    raise AttributeError("No attribute or service found with name %r." % name)
AttributeError: No attribute or service found with name 'WANIPConn1'.
>>> d.services
[<Service service_id='urn:upnp-org:serviceId:AVTransport'>, <Service service_id='urn:upnp-org:serviceId:RenderingControl'>, <Service service_id='urn:upnp-org:serviceId:ConnectionManager'>]
>>> d.Layer3Forwarding1.actions
Traceback (most recent call last):
  File "/home/ahaslam/.local/lib/python3.10/site-packages/upnpclient/upnp.py", line 148, in __getattr__
    return self.service_map[name]
KeyError: 'Layer3Forwarding1'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ahaslam/.local/lib/python3.10/site-packages/upnpclient/upnp.py", line 150, in __getattr__
    raise AttributeError("No attribute or service found with name %r." % name)
AttributeError: No attribute or service found with name 'Layer3Forwarding1'.
brostosjoined commented 1 year ago

@R0CKH0PP3R Could you show the output of

print(d.services)

This is my output

[<Service service_id='urn:upnp-org:serviceId:L3Forwarding1'>, <Service service_id='urn:upnp-org:serviceId:WANCommonIFC1'>, <Service service_id='urn:upnp-org:serviceId:WANIPConn1'>]
rytilahti commented 1 year ago

WANIPConn1 is found commonly only on routers while the first device your list sounds like an AV device (<Device 'PiFi (UpMpd AV)'>). You can use services to access the list of available services for that device like mentioned by @brostosjoined, and use the last part of the service_id field to access the service by name.

The second last element in your devices list (the bt home hub) is something that might expose the WANIPConn1, if you want to follow the README instructions.

sergiomb2 commented 6 months ago

I have the same problem:

import upnpclient
d = upnpclient.Device("http://192.168.1.108:8200/rootDesc.xml")
d.services

[<Service service_id='urn:upnp-org:serviceId:ContentDirectory'>,
<Service service_id='urn:upnp-org:serviceId:ConnectionManager'>,
<Service service_id='urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar'>]

after this what I can do ? how I list / browse the server ?

joncox123 commented 5 months ago

After installing with pip as user, I get the following when trying the usage examples:


Python 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import upnpclient
>>> devices = upnpclient.discover()
>>> devices
[<Device 'PiFi (UpMpd AV)'>, <Device 'Focal UpMpd AV'>, <Device 'Plex Media Server: odroid'>, <Device 'PiFi (UpMpd OH)'>, <Device 'WFADevice'>, <Device 'BT Home Hub 6.0A'>, <Device 'Focal UpMpd OH'>]
>>> d = devices[0]
>>> d.WANIPConn1.GetStatusInfo()
Traceback (most recent call last):
  File "/home/ahaslam/.local/lib/python3.10/site-packages/upnpclient/upnp.py", line 148, in __getattr__
    return self.service_map[name]
KeyError: 'WANIPConn1'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ahaslam/.local/lib/python3.10/site-packages/upnpclient/upnp.py", line 150, in __getattr__
    raise AttributeError("No attribute or service found with name %r." % name)
AttributeError: No attribute or service found with name 'WANIPConn1'.
>>> d.services
[<Service service_id='urn:upnp-org:serviceId:AVTransport'>, <Service service_id='urn:upnp-org:serviceId:RenderingControl'>, <Service service_id='urn:upnp-org:serviceId:ConnectionManager'>]
>>> d.Layer3Forwarding1.actions
Traceback (most recent call last):
  File "/home/ahaslam/.local/lib/python3.10/site-packages/upnpclient/upnp.py", line 148, in __getattr__
    return self.service_map[name]
KeyError: 'Layer3Forwarding1'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ahaslam/.local/lib/python3.10/site-packages/upnpclient/upnp.py", line 150, in __getattr__
    raise AttributeError("No attribute or service found with name %r." % name)
AttributeError: No attribute or service found with name 'Layer3Forwarding1'.

I figured out a solution. Its a little more complicated, as I'm not sure what happened to the API, as it seems to have changed a bit since the README was written. However, I developed and tested this code for my TP-Link ER7206 router, and it works fine. The process is slightly more cumbersome, but not too bad.

"""
Configures your home router to allow incoming connections to the PyBolo server, using the IGD/UPnP protocol.
"""

import upnpclient
import socket

class BoloUPnP:
    def __init__(self):
        self.router = None
        self.ip = None

        self.findRouter()

    # Search for a UPnP router with WAN connection
    def findRouter(self):
        print("Searching for UPnP router devices with WAN connection...", flush=True)
        devices = upnpclient.discover()
        for device in devices:
            WANIPConnection = getattr(device, "WANIPConnection", None)
            if callable(WANIPConnection):
                try:
                    ip = WANIPConnection.GetExternalIPAddress()["NewExternalIPAddress"]
                except KeyError as e:
                    print("BoloUPnP::findRouter: Error getting WAN IP address: %s" % str(e), flush=True)
                    continue
                print(
                    "BoloUPnP::findRouter: Found router %s with external IP %s" % (device.model_description, ip),
                    flush=True,
                )
                self.router = device
                self.ip = ip
        if self.router is None:
            print("BoloUPnP::findRouter: Failed to find any UPnP WAN routers", flush=True)

    # Open a port on the router
    def openPort(self, port, durationSeconds=21600):
        if self.router is None:
            print("BoloUPnP::openPort: No router found, please try calling findRouter first/again.", flush=True)
            return

        hostname = socket.gethostname()
        myIPAddress = socket.gethostbyname(hostname)

        AddPortMapping = getattr(self.router.WANIPConnection, "AddPortMapping", None)
        if callable(AddPortMapping):
            AddPortMapping(
                NewRemoteHost="0.0.0.0",
                NewExternalPort=port,
                NewProtocol="TCP",
                NewInternalPort=port,
                NewInternalClient=myIPAddress,
                NewEnabled="1",
                NewPortMappingDescription="PyBolo Server",
                NewLeaseDuration=durationSeconds,
            )
            print("BoloUPnP::openPort: Opened port %d to local IP %s" % (port, myIPAddress), flush=True)
        else:
            print("BoloUPnP::openPort: could not open a port!", flush=True)

if __name__ == "__main__":
    pnp = BoloUPnP()
    pnp.openPort(6901, durationSeconds=360)
brostosjoined commented 5 months ago
import upnpclient
# Plucked from https://github.com/ethereum/upnp-port-forward/blob/master/upnp_port_forward/
WAN_SERVICE_NAMES = (
    "WANIPConn1",
    "WANIPConnection.1",  # Nighthawk C7800
    "WANPPPConnection.1",  # CenturyLink C1100Z
    "WANPPPConn1",  # Huawei B528s-23a
)

devices = upnpclient.discover()

if devices == []:
    print("No devices found")
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # connect() for UDP doesn't send packets
    s.connect(('10.0.0.0', 0))
    local_ip = s.getsockname()[0]
    s.close()
except:
    pass
for upnp_dev in devices:
    for service in upnp_dev.services:
        if service.name in WAN_SERVICE_NAMES:
            service.AddPortMapping(
                NewRemoteHost="0.0.0.0",
                NewExternalPort=43210,
                NewProtocol="UDP",
                NewInternalPort=43210,
                NewInternalClient=local_ip,
                NewEnabled="1",
                NewPortMappingDescription="Bombsquad",
                NewLeaseDuration=14400)

have you tried this