Python: Open a Listening Port Behind a Router (upnp?)

14,712

Solution 1

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', '')

Solution 2

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/

Solution 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()

Solution 4

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

Share:
14,712
Admin
Author by

Admin

Updated on June 06, 2022

Comments

  • Admin
    Admin almost 2 years

    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!

  • datashaman
    datashaman about 6 years
    Thanks, @lionello, good catch! I've edited your edit slightly.