suricatasc: update python packaging

'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.
pull/299/head
Eric Leblond 13 years ago committed by Victor Julien
parent c39c5453e9
commit cd305c3a78

@ -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.
@ -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}

@ -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

@ -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',
],
)

@ -0,0 +1,2 @@
from suricatasc import *

@ -0,0 +1,218 @@
#!/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"

@ -1,5 +1,5 @@
#!/usr/bin/python
# Copyright(C) 2012 Open Information Security Foundation
# Copyright(C) 2013 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
@ -14,237 +14,38 @@
# 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
from socket import socket, AF_UNIX, error
from time import sleep
import sys
VERSION = "0.1"
SIZE = 4096
import argparse
from suricatasc import *
class SuricataException(Exception):
"""
Generic class for suricatasc exception
"""
def __init__(self, value):
self.value = value
parser = argparse.ArgumentParser(prog='suricatasc', description='Client for Suricata unix socket')
parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output (including JSON dump)')
parser.add_argument('socket', metavar='socket', nargs='?', help='socket file to connnect to', default=None)
args = parser.parse_args()
def __str__(self):
return str(self.value)
if args.socket != None:
SOCKET_PATH = "@e_localstatedir@/" + args.socket[0]
else:
SOCKET_PATH = "@e_localstatedir@/suricata-command.socket"
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(SOCKET_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"]))
def close(self):
self.socket.close()
def interactive(self):
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")
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"
if __name__ == '__main__':
import readline
import argparse
parser = argparse.ArgumentParser(prog='suricatasc', description='Client for Suricata unix socket')
parser.add_argument('-v', '--verbose', action='store_const', const=True, help='verbose output (including JSON dump)')
parser.add_argument('socket', metavar='socket', nargs='?', help='socket file to connnect to', default=None)
args = parser.parse_args()
if args.socket != None:
SOCKET_PATH = "@e_localstatedir@/" + args.socket[0]
else:
SOCKET_PATH = "@e_localstatedir@/suricata-command.socket"
sc = SuricataSC(SOCKET_PATH, verbose=args.verbose)
try:
sc.connect()
except SuricataNetException, err:
print "Unable to connect to socket %s: %s" % (SOCKET_PATH, err)
sys.exit(1)
except SuricataReturnException, err:
print "Unable to negotiate version with server: %s" % (err)
sys.exit(1)
try:
sc.interactive()
except SuricataNetException, err:
print "Communication error: %s" % (err)
sys.exit(1)
except SuricataReturnException, err:
print "Invalid return from server: %s" % (err)
sys.exit(1)
print "[+] Quit command client"
sc = SuricataSC(SOCKET_PATH, verbose=args.verbose)
try:
sc.connect()
except SuricataNetException, err:
print "Unable to connect to socket %s: %s" % (SOCKET_PATH, err)
sys.exit(1)
except SuricataReturnException, err:
print "Unable to negotiate version with server: %s" % (err)
sys.exit(1)
try:
sc.interactive()
except SuricataNetException, err:
print "Communication error: %s" % (err)
sys.exit(1)
except SuricataReturnException, err:
print "Invalid return from server: %s" % (err)
sys.exit(1)
sc.close()
print "[+] Quit command client"
sys.exit(1)
sc.close()

Loading…
Cancel
Save