unix socket: protocol v0.2

This patch updates the unix socket protocol. Messages send from
the server and the client have now a '\n' at the end. This allows
both sides to detect easily the end of a command.

As a side effect, this fixes the problem of long answer in
suricatasc. There is now a limit at the arbitrary value of 65536.

Backward compatility is preserved as a client with the older
version of the protocol can still connect to a Suricata with
version 2 of the protocol.
pull/3209/head
Eric Leblond 11 years ago committed by Victor Julien
parent 3fd7256af5
commit 3d0ba36ba8

@ -25,10 +25,10 @@ from time import sleep
import select
import sys
SURICATASC_VERSION = "0.9"
SURICATASC_VERSION = "1.0"
VERSION = "0.1"
SIZE = 4096
VERSION = "0.2"
INC_SIZE = 1024
class SuricataException(Exception):
"""
@ -86,19 +86,15 @@ class SuricataSC:
def json_recv(self):
cmdret = None
i = 0
data = ""
while i < 5:
i += 1
while True:
if sys.version < '3':
data += self.socket.recv(SIZE)
data += self.socket.recv(INC_SIZE)
else:
data += self.socket.recv(SIZE).decode('iso-8859-1')
try:
data += self.socket.recv(INC_SIZE).decode('iso-8859-1')
if data.endswith('\n'):
cmdret = json.loads(data)
break
except:
sleep(0.3)
return cmdret
def send_command(self, command, arguments = None):
@ -111,10 +107,11 @@ class SuricataSC:
cmdmsg['arguments'] = arguments
if self.verbose:
print("SND: " + json.dumps(cmdmsg))
cmdmsg_str = json.dumps(cmdmsg) + "\n"
if sys.version < '3':
self.socket.send(json.dumps(cmdmsg))
self.socket.send(cmdmsg_str)
else:
self.socket.send(bytes(json.dumps(cmdmsg), 'iso-8859-1'))
self.socket.send(bytes(cmdmsg_str, 'iso-8859-1'))
ready = select.select([self.socket], [], [], 600)
if ready[0]:

@ -1,4 +1,4 @@
/* Copyright (C) 2013 Open Information Security Foundation
/* Copyright (C) 2013-2018 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
@ -78,6 +78,7 @@ typedef struct Task_ {
typedef struct UnixClient_ {
int fd;
MemBuffer *mbuf; /**< buffer for response construction */
int version;
TAILQ_ENTRY(UnixClient_) next;
} UnixClient;
@ -278,7 +279,10 @@ static void UnixCommandClose(UnixCommand *this, int fd)
}
#define UNIX_PROTO_VERSION_LENGTH 200
#define UNIX_PROTO_VERSION "0.1"
#define UNIX_PROTO_VERSION_V1 "0.1"
#define UNIX_PROTO_V1 1
#define UNIX_PROTO_VERSION "0.2"
#define UNIX_PROTO_V2 2
static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js)
{
@ -297,6 +301,13 @@ static int UnixCommandSendJSONToClient(UnixClient *client, json_t *js)
return -1;
}
if (client->version > UNIX_PROTO_V1) {
if (MEMBUFFER_OFFSET(client->mbuf) + 1 >= MEMBUFFER_SIZE(client->mbuf)) {
MemBufferExpand(&client->mbuf, 1);
}
MemBufferWriteRaw(client->mbuf, "\n", 1);
}
if (send(client->fd, (const char *)MEMBUFFER_BUFFER(client->mbuf),
MEMBUFFER_OFFSET(client->mbuf), MSG_NOSIGNAL) == -1)
{
@ -328,6 +339,7 @@ static int UnixCommandAccept(UnixCommand *this)
json_t *version;
json_error_t jerror;
int client;
int client_version;
int ret;
UnixClient *uclient = NULL;
@ -374,7 +386,8 @@ static int UnixCommandAccept(UnixCommand *this)
}
/* check client version */
if (strcmp(json_string_value(version), UNIX_PROTO_VERSION) != 0) {
if ((strcmp(json_string_value(version), UNIX_PROTO_VERSION) != 0)
&& (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) != 0)) {
SCLogInfo("Unix socket: invalid client version: \"%s\"",
json_string_value(version));
json_decref(client_msg);
@ -383,6 +396,11 @@ static int UnixCommandAccept(UnixCommand *this)
} else {
SCLogDebug("Unix socket: client version: \"%s\"",
json_string_value(version));
if (strcmp(json_string_value(version), UNIX_PROTO_VERSION_V1) == 0) {
client_version = UNIX_PROTO_V1;
} else {
client_version = UNIX_PROTO_V2;
}
}
json_decref(client_msg);
@ -402,6 +420,7 @@ static int UnixCommandAccept(UnixCommand *this)
return 0;
}
uclient->fd = client;
uclient->version = client_version;
if (UnixCommandSendJSONToClient(uclient, server_msg) != 0) {
SCLogWarning(SC_ERR_SOCKET, "Unable to send command");
@ -416,7 +435,6 @@ static int UnixCommandAccept(UnixCommand *this)
/* client connected */
SCLogDebug("Unix socket: client connected");
TAILQ_INSERT_TAIL(&this->clients, uclient, next);
UnixCommandSetMaxFD(this);
return 1;
@ -526,23 +544,82 @@ static void UnixCommandRun(UnixCommand * this, UnixClient *client)
{
char buffer[4096];
int ret;
ret = recv(client->fd, buffer, sizeof(buffer) - 1, 0);
if (ret <= 0) {
if (ret == 0) {
SCLogDebug("Unix socket: lost connection with client");
} else {
SCLogError(SC_ERR_SOCKET, "Unix socket: error on recv() from client: %s",
strerror(errno));
if (client->version <= UNIX_PROTO_V1) {
ret = recv(client->fd, buffer, sizeof(buffer) - 1, 0);
if (ret <= 0) {
if (ret == 0) {
SCLogDebug("Unix socket: lost connection with client");
} else {
SCLogError(SC_ERR_SOCKET, "Unix socket: error on recv() from client: %s",
strerror(errno));
}
UnixCommandClose(this, client->fd);
return;
}
if (ret >= (int)(sizeof(buffer)-1)) {
SCLogError(SC_ERR_SOCKET, "Command server: client command is too long, "
"disconnect him.");
UnixCommandClose(this, client->fd);
}
buffer[ret] = 0;
} else {
int try = 0;
int offset = 0;
int cmd_over = 0;
ret = recv(client->fd, buffer + offset, sizeof(buffer) - offset - 1, 0);
do {
if (ret <= 0) {
if (ret == 0) {
SCLogInfo("Unix socket: lost connection with client");
} else {
SCLogInfo("Unix socket: error on recv() from client: %s",
strerror(errno));
}
UnixCommandClose(this, client->fd);
return;
}
if (ret >= (int)(sizeof(buffer)- offset - 1)) {
SCLogInfo("Command server: client command is too long, "
"disconnect him.");
UnixCommandClose(this, client->fd);
}
if (buffer[ret - 1] == '\n') {
buffer[ret-1] = 0;
cmd_over = 1;
} else {
struct timeval tv;
fd_set select_set;
offset += ret;
do {
FD_ZERO(&select_set);
FD_SET(client->fd, &select_set);
tv.tv_sec = 0;
tv.tv_usec = 200 * 1000;
try++;
ret = select(client->fd, &select_set, NULL, NULL, &tv);
/* catch select() error */
if (ret == -1) {
/* Signal was caught: just ignore it */
if (errno != EINTR) {
SCLogInfo("Unix socket: lost connection with client");
UnixCommandClose(this, client->fd);
return;
}
}
} while (ret == 0 && try < 3);
if (ret > 0) {
ret = recv(client->fd, buffer + offset,
sizeof(buffer) - offset - 1, 0);
}
}
} while (try < 3 && cmd_over == 0);
if (try == 3 && cmd_over == 0) {
SCLogInfo("Unix socket: imcomplete client message, closing connection");
UnixCommandClose(this, client->fd);
return;
}
UnixCommandClose(this, client->fd);
return;
}
if (ret >= (int)(sizeof(buffer)-1)) {
SCLogInfo("Command server: client command is too long, "
"disconnect him.");
UnixCommandClose(this, client->fd);
}
buffer[ret] = 0;
UnixCommandExecute(this, buffer, client);
}

Loading…
Cancel
Save