1 /****************************************************************************
2  *
3  * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License Version 2 as
7  * published by the Free Software Foundation.  You may not use, modify or
8  * distribute this program under any other version of the GNU General
9  * Public License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  *****************************************************************************/
21 
22 /**************************************************************************
23  *
24  * file_ss.c
25  *
26  * Authors: Bhargava Jandhyala <bjandhya@cisco.com>
27  *
28  * Description:
29  *
30  * File cache sharing support.
31  *
32  **************************************************************************/
33 
34 #ifdef SIDE_CHANNEL
35 
36 #include "file_ss.h"
37 #include "sidechannel.h"
38 #include "file_resume_block.h"
39 #include "packet_time.h"
40 #include <errno.h>
41 #include <fcntl.h>
42 
43 #ifdef REG_TEST
44 typedef struct _MsgHeader
45 {
46     uint32_t type;
47     uint32_t data_length;
48 } MsgHeader;
49 
50 #endif
51 
52 typedef struct _FileSSStats
53 {
54     uint32_t messages_received;
55     uint32_t messages_sent;
56 } FileSSStats;
57 
58 static uint8_t file_io_buffer[UINT16_MAX];
59 static FileSSStats file_ss_stats;
60 
61 #ifdef REG_TEST
62 static int runtime_output_fd = -1;
63 static uint32_t WriteFileSSMsgHeader(uint8_t *, uint32_t , uint32_t );
64 static inline ssize_t Read(int , void *, size_t );
65 static inline ssize_t Write(int , const void *, size_t );
66 static int ReadFileSSMessagesFromFile(const char *);
67 static uint32_t WriteFileSSMsgHeader(uint8_t *, uint32_t , uint32_t );
68 #endif
69 
FilePrintSSStats(void)70 void FilePrintSSStats(void)
71 {
72     LogMessage("    File Cache Sharing:\n");
73     LogMessage("        Messages Received: %u\n", file_ss_stats.messages_received);
74     LogMessage("        Messages Sent: %u\n", file_ss_stats.messages_sent);
75 }
76 
ConsumeFileSSMsg(uint32_t type,const uint8_t * msg,uint32_t msglen)77 static int ConsumeFileSSMsg(uint32_t type, const uint8_t *msg, uint32_t msglen)
78 {
79     int rval = 1;
80 
81     switch(type)
82     {
83         case SC_MSG_TYPE_FILE_SS_HOST_CACHE:
84             rval = ConsumeSSFileCache(msg, msglen);
85             break;
86         default:
87             break;
88     }
89 
90     file_ss_stats.messages_received++;
91     return rval;
92 }
93 
94 
95 #ifndef REG_TEST
96 
FileSSSCMsgHandler(SCMsgHdr * hdr,const uint8_t * msg,uint32_t msglen)97 static int FileSSSCMsgHandler(SCMsgHdr *hdr, const uint8_t *msg, uint32_t msglen)
98 {
99     int rval = 1;
100 
101     if(!hdr)
102         return rval;
103 
104     rval = ConsumeFileSSMsg(hdr->type, msg, msglen);
105 
106     return rval;
107 }
108 
109 
110 /* Caller should proceed writing to the 'data_ptr' ONLY upon successful return i.e 0 */
CreateFileSSUpdate(void ** msg_handle,void ** hdr_ptr,void ** data_ptr,uint32_t type,uint32_t data_len)111 int CreateFileSSUpdate(void **msg_handle, void **hdr_ptr, void **data_ptr, uint32_t type, uint32_t data_len)
112 {
113     FileConfig *file_config;
114     SCMsgHdr *schdr;
115     uint8_t *msg;
116     int rval;
117     file_config =  (FileConfig *)(snort_conf->file_config);
118     if (!msg_handle || !hdr_ptr || !data_ptr)
119     {
120       ErrorMessage("Param %s is null for side channel update\n", msg_handle ?
121           (hdr_ptr ? "data pointer" : "header pointer") : "Message handle");
122       return -1;
123     }
124 
125 
126     if (file_config->use_side_channel)
127     {
128         /* Allocate space for the message. */
129         if ((rval = SideChannelPreallocMessageTX(data_len, &schdr, &msg, msg_handle)) != 0)
130         {
131             ErrorMessage("Unable to allocate memory for enqueing File SS message\n");
132             return -1;
133         }
134 
135         *hdr_ptr = (void *)schdr;
136         *data_ptr = (void *)msg;
137     }
138     else
139     {
140 #if defined(DAQ_VERSION) && DAQ_VERSION > 6
141       if(ScSideChannelEnabled())
142       {
143         file_config->use_side_channel = true;
144         ErrorMessage("Enabling file side channel runtime \n");
145         /* Allocate space for the message. */
146         if ((rval = SideChannelPreallocMessageTX(data_len, &schdr, &msg, msg_handle)) != 0)
147         {
148           ErrorMessage("Unable to allocate memory for enqueing File SS message after at runtime\n");
149           return -1;
150         }
151 
152         *hdr_ptr = (void *)schdr;
153         *data_ptr = (void *)msg;
154       }
155       else
156 #endif
157       {
158         ErrorMessage("side channel infra is not up\n");
159         return -1;
160       }
161     }
162     return 0;
163 }
SendFileSSUpdate(void * msg_handle,void * hdr_ptr,void * data_ptr,uint32_t type,uint32_t data_len)164 int SendFileSSUpdate(void *msg_handle, void *hdr_ptr, void *data_ptr, uint32_t type, uint32_t data_len)
165 {
166    FileConfig *file_config;
167    file_config =  (FileConfig *)(snort_conf->file_config);
168    SCMsgHdr *schdr;
169    uint8_t *msg;
170 
171    if (!msg_handle || !hdr_ptr || !data_ptr)
172    {
173         return -1;
174    }
175 
176     if (file_config->use_side_channel)
177     {
178         schdr = (SCMsgHdr *)hdr_ptr;
179         msg = (uint8_t *)data_ptr;
180 
181         schdr->type = type;
182         schdr->timestamp = packet_time();
183 
184         SideChannelEnqueueMessageTX(schdr, msg, data_len, msg_handle, NULL);
185         file_ss_stats.messages_sent++;
186     }
187     return 0;
188 }
189 
FileSSConfigInit(void)190 void FileSSConfigInit(void)
191 {
192     int rval;
193     FileConfig *file_config;
194     file_config =  (FileConfig *)(snort_conf->file_config);
195     if ((rval = SideChannelRegisterRXHandler(SC_MSG_TYPE_FILE_SS_HOST_CACHE, FileSSSCMsgHandler, NULL)) != 0)
196     {
197           ErrorMessage("Unable to register File SS message handler\n");
198     }
199     return;
200 }
201 #endif
202 #ifdef REG_TEST
203 /*
204  * File I/O for regression only
205  */
FileCleanSS(void)206 void FileCleanSS(void)
207 {
208     if (runtime_output_fd >= 0)
209     {
210         close(runtime_output_fd);
211         runtime_output_fd = -1;
212     }
213 }
FilePrintSSConfig(FileSSConfig * file_ss_config)214 void FilePrintSSConfig(FileSSConfig *file_ss_config)
215 {
216     if (file_ss_config == NULL)
217         return;
218 
219     LogMessage("    File SS config:\n");
220     if (file_ss_config->startup_input_file)
221         LogMessage("        Startup Input File:    %s\n", file_ss_config->startup_input_file);
222     if (file_ss_config->runtime_output_file)
223         LogMessage("        Runtime Output File:   %s\n", file_ss_config->runtime_output_file);
224     return;
225 }
CreateFileSSUpdate(void ** msg_handle,void ** hdr_ptr,void ** data_ptr,uint32_t type,uint32_t data_len)226 int CreateFileSSUpdate(void **msg_handle, void **hdr_ptr, void **data_ptr, uint32_t type, uint32_t data_len)
227 {
228     if (!data_ptr)
229         return -1;
230 
231     if (runtime_output_fd >= 0)
232     {
233         WriteFileSSMsgHeader(file_io_buffer, type, data_len);
234         *data_ptr = (void *)(&file_io_buffer[0] + sizeof(MsgHeader));
235     }
236     else
237     {
238         return -1;
239     }
240     return 0;
241 }
SendFileSSUpdate(void * msg_handle,void * hdr_ptr,void * data_ptr,uint32_t type,uint32_t data_len)242 int SendFileSSUpdate(void *msg_handle, void *hdr_ptr, void *data_ptr, uint32_t type, uint32_t data_len)
243 {
244     if (runtime_output_fd >= 0)
245     {
246         if (Write(runtime_output_fd, file_io_buffer, sizeof(MsgHeader) + data_len) == -1)
247         {
248             /* Already reported Error inside the 'Write' call */
249         }
250         else
251         {
252             file_ss_stats.messages_sent++;
253         }
254     }
255     return 0;
256 }
FileSSConfigInit(void)257 void FileSSConfigInit(void)
258 {
259     int rval;
260     FileConfig *file_config;
261     file_config =  (FileConfig *)(snort_conf->file_config);
262     /* Probably need to do this through a different function for Reload. But we're okay for now. */
263     if (file_config && file_config->file_ss_config)
264     {
265         if (file_config->file_ss_config->startup_input_file)
266         {
267             if ((rval = ReadFileSSMessagesFromFile(file_config->file_ss_config->startup_input_file)) != 0)
268             {
269                 ErrorMessage("Errors were encountered while reading File SS messages from file '%s'\n",
270                         file_config->file_ss_config->startup_input_file);
271             }
272         }
273 
274         if (file_config->file_ss_config->runtime_output_file)
275         {
276             runtime_output_fd = open(file_config->file_ss_config->runtime_output_file, O_WRONLY | O_CREAT | O_TRUNC, 0664);
277             if (runtime_output_fd < 0)
278             {
279                 ErrorMessage("Could not open %s for writing File SS messages: %s (%d)\n",
280                         file_config->file_ss_config->runtime_output_file, strerror(errno), errno);
281             }
282         }
283     }
284 }
Read(int fd,void * buf,size_t count)285 static inline ssize_t Read(int fd, void *buf, size_t count)
286 {
287     ssize_t n;
288     errno = 0;
289 
290     while ((n = read(fd, buf, count)) <= (ssize_t) count)
291     {
292         if (n == (ssize_t) count)
293             return 0;
294 
295         if (n > 0)
296         {
297             buf = (uint8_t *) buf + n;
298             count -= n;
299         }
300         else if (n == 0)
301             break;
302         else if (errno != EINTR)
303         {
304             ErrorMessage("Error reading from File SS message file: %s (%d)\n", strerror(errno), errno);
305             break;
306         }
307     }
308     return -1;
309 }
310 
Write(int fd,const void * buf,size_t count)311 static inline ssize_t Write(int fd, const void *buf, size_t count)
312 {
313     ssize_t n;
314     errno = 0;
315 
316     while ((n = write(fd, buf, count)) <= (ssize_t) count)
317     {
318         if (n == (ssize_t) count)
319             return 0;
320 
321         if (n > 0)
322             count -= n;
323         else if (errno != EINTR)
324         {
325             ErrorMessage("Error writing to File SS message file: %s (%d)\n", strerror(errno), errno);
326             break;
327         }
328     }
329 
330     return -1;
331 }
332 
ReadFileSSMessagesFromFile(const char * filename)333 static int ReadFileSSMessagesFromFile(const char *filename)
334 {
335     MsgHeader *msg_header;
336     uint8_t *msg;
337     int rval = 0, fd, offset = 0;
338 
339     fd = open(filename, O_RDONLY , 0664);
340     if (fd < 0)
341     {
342         if (errno == ENOENT)
343             return 0;
344 
345         ErrorMessage("Could not open %s for reading File SS messages from: %s (%d)\n", filename, strerror(errno), errno);
346     }
347 
348     msg = file_io_buffer;
349 
350     while ((rval = Read(fd, msg, sizeof(*msg_header))) == 0)
351     {
352         msg_header = (MsgHeader *) msg;
353         offset = sizeof(*msg_header);
354 
355         if ((rval = Read(fd, msg + offset, msg_header->data_length)) != 0)
356         {
357             ErrorMessage("Error reading the remaining %u bytes of File SS message from file: %s (%d)\n",
358                 msg_header->data_length, strerror(errno), errno);
359 
360             close(fd);
361             return rval;
362         }
363 
364         if ((rval = ConsumeFileSSMsg(msg_header->type, msg + offset, msg_header->data_length) != 0))
365         {
366             close(fd);
367             return rval;
368         }
369 
370         offset += msg_header->data_length;
371         msg += offset;
372     }
373     close(fd);
374     return 0;
375 }
376 
WriteFileSSMsgHeader(uint8_t * msg,uint32_t type,uint32_t data_len)377 static uint32_t WriteFileSSMsgHeader(uint8_t *msg, uint32_t type, uint32_t data_len)
378 {
379     MsgHeader *msg_hdr;
380 
381     msg_hdr = (MsgHeader *) msg;
382     msg_hdr->type = type;
383     msg_hdr->data_length = data_len;
384 
385     return 0;
386 }
387 #endif
388 #endif /* SIDE_CHANNEL */
389