Пример #1
0
def fail_recover(name, addy, active_pings):
    if len(active_pings) == 0:
        logger.info("We have no active pingers for %s", name)
        db.mark_failed(name, addy, timefunc.utcnow())
    else:
        uptime = up_today(active_pings)
        # If a remailers uptime is < 20%, then we mark it as failed and
        # record the time of failure in the genealogy table.  This has to
        # be a low percentage or bunker would be considered dead.
        if uptime < config.deadpoint:
            logger.debug("%s is under %d%%, flagging it failed", name, config.deadpoint * 10)
            db.mark_failed(name, addy, timefunc.utcnow())
        # Stats are greater than 50%, so delete any entries for this
        # remailer from the failed table.
        if uptime > config.livepoint:
            logger.debug("%s is healthy, deleting any failed flags it might have", name)
            db.mark_recovered(name, addy)
Пример #2
0
def uptimes():
    ago = timefunc.hours_ago(config.active_age)
    ahead = timefunc.hours_ahead(config.active_future)
    uptimes = avg_uptime()
    #logger.debug("Writing Uptime HTML file %s", config.uptime_report_name)
    filename = "%s/%s" % (config.reportdir, config.uptime_report_name)
    uptimefile = open(filename, 'w')
    uptimefile.write("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="Content-Style-Type" content="text/css2" />
<meta name="keywords" content="Mixmaster,Remailer,Banana,Bananasplit">
<title>Bananasplit Website - Failing Remailers</title>
<link rel="StyleSheet" href="stats.css" type="text/css">
</head>

<body>
<h1>Remailer Uptimes</h1>
<p>This report provides an overview of the average uptime for each remailer
based on the results from all currently responding pingers.  Consider that this
report doesn't define a scope for acceptable ping results; all are considered
good.  This means a single pinger can skew the average.</p>
<table border="0" bgcolor="#000000">
<tr bgcolor="#F08080">
<th>Remailer Name</th>
<th>Average Uptime</th>
<th>Average Latency</th>
<th>Pingers Reporting</th></tr>\n""")
    rotate_color = 0
    for uptime in uptimes:
        # Rotate background colours for rows
        if rotate_color:
            bgcolor = "#ADD8E6"
        else:
            bgcolor = "#E0FFFF"
        rotate_color = not rotate_color

        name = uptime[0]
        up = uptime[1]
        count = uptime[3]
        lathrs,latmin = timefunc.hours_mins(uptime[2])
        uptimefile.write('<tr bgcolor="%s">' % bgcolor)
        uptimefile.write('<th class="tableleft">%s</th>' % name)
        uptimefile.write('<td>%3.2f</td>' % up)
        uptimefile.write('<td>%d:%02d</td>' % (lathrs, latmin))
        uptimefile.write('<td>%d</td></tr>\n' % (count, ))

    uptimefile.write('</table>\n')
    uptimefile.write('<br>Last update: %s (UTC)<br>\n' % timefunc.utcnow())
    uptimefile.write('<br><a href="index.html">Index</a>\n')
    uptimefile.write('</body></html>')
    uptimefile.close()
Пример #3
0
def write_remailer_stats(name, addy, vitals):
    # Create a filename for the remailer details, open it and write a title and timestamp.
    noat = addy.replace("@", ".")
    filename = "%s/%s.%s.txt" % (config.reportdir, name, noat)
    statfile = open("%s" % (filename,), "w")
    statfile.write("Pinger statistics for the %(rem_name)s remailer (%(rem_addy)s)\n" % vitals)
    statfile.write("Last update: %s (UTC)\n" % timefunc.utcnow())

    statfile.write("\nPingers\n")
    statfile.write(" Known: %d\t" % db.count_total_pingers())
    statfile.write("Alive: %d\t" % vitals["rem_count_all"])
    statfile.write("In-Scope: %d\t" % vitals["rem_active_count"])
    # Out of scope pings are total Alive pings minus In-Scope Pings
    oos = vitals["rem_count_all"] - vitals["rem_active_count"]
    statfile.write("Out-of-Scope: %d\n" % oos)
    statfile.write("\nUptime\n")
    statfile.write(" Lowest: %3.2f%%\t\t" % (vitals["rem_uptime_min"] / 10.00))
    statfile.write("Average: %3.2f%%\n" % (float(vitals["rem_uptime_avg"]) / 10.00))
    statfile.write(" Highest: %3.2f%%\t" % (vitals["rem_uptime_max"] / 10.00))
    statfile.write("StdDev: %3.2f%%\n" % (float(vitals["rem_uptime_stddev"]) / 10.00))
    statfile.write("\nLatency\n")
    statfile.write(" Lowest: %d:%02d\t\t" % timefunc.hours_mins(vitals["rem_latency_min"]))
    statfile.write("Average: %d:%02d\n" % timefunc.hours_mins(vitals["rem_latency_avg"]))
    statfile.write(" Highest: %d:%02d\t\t" % timefunc.hours_mins(vitals["rem_latency_max"]))
    statfile.write("StdDev: %d:%02d\n" % timefunc.hours_mins(vitals["rem_latency_stddev"]))

    statfile.write("\nIn-scope pings\n")
    for row in db.remailer_active_pings(vitals):
        entry = db_process(row)
        statfile.write(entry)

    statfile.write("\n\nOut of scope pings\n")
    for row in db.remailer_ignored_pings(vitals):
        entry = db_process(row)
        statfile.write(entry)

    statfile.write("\n\nDead pings\n")
    for row in db.remailer_inactive_pings(vitals):
        entry = db_process(row)
        statfile.write(entry)

    statfile.close()
Пример #4
0
def writekeystats():
    global now, ago, ahead
    now = timefunc.utcnow()
    ago = timefunc.hours_ago(config.active_age)
    ahead = timefunc.hours_ahead(config.active_future)
    write_stats()
Пример #5
0
def index():
    """Generate an HTML index table referencing remailer name against pinger
    name.  The content of the table is remailer uptimes."""
    # Generate an index filename and open it.
    filename = "%s/index.html" % config.reportdir
    index = open(filename, 'w')
    # Write the standard HTML headers and the initial BODY parts.
    index.write('''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="Content-Style-Type" content="text/css2" />
<meta name="keywords" content="Mixmaster,Echolot,Remailer,Banana,Bananasplit">
<title>Bananasplit Website - Meta Statistics</title>
<link rel="StyleSheet" href="stats.css" type="text/css">
</head>
<body>
<table border="0" bgcolor="#000000">\n''')
    # For a pinger to be considered active, it must appear in tables mlist2
    # and pingers.  This basically means, don't create empty pinger columns
    # in the index file.
    active_pingers = active_pinger_names()
    index.write('<tr bgcolor="#F08080"><th></th><th>Chain From</th><th>Chain To</th>\n')
    # Write the pinger names as a header row.
    for pinger in active_pingers:
        index.write('<th><a href="%s">%s</a></th>\n' % (pinger[1], pinger[0]))
    # Add the final header row titles and close the row.
    index.write('<th>Average</th><th>StdDev</th><th>Count</th></tr>\n')
    # Set a flag for rotating backgroup colours
    color_flag = False
    # Define some time related variables
    now = utcnow()
    # Make a dictionary of how many chain from's for each remailer
    chfr_dict = chain_from_count2()
    chto_dict = chain_to_count2()
    for name, addy in distinct_rem_names():
        # We should have a key for every remailer, this is just a safeguard
        fr_count = keycheck(chfr_dict, name)
        to_count = keycheck(chto_dict, name)

        # First lets establish the bacground color for the row being processed
        color = bg_color(color_flag)
        color_flag = not color_flag
        file, chfr, chto, url = gen_filename(name, addy)
        # Generate the HTML for Table Row headers
        index.write('<tr bgcolor="%s"><th class="tableleft">\n' % (color,))
        # Generate the HTML for the Remailer Name column
        index.write('<a href="%s" title="%s">' % (url, addy))
        index.write('%s</a></th>\n' % (name,))
        # Generate the HTML for the Chain From column
        index.write('<td align="center">')
        index.write('<a href="chfr.%s" title="Broken Chains from %s">' % (url, addy))
        index.write('%s</a></td>\n' % (fr_count,))
        # Generate the HTML for the Chain To column
        index.write('<td align="center">')
        index.write('<a href="chto.%s" title="Broken Chains to %s">' % (url, addy))
        index.write('%s</a></td>\n' % (to_count,))
        uptimes = remailer_index_pings(name, addy)
        # Now we need a loop to parse each pinger column within the remailer
        # row
        for pinger in active_pingers:
            ping_name = pinger[0]
            title = "Remailer: %s Pinger: %s" % (name, ping_name)
            index.write('<td align="center" title="%s">' % title)
            if ping_name in uptimes:
                index.write('%3.1f</td>\n' % (uptimes[ping_name],))
            else:
                index.write('</td>\n')
        avg,stddev,count = remailer_index_stats(name, addy)
        # Average and StdDev can return 'None' if remailers have no current
        # data.  We have to catch this in order to present floats to the string
        # formatting line.
        if avg == None: avg = 0
        if stddev == None: stddev = 0
        # Write the average, stddev and count to the end of each index row.
        index.write('<td>%3.2f</td><td>%3.2f</td><td>%d</td>' % (avg, stddev, count))
    index.write('</tr>\n')

    # Add a row to the bottom of the table showing the count of remailer known
    # to each pinger.  We have to write a few empty cells to make things line
    # up because of the chain counts and totals columns.
    pinger_totals = remailer_index_count()
    index.write('<tr bgcolor="#F08080"><th class="tableleft">Count</th><td></td><td></td>\n')
    for pinger in active_pingers:
        ping_name = pinger[0]
        if pinger_totals.has_key(ping_name):
            index.write('<td title="%s">%s</td>\n' % (ping_name, pinger_totals[ping_name]))
        else:
            index.write('<td title="%s">0</td>\n' % (ping_name,))
    index.write('<td></td><td></td><td></td></tr>\n</table>\n')

    index.write('<br>Last update: %s (UTC)<br>\n' % utcnow())
    index.write('<br><a href="%s">Remailer Genealogy</a>' % config.gene_report_name)
    index.write('<br><a href="%s">Failing Remailers</a>' % config.failed_report_name)
    index.write('<br><a href="%s">Uptime Averages</a>' % config.uptime_report_name)
    index.write('<br><a href="%s">Keyring Stats</a>' % config.keyindex)
    # Write closing tags and close file
    index.write('</body></html>')
    index.close()
Пример #6
0
def genealogy():
    #logger.debug("Writing Geneology HTML file %s", config.gene_report_name)
    filename = "%s/%s" % (config.reportdir, config.gene_report_name)
    genefile = open(filename, 'w')
    # Write standard html header section
    genefile.write('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n')
    genefile.write('<html>\n<head>\n')
    genefile.write('<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">\n')
    genefile.write('<meta http-equiv="Content-Style-Type" content="text/css2" />\n')
    genefile.write('<meta name="keywords" content="Mixmaster,Echolot,Remailer,Banana,Bananasplit">\n')
    genefile.write('<title>Bananasplit Website - Remailer Genealogy</title>\n')
    genefile.write('<link rel="StyleSheet" href="stats.css" type="text/css">\n')
    genefile.write('</head>\n\n<body>\n')
    genefile.write('<h1>Remailer Genealogy</h1>\n')
    genefile.write('When pingers report a remailer as below %s0%%, ' % config.deadpoint)
    genefile.write('it is timestamped with a failed date.  ')
    genefile.write('If it recovers to above ')
    genefile.write('%s0%%, the timestamp is removed. ' % config.livepoint)
    down_days = config.dead_after_hours / 24
    genefile.write('Should the remailer fail to recover after %s days, ' % down_days)
    genefile.write('it is considered dead.  If it returns after this ')
    genefile.write('it will be considered a new remailer.<br><br>\n')
    genefile.write('<table border="0" bgcolor="#000000">\n')
    genefile.write('<tr bgcolor="#F08080">\n')
    genefile.write('<th>Remailer Name</th><th>Remailer Address</th>')
    genefile.write('<th>First Seen Date</th><th>Died On Date</th>')
    genefile.write('<th>Failed Date</th><th>Comments</th>\n</tr>\n')

    genealogies = gene_get_stats()

    rotate_color = 0
    for genealogy in genealogies:
        #Set up some friendly names for fields
        if genealogy[0]: rem_name = genealogy[0]
        #else: logger.error("Genealogy entry with no remailer name")
        if genealogy[1]:
            rem_addy = genealogy[1]
            rem_addy_noat = genealogy[1].replace('@','.')
        #else: logger.error("Genealogy entry with no remailer address")
        if genealogy[2]: first_seen = genealogy[2].strftime("%Y-%m-%d")
        else: first_seen = False
        if genealogy[3]: last_seen = genealogy[3].strftime("%Y-%m-%d")
        else: last_seen = False
        if genealogy[4]: last_fail = genealogy[4].strftime("%Y-%m-%d")
        else: last_fail = False
        if genealogy[5]: comments = genealogy[5]
        else: comments = ""
        
        # Rotate background colours for rows
        if rotate_color:
            bgcolor = "#ADD8E6"
        else:
            bgcolor = "#E0FFFF"
        rotate_color = not rotate_color

        if last_seen:
            genefile.write('<tr bgcolor="%s">' % bgcolor)
            genefile.write('<th class="tableleft">%s</th>\n' % rem_name)
        else:
            geneurl = '%s.%s.txt' % (rem_name, rem_addy_noat)
            genefile.write('<tr bgcolor="%s"><th class="tableleft">' % bgcolor)
            genefile.write('<a href="%s" title="%s">' % (geneurl, rem_addy))
            genefile.write('%s</a></th>\n' % rem_name)

        # If the remailer address exists, write a table cell for it
        if rem_addy:
            genefile.write('<td>%s</td>' % rem_addy)
        else:
            genefile.write('<td></td>')

        # If the remailer has a first_seen entry, write a table cell for it
        if first_seen:
            genefile.write('<td>%s</td>' % first_seen)
        else:
            genefile.write('<td></td>')

        # If thre remailer has a lest_seen entry, write a table cell for it
        if last_seen:
            genefile.write('<td>%s</td>' % last_seen)
        else:
            genefile.write('<td></td>')

        # If the remailer has a lest_fail entry, write a table cell for it
        if last_fail:
            genefile.write('<td>%s</td>' % last_fail)
        else:
            genefile.write('<td></td>')

        # If the remailer has a comment, write a table cell for it
        if comments:
            genefile.write('<td>%s</td>' % comments)
        else:
            genefile.write('<td></td>')
        genefile.write('<tr>\n')
    genefile.write('</table>\n')
    genefile.write('<br>Last update: %s (UTC)<br>\n' % utcnow())
    genefile.write('<br><a href="index.html">Index</a>\n')
    genefile.write('<br><a href="%s">Failing Remailers</a>\n' % config.failed_report_name)
    genefile.write('</body></html>')
    genefile.close()
Пример #7
0
def main():
    init_logging()  # Before anything else, initialise logging.
    logger.info("Beginning process cycle at %s (UTC)", timefunc.utcnow())
    socket.setdefaulttimeout(config.timeout)
    global stat_re, addy_re, chain_re
    stat_re = re.compile("(\w{1,12})\s+([0-9A-H?]{12}\s.*)")
    addy_re = re.compile('\$remailer\{"([0-9a-z]{1,12})"\}\s\=\s"\<(.*)\>\s')
    chain_re = re.compile("\((\S{1,12})\s(\S{1,12})\)")

    # Are we running in testmode?  Testmode implies the script was executed
    # without a --live argument.
    testmode = live_or_test(sys.argv)

    # If not in testmode, fetch url's and process them
    if not testmode:
        pingers = db.pinger_names()
        for row in pingers:
            url = url_fetch(row[1])
            if url:
                url_process(row[0], url)
        # Fetch pubring.mix files and write them to the DB
        getkeystats()
    else:
        logger.debug("Running in testmode, url's will not be retreived")

    # We need to do some periodic housekeeping.  It's not very process
    # intensive so might as well do it every time we run.
    db.housekeeping(timefunc.hours_ago(config.dead_after_hours))

    # For a pinger to be considered active, it must appear in tables mlist2
    # and pingers.  This basically means, don't create empty pinger columns
    # in the index file.
    active_pingers = db.active_pinger_names()

    # A boolean value to rotate row colours within the index
    rotate_color = 0

    # The main loop.  This creates individual remailer text files and
    # indexing data based on database values.
    for name, addy in db.distinct_rem_names():
        logger.debug("Generating statsistics for remailer %s", name)

        # remailer_vitals is a dictionary of standard deviation and average
        # values for a specific remailer.
        remailer_vitals = gen_remailer_vitals(name, addy)

        # remailer_active_pings: Based on the vitals generated above, we now
        # extract stats lines for pingers considered active.  The up_hist
        # part is used by the fail_recover routine.
        remailer_active_pings = db.remailer_active_pings(remailer_vitals)
        # If a remailers is perceived to be dead, timestamp it in the
        # genealogy table.  Likewise, if it's not dead, unstamp it.
        fail_recover(name, addy, remailer_active_pings)

        # Write the remailer text file that contains pinger stats and averages
        logger.debug("Writing stats file for %s %s", name, addy)
        write_remailer_stats(name, addy, remailer_vitals)

        # Rotate the colour used in index generation.
        rotate_color = not rotate_color

    db.gene_find_new()
    index()
    genealogy()
    uptimes()
    chainstats()
    writekeystats()
    logger.info("Processing cycle completed at %s (UTC)", timefunc.utcnow())
Пример #8
0
        # remailer_active_pings: Based on the vitals generated above, we now
        # extract stats lines for pingers considered active.  The up_hist
        # part is used by the fail_recover routine.
        remailer_active_pings = db.remailer_active_pings(remailer_vitals)
        # If a remailers is perceived to be dead, timestamp it in the
        # genealogy table.  Likewise, if it's not dead, unstamp it.
        fail_recover(name, addy, remailer_active_pings)

        # Write the remailer text file that contains pinger stats and averages
        logger.debug("Writing stats file for %s %s", name, addy)
        write_remailer_stats(name, addy, remailer_vitals)

        # Rotate the colour used in index generation.
        rotate_color = not rotate_color

    db.gene_find_new()
    index()
    genealogy()
    uptimes()
    chainstats()
    writekeystats()
    logger.info("Processing cycle completed at %s (UTC)", timefunc.utcnow())


# Call main function.
now = timefunc.utcnow()
ago = timefunc.hours_ago(config.active_age)
ahead = timefunc.hours_ahead(config.active_future)
if __name__ == "__main__":
    main()
Пример #9
0
def failed(report_name):
    filename = "%s/%s" % (config.reportdir, config.failed_report_name)
    htmlfile = open(filename, 'w')

# Write standard html header section
    htmlfile.write("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="Content-Style-Type" content="text/css2" />
<meta name="keywords" content="Mixmaster,Remailer,Banana,Bananasplit">
<title>Bananasplit Website - Failing Remailers</title>
<link rel="StyleSheet" href="stats.css" type="text/css">
</head>

<body>
<h1>Failing Remailers</h1>
Remailer stats are normally biased away from the current day.  This is because
different latencies would skew results due to outstanding pings.  However the
current day does provide a rapid insight into remailers that are currently
experiencing problems.<br>
<p>The following table lists remailers that are <u>currently</u> averaging less
than %d%% return on pings. Please consider that this could be due to very high
latency rather than actual remailer failure.</p>
<p><i>Note: Bunker is not actually failing.  It's a Middleman remailer with no
current stats which means it cannot random hop pings back to the pinger.</i></P>
<table border="0" bgcolor="#000000">
<tr bgcolor="#F08080">
<th>Remailer Name</th><th>Ping Responses</th>
</tr>""" % (config.failpoint * 10))

    rotate_color = 0

    for name, addy in db.distinct_rem_names():
        remailer_vitals = gen_remailer_vitals(name, addy)
        logger.debug("Checking remailer %s %s", name, addy)
        addy_noat = addy.replace('@',".")
        full_name = "%s.%s" % (name, addy_noat)

        active_pings = db.remailer_active_pings(remailer_vitals)
        if len(active_pings) == 0:
            logger.info("We have no active pings for %s %s", name, addy)
            continue

        remailer_vitals['uptime'] = up_today(active_pings)

        if remailer_vitals['uptime'] < config.failpoint:
            logger.info("Remailer %s %s is failed.", name, addy)
            # Rotate background colours for rows
            if rotate_color:
                bgcolor = "#ADD8E6"
            else:
                bgcolor = "#E0FFFF"
            rotate_color = not rotate_color
            
            htmlfile.write('<tr bgcolor="%s"><th class="tableleft"><a href="%s.txt" title="%s">%s</a></th>' % (bgcolor, full_name, addy, name))
            htmlfile.write('<td>%d%%</td></tr>\n' % (remailer_vitals['uptime'] * 10))

