def test_parse_interfaces(self):
        with mock.patch('aioupnp.interfaces.get_netifaces') as patch:
            patch.return_value = mock_netifaces

            lan, gateway = UPnP.get_lan_and_gateway(interface_name='test0')
            self.assertEqual(gateway, '192.168.1.1')
            self.assertEqual(lan, '192.168.1.2')
Beispiel #2
0
def get_help(command: str) -> str:
    annotations, doc = UPnP.get_annotations(command)
    doc = doc or ""

    arg_strs = []
    for k, v in annotations.items():
        if k not in ['return', 'igd_args', 'loop']:
            t = str(v) if not hasattr(v, "__name__") else v.__name__
            if t == 'bool':
                arg_strs.append(f"[--{k}]")
            else:
                arg_strs.append(f"[--{k}=<{t}>]")
        elif k == 'igd_args':
            arg_strs.append(f"[--<header key>=<header value>, ...]")

    params = " ".join(arg_strs)
    usage = "\n".join(textwrap.wrap(
        f"aioupnp [-h] [--debug_logging] {command} {params}",
        100, subsequent_indent='  ', break_long_words=False)) + "\n"

    return usage + textwrap.dedent(doc)
Beispiel #3
0
def main(argv=None, loop=None):
    argv = argv or sys.argv
    commands = [n for n in dir(UPnP) if hasattr(getattr(UPnP, n, None), "_cli")]
    help_str = "\n".join(textwrap.wrap(
        " | ".join(commands), 100, initial_indent='  ', subsequent_indent='  ', break_long_words=False
    ))

    usage = \
        "\n%s\n" \
        "If m-search headers are provided as keyword arguments all of the headers to be used must be provided,\n" \
        "in the order they are to be used. For example:\n" \
        "  aioupnp --HOST=239.255.255.250:1900 --MAN=\"ssdp:discover\" --MX=1 --ST=upnp:rootdevice m_search\n\n" \
        "Commands:\n" \
        "%s\n\n" \
        "For help with a specific command:" \
        "  aioupnp help <command>\n" % (base_usage, help_str)

    args = argv[1:]
    if args[0] in ['help', '-h', '--help']:
        if len(args) > 1:
            if args[1] in commands:
                sys.exit(get_help(args[1]))
        sys.exit(print(usage))

    defaults = {
        'debug_logging': False,
        'interface': 'default',
        'gateway_address': '',
        'lan_address': '',
        'timeout': 30,
        'unicast': False
    }

    options = OrderedDict()
    command = None
    for arg in args:
        if arg.startswith("--"):
            if "=" in arg:
                k, v = arg.split("=")
            else:
                k, v = arg, True
            k = k.lstrip('--')
            options[k] = v
        else:
            command = arg
            break
    if not command:
        print("no command given")
        sys.exit(print(usage))
    kwargs = {}
    for arg in args[len(options)+1:]:
        if arg.startswith("--"):
            k, v = arg.split("=")
            k = k.lstrip('--')
            kwargs[k] = v
        else:
            break
    for k, v in defaults.items():
        if k not in options:
            options[k] = v

    if options.pop('debug_logging'):
        log.setLevel(logging.DEBUG)

    UPnP.run_cli(
        command.replace('-', '_'), options, options.pop('lan_address'), options.pop('gateway_address'),
        options.pop('timeout'), options.pop('interface'), options.pop('unicast'), kwargs, loop
    )
Beispiel #4
0
    def _maintain_redirects(self):
        # setup the gateway if necessary
        if not self.upnp:
            try:
                self.upnp = yield from_future(UPnP.discover())
                log.info("found upnp gateway: %s",
                         self.upnp.gateway.manufacturer_string)
            except Exception as err:
                log.warning("upnp discovery failed: %s", err)
                return

        # update the external ip
        try:
            external_ip = yield from_future(self.upnp.get_external_ip())
            if external_ip == "0.0.0.0":
                log.warning(
                    "upnp doesn't know the external ip address (returned 0.0.0.0), using fallback"
                )
                external_ip = CS.get_external_ip()
            if self.external_ip and self.external_ip != external_ip:
                log.info("external ip changed from %s to %s", self.external_ip,
                         external_ip)
            elif not self.external_ip:
                log.info("got external ip: %s", external_ip)
            self.external_ip = external_ip
        except (asyncio.TimeoutError, UPnPError):
            pass

        if not self.upnp_redirects:  # setup missing redirects
            try:
                upnp_redirects = yield DeferredDict({
                    "UDP":
                    from_future(
                        self.upnp.get_next_mapping(self._int_dht_node_port,
                                                   "UDP", "LBRY DHT port")),
                    "TCP":
                    from_future(
                        self.upnp.get_next_mapping(self._int_peer_port, "TCP",
                                                   "LBRY peer port"))
                })
                self.upnp_redirects.update(upnp_redirects)
            except (asyncio.TimeoutError, UPnPError):
                self.upnp = None
                return self._maintain_redirects()
        else:  # check existing redirects are still active
            found = set()
            mappings = yield from_future(self.upnp.get_redirects())
            for mapping in mappings:
                proto = mapping['NewProtocol']
                if proto in self.upnp_redirects and mapping[
                        'NewExternalPort'] == self.upnp_redirects[proto]:
                    if mapping['NewInternalClient'] == self.upnp.lan_address:
                        found.add(proto)
            if 'UDP' not in found:
                try:
                    udp_port = yield from_future(
                        self.upnp.get_next_mapping(self._int_dht_node_port,
                                                   "UDP", "LBRY DHT port"))
                    self.upnp_redirects['UDP'] = udp_port
                    log.info("refreshed upnp redirect for dht port: %i",
                             udp_port)
                except (asyncio.TimeoutError, UPnPError):
                    del self.upnp_redirects['UDP']
            if 'TCP' not in found:
                try:
                    tcp_port = yield from_future(
                        self.upnp.get_next_mapping(self._int_peer_port, "TCP",
                                                   "LBRY peer port"))
                    self.upnp_redirects['TCP'] = tcp_port
                    log.info("refreshed upnp redirect for peer port: %i",
                             tcp_port)
                except (asyncio.TimeoutError, UPnPError):
                    del self.upnp_redirects['TCP']
            if 'TCP' in self.upnp_redirects and 'UDP' in self.upnp_redirects:
                log.debug("upnp redirects are still active")
