Forward a port via UPnP in Python
Question: I am making a Python application that requires the user to have a port
forwarded to his computer in order to communicate with a server or another
user. The current implementation works quite great, yet the only thing is that
the person who's running the file must forward the port to the local IP
manually. I want to automate this. He picks a port, script checks if it can be
forwarded, then it forwards it. If it can't, it handles the error
respectively.

I've looked into some libraries that claim they can do this in pure Python
(since I will need to compile to .exe's [...] after finishing) but didn't
manage to find something useful. If you could provide me with a code sample on
how to attempt to forward a port and handle success/fail respectively, that
would be great.

Thanks in advance for your time.

P.S.:It's Python 2.7.X that I am targeting


Answer: Looks like there are a few options:

  * Miniupnp has [python bindings](https://github.com/miniupnp/miniupnp/blob/master/miniupnpc/testupnpigd.py)
  * [Python bindings for GNUPnP](https://packages.debian.org/sid/python/python-gupnp-igd)
  * [miranda-upnp](https://code.google.com/p/miranda-upnp/) is pure python

There is a nice example of the python bindings for GNUPnP being used to open
ports on a router [here](http://www.gniibe.org/memo/system/dynamic-
ip/upnp.html). In that example the lease time is set to 0, which is unlimited.
See [here](https://developer.gnome.org/gupnp-
igd/unstable/GUPnPSimpleIgd.html#gupnp-simple-igd-add-port) 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()
    

