suricatasc: refactor as a class

The goal of this commit is to be able to use suricatasc has a library
and and program. This is done by putting all active code in class and
adding a Python magic to detect when file is used as a program.
pull/299/head
Eric Leblond 13 years ago committed by Victor Julien
parent 31c03d38b9
commit c39c5453e9

@ -15,17 +15,44 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import simplejson as json import simplejson as json
import readline
import re import re
from socket import socket, AF_UNIX, error from socket import socket, AF_UNIX, error
from time import sleep from time import sleep
import sys import sys
import argparse
VERSION = "0.1" VERSION = "0.1"
SIZE = 4096 SIZE = 4096
class Completer: 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): def __init__(self, words):
self.words = words self.words = words
self.generator = None self.generator = None
@ -44,155 +71,180 @@ class Completer:
return None return None
return None return None
def json_recv(socket): class SuricataSC:
cmdret = None def __init__(self, sck_path, verbose=False):
i = 0 self.cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat']
data = "" self.sck_path = sck_path
while i < 5: self.verbose = verbose
i += 1
data += socket.recv(SIZE) 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: try:
cmdret = json.loads(data) self.socket = socket(AF_UNIX)
break self.socket.connect(SOCKET_PATH)
except json.decoder.JSONDecodeError: except error, err:
sleep(0.3) raise SuricataNetException(err)
return cmdret
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"
socket = socket(AF_UNIX)
socket.connect(SOCKET_PATH)
socket.settimeout(10)
#send version
if args.verbose:
print "SND: " + json.dumps({"version": VERSION})
socket.send(json.dumps({"version": VERSION}))
# get return
cmdret = json_recv(socket)
if cmdret == None:
sys.stderr.write("Unable to get message from server")
sys.exit(1)
if args.verbose: self.socket.settimeout(10)
print "RCV: "+ json.dumps(cmdret) #send version
# if ok loop if self.verbose:
if cmdret["return"] == "NOK": print "SND: " + json.dumps({"version": VERSION})
sys.stderr.write("Error: %s" % (cmdret["message"])) self.socket.send(json.dumps({"version": VERSION}))
sys.exit(1)
# get command list # get return
cmdret = self.json_recv()
if args.verbose: if cmdret == None:
print "SND: " + json.dumps({"command": "command-list"}) raise SuricataReturnException("Unable to get message from server")
socket.send(json.dumps({"command": "command-list"}))
cmdret = json_recv(socket)
if cmdret == None: if self.verbose:
sys.stderr.write("Unable to get message from server") print "RCV: "+ json.dumps(cmdret)
sys.exit(1)
if args.verbose: if cmdret["return"] == "NOK":
print "RCV: "+ json.dumps(cmdret) raise SuricataReturnException("Error: %s" % (cmdret["message"]))
def close(self):
if cmdret["return"] == "OK": self.socket.close()
cmd_list = cmdret["message"]["commands"]
cmd_list.append("quit") def interactive(self):
print "Command list: " + ", ".join(cmd_list) cmdret = self.send_command("command-list")
else:
# This is the list of commands before command-list was added to the code. # we silently ignore NOK as this means server is old
cmd_list=['shutdown','quit','pcap-file','pcap-file-number','pcap-file-list','iface-list','iface-stat'] if cmdret["return"] == "OK":
self.cmd_list = cmdret["message"]["commands"]
# if ok loop self.cmd_list.append("quit")
try: print "Command list: " + ", ".join(self.cmd_list)
readline.set_completer(Completer(cmd_list)) try:
readline.set_completer_delims(";") readline.set_completer(SuricataCompleter(self.cmd_list))
readline.parse_and_bind('tab: complete') readline.set_completer_delims(";")
while True: readline.parse_and_bind('tab: complete')
command = raw_input(">>> ").strip() while True:
if command.split(' ', 2)[0] in cmd_list: command = raw_input(">>> ").strip()
if command == "quit": arguments = None
break; if command.split(' ', 2)[0] in self.cmd_list:
cmdmsg = {} if command == "quit":
if "pcap-file " in command: break;
try: if "pcap-file " in command:
[cmd, filename, output] = command.split(' ', 2) try:
except: [cmd, filename, output] = command.split(' ', 2)
print "Error: unable to split command '%s'" % (command) except:
continue print "Error: arguments to command '%s' is missing" % (command)
if cmd != "pcap-file": continue
print "Error: invalid command '%s'" % (command) if cmd != "pcap-file":
continue print "Error: invalid command '%s'" % (command)
else: continue
cmdmsg["command"] = cmd else:
cmdmsg["arguments"] = {} arguments = {}
cmdmsg["arguments"]["filename"] = filename arguments["filename"] = filename
cmdmsg["arguments"]["output-dir"] = output arguments["output-dir"] = output
elif "iface-stat" in command: elif "iface-stat" in command:
try: try:
[cmd, iface] = command.split(' ', 1) [cmd, iface] = command.split(' ', 1)
except: except:
print "Error: unable to split command '%s'" % (command) print "Error: unable to split command '%s'" % (command)
continue continue
if cmd != "iface-stat": if cmd != "iface-stat":
print "Error: invalid command '%s'" % (command) print "Error: invalid command '%s'" % (command)
continue 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: else:
cmdmsg["command"] = cmd print "Error: unknown command '%s'" % (command)
cmdmsg["arguments"] = {}
cmdmsg["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 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: else:
cmdmsg["command"] = cmd print "Success:"
cmdmsg["arguments"] = {} print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': '))
cmdmsg["arguments"]["variable"] = variable except KeyboardInterrupt:
else: print "[!] Interrupted"
cmdmsg["command"] = command
if args.verbose: if __name__ == '__main__':
print "SND: " + json.dumps(cmdmsg) import readline
socket.send(json.dumps(cmdmsg)) import argparse
cmdret = json_recv(socket) 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)')
if cmdret == None: parser.add_argument('socket', metavar='socket', nargs='?', help='socket file to connnect to', default=None)
sys.stderr.write("Unable to get message from server") args = parser.parse_args()
sys.exit(1)
if args.socket != None:
if args.verbose: SOCKET_PATH = "@e_localstatedir@/" + args.socket[0]
print "RCV: "+ json.dumps(cmdret) else:
SOCKET_PATH = "@e_localstatedir@/suricata-command.socket"
#decode json message
if cmdret["return"] == "NOK": sc = SuricataSC(SOCKET_PATH, verbose=args.verbose)
print "Error:" try:
print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': ')) sc.connect()
else: except SuricataNetException, err:
print "Success:" print "Unable to connect to socket %s: %s" % (SOCKET_PATH, err)
print json.dumps(cmdret["message"], sort_keys=True, indent=4, separators=(',', ': ')) sys.exit(1)
else: except SuricataReturnException, err:
print "Unknown command: '%s'" % (command) print "Unable to negotiate version with server: %s" % (err)
except KeyboardInterrupt: sys.exit(1)
print "[!] Interrupted" try:
sc.interactive()
print "[+] Quit command client" except SuricataNetException, err:
print "Communication error: %s" % (err)
socket.close() sys.exit(1)
except SuricataReturnException, err:
sys.exit(1) print "Invalid return from server: %s" % (err)
sys.exit(1)
print "[+] Quit command client"
sc.close()
sys.exit(1)

Loading…
Cancel
Save