Beispiel #5
0
    def _maintain_redirects(self):
        # setup the gateway if necessary
        if not self.upnp:
            try:
                self.upnp = yield from_future(UPnP.discover())
                log.info("found upnp gateway: %s",
                         self.upnp.gateway.manufacturer_string)
            except Exception as err:
                log.warning("upnp discovery failed: %s", err)
                self.upnp = None

        # update the external ip
        external_ip = None
        if self.upnp:
            try:
                external_ip = yield from_future(self.upnp.get_external_ip())
                if external_ip != "0.0.0.0" and not self.external_ip:
                    log.info("got external ip from UPnP: %s", external_ip)
            except (asyncio.TimeoutError, UPnPError):
                pass

        if external_ip == "0.0.0.0" or not external_ip:
            log.warning(
                "unable to get external ip from UPnP, checking lbry.io fallback"
            )
            external_ip = yield CS.get_external_ip()
        if self.external_ip and self.external_ip != external_ip:
            log.info("external ip changed from %s to %s", self.external_ip,
                     external_ip)
        self.external_ip = external_ip
        assert self.external_ip is not None  # TODO: handle going/starting offline

        if not self.upnp_redirects and self.upnp:  # setup missing redirects
            try:
                log.info("add UPnP port mappings")
                d = {}
                if PEER_PROTOCOL_SERVER_COMPONENT not in self.component_manager.skip_components:
                    d["TCP"] = from_future(
                        self.upnp.get_next_mapping(self._int_peer_port, "TCP",
                                                   "LBRY peer port"))
                if DHT_COMPONENT not in self.component_manager.skip_components:
                    d["UDP"] = from_future(
                        self.upnp.get_next_mapping(self._int_dht_node_port,
                                                   "UDP", "LBRY DHT port"))
                upnp_redirects = yield DeferredDict(d)
                log.info("set up redirects: %s", upnp_redirects)
                self.upnp_redirects.update(upnp_redirects)
            except (asyncio.TimeoutError, UPnPError):
                self.upnp = None
                return self._maintain_redirects()
        elif self.upnp:  # check existing redirects are still active
            found = set()
            mappings = yield from_future(self.upnp.get_redirects())
            for mapping in mappings:
                proto = mapping['NewProtocol']
                if proto in self.upnp_redirects and mapping[
                        'NewExternalPort'] == self.upnp_redirects[proto]:
                    if mapping['NewInternalClient'] == self.upnp.lan_address:
                        found.add(proto)
            if 'UDP' not in found and DHT_COMPONENT not in self.component_manager.skip_components:
                try:
                    udp_port = yield from_future(
                        self.upnp.get_next_mapping(self._int_dht_node_port,
                                                   "UDP", "LBRY DHT port"))
                    self.upnp_redirects['UDP'] = udp_port
                    log.info("refreshed upnp redirect for dht port: %i",
                             udp_port)
                except (asyncio.TimeoutError, UPnPError):
                    del self.upnp_redirects['UDP']
            if 'TCP' not in found and PEER_PROTOCOL_SERVER_COMPONENT not in self.component_manager.skip_components:
                try:
                    tcp_port = yield from_future(
                        self.upnp.get_next_mapping(self._int_peer_port, "TCP",
                                                   "LBRY peer port"))
                    self.upnp_redirects['TCP'] = tcp_port
                    log.info("refreshed upnp redirect for peer port: %i",
                             tcp_port)
                except (asyncio.TimeoutError, UPnPError):
                    del self.upnp_redirects['TCP']
            if ('TCP' in self.upnp_redirects and PEER_PROTOCOL_SERVER_COMPONENT
                    not in self.component_manager.skip_components) and (
                        'UDP' in self.upnp_redirects and DHT_COMPONENT
                        not in self.component_manager.skip_components):
                if self.upnp_redirects:
                    log.debug("upnp redirects are still active")