#        if remailer_vitals('uptime'] > config.goodpoint:
#            # Stats are greater than 50%, so delete any entries for this
#            # remailer from the failed table.
#            logger.debug("%s is healthy, deleting any DB entries it might have", name)

    htmlfile.write('</table>\n')

    htmlfile.write('<br>Last update: %s (UTC)<br>\n' % utcnow())
    htmlfile.write('<br><a href="index.html">Return to Index</a>')

    htmlfile.write('</body></html>')
Пример #10
0
        elif uptime_now == '?':
            score = 0
        else:
            score = int(uptime_now)
        total += score
    return int(total / len(entries))

def init_logging():
    """Initialise logging.  This should be the first thing done so that all
    further operations are logged."""
    loglevels = {'debug': logging.DEBUG, 'info': logging.INFO,
                'warn': logging.WARN, 'error': logging.ERROR}
    level = loglevels['info']
    global logger
    logger = logging.getLogger('failed')
    hdlr = logging.FileHandler("/home/crooks/failed.log")
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
    hdlr.setFormatter(formatter)
    logger.addHandler(hdlr)
    logger.setLevel(level)

# ----- Main Routine -----

init_logging()
logger.info("Processing started at %s", utcnow())
# Look for remailers in mlist2 that aren't in contacts. If there are any,
# insert them into contacts.
failed('failed')
logger.info("Processing finished at %s", utcnow())