suricata
util-device.c
Go to the documentation of this file.
1 /* Copyright (C) 2011-2016 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 #include "suricata-common.h"
19 #include "conf.h"
20 #include "util-device.h"
21 #include "util-ioctl.h"
22 
23 #include "device-storage.h"
24 
25 #define MAX_DEVNAME 10
26 
27 /**
28  * \file
29  *
30  * \author Eric Leblond <eric@regit.org>
31  *
32  * \brief Utility functions to handle device list
33  */
34 
35 /** private device list */
36 static TAILQ_HEAD(, LiveDevice_) live_devices =
37  TAILQ_HEAD_INITIALIZER(live_devices);
38 
39 /** List of the name of devices
40  *
41  * As we don't know the size of the Storage on devices
42  * before the parsing we need to wait and use this list
43  * to create later the LiveDevice via LiveDeviceFinalize()
44  */
45 static TAILQ_HEAD(, LiveDeviceName_) pre_live_devices =
46  TAILQ_HEAD_INITIALIZER(pre_live_devices);
47 
48 /** if set to 0 when we don't have real devices */
49 static int live_devices_stats = 1;
50 
51 static int LiveSafeDeviceName(const char *devname,
52  char *newdevname, size_t destlen);
53 
54 static int g_live_devices_disable_offloading = 1;
55 
56 void LiveSetOffloadDisable(void)
57 {
58  g_live_devices_disable_offloading = 1;
59 }
60 
62 {
63  g_live_devices_disable_offloading = 0;
64 }
65 
66 int LiveGetOffload(void)
67 {
68  return g_live_devices_disable_offloading;
69 }
70 
71 /**
72  * \brief Add a device for monitoring
73  *
74  * To be used during option parsing. When a device has
75  * to be created during runmode init, use LiveRegisterDevice()
76  *
77  * \param dev string with the device name
78  *
79  * \retval 0 on success.
80  * \retval -1 on failure.
81  */
82 int LiveRegisterDeviceName(const char *dev)
83 {
84  LiveDeviceName *pd = NULL;
85 
86  pd = SCCalloc(1, sizeof(LiveDeviceName));
87  if (unlikely(pd == NULL)) {
88  return -1;
89  }
90 
91  pd->dev = SCStrdup(dev);
92  if (unlikely(pd->dev == NULL)) {
93  SCFree(pd);
94  return -1;
95  }
96 
97  TAILQ_INSERT_TAIL(&pre_live_devices, pd, next);
98 
99  SCLogDebug("Device \"%s\" registered.", dev);
100  return 0;
101 }
102 
103 /**
104  * \brief Add a pcap device for monitoring and create structure
105  *
106  * \param dev string with the device name
107  *
108  * \retval 0 on success.
109  * \retval -1 on failure.
110  */
111 int LiveRegisterDevice(const char *dev)
112 {
113  LiveDevice *pd = NULL;
114 
115  pd = SCCalloc(1, sizeof(LiveDevice) + LiveDevStorageSize());
116  if (unlikely(pd == NULL)) {
117  return -1;
118  }
119 
120  pd->dev = SCStrdup(dev);
121  if (unlikely(pd->dev == NULL)) {
122  SCFree(pd);
123  return -1;
124  }
125  /* create a short version to be used in thread names */
126  if (strlen(pd->dev) > MAX_DEVNAME) {
127  LiveSafeDeviceName(pd->dev, pd->dev_short, sizeof(pd->dev_short));
128  } else {
129  (void)strlcpy(pd->dev_short, pd->dev, sizeof(pd->dev_short));
130  }
131 
132  SC_ATOMIC_INIT(pd->pkts);
133  SC_ATOMIC_INIT(pd->drop);
134  SC_ATOMIC_INIT(pd->invalid_checksums);
135  pd->ignore_checksum = 0;
136  pd->id = LiveGetDeviceCount();
137  TAILQ_INSERT_TAIL(&live_devices, pd, next);
138 
139  SCLogDebug("Device \"%s\" registered and created.", dev);
140  return 0;
141 }
142 
143 /**
144  * \brief Get the number of registered devices
145  *
146  * \retval cnt the number of registered devices
147  */
149 {
150  int i = 0;
151  LiveDevice *pd;
152 
153  TAILQ_FOREACH(pd, &live_devices, next) {
154  i++;
155  }
156 
157  return i;
158 }
159 
160 /**
161  * \brief Get a pointer to the device name at idx
162  *
163  * \param number idx of the device in our list
164  *
165  * \retval ptr pointer to the string containing the device
166  * \retval NULL on error
167  */
168 const char *LiveGetDeviceName(int number)
169 {
170  int i = 0;
171  LiveDevice *pd;
172 
173  TAILQ_FOREACH(pd, &live_devices, next) {
174  if (i == number) {
175  return pd->dev;
176  }
177 
178  i++;
179  }
180 
181  return NULL;
182 }
183 
184 /** \internal
185  * \brief Shorten a device name that is to long
186  *
187  * \param device name from config and destination for modified
188  *
189  * \retval None, is added to destination char *newdevname
190  */
191 static int LiveSafeDeviceName(const char *devname, char *newdevname, size_t destlen)
192 {
193  size_t devnamelen = strlen(devname);
194 
195  /* If we have to shorten the interface name */
196  if (devnamelen > MAX_DEVNAME) {
197 
198  /* IF the dest length is over 10 chars long it will not do any
199  * good for the shortening. The shortening is done due to the
200  * max length of pthread names (15 chars) and we use 3 chars
201  * for the threadname indicator eg. "W#-" and one-two chars for
202  * the thread number. And if the destination buffer is under
203  * 6 chars there is no point in shortening it since we must at
204  * least enter two periods (.) into the string.
205  */
206  if ((destlen-1) > 10 || (destlen-1) < 6) {
207  return 1;
208  }
209 
210  size_t length;
211  size_t half;
212  size_t spaces;
213 
214  half = (destlen-1) / 2;
215 
216  /* If the destlen is an even number */
217  if (half * 2 == (destlen-1)) {
218  half = half - 1;
219  }
220 
221  spaces = (destlen-1) - (half*2);
222  length = half;
223 
224  /* Add the first half to the new dev name */
225  snprintf(newdevname, half+1, "%s", devname);
226 
227  /* Add the amount of spaces wanted */
228  for (size_t i = half; i < half+spaces; i++) {
229  length = strlcat(newdevname, ".", destlen);
230  }
231 
232  snprintf(newdevname+length, half+1, "%s", devname+(devnamelen-half));
233  SCLogInfo("Shortening device name to: %s", newdevname);
234  } else {
235  strlcpy(newdevname, devname, destlen);
236  }
237  return 0;
238 }
239 
240 /**
241  * \brief Get a pointer to the device at idx
242  *
243  * \param number idx of the device in our list
244  *
245  * \retval ptr pointer to the string containing the device
246  * \retval NULL on error
247  */
248 LiveDevice *LiveGetDevice(const char *name)
249 {
250  int i = 0;
251  LiveDevice *pd;
252 
253  if (name == NULL) {
254  SCLogWarning(SC_ERR_INVALID_VALUE, "Name of device should not be null");
255  return NULL;
256  }
257 
258  TAILQ_FOREACH(pd, &live_devices, next) {
259  if (!strcmp(name, pd->dev)) {
260  return pd;
261  }
262 
263  i++;
264  }
265 
266  return NULL;
267 }
268 
269 const char *LiveGetShortName(const char *dev)
270 {
271  LiveDevice *live_dev = LiveGetDevice(dev);
272  if (live_dev == NULL)
273  return NULL;
274  return live_dev->dev_short;
275 }
276 
277 int LiveBuildDeviceList(const char *runmode)
278 {
279  return LiveBuildDeviceListCustom(runmode, "interface");
280 }
281 
282 int LiveBuildDeviceListCustom(const char *runmode, const char *itemname)
283 {
284  ConfNode *base = ConfGetNode(runmode);
285  ConfNode *child;
286  int i = 0;
287 
288  if (base == NULL)
289  return 0;
290 
291  TAILQ_FOREACH(child, &base->head, next) {
292  ConfNode *subchild;
293  TAILQ_FOREACH(subchild, &child->head, next) {
294  if ((!strcmp(subchild->name, itemname))) {
295  if (!strcmp(subchild->val, "default"))
296  break;
297  SCLogConfig("Adding %s %s from config file",
298  itemname, subchild->val);
299  LiveRegisterDeviceName(subchild->val);
300  i++;
301  }
302  }
303  }
304 
305  return i;
306 }
307 
308 /** Call this function to disable stat on live devices
309  *
310  * This can be useful in the case, this is not a real interface.
311  */
313 {
314  live_devices_stats = 0;
315 }
316 
318 {
319  SCEnter();
320  LiveDevice *pd, *tpd;
321 
322  TAILQ_FOREACH_SAFE(pd, &live_devices, next, tpd) {
323  if (live_devices_stats) {
324  SCLogNotice("Stats for '%s': pkts: %" PRIu64", drop: %" PRIu64 " (%.2f%%), invalid chksum: %" PRIu64,
325  pd->dev,
326  SC_ATOMIC_GET(pd->pkts),
327  SC_ATOMIC_GET(pd->drop),
328  100 * (SC_ATOMIC_GET(pd->drop) * 1.0) / SC_ATOMIC_GET(pd->pkts),
329  SC_ATOMIC_GET(pd->invalid_checksums));
330  }
331 
333 
334  if (pd->dev)
335  SCFree(pd->dev);
336  SC_ATOMIC_DESTROY(pd->pkts);
337  SC_ATOMIC_DESTROY(pd->drop);
338  SC_ATOMIC_DESTROY(pd->invalid_checksums);
339  LiveDevFreeStorage(pd);
340  SCFree(pd);
341  }
342 
344 }
345 
346 #ifdef BUILD_UNIX_SOCKET
347 TmEcode LiveDeviceIfaceStat(json_t *cmd, json_t *answer, void *data)
348 {
349  SCEnter();
350  LiveDevice *pd;
351  const char * name = NULL;
352  json_t *jarg = json_object_get(cmd, "iface");
353  if(!json_is_string(jarg)) {
354  json_object_set_new(answer, "message", json_string("Iface is not a string"));
356  }
357  name = json_string_value(jarg);
358  if (name == NULL) {
359  json_object_set_new(answer, "message", json_string("Iface name is NULL"));
361  }
362 
363  TAILQ_FOREACH(pd, &live_devices, next) {
364  if (!strcmp(name, pd->dev)) {
365  json_t *jdata = json_object();
366  if (jdata == NULL) {
367  json_object_set_new(answer, "message",
368  json_string("internal error at json object creation"));
370  }
371  json_object_set_new(jdata, "pkts",
372  json_integer(SC_ATOMIC_GET(pd->pkts)));
373  json_object_set_new(jdata, "invalid-checksums",
374  json_integer(SC_ATOMIC_GET(pd->invalid_checksums)));
375  json_object_set_new(jdata, "drop",
376  json_integer(SC_ATOMIC_GET(pd->drop)));
377  json_object_set_new(jdata, "bypassed",
378  json_integer(SC_ATOMIC_GET(pd->bypassed)));
379  json_object_set_new(answer, "message", jdata);
381  }
382  }
383  json_object_set_new(answer, "message", json_string("Iface does not exist"));
385 }
386 
387 TmEcode LiveDeviceIfaceList(json_t *cmd, json_t *answer, void *data)
388 {
389  SCEnter();
390  json_t *jdata;
391  json_t *jarray;
392  LiveDevice *pd;
393  int i = 0;
394 
395  jdata = json_object();
396  if (jdata == NULL) {
397  json_object_set_new(answer, "message",
398  json_string("internal error at json object creation"));
399  return TM_ECODE_FAILED;
400  }
401  jarray = json_array();
402  if (jarray == NULL) {
403  json_object_set_new(answer, "message",
404  json_string("internal error at json object creation"));
405  return TM_ECODE_FAILED;
406  }
407  TAILQ_FOREACH(pd, &live_devices, next) {
408  json_array_append_new(jarray, json_string(pd->dev));
409  i++;
410  }
411 
412  json_object_set_new(jdata, "count", json_integer(i));
413  json_object_set_new(jdata, "ifaces", jarray);
414  json_object_set_new(answer, "message", jdata);
416 }
417 
418 #endif /* BUILD_UNIX_SOCKET */
419 
421 {
422  if (*ldev == NULL) {
423  *ldev = TAILQ_FIRST(&live_devices);
424  *ndev = TAILQ_NEXT(*ldev, next);
425  return *ldev;
426  } else {
427  *ldev = *ndev;
428  if (*ldev) {
429  *ndev = TAILQ_NEXT(*ldev, next);
430  }
431  return *ldev;
432  }
433  return NULL;
434 }
435 
436 /**
437  * Create registered devices
438  *
439  * This function creates all needed LiveDevice from
440  * the LiveDeviceName list created via LiveRegisterDevice()
441  */
443 {
444  LiveDeviceName *ld, *pld;
445  SCLogDebug("Finalize live device");
446  /* Iter on devices and register them */
447  TAILQ_FOREACH_SAFE(ld, &pre_live_devices, next, pld) {
448  if (ld->dev) {
449  LiveRegisterDevice(ld->dev);
450  SCFree(ld->dev);
451  }
452  SCFree(ld);
453  }
454 }
const char * LiveGetDeviceName(int number)
Get a pointer to the device name at idx.
Definition: util-device.c:168
#define SCLogDebug(...)
Definition: util-debug.h:335
#define TAILQ_FIRST(head)
Definition: queue.h:339
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
int LiveRegisterDevice(const char *dev)
Add a pcap device for monitoring and create structure.
Definition: util-device.c:111
struct HtpBodyChunk_ * next
LiveDevice * LiveDeviceForEach(LiveDevice **ldev, LiveDevice **ndev)
Definition: util-device.c:420
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
#define unlikely(expr)
Definition: util-optimize.h:35
void LiveDevFreeStorage(LiveDevice *d)
size_t strlcat(char *, const char *src, size_t siz)
Definition: util-strlcatu.c:45
#define TAILQ_FOREACH_SAFE(var, head, field, tvar)
Definition: queue.h:356
int LiveBuildDeviceList(const char *runmode)
Definition: util-device.c:277
unsigned int LiveDevStorageSize(void)
int LiveGetDeviceCount(void)
Get the number of registered devices.
Definition: util-device.c:148
#define TAILQ_HEAD(name, type)
Definition: queue.h:321
char * val
Definition: conf.h:34
char dev_short[MAX_DEVNAME+1]
Definition: util-device.h:42
#define SC_ATOMIC_DESTROY(name)
Destroy the lock used to protect this variable.
Definition: util-atomic.h:98
char * dev
Definition: util-device.h:41
void LiveDeviceFinalize(void)
Definition: util-device.c:442
#define SC_ATOMIC_INIT(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:82
#define SCCalloc(nm, a)
Definition: util-mem.h:205
int LiveDeviceListClean()
Definition: util-device.c:317
void LiveSetOffloadDisable(void)
#define SCEnter(...)
Definition: util-debug.h:337
#define SCReturnInt(x)
Definition: util-debug.h:341
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
Definition: util-device.c:248
#define SCLogWarning(err_code,...)
Macro used to log WARNING messages.
Definition: util-debug.h:281
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:385
Definition: conf.h:32
int ignore_checksum
Definition: util-device.h:45
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:254
#define SCFree(a)
Definition: util-mem.h:236
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:269
const char * LiveGetShortName(const char *dev)
Definition: util-device.c:269
char * name
Definition: conf.h:33
int LiveBuildDeviceListCustom(const char *runmode, const char *itemname)
Definition: util-device.c:282
#define MAX_DEVNAME
Definition: util-device.c:25
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:193
void LiveSetOffloadWarn(void)
Definition: util-device.c:61
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:176
#define SCStrdup(a)
Definition: util-mem.h:220
uint16_t length
#define TAILQ_NEXT(elm, field)
Definition: queue.h:341
void RestoreIfaceOffloading(LiveDevice *dev)
Definition: util-ioctl.c:724
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:327
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
int LiveGetOffload(void)
Definition: util-device.c:66
void LiveDeviceHasNoStats()
Definition: util-device.c:312
int LiveRegisterDeviceName(const char *dev)
Add a device for monitoring.
Definition: util-device.c:82