#!/usr/bin/python2
# vim: tabstop=4 softtabstop=4 shiftwidth=4 textwidth=80 smarttab expandtab
"""
* Copyright (C) 2014  Sangoma Technologies Corp.
* All Rights Reserved.
*
* Author(s):
* Leonardo Lang <lang@sangoma.com>
*
* This code is Sangoma Technologies Confidential Property.
* Use of and access to this code is covered by a previously executed
* non-disclosure agreement between Sangoma Technologies and the Recipient.
* This code is being supplied for evaluation purposes only and is not to be
* used for any other purpose.
"""

import os
import re
import sys
import logging
import logging.handlers
import subprocess
import syslog
import time

class DirectSyslogHandler(logging.Handler):
    def __init__(self, name):
        self.levelmap = { 'DEBUG': syslog.LOG_DEBUG, 'INFO': syslog.LOG_INFO, 'NOTICE': syslog.LOG_NOTICE,
                          'WARNING': syslog.LOG_WARNING, 'ERROR': syslog.LOG_ERR, 'CRITICAL': syslog.LOG_CRIT }
        logging.Handler.__init__(self)
        syslog.openlog(name, syslog.LOG_PID)

    def emit(self, record):
        try:
            msg = self.format(record)
            level = self.levelmap.get(record.levelname, syslog.LOG_INFO)
            syslog.syslog(level, msg)
        except Exception, e:
            pass

def setup_logger(progname):
    logger = logging.getLogger(progname)
    logger.setLevel(logging.INFO)

    handler = DirectSyslogHandler(progname)
    handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
    logger.addHandler(handler)

    return logger

def get_runlevel():
    out, _ = subprocess.Popen(['/sbin/runlevel'], stdout=subprocess.PIPE).communicate()
    data = out.strip().split(' ')
    if len(data) == 0:
        return 'unknown'
    else:
        return data[-1]

def snort_service_restart(logger):
    # double fork so we can wait a bit for restarting
    pid1 = os.fork()
    if pid1 == 0:
        pid2 = os.fork()
        if pid2 == 0:
            # wait a bit and then restart snort
            time.sleep(5)
            fdnull = open('/dev/null', 'w')
            retsrv = subprocess.Popen(['service', 'snort', 'restart'], stdout=fdnull, stderr=fdnull)
            if retsrv.wait() <> 0:
                logger.info('service restart returned code ' + str(retsrv.returncode))

progname = os.path.basename(os.path.abspath(sys.argv[0]))

logger = setup_logger(progname)

if not sys.argv[2].startswith('eth'):
    sys.exit(0)

regname = re.compile('^[0-9]+: ([^:]+): ')
regaddr = re.compile('^[ ]+inet[ ]([0-9.]+)/')

try:
    ifaddr = subprocess.Popen([ 'ip', 'addr', 'show' ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    stout, sterr = ifaddr.communicate()

    addrs = []
    iface = None

    for ln in stout.splitlines():
        m1 = regname.match(ln)
        if m1:
            tmpstr = m1.group(1)
            if tmpstr.startswith('eth') or tmpstr == 'lo':
                iface = tmpstr
            continue

        if iface is None:
            continue

        m2 = regaddr.match(ln)
        if m2:
            addrs.append(m2.group(1) + '/32')

except Exception, e:
    logger.error('failure processing interfaces: %s' % str(e))
    sys.exit(1)

netstr = '127.0.0.1/32'

if len(addrs) <> 0:
    netstr = ','.join(addrs)

args = ['/usr/local/nsc/bin/snort-update-config', '--no-reload', '--home-network', netstr]
rc = subprocess.call(args)

if rc == 0:
    if sys.argv[1] == 'down' and get_runlevel() in [ '0', '6' ]:
        logger.info('system shutting down, skipping snort reload or restart...')
        sys.exit(0)

    args = ['/usr/local/nsc/bin/snort-update-config', '--running']
    rc = subprocess.call(args)

    if rc == 0:
        args = ['/usr/local/nsc/bin/snort-update-config', '--on-interface', sys.argv[2]]
        rc = subprocess.call(args)

        if rc == 0:
            logger.info('snort running on ' + sys.argv[2] + ', reloading...')

            args = ['/usr/local/nsc/bin/snort-update-config', '--reload']
            rc = subprocess.call(args)

            if rc <> 0:
                logger.warning('command ' + str(args) + ' returned ' + str(rc))

        elif rc == 123:
            logger.info('snort running but not on ' + sys.argv[2] + ', restarting...')
            snort_service_restart(logger)

        else:
            logger.warning('command ' + str(args) + ' returned ' + str(rc))

    elif rc == 123:
        logger.info('snort not running, skipping reload or restart...')

    else:
        logger.warning('command ' + str(args) + ' returned ' + str(rc))

elif rc == 123:
    logger.info('config file already modified, skipping reload or restart...')

else:
    logger.warning('command ' + str(args) + ' returned ' + str(rc))

sys.exit(0)
