Skip to content

Commit

Permalink
suricatasc: update python packaging
Browse files Browse the repository at this point in the history
'make install' install now suricatasc script and Python module to
the system. The suricatasc client module can now be used in other
Python projects by using 'import suricatasc'.

A transformation was needed for distribution of a module and a script.
Module in src directory is now containing most of the code and the
script only handle argument parsing and the creation of a unix socket
client through 'suricatasc' module.
  • Loading branch information
regit committed Feb 22, 2013
1 parent 823bf69 commit 94fb128
Show file tree
Hide file tree
Showing 6 changed files with 311 additions and 230 deletions.
15 changes: 15 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@ AC_INIT(configure.ac)
fi
AM_CONDITIONAL([HAVE_COCCINELLE], [test "$HAVE_COCCINELLE_CONFIG" != "no"])

AC_PATH_PROG(HAVE_PYTHON_CONFIG, python, "no")
if test "$HAVE_PYTHON_CONFIG" = "no"; then
echo
echo " Warning! python not found, you will not be "
echo " able to install surictasc unix socket client "
echo
enable_python="no"
else
enable_python="yes"
fi
AM_CONDITIONAL([HAVE_PYTHON], [test "$HAVE_PYTHON_CONFIG" != "no"])



# Checks for libraries.

Expand Down Expand Up @@ -1521,6 +1534,8 @@ SURICATA_BUILD_CONF="Suricata Configuration:
Old barnyard2 support: ${enable_old_barnyard2}
CUDA enabled: ${enable_cuda}

Suricatasc install: ${enable_python}

Unit tests enabled: ${enable_unittests}
Debug output enabled: ${enable_debug}
Debug validation enabled: ${enable_debug_validation}
Expand Down
19 changes: 18 additions & 1 deletion scripts/suricatasc/Makefile.am
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
bin_SCRIPTS = suricatasc
EXTRA_DIST = setup.py suricatasc.in src/__init__.py src/suricatasc.py

if HAVE_PYTHON
all-local:
$(PYTHON) $(srcdir)/setup.py build;

install-exec-local:
$(PYTHON) $(srcdir)/setup.py install --prefix $(DESTDIR)$(prefix)

clean-local:
$(PYTHON) $(srcdir)/setup.py clean;
rm -rf $(top_builddir)/scripts/suricatasc/build

uninstall-local:
[ ! -f "$(DESTDIR)$(prefix)/bin/suricatasc" ] || rm -f "$(DESTDIR)$(prefix)/bin/suricatasc"
find "$(DESTDIR)$(prefix)/lib" -name "suricatasc-*.egg-info" -delete ||true

endif
26 changes: 26 additions & 0 deletions scripts/suricatasc/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python
from distutils.core import setup

SURICATASC_VERSION = "0.9"

setup(name='suricatasc',
version=SURICATASC_VERSION,
description='Suricata unix socket client',
author='Eric Leblond',
author_email='eric@regit.org',
url='https://www.suricata-ids.org/',
scripts=['suricatasc'],
packages=['suricatasc'],
package_dir={'suricatasc':'src'},
provides=['suricatasc'],
requires=['argparse','simplejson'],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Console',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: GNU General Public License (GPL)',
'Operating System :: POSIX',
'Programming Language :: Python',
'Topic :: System :: Systems Administration',
],
)
2 changes: 2 additions & 0 deletions scripts/suricatasc/src/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

from suricatasc import *
220 changes: 220 additions & 0 deletions scripts/suricatasc/src/suricatasc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
#!/usr/bin/python
# Copyright(C) 2012 Open Information Security Foundation

# 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.

import simplejson as json
import re
import readline
from socket import socket, AF_UNIX, error
from time import sleep
import sys

SURICATASC_VERSION = "0.9"

VERSION = "0.1"
SIZE = 4096

class SuricataException(Exception):
"""
Generic class for suricatasc exception
"""
def __init__(self, value):
self.value = value

def __str__(self):
return str(self.value)

class SuricataNetException(SuricataException):
"""
Exception raised when network error occur.
"""
pass

