Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions hacklog.spec
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ mkdir -p $RPM_BUILD_ROOT%{_initrddir}
install -p -m 0640 conf/server.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/server.conf
install -p -m 0755 bin/%{name} $RPM_BUILD_ROOT%{_bindir}/%{name}
install -p -m 0755 scripts/%{name}.init.d $RPM_BUILD_ROOT%{_initrddir}/%{name}
install -p -m 0755 twisted/plugins/%{name}_plugin.py $RPM_BUILD_ROOT%{python_sitelib}/twisted/plugins/%{name}_plugin.py

%if ((0%{?rhel} >= 6 || 0%{?fedora} > 12) && 0%{?include_tests})
%check
Expand All @@ -105,6 +106,7 @@ rm -rf $RPM_BUILD_ROOT
%doc $RPM_BUILD_DIR/%{name}-%{version}/%{name}-%{version}/LICENSE
%{python_sitelib}/%{name}
%{python_sitelib}/%{name}-%{version}-py?.?.egg-info
%{python_sitelib}/twisted/plugins/%{name}_plugin.py

%files -n hacklog
%defattr(-,root,root)
Expand All @@ -120,6 +122,7 @@ rm -rf $RPM_BUILD_ROOT
%doc $RPM_BUILD_DIR/%{name}-%{version}/%{name}-%{version}/LICENSE
%{python_sitelib}/%{name}
%{python_sitelib}/%{name}-%{version}-py?.?.egg-info
%{python_sitelib}/twisted/plugins/%{name}_plugin.py

# less than RHEL 8 / Fedora 16
# not sure if RHEL 7 will use systemd yet
Expand Down
61 changes: 41 additions & 20 deletions hacklog/server.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/usr/bin/env python
import sys
import time
import thread
Expand All @@ -8,6 +9,7 @@

from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor, defer
from twisted.application import service, internet

from optparse import OptionParser
from ConfigParser import ConfigParser
Expand All @@ -22,19 +24,21 @@ class SyslogServer():
"""
Syslog server based on twisted library
"""
def __init__(self):
def __init__(self, config_file='../conf/server.conf'):
self.dbFile = 'hacklog.db'
self.port = 10514
self.bind_address = '127.0.0.1'
self.config_file = '../conf/server.conf'
self.config_file = config_file
self.loglevel = logging.DEBUG
self.running = True
self.started = False
self.parser_thread = False
self.usage = "usage: %prog -c config_file"
self.testEnabled = False
self.emailTest = False
self.successPattern = None
self.failurePattern = None

def parceConfig(self, config_file):
config = ConfigParser()
config.read(config_file)
Expand Down Expand Up @@ -73,39 +77,43 @@ def interrupt(self, signum, stackframe):
self.stop()

def messageParcer(self):
logging.debug("messageParcer in thread " + str(thread.get_ident()))
self.parser_thread = thread.get_ident()
# output will be logged when app works under twistd plugin
print("messageParcer in thread " + str(self.parser_thread))
logging.info("messageParcer in thread " + str(self.parser_thread))

parser = None
# get parsing patterns from config file when in testing mode
if self.testEnabled:
parser = Parser(self.successPattern, self.failurePattern, self.testEnabled)
else:
parser = Parser()

while self.running:
msg = queue.get()
eventLog = parser.parseLogLine(msg)
if eventLog:
algorithm.processEventLog(eventLog)
logging.debug("messages in queue " + str(queue.qsize()) + ", received %r from %s:%d" % (msg.data, msg.host, msg.port))

def cleanupThread(self):
threadPool = reactor.getThreadPool()
threadPool.stop()

def run(self):
signal.signal(signal.SIGINT, self.interrupt)
reactor.callInThread(self.messageParcer)
reactor.listenUDP(self.port, SyslogReader())
reactor.run()

def init(self):
if not self.parser_thread:
print('Staring parser thread')
signal.signal(signal.SIGINT, self.interrupt)
reactor.callInThread(self.messageParcer)

def start(self):
self.readCmdArgs()
self.parceConfig(self.config_file)
self.setLogging()
algorithm.setServices(MailConf(self.emailTest))
create_db_engine(self)
create_tables()
self.run()
while not self.started:
self.parceConfig(self.config_file)
self.setLogging()
algorithm.setServices(MailConf(self.emailTest))
create_db_engine(self)
create_tables()
self.started = True

def stop(self):
reactor.stop()
Expand All @@ -117,10 +125,23 @@ def datagramReceived(self, data, (host, port)):
syslogMsg = SyslogMsg(data, host, port)
queue.put(syslogMsg)

def main():
def getApplicationService():
return internet.UDPServer(server.port, SyslogReader())

server = SyslogServer()
def main():
server.readCmdArgs()
server.start()
server.init()
server.run()

# default context
server = SyslogServer()

if __name__ == '__main__':
main()
else:
logging.info('starting as twisted plugin or application: {0}'.format(__name__))

application = service.Application("hacklog")
service = getApplicationService()
service.setServiceParent(application)
1 change: 0 additions & 1 deletion hacklog/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from datetime import datetime
import smtplib
from entities import *
import server

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
Expand Down
39 changes: 39 additions & 0 deletions twisted/plugins/hacklog_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from zope.interface import implements

from twisted.python import usage
from twisted.plugin import IPlugin
from twisted.application.service import IServiceMaker
from twisted.application import internet

from hacklog.server import SyslogServer, SyslogReader


class Options(usage.Options):
optParameters = [["config", "c", 'conf/server.conf', "path to configuration file."]]


class MyServiceMaker(object):
implements(IServiceMaker, IPlugin)
tapname = "hacklog"
description = "Syslog server for detection of compromised user accounts"
options = Options

server = SyslogServer()

def makeService(self, options):
"""
Construct a UDP Server
"""
self.server.config_file = options['config']

self.server.start()
self.server.init()

return internet.UDPServer(self.server.port, SyslogReader())


# Now construct an object which *provides* the relevant interfaces
# The name of this variable is irrelevant, as long as there is *some*
# name bound to a provider of IPlugin and IServiceMaker.

serviceMaker = MyServiceMaker()