#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Copyright(C) 2006 INL
Written by Damien Boucard <damien.boucard AT inl.fr>

This program 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, version 2 of the License.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
---
pyctd.py is daemon which serves netfilter connection tracking via XML-RPC
"""

import logging
from optparse import OptionGroup
from auto_daemon import AutoDaemon
import thread
import pyctd
from pyctd import DataCollector, PyctServer, version
__revision__= version.VERSION
__status__=  version.STATUS

class PyctDaemon(AutoDaemon):
    DEFAULT_PORT = 1910

    def __init__(self):
        AutoDaemon.__init__(self, "pyctd")
        AutoDaemon.APP_NAME = "pyctd"
        self.parseOptions()
        self.start()

    def additionalOptions(self, parser):
        parser.add_option("", "--version",
            help="Program version number",
            action="store_true", default=False)
        parser.add_option("", "--uid-mask",
            help="Bitmask where UID is coded in netfilter mark to retrieve username",
            action="store", type="string", metavar="BITMASK", default=None)
        parser.add_option("", "--filter",
            help="Ignore given IPs (comma separated list of networks)",
            action="store", type="string", default=None)
        group = OptionGroup(parser, "XML-RPC server")

        group.add_option("", "--host",
            help="Hostname to be listened by server (all by default)",
            action="store", type="string", metavar="HOSTNAME", default="")
        group.add_option("", "--port",
            help="TCP Port to be listened by server (%s by default)" %(self.DEFAULT_PORT),
            action="store", type="int", metavar="NUMBER", default=self.DEFAULT_PORT)
        group.add_option("", "--auth",
            help="Python script for authentication (none by default)",
            action="store", type="string", metavar="LOCATION", default=None)
        parser.add_option_group(group)

    def additionalOptionCheck(self, options, arguments):
        if options.version:
            import sys
            print "%(program_name)s version %(revision)s%(status)s" \
                                        %{'program_name': self.APP_NAME,\
                                          'revision': __revision__,\
                                          'status': __status__}
            sys.exit(0)
        if options.uid_mask is not None:
            options.uid_mask = int(options.uid_mask, 16)
        if options.filter is not None:
            options.filter = options.filter.split(',')
        if options.auth:
            import imp, os.path, sys
            auth = os.path.abspath(options.auth)
            name = os.path.splitext(os.path.basename(auth))[0]
            path = os.path.dirname(auth)
            syspath = sys.path
            sys.path = [path, ]
            f, fn, d = imp.find_module(name)
            sys.path = syspath
            self.mod_auth = imp.load_module("pyctd_auth", f, fn, d)
            if (not hasattr(self.mod_auth, "authenticate")) or (not callable(self.mod_auth.authenticate)):
                print >>sys.stderr, "'--auth' option must be a Python script with a boolean function called authenticate(username, password)."
                sys.exit(1)
        else:
            self.mod_auth = None

    def run(self):
        # Overriding AutoDaemon method
        self.data = DataCollector(AutoDaemon.APP_NAME, self.options.uid_mask, filter = self.options.filter)
        thread.start_new_thread(self.data.run, ())
        self.server = PyctServer(self.data, self.options.host, self.options.port, self.mod_auth)
        self.server.serve_forever()

    def stop(self):
        log = logging.getLogger(AutoDaemon.APP_NAME)
        if hasattr(self, "server"):
            del self.server
            log.debug("Server stopped")
        if hasattr(self, "data"):
            self.data.stop()
            del self.data
            log.debug("Conntracking stopped")
        AutoDaemon.stop(self)

if __name__ == "__main__":
    daemon = PyctDaemon()
