annotate src/plugins/plugin_misc_nat-port.py @ 1536:04a13d9ae265

plugin nat-port: NAT port first draft: - this plugin use UPnP-IGD (and maybe later NAT-PMP) to open a port or get local/external IP - for now, only IP retrieval is implemented
author Goffi <goffi@goffi.org>
date Tue, 29 Sep 2015 17:54:24 +0200
parents
children e281ed2c21db
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1536
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/python
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 # SAT plugin for NAT port mapping
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
5 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Jérôme Poisson (goffi@goffi.org)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
6
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # This program is free software: you can redistribute it and/or modify
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 # (at your option) any later version.
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
11
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # This program is distributed in the hope that it will be useful,
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 # GNU Affero General Public License for more details.
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from sat.core.i18n import _
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 from sat.core.constants import Const as C
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 from sat.core.log import getLogger
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 log = getLogger(__name__)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from sat.core import exceptions
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 from twisted.internet import threads
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from twisted.internet import defer
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
27
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 try:
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
29 import miniupnpc
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 except ImportError:
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
31 raise exceptions.MissingModule(u"Missing module MiniUPnPc, please download/install it (and its Python binding) at http://miniupnp.free.fr/")
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
32
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
33
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
34 PLUGIN_INFO = {
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
35 "name": "NAT port mapping",
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 "import_name": "NAT-PORT",
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 "type": C.PLUG_TYPE_MISC,
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
38 "main": "NatPort",
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
39 "handler": "no",
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
40 "description": _("""Automatic NAT port mapping using UPnP"""),
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
41 }
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
42
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
43
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 class NatPort(object):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 # TODO: refresh data if a new connection is detected (see plugin_misc_ip)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
46
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 def __init__(self, host):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 log.info(_("plugin NAT Port initialization"))
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 self.host = host
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 self._external_ip = None
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 self._initialised = defer.Deferred()
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
52 self._upnp = miniupnpc.UPnP() # will be None if no device is available
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 self._upnp.discoverdelay=200
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 discover_d = threads.deferToThread(self._discover)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 discover_d.chainDeferred(self._initialised)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 self._initialised.addErrback(self._init_failed)
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
57
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 def _init_failed(self, failure):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 log.info(u"UPnP-GID not available")
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 self._upnp = None
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
61
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 def _discover(self):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
63 devices = self._upnp.discover()
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
64 if devices:
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
65 log.info(u"{nb} UPnP-IGD device(s) found".format(nb=devices))
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
66 else:
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 log.info(u"Can't find UPnP-IGD device on the local network")
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 raise exceptions.NotFound
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 self._upnp.selectigd()
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 self._external_ip = self._upnp.externalipaddress()
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
71
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 def getIP(self, local=False):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 """Return IP address found with UPnP-IGD
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
74
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 @param local(bool): True to get external IP address, False to get local network one
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 @return (None, str): found IP address, or None of something got wrong
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
77 """
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 def getIP(dummy):
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 if self._upnp is None:
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
80 return None
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
81 # lanaddr can be the empty string if not found,
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 # we need to return None in this case
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 return (self._upnp.lanaddr or None) if local else self._external_ip
04a13d9ae265 plugin nat-port: NAT port first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
84 return self._initialised.addCallback(getIP)