]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
unix socket: protocol v0.2
authorEric Leblond <eric@regit.org>
Fri, 20 Mar 2015 13:23:12 +0000 (14:23 +0100)
committerVictor Julien <victor@inliniac.net>
Wed, 31 Jan 2018 13:25:13 +0000 (14:25 +0100)
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.

scripts/suricatasc/src/suricatasc.py
src/unix-manager.c

index af7615ee1df608aca56c54cc8e1e1e0cccca93f9..a5389479719341d2deb31489b20006345078cef8 100644 (file)
@@ -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]:
index 6a91b4ed238fd74c5b498743e126222fe3beea01..75ca92daba5227ce29eb298e4de78d7c4f31eaa7 100644 (file)
@@ -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);
 }