Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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!

like image 557
Boona Avatar asked Dec 08 '10 20:12

Boona


People also ask

Can you have UPnP and port forwarding?

Universal Plug and Play (UPnP) is a network protocol that allows compliant devices to automatically set port forwarding rules for themselves. These devices can be personal computers, printers, security cameras, game consoles or mobile devices that communicate with each other and share data over your network.

Is it safe to enable UPnP on my router?

UPnP, therefore, is not inherently dangerous if your router is up to date and has all the latest firmware updates, and your connected devices are free of malware. UPnP becomes an issue if a connected device is infected with malware, as it can spread to your local devices.

What is UPnP routing?

UPnP (Universal Plug and Play) is a networking protocol that enables devices to discover each other and connect without the need for manual configuration or user intervention. The protocol automates all the steps necessary for recognition and communication between devices on the same network.


4 Answers

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', '')
like image 104
datashaman Avatar answered Oct 20 '22 09:10

datashaman


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/

like image 43
GregD Avatar answered Oct 20 '22 08:10

GregD


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()
like image 43
KernelSanders Avatar answered Oct 20 '22 10:10

KernelSanders


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

like image 31
Martin v. Löwis Avatar answered Oct 20 '22 10:10

Martin v. Löwis