#!/usr/bin/python import os import sys import pwd import argparse import datetime import time import hashlib import base64 import configobj import daemon import daemon.pidlockfile from i2p import samclasses from i2p import socket def check(): all_hosts = i2phost.objects.all() # determine SAM interface address if 'sam_addr' in config: sam_addr = config['sam_addr'] else: log.warning('SAM address isn\'t specified in config, falling back to localhost') sam_addr = '127.0.0.1:7656' S = samclasses.BaseSession(sam_addr) log.info('starting check') for host in all_hosts: log.debug('testing %s', host.name) # get b32 address from full dest key dest = host.b64hash raw_key = base64.b64decode(dest.encode('utf-8'), '-~') hash = hashlib.sha256(raw_key) b32dest = base64.b32encode(hash.digest()).lower().replace('=', '')+'.b32.i2p' # do name lookup query with b32 address # it success only if host is alive try: a = S._namelookup(b32dest) except socket.NetworkError, e: log.debug('%s: %s', host.name, e.args[0][0]) continue log.info('alive host: %s', host.name) # update lastseen timestamp host.last_seen = datetime.datetime.now() host.save() S.close() log.info('check finished') def main(): while True: check() if args.debug or args.verbose: sys.exit(0) else: time.sleep(float(config['check_interval'])) # parse command line options parser = argparse.ArgumentParser( description='Hosts checker for py-i2phosts.', epilog='Report bugs to http://zzz.i2p/topics/733') parser.add_argument('-d', '--debug', action='store_true', help='set loglevel to debug and write messages to stdout'), parser.add_argument('-v', '--verbose', action='store_true', help='set loglevel to info and write messages to stdout'), parser.add_argument('-c', '--config', default='/etc/py-i2phosts/checker.conf', dest='config_file', help='config file to use') args = parser.parse_args() # read config config = configobj.ConfigObj(args.config_file) if 'include' in config: config_included = configobj.ConfigObj(config['include']) config.merge(config_included) # django setup DJANGO_SETTINGS_MODULE = 'settings' if 'DJANGO_PROJECT_PATH' in config: DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH'] else: DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/web' sys.path.insert(1, DJANGO_PROJECT_PATH) os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE from web.postkey.models import i2phost from web.lib.utils import get_logger # configure logger if args.debug == True: log_level = 'debug' log_file = None elif args.verbose == True: log_level = 'info' log_file = None else: if 'log_level' in config: log_level = config['log_level'] else: sys.stderr.write('"log_level" missing in config\n') sys.exit(1) if 'log_file' in config: log_file = config['log_file'] else: sys.stderr.write('"log_file missing in config\n') sys.exit(1) if not args.debug and not args.verbose: # get pid object for daemon if 'pid_file' in config: pid = daemon.pidlockfile.TimeoutPIDLockFile(config['pid_file'], 10) else: sys.stderr.write('"pid_file" missing in config\n') sys.exit(1) # create daemon context d = daemon.DaemonContext(pidfile=pid, umask=077) # write stderr to logfile # FIXME: and how we will deal with log rotation? logfile = open(config['log_file'], 'a') d.stderr = logfile d.stdout = logfile # drop privileges when started as root if os.getuid() == 0: runas = '_pyi2phosts' pw_entry = pwd.getpwnam(runas) d.uid = pw_entry[2] d.gid = pw_entry[3] d.open() # become daemon log = get_logger(filename=log_file, log_level=log_level) main()