class SuricataCommandException(SuricataException):
"""
Exception raised when command is not correct.
"""
pass

class SuricataReturnException(SuricataException):
"""
Exception raised when return message is not correct.
"""
pass


class SuricataCompleter:
def __init__(self, words):
self.words = words
self.generator = None

def complete(self, text):
for word in self.words:
if word.startswith(text):
yield word

def __call__(self, text, state):
if state == 0:
self.generator = self.complete(text)
try:
return self.generator.next()
except StopIteration:
return None
return None

class SuricataSC:
def __init__(self, sck_path, verbose=False):
self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat']
self.sck_path = sck_path
self.verbose = verbose

def json_recv(self):
cmdret = None
i = 0
data = ""
while i < 5:
i += 1
data += self.socket.recv(SIZE)
try:
cmdret = json.loads(data)
break
except json.decoder.JSONDecodeError:
sleep(0.3)
return cmdret

def send_command(self, command, arguments = None):
if command not in self.cmd_list and command != 'command-list':
raise SuricataCommandException("No such command: %s", command)

cmdmsg = {}
cmdmsg['command'] = command
if (arguments != None):
cmdmsg['arguments'] = arguments
if self.verbose:
print "SND: " + json.dumps(cmdmsg)
self.socket.send(json.dumps(cmdmsg))
cmdret = self.json_recv()

if cmdret == None:
raise SuricataReturnException("Unable to get message from server")

if self.verbose:
print "RCV: "+ json.dumps(cmdret)

return cmdret

def connect(self):
try:
self.socket = socket(AF_UNIX)
self.socket.connect(self.sck_path)
except error, err:
raise SuricataNetException(err)

self.socket.settimeout(10)
#send version
if self.verbose:
print "SND: " + json.dumps({"version": VERSION})
self.socket.send(json.dumps({"version": VERSION}))

# get return
cmdret = self.json_recv()

if cmdret == None:
raise SuricataReturnException("Unable to get message from server")

if self.verbose:
print "RCV: "+ json.dumps(cmdret)

if cmdret["return"] == "NOK":
raise SuricataReturnException("Error: %s" % (cmdret["message"]))

cmdret = self.send_command("command-list")

# we silently ignore NOK as this means server is old
if cmdret["return"] == "OK":
self.cmd_list = cmdret["message"]["commands"]
self.cmd_list.append("quit")


def close(self):
self.socket.close()

def interactive(self):
print "Command list: " + ", ".join(self.cmd_list)
try:
readline.set_completer(SuricataCompleter(self.cmd_list))
readline.set_completer_delims(";")
readline.parse_and_bind('tab: complete')
while True:
command = raw_input(">>> ").strip()
arguments = None
if command.split(' ', 2)[0] in self.cmd_list:
if command == "quit":
break;
if "pcap-file " in command:
try:
[cmd, filename, output] = command.split(' ', 2)
except:
print "Error: arguments to command '%s' is missing" % (command)
continue
if cmd != "pcap-file":
print "Error: invalid command '%s'" % (command)
continue
else:
arguments = {}
arguments["filename"] = filename
arguments["output-dir"] = output
elif "iface-stat" in command:
try:
[cmd, iface] = command.split(' ', 1)
except:
print "Error: unable to split command '%s'" % (command)
continue
if cmd != "iface-stat":
print "Error: invalid command '%s'" % (command)
continue
else:
arguments = {}
arguments["iface"] = iface
elif "conf-get" in command:
try:
[cmd, variable] = command.split(' ', 1)
except:
print "Error: unable to split command '%s'" % (command)
continue
if cmd != "conf-get":
print "Error: invalid command '%s'" % (command)
continue
else:
arguments = {}
arguments["variable"] = variable
else:
cmd = command
else:
print "Error: unknown command '%s'" % (command)
continue

cmdret = self.send_command(cmd, arguments)
#decode json message
if cmdret["return"] == "NOK":
print "Error:"
print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))
else:
print "Success:"
print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))
except KeyboardInterrupt:
print "[!] Interrupted"


0 comments on commit 94fb128

Please sign in to comment.