Python: Open a Listening Port Behind a Router (upn

2019-02-03 12:39发布

问题:

I've developed an application that is essentially just a little ftp server with the ability to specify which directory you wish to share on startup. I'm using ftplib for the server because it's sick easy. The only issue I'm having is that if you are behind a router you have to manually forward the ports on your router and I'm finding that it's a little too complicated for my users (aka co-workers/clients).

So I've been looking for a simple solution to open ports but I'm finding that most APIs are too broad and way over my head. Does someone know of a solution that would be relatively simple to implement?

Note: It will really only be used on windows although cross-platform compatibility would be welcomed. If there is a windows only solution that is simpler then I would opt for that.

Thanks!

回答1:

The protocol you want is called IGD (for Internet Gateway Device) and is based on UPNP. It allows a client program (yours) to discover the router on the network (using UPNP) and then ask it to forward a specific port.

This is supported by most home routers, and the technique is used by a lot of services like BitTorrent or multiPlayer games, bit it's a bit complicated to use or implement. There are several open source libraries that support IGD and one of the simplest one (which is also cross-platform) is "miniupnp": see http://miniupnp.free.fr/



回答2:

Simple example for miniupnp. It creates a mapping on the discovered gateway from external port 43210 to the interface connected to port 43210 on the interface connected to the discovered gateway.

import miniupnpc

upnp = miniupnpc.UPnP()

upnp.discoverdelay = 10
upnp.discover()

upnp.selectigd()

port = 43210

# addportmapping(external-port, protocol, internal-host, internal-port, description, remote-host)
upnp.addportmapping(port, 'TCP', upnp.lanaddr, port, 'testing', '')


回答3:

Looks like there are a few options, one being miniupnp. There are also python bindings for GNUPnP here. For windows minupnp will work, or you could go pure python with miranda-upnp.

There is a nice example of the python GNUPnP bindings being used to open ports on a router here. In that example the lease time is set to 0, which is unlimited. See here for the definition of add_port.

A simple example might be:

#! /usr/bin/python
import gupnp.igd
import glib
from sys import stderr

my_ip = YOUR_IP

igd = gupnp.igd.Simple()
igd.external_ip = None

main = glib.MainLoop()

def mep(igd, proto, eip, erip, port, localip, lport, msg):
    if port == 80:
        igd.external_ip = eip
        main.quit()

def emp(igd, err, proto, ep, lip, lp, msg):
    print >> stderr, "ERR"
    print >> stderr, err, proto, ep, lip, lp, msg
    main.quit()

igd.connect("mapped-external-port", mep)
igd.connect("error-mapping-port", emp)

#igd.add_port("PROTO", EXTERNAL_PORT, INTERNAL_IP, INTERNAL_PORT, LEASE_DURATION_IN_SECONDS, "NAME")
igd.add_port("TCP", 80, my_ip, 8080, 86400, "web")

main.run()


回答4:

There is an article explaining how to use the Windows IGD COM object with win32com.



回答5:

I looked for this for many days. I was unable to install miniupnpc using pip for python 3.

I solved this isue with an implementation found here which will work for python 2.

I forked it and make the changes to be used on python 3, you can find it Here

This implementation is by far the simplest I have seen and works well.