###
### This file is part of Trivial IP Encryption (TrIPE).
###
-### TrIPE is free software; you can redistribute it and/or modify
-### it under the terms of the GNU General Public License as published by
-### the Free Software Foundation; either version 2 of the License, or
-### (at your option) any later version.
+### TrIPE is free software: you can redistribute it and/or modify it under
+### the terms of the GNU General Public License as published by the Free
+### Software Foundation; either version 3 of the License, or (at your
+### option) any later version.
###
-### TrIPE is distributed in the hope that it will be useful,
-### but WITHOUT ANY WARRANTY; without even the implied warranty of
-### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-### GNU General Public License for more details.
+### TrIPE is distributed in the hope that it will be useful, but WITHOUT
+### ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+### FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+### for more details.
###
### You should have received a copy of the GNU General Public License
-### along with TrIPE; if not, write to the Free Software Foundation,
-### Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+### along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
VERSION = '@VERSION@'
## a mask with N leading ones followed by trailing zeroes.
slash = net.index('/')
addr, = unpack('>L', S.inet_aton(net[:slash]))
- if net.find('.', slash + 1) >= 0:
- mask, = unpack('>L', S.inet_aton(net[:slash]))
- else:
+ if net[slash + 1:].isdigit():
n = int(net[slash + 1:], 10)
mask = (1 << 32) - (1 << 32 - n)
+ else:
+ mask, = unpack('>L', S.inet_aton(net[slash + 1:]))
pats.append((tag, peer, addr & mask, mask))
## Annoyingly, RawConfigParser doesn't preserve the order of options.
### This will be a configuration file.
CF = None
-def straddr(a): return S.inet_ntoa(pack('>L', a))
+def straddr(a): return a is None and '#<none>' or S.inet_ntoa(pack('>L', a))
def strmask(m):
for i in xrange(33):
- if m == 0xffffffff ^ ((1 << (32 - i)) - 1): return i
+ if m == 0xffffffff ^ ((1 << (32 - i)) - 1): return str(i)
return straddr(m)
def cmd_showconfig():
pats = p
break
else:
- raise T.TripeJobError, 'unknown-group', g
+ raise T.TripeJobError('unknown-group', g)
for t, p, a, m in pats:
T.svcinfo('peer', t,
'target', p or '(default)',
sk.close()
_kick = T.Queue()
+_delay = None
+
+def cancel_delay():
+ global _delay
+ if _delay is not None:
+ if T._debug: print '# cancel delayed kick'
+ G.source_remove(_delay)
+ _delay = None
+
+def netupdown(upness, reason):
+ """
+ Add or kill peers according to whether the network is up or down.
+
+ UPNESS is true if the network is up, or false if it's down.
+ """
+
+ _kick.put((upness, reason))
+
+def delay_netupdown(upness, reason):
+ global _delay
+ cancel_delay()
+ def _func():
+ global _delay
+ if T._debug: print '# delayed %s: %s' % (upness, reason)
+ _delay = None
+ netupdown(upness, reason)
+ return False
+ if T._debug: print '# delaying %s: %s' % (upness, reason)
+ _delay = G.timeout_add(2000, _func)
+
def kickpeers():
while True:
upness, reason = _kick.get()
if T._debug: print '# kickpeers %s: %s' % (upness, reason)
select = []
+ cancel_delay()
## Make sure the configuration file is up-to-date. Don't worry if we
## can't do anything useful.
if want is not None and not found:
def _(want = want):
try:
- SM.svcsubmit('connect', 'active', want)
+ list(SM.svcsubmit('connect', 'active', want))
except T.TripeError, exc:
SM.warn('conntrack', 'connect-failed', want, *exc.args)
if T._debug: print '# peer %s: bring up' % want
SM.notify('conntrack', upness and 'up' or 'down', *select + reason)
for c in changes: c()
-def netupdown(upness, reason):
- """
- Add or kill peers according to whether the network is up or down.
-
- UPNESS is true if the network is up, or false if it's down.
- """
-
- _kick.put((upness, reason))
-
###--------------------------------------------------------------------------
### NetworkManager monitor.
+DBPROPS_IFACE = 'org.freedesktop.DBus.Properties'
+
NM_NAME = 'org.freedesktop.NetworkManager'
NM_PATH = '/org/freedesktop/NetworkManager'
NM_IFACE = NM_NAME
NMCA_IFACE = NM_NAME + '.Connection.Active'
-NM_STATE_CONNECTED = 3
+NM_STATE_CONNECTED = 3 #obsolete
+NM_STATE_CONNECTED_LOCAL = 50
+NM_STATE_CONNECTED_SITE = 60
+NM_STATE_CONNECTED_GLOBAL = 70
+NM_CONNSTATES = set([NM_STATE_CONNECTED,
+ NM_STATE_CONNECTED_LOCAL,
+ NM_STATE_CONNECTED_SITE,
+ NM_STATE_CONNECTED_GLOBAL])
class NetworkManagerMonitor (object):
"""
def attach(me, bus):
try:
nm = bus.get_object(NM_NAME, NM_PATH)
- state = nm.Get(NM_IFACE, 'State')
- if state == NM_STATE_CONNECTED:
+ state = nm.Get(NM_IFACE, 'State', dbus_interface = DBPROPS_IFACE)
+ if state in NM_CONNSTATES:
netupdown(True, ['nm', 'initially-connected'])
else:
netupdown(False, ['nm', 'initially-disconnected'])
- except D.DBusException:
- pass
- bus.add_signal_receiver(me._nm_state, 'StateChanged', NM_IFACE,
- NM_NAME, NM_PATH)
- bus.add_signal_receiver(me._nm_connchange,
- 'PropertiesChanged', NMCA_IFACE,
- NM_NAME, None)
+ except D.DBusException, e:
+ if T._debug: print '# exception attaching to network-manager: %s' % e
+ bus.add_signal_receiver(me._nm_state, 'StateChanged',
+ NM_IFACE, NM_NAME, NM_PATH)
+ bus.add_signal_receiver(me._nm_connchange, 'PropertiesChanged',
+ NMCA_IFACE, NM_NAME, None)
def _nm_state(me, state):
- if state == NM_STATE_CONNECTED:
- netupdown(True, ['nm', 'connected'])
+ if state in NM_CONNSTATES:
+ delay_netupdown(True, ['nm', 'connected'])
else:
- netupdown(False, ['nm', 'disconnected'])
+ delay_netupdown(False, ['nm', 'disconnected'])
def _nm_connchange(me, props):
- if props.get('Default', False):
- netupdown(True, ['nm', 'default-connection-change'])
+ if props.get('Default', False) or props.get('Default6', False):
+ delay_netupdown(True, ['nm', 'default-connection-change'])
+
+##--------------------------------------------------------------------------
+### Connman monitor.
+
+CM_NAME = 'net.connman'
+CM_PATH = '/'
+CM_IFACE = 'net.connman.Manager'
+
+class ConnManMonitor (object):
+ """
+ Watch ConnMan signls for changes in network state.
+ """
+
+ ## Strategy. Everything seems to be usefully encoded in the `State'
+ ## property. If it's `offline', `idle' or `ready' then we don't expect a
+ ## network connection. During handover from one network to another, the
+ ## property passes through `ready' to `online'.
+
+ def attach(me, bus):
+ try:
+ cm = bus.get_object(CM_NAME, CM_PATH)
+ props = cm.GetProperties(dbus_interface = CM_IFACE)
+ state = props['State']
+ netupdown(state == 'online', ['connman', 'initially-%s' % state])
+ except D.DBusException, e:
+ if T._debug: print '# exception attaching to connman: %s' % e
+ bus.add_signal_receiver(me._cm_state, 'PropertyChanged',
+ CM_IFACE, CM_NAME, CM_PATH)
+
+ def _cm_state(me, prop, value):
+ if prop != 'State': return
+ delay_netupdown(value == 'online', ['connman', value])
###--------------------------------------------------------------------------
### Maemo monitor.
except D.DBusException:
me._iap = None
netupdown(False, ['icd', 'initially-disconnected'])
- except D.DBusException:
+ except D.DBusException, e:
+ if T._debug: print '# exception attaching to icd: %s' % e
me._iap = None
bus.add_signal_receiver(me._icd_state, 'status_changed', ICD_IFACE,
ICD_NAME, ICD_PATH)
def _icd_state(me, iap, ty, state, hunoz):
if state == 'CONNECTED':
me._iap = iap
- netupdown(True, ['icd', 'connected', iap])
+ delay_netupdown(True, ['icd', 'connected', iap])
elif state == 'IDLE' and iap == me._iap:
me._iap = None
- netupdown(False, ['icd', 'idle'])
+ delay_netupdown(False, ['icd', 'idle'])
###--------------------------------------------------------------------------
### D-Bus connection tracking.
T.Coroutine(kickpeers, name = 'kickpeers').switch()
DBM = DBusMonitor()
DBM.addmon(NetworkManagerMonitor())
+ DBM.addmon(ConnManMonitor())
DBM.addmon(MaemoICdMonitor())
- G.timeout_add_seconds(30, lambda: (netupdown(True, ['interval-timer'])
- or True))
+ G.timeout_add_seconds(30, lambda: (_delay is not None or
+ netupdown(True, ['interval-timer']) or
+ True))
def parse_options():
"""