def _update_graphs(quick=False): """Update RRD data and web UI graphs.""" if os.path.exists(constants.LOWMEM_MARKER_FILE): _log.debug('lowmem marker exists, not updating graphs') return # measure and update rrd data g = graphs.Graphs() try: if helpers.check_marker_file(constants.TIMESYNC_TIMESTAMP_FILE) or \ helpers.check_marker_file(constants.WEBUI_LAST_TIMESYNC_FILE): _log.debug('timesync ok, updating rrd') update_rrd = True else: # If rrdtool is updated with a future timestamp (say Jan 1, 2010) it will # refuse to update values in the 'past' (say Jan 1, 2007); so we only want # to run rrd updates if we do have a server-based timesync. _log.info('no timesync, not updating rrd information to avoid confusing rrdtool') update_rrd = False g.measure_and_update(update_rrd=update_rrd, update_rdf=True, quick=quick) except: _log.exception('measure_and_update() failed') # draw graphs required by web UI here, but only if it "makes a difference" try: if _check_draw_graph(constants.RRDGRAPH_USER_COUNT): g.draw_user_graph() else: _log.info('not drawing user graph on this cron run') except: _log.exception('draw_user_graph() failed') try: if _check_draw_graph(constants.RRDGRAPH_SITETOSITE_COUNT): g.draw_sitetosite_graph() else: _log.info('not drawing user graph on this cron run') except: _log.exception('draw_sitetosite_graph() failed')
def _check_draw_graph(graph_file): """Check whether the specified graph file should be redrawn. Currently we use the following heuristic: (1) if graph is older than N minutes, redraw it; (2) if admin has active session(s), redraw on every cron run (we detect this by ajax active timestamp). We could also redraw if an interesting parameter has changed (user or s2s count, license limits, timezones, etc). But because these entail RRD accesses, we just use the simpler heuristic above. """ now = datetime.datetime.utcnow() # consider ajax "off-line" if timestamp older than this (or negative) ajax_limit = datetime.timedelta(0, 5*60, 0) # XXX: constants? # redraw graphs if graph age below zero or over limit below graph_zero = datetime.timedelta(0, 0, 0) graph_maxage = datetime.timedelta(0, 15*60, 0) # XXX: constants? if helpers.check_marker_file(constants.WEBUI_ADMIN_ACTIVE_TIMESTAMP): dt = helpers.read_datetime_marker_file(constants.WEBUI_ADMIN_ACTIVE_TIMESTAMP) diff = now - dt if diff < ajax_limit: # ajax active, draw _log.info('ajax active, redraw graph %s' % graph_file) return True else: # fall through, check graph file pass if os.path.exists(graph_file): mtime = datetime.datetime.utcfromtimestamp(os.stat(graph_file).st_mtime) diff = now - mtime if (diff < graph_zero) or (diff > graph_maxage): # bogus or too old, redraw _log.info('graph too old, redraw graph %s' % graph_file) return True else: _log.info('graph not too old, skipping redraw for %s' % graph_file) return False # no graph file, redraw always _log.info('graph does not exist, redraw graph %s' % graph_file) return True
def renderHTTP(self, ctx): # XXX: refactor this to a helper?? def _xml_escape(x): return helpers.xml_escape(x) # XXX: simple base64 encoding does not seem to be enough def _base64_encode(x): # base64 produces a newline, strip it away; still not correct tho return x.encode('base64').strip() request = inevow.IRequest(ctx) # figure parameters server_address = '' try: server_address = str(request.getRequestHostname()) except: _log.exception('cannot figure out server_address') preshared_key = '' try: psk_seq = helpers.get_ui_config().getS( ns_ui.preSharedKeys, rdf.Seq(rdf.Type(ns_ui.PreSharedKey))) preshared_key = str(psk_seq[0].getS(ns_ui.preSharedKey, rdf.String)) except: _log.exception('cannot figure out preshared_key') username = '' try: tmp = self.get_logged_in_username() if tmp is not None: username = str(tmp) except: _log.exception('cannot figure out username') # Profile name profile_prefix = 'VPNease' try: if os.path.exists(constants.AUTOCONFIG_PROFILE_PREFIX_FILE): profile_prefix = helpers.read_and_strip_file( constants.AUTOCONFIG_PROFILE_PREFIX_FILE) except: _log.exception('failed when checking for alternative profile name') profile_name = '%s (%s)' % (profile_prefix, server_address) # Server behind port forward server_portfw = False try: global_st = helpers.get_global_status() if global_st.hasS(ns.behindNat): if global_st.getS(ns.behindNat, rdf.Boolean): server_portfw = True else: server_portfw = False else: # assume worst - reboot *MAY* be required server_portfw = True # markerfile for debugging if helpers.check_marker_file( constants.FORCE_NATTREBOOT_MARKERFILE): _log.warning( 'force nat-t reboot marker file exists, pretending server is behind port forward' ) server_portfw = True except: _log.exception( 'cannot determine whether server is behind port forward, may be OK' ) # # Notes about OSX plist for networkConnect # # * There are settings for PPP redial counts etc. We don't use them # because we want to minimize risks. # # * DisconnectOnXXX settings only seem to work when inside SystemConfig, # not inside UserConfigs. # # * SystemConfig -> IPv4 -> OverridePrimary=1 should, based on PPP code, # set 'default route' setting but doesn't seem to work. # # * UserConfigs -> IPsec -> ExportedSharedSecret contains the pre-shared # key for IKE in some sort of encrypted format. The value is base64 # encoded but the pre-shared key is processed (encrypted or masked) # prior to base64. Note that whatever the unknown (and seemingly # undocumented transform is, it has to be reversible because IKE needs # the PSK. # # * CCP / MPPC / MPPE are disabled now. They don't actually work in # Leopard at least. # # create xml plist textdata = textwrap.dedent("""\ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>L2TP</key> <dict> <key>SystemConfig</key> <dict> <key>PPP</key> <dict> <key>DisconnectOnSleep</key> <integer>1</integer> <key>DisconnectOnFastUserSwitch</key> <integer>1</integer> <key>DisconnectOnLogout</key> <integer>1</integer> </dict> </dict> <key>UserConfigs</key> <array> <dict> <key>EAP</key> <dict/> <key>IPSec</key> <dict> <key>AuthenticationMethod</key> <string>SharedSecret</string> <key>LocalIdentifier</key> <string></string> <key>LocalIdentifierType</key> <string>KeyID</string> </dict> <key>PPP</key> <dict> <key>AuthName</key> <string>%(username)s</string> <key>CommRemoteAddress</key> <string>%(server_address)s</string> <key>UserDefinedName</key> <string>%(profile_name)s</string> <key>CCPEnabled</key> <integer>%(ccp_enabled)d</integer> <key>CCPMPPE128Enabled</key> <integer>%(ccp_mppe40_enabled)d</integer> <key>CCPMPPE40Enabled</key> <integer>%(ccp_mppe128_enabled)d</integer> </dict> </dict> </array> </dict> </dict> </plist> """) % { 'preshared_key_base64': _xml_escape(_base64_encode(preshared_key)), 'username': _xml_escape(username), 'server_address': _xml_escape(server_address), 'profile_name': _xml_escape(profile_name), 'override_primary': 1, # XXX: force default route 'ccp_enabled': 0, 'ccp_mppe40_enabled': 0, 'ccp_mppe128_enabled': 0, } # # Content-Type is interesting. If this is served as 'text/xml', Safari # will display the file without offering a save option. Even if it is # saved, Safari will *refuse* saving the file with '.networkConnect' # extension. # # 'application/octet-stream' causes Safari to save the file, and use can # double click to run it. # return uihelpers.UncachedData(textdata, 'application/octet-stream')
def renderHTTP(self, ctx): # XXX: refactor this to a helper?? def _xml_escape(x): return helpers.xml_escape(x) # XXX: simple base64 encoding does not seem to be enough def _base64_encode(x): # base64 produces a newline, strip it away; still not correct tho return x.encode('base64').strip() request = inevow.IRequest(ctx) # figure parameters server_address = '' try: server_address = str(request.getRequestHostname()) except: _log.exception('cannot figure out server_address') preshared_key = '' try: psk_seq = helpers.get_ui_config().getS(ns_ui.preSharedKeys, rdf.Seq(rdf.Type(ns_ui.PreSharedKey))) preshared_key = str(psk_seq[0].getS(ns_ui.preSharedKey, rdf.String)) except: _log.exception('cannot figure out preshared_key') username = '' try: tmp = self.get_logged_in_username() if tmp is not None: username = str(tmp) except: _log.exception('cannot figure out username') # Profile name profile_prefix = 'VPNease' try: if os.path.exists(constants.AUTOCONFIG_PROFILE_PREFIX_FILE): profile_prefix = helpers.read_and_strip_file(constants.AUTOCONFIG_PROFILE_PREFIX_FILE) except: _log.exception('failed when checking for alternative profile name') profile_name = '%s (%s)' % (profile_prefix, server_address) # Server behind port forward server_portfw = False try: global_st = helpers.get_global_status() if global_st.hasS(ns.behindNat): if global_st.getS(ns.behindNat, rdf.Boolean): server_portfw = True else: server_portfw = False else: # assume worst - reboot *MAY* be required server_portfw = True # markerfile for debugging if helpers.check_marker_file(constants.FORCE_NATTREBOOT_MARKERFILE): _log.warning('force nat-t reboot marker file exists, pretending server is behind port forward') server_portfw = True except: _log.exception('cannot determine whether server is behind port forward, may be OK') # # Notes about OSX plist for networkConnect # # * There are settings for PPP redial counts etc. We don't use them # because we want to minimize risks. # # * DisconnectOnXXX settings only seem to work when inside SystemConfig, # not inside UserConfigs. # # * SystemConfig -> IPv4 -> OverridePrimary=1 should, based on PPP code, # set 'default route' setting but doesn't seem to work. # # * UserConfigs -> IPsec -> ExportedSharedSecret contains the pre-shared # key for IKE in some sort of encrypted format. The value is base64 # encoded but the pre-shared key is processed (encrypted or masked) # prior to base64. Note that whatever the unknown (and seemingly # undocumented transform is, it has to be reversible because IKE needs # the PSK. # # * CCP / MPPC / MPPE are disabled now. They don't actually work in # Leopard at least. # # create xml plist textdata = textwrap.dedent("""\ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>L2TP</key> <dict> <key>SystemConfig</key> <dict> <key>PPP</key> <dict> <key>DisconnectOnSleep</key> <integer>1</integer> <key>DisconnectOnFastUserSwitch</key> <integer>1</integer> <key>DisconnectOnLogout</key> <integer>1</integer> </dict> </dict> <key>UserConfigs</key> <array> <dict> <key>EAP</key> <dict/> <key>IPSec</key> <dict> <key>AuthenticationMethod</key> <string>SharedSecret</string> <key>LocalIdentifier</key> <string></string> <key>LocalIdentifierType</key> <string>KeyID</string> </dict> <key>PPP</key> <dict> <key>AuthName</key> <string>%(username)s</string> <key>CommRemoteAddress</key> <string>%(server_address)s</string> <key>UserDefinedName</key> <string>%(profile_name)s</string> <key>CCPEnabled</key> <integer>%(ccp_enabled)d</integer> <key>CCPMPPE128Enabled</key> <integer>%(ccp_mppe40_enabled)d</integer> <key>CCPMPPE40Enabled</key> <integer>%(ccp_mppe128_enabled)d</integer> </dict> </dict> </array> </dict> </dict> </plist> """) % { 'preshared_key_base64': _xml_escape(_base64_encode(preshared_key)), 'username': _xml_escape(username), 'server_address': _xml_escape(server_address), 'profile_name': _xml_escape(profile_name), 'override_primary': 1, # XXX: force default route 'ccp_enabled': 0, 'ccp_mppe40_enabled': 0, 'ccp_mppe128_enabled': 0, } # # Content-Type is interesting. If this is served as 'text/xml', Safari # will display the file without offering a save option. Even if it is # saved, Safari will *refuse* saving the file with '.networkConnect' # extension. # # 'application/octet-stream' causes Safari to save the file, and use can # double click to run it. # return uihelpers.UncachedData(textdata, 'application/octet-stream')
def renderHTTP(self, ctx): request = inevow.IRequest(ctx) # read unpatched exe f = None exedata = '' try: f = open(self.autoconfig_exe_filename, 'rb') exedata = f.read() finally: if f is not None: f.close() f = None # figure parameters server_address_in_uri = None try: server_address_in_uri = str(request.getRequestHostname()) except: _log.exception('cannot figure out server_address_in_uri') server_ip = None try: server_ip = self._get_server_ip_for_win2k(ctx) except: _log.exception('cannot figure out server_ip') server_address = None if self.force_server_address_to_ip: server_address = server_ip else: server_address = server_address_in_uri if (server_address_in_uri is None) or (server_address_in_uri == ''): raise Exception('server_address_in_uri missing, failing') if (server_address is None) or (server_address == ''): raise Exception('server_address missing, failing') if self.include_win2k_regdata and ((server_ip is None) or (server_ip == '')): raise Exception('server_ip is needed and missing, failing') preshared_key = '' try: psk_seq = helpers.get_ui_config().getS(ns_ui.preSharedKeys, rdf.Seq(rdf.Type(ns_ui.PreSharedKey))) preshared_key = str(psk_seq[0].getS(ns_ui.preSharedKey, rdf.String)) except: _log.exception('cannot figure out preshared_key') username = '' try: tmp = self.get_logged_in_username() if tmp is not None: username = str(tmp) except: _log.exception('cannot figure out username') # Profile name, always uses address in URI, even if server address itself forced to IP profile_prefix = 'VPNease' try: if os.path.exists(constants.AUTOCONFIG_PROFILE_PREFIX_FILE): profile_prefix = helpers.read_and_strip_file(constants.AUTOCONFIG_PROFILE_PREFIX_FILE) except: _log.exception('failed when checking for alternative profile name') profile_name = '%s (%s)' % (profile_prefix, server_address_in_uri) # Server behind port forward server_portfw = False try: global_st = helpers.get_global_status() if global_st.hasS(ns.behindNat): if global_st.getS(ns.behindNat, rdf.Boolean): server_portfw = True else: server_portfw = False else: # assume worst - reboot *MAY* be required server_portfw = True # markerfile for debugging if helpers.check_marker_file(constants.FORCE_NATTREBOOT_MARKERFILE): _log.warning('force nat-t reboot marker file exists, pretending server is behind port forward') server_portfw = True except: _log.exception('cannot determine whether server is behind port forward, may be OK') # Windows 2000 registry-based IPsec policy + prohibitIpsec win2k_ipsec_policy_registry_file = '' try: if self.include_win2k_regdata: # Registry data is HEX encoded UTF-16; HEX encoding is used to avoid problems # with the parameters.cpp mechanism (null termination). The resulting data is # large, around 50 kilobytes (!). # Always uses server IP for IPsec policy, because that's what Windows 2000 IPsec wants t = self._get_win2k_reg_file(server_ip, preshared_key) t = self._encode_windows_reg_file(t) # UTF-16 win2k_ipsec_policy_registry_file = t.encode('hex') # hex-encoded UTF-16 except: _log.exception('cannot create win2k registry file') # Fill paramdict and return paramdict = {} paramdict['operation'] = 'configure_profile' paramdict['profile_name'] = profile_name paramdict['desktop_shortcut_name'] = '%s.LNK' % profile_name # xxx: for now the same paramdict['server_address'] = server_address paramdict['preshared_key'] = preshared_key paramdict['username'] = username paramdict['ppp_compression_enabled'] = '1' paramdict['default_route_enabled'] = '1' paramdict['create_desktop_shortcut'] = '1' paramdict['open_profile_after_creation'] = '1' if server_portfw: paramdict['server_behind_port_forward'] = '1' else: paramdict['server_behind_port_forward'] = '0' if self.include_win2k_regdata: paramdict['win2k_registry_file'] = win2k_ipsec_policy_registry_file return uihelpers.RewritingBinaryResource(exedata, paramdict)