1 /*
2 ** Copyright (C) 2007-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  Python wrappers
11 **
12 */
13 
14 #define PY_SSIZE_T_CLEAN        /* "s#" "y#" formats must use ssize_t */
15 #include <Python.h>             /* Must be included before any system
16                                    headers */
17 #include <silk/silk.h>
18 
19 RCSIDENT("$SiLK: pysilk.c 01d273aa43de 2020-04-16 15:57:54Z mthomas $");
20 
21 #include <silk/rwrec.h>
22 #include <silk/skbag.h>
23 #include <silk/skcountry.h>
24 #include <silk/skipaddr.h>
25 #include <silk/skipset.h>
26 #include <silk/skprefixmap.h>
27 #include <silk/sksite.h>
28 #include <silk/skstream.h>
29 #include <silk/skvector.h>
30 #include <silk/utils.h>
31 #include <datetime.h>
32 #include <structmember.h>
33 #include "pysilk_common.h"
34 
35 SK_DIAGNOSTIC_IGNORE_PUSH("-Wwrite-strings")
36 SK_DIAGNOSTIC_IGNORE_PUSH("-Wcast-function-type")
37 
38 
39 /* LOCAL DEFINES AND TYPEDEFS */
40 
41 #define MAX_EPOCH (((INT64_C(1) << 31)-1)*1000) /* Tue Jan 19 03:14:07 2038 */
42 
43 #define XSTR(s) #s
44 #define STR(s) XSTR(s)
45 
46 
47 /* In Python 2.4, length()-type functions are 'inquiry's that return
48  * int.  In Python 2.5, they are 'lenfunc's that return Py_ssize_t. */
49 #if PY_VERSION_HEX < 0x02050000
50 #define Py_ssize_t     int
51 #define PY_SSIZE_T_MAX INT_MAX
52 #endif
53 
54 #define NOT_SET -9999
55 
56 #if SK_ENABLE_IPV6
57 #define UNUSED_NOv6(x) x
58 #else
59 #define UNUSED_NOv6(x) UNUSED(x)
60 #endif
61 
62 
63 #define CHECK_SITE(err)                         \
64     do {                                        \
65         if (init_site(NULL)) {                  \
66             return err;                         \
67         }                                       \
68     } while(0)
69 
70 
71 /*
72  *  ASSERT_RESULT(ar_func_args, ar_type, ar_expected);
73  *
74  *    ar_func_args  -- is a function and any arguments it requires
75  *    ar_type       -- is the type that ar_func_args returns
76  *    ar_expected   -- is the expected return value from ar_func_args
77  *
78  *    If assert() is disabled, simply call 'ar_func_args'.
79  *
80  *    If assert() is enabled, call 'ar_func_args', capture its result,
81  *    and assert() that its result is 'ar_expected'.
82  */
83 #ifdef  NDEBUG
84 /* asserts are disabled; just call the function */
85 #define ASSERT_RESULT(ar_func_args, ar_type, ar_expected)  ar_func_args
86 #else
87 #define ASSERT_RESULT(ar_func_args, ar_type, ar_expected)       \
88     do {                                                        \
89         ar_type ar_rv = (ar_func_args);                         \
90         assert(ar_rv == (ar_expected));                         \
91     } while(0)
92 #endif
93 
94 
95 typedef skBagErr_t (*silkBagModFn)(
96     skBag_t *,
97     const skBagTypedKey_t *,
98     const skBagTypedCounter_t *,
99     skBagTypedCounter_t *);
100 
101 typedef struct silkpy_globals_st {
102     PyObject *silkmod;
103     PyObject *timedelta;
104     PyObject *datetime;
105     PyObject *maxelapsed;
106     PyObject *minelapsed;
107     PyObject *epochtime;
108     PyObject *maxtime;
109     PyObject *thousand;
110     PyObject *havesite;
111     PyObject *sensors;
112     PyObject *classes;
113     PyObject *flowtypes;
114     PyObject *newrawrec;
115     PyObject *maxintipv4;
116 #if SK_ENABLE_IPV6
117     PyObject *maxintipv6;
118 #endif
119     int site_configured;
120 } silkpy_globals_t;
121 
122 
123 /* LOCAL VARIABLE DEFINITIONS */
124 
125 static  char error_buffer[1024];
126 
127 #if PY_MAJOR_VERSION >= 3
128 /* Global state for 3.0 Python is found by searching for this
129  * module */
130 static struct PyModuleDef *pysilk_module = NULL;
131 
132 #define GLOBALS                                                         \
133     ((silkpy_globals_t*)PyModule_GetState(PyState_FindModule(pysilk_module)))
134 
135 #else
136 
137 /* Global state for Pre-3.0 Python */
138 static silkpy_globals_t silkpy_globals_static;
139 
140 #define GLOBALS   (&silkpy_globals_static)
141 
142 #endif  /* #else of #if PY_MAJOR_VERSION >= 3 */
143 
144 /*    A pointer to pass as the closure to C functions that implement
145  *    multiple Python functions where some of the Python function
146  *    names are deprecated. */
147 static const char deprecated_true_str[] = "1";
148 
149 /*    Cast away the const */
150 #define deprecated_true ((void*)deprecated_true_str)
151 
152 
153 /* LOCAL FUNCTION PROTOTYPES */
154 
155 /* basic support functions */
156 static PyObject *
157 any_obj_error(
158     PyObject           *exc,
159     const char         *format,
160     PyObject           *obj);
161 #ifdef TEST_PRINTF_FORMATS
162 #define error_printf  printf
163 #else  /* TEST_PRINTF_FORMATS */
164 static int
165 error_printf(
166     const char         *fmt,
167     ...)
168     SK_CHECK_PRINTF(1, 2);
169 #endif
170 static int init_classes(void);
171 static int init_flowtypes(void);
172 static int init_sensors(void);
173 static int
174 init_silkfile_module(
175     PyObject           *mod);
176 static int
177 init_site(
178     const char         *site_file);
179 static PyObject *
180 initpysilkbase(
181     char*               name);
182 static PyObject *
183 iter_iter(
184     PyObject           *self);
185 static void
186 obj_dealloc(
187     PyObject           *obj);
188 static PyObject *
189 obj_error(
190     const char         *format,
191     PyObject           *obj);
192 static skstream_t *
193 open_silkfile_write(
194     PyObject           *args,
195     PyObject           *kwds);
196 static PyObject *
197 reduce_error(
198     PyObject           *self);
199 static int
200 silkPyDatetimeToSktime(
201     sktime_t           *silktime,
202     PyObject           *datetime);
203 #if !SK_ENABLE_IPV6
204 static PyObject *
205 silkPyNotImplemented(
206     PyObject    UNUSED(*self),
207     PyObject    UNUSED(*args),
208     PyObject    UNUSED(*kwds));
209 #endif
210 
211 
212 /* FUNCTION DEFINITIONS */
213 
214 
215 /*
216  *************************************************************************
217  *   IPAddr
218  *************************************************************************
219  */
220 
221 typedef struct silkPyIPAddr_st {
222     PyObject_HEAD
223     skipaddr_t addr;
224 } silkPyIPAddr;
225 
226 /* function prototypes */
227 static PyObject *
228 silkPyIPAddr_country_code(
229     silkPyIPAddr       *self);
230 static long
231 silkPyIPAddr_hash(
232     silkPyIPAddr       *obj);
233 static PyObject *
234 silkPyIPAddr_int(
235     silkPyIPAddr       *obj);
236 static PyObject *
237 silkPyIPAddr_is_ipv6(
238     silkPyIPAddr        UNUSED_NOv6(*self));
239 static PyObject *
240 silkPyIPAddr_isipv6_deprecated(
241     silkPyIPAddr       *self);
242 static PyObject *
243 silkPyIPAddr_mask(
244     silkPyIPAddr       *self,
245     PyObject           *mask);
246 static PyObject *
247 silkPyIPAddr_mask_prefix(
248     silkPyIPAddr       *self,
249     PyObject           *prefix);
250 static PyObject *
251 silkPyIPAddr_new(
252     PyTypeObject       *type,
253     PyObject           *args,
254     PyObject           *kwds);
255 static PyObject *
256 silkPyIPAddr_octets(
257     silkPyIPAddr       *self);
258 static PyObject *
259 silkPyIPAddr_padded(
260     silkPyIPAddr       *obj);
261 static PyObject *
262 silkPyIPAddr_repr(
263     silkPyIPAddr       *obj);
264 static PyObject *
265 silkPyIPAddr_richcompare(
266     silkPyIPAddr       *self,
267     PyObject           *obj,
268     int                 cmp);
269 static int
270 silkPyIPAddr_setup(
271     PyObject           *mod);
272 static PyObject *
273 silkPyIPAddr_str(
274     silkPyIPAddr       *obj);
275 static PyObject *
276 silkPyIPAddr_to_ipv4(
277     PyObject           *self);
278 #if SK_ENABLE_IPV6
279 static PyObject *
280 silkPyIPAddr_to_ipv6(
281     PyObject           *self);
282 #endif
283 static int
284 silkPyIPv4Addr_init(
285     silkPyIPAddr       *self,
286     PyObject           *args,
287     PyObject           *kwds);
288 static PyObject *
289 silkPyIPv4Addr_new(
290     PyTypeObject       *type,
291     PyObject           *args,
292     PyObject           *kwds);
293 static int
294 silkPyIPv6Addr_init(
295     silkPyIPAddr       *self,
296     PyObject           *args,
297     PyObject           *kwds);
298 #if SK_ENABLE_IPV6
299 static PyObject *
300 silkPyIPv6Addr_new(
301     PyTypeObject       *type,
302     PyObject           *args,
303     PyObject           *kwds);
304 #endif
305 static PyObject *
306 silkPyIPvXAddr_new(
307     PyTypeObject       *basetype,
308     PyTypeObject       *type,
309     PyObject           *args,
310     PyObject           *kwds);
311 
312 /* define docs and methods */
313 #define silkPyIPAddr_doc                        \
314     "IPAddr(string) -> ip address\n"            \
315     "IPAddr(ipaddr) -> copy of ip address"
316 
317 #define silkPyIPv4Addr_doc                                      \
318     "IPv4Addr(string) -> IPv4 address\n"                        \
319     "IPv4Addr(int) -> IPv4 address\n"                           \
320     "IPv4Addr(IPV6Addr) -> IPv4 from IPv4 in IPv6 address\n"    \
321     "IPv4Addr(IPv4Addr) -> copy of ip address"
322 
323 #define silkPyIPv6Addr_doc                              \
324     "IPv6Addr(string) -> IPv6 address\n"                \
325     "IPv6Addr(int) -> IPv6 address\n"                   \
326     "IPv6Addr(IPV4Addr) -> IPv4 in IPv6 address\n"      \
327     "IPv6Addr(IPv6Addr) -> copy of ip address"
328 
329 static PyNumberMethods silkPyIPAddr_number_methods;
330 
331 static PyMethodDef silkPyIPAddr_methods[] = {
332     {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
333     {"isipv6", (PyCFunction)silkPyIPAddr_isipv6_deprecated, METH_NOARGS,
334      ("addr.isipv6() -> bool -- return whether addr is an IPv6 address."
335       " DEPRECATED Use addr.is_ipv6() instead.")},
336     {"is_ipv6", (PyCFunction)silkPyIPAddr_is_ipv6, METH_NOARGS,
337      "addr.is_ipv6() -> bool -- return whether addr is an IPv6 address"},
338     {"to_ipv6", (PyCFunction)
339 #if SK_ENABLE_IPV6
340      silkPyIPAddr_to_ipv6, METH_NOARGS,
341 #else
342      silkPyNotImplemented, METH_VARARGS | METH_KEYWORDS,
343 #endif
344      "addr.to_ipv6() -- return addr converted to an IPv6 address"},
345     {"to_ipv4", (PyCFunction)silkPyIPAddr_to_ipv4, METH_NOARGS,
346      "addr.to_ipv4() -- return addr converted to an IPv4 address"},
347     {"padded", (PyCFunction)silkPyIPAddr_padded, METH_NOARGS,
348      "addr.padded() -> str -- return zero-padded IP string"},
349     {"mask", (PyCFunction)silkPyIPAddr_mask, METH_O,
350      "addr.mask(addr2) -> addr3 -- return addr masked by addr2"},
351     {"mask_prefix", (PyCFunction)silkPyIPAddr_mask_prefix, METH_O,
352      ("addr.mask(prefix) -> addr2 -- "
353       "return addr masked by the top prefix bits")},
354     {"country_code", (PyCFunction)silkPyIPAddr_country_code, METH_NOARGS,
355      "addr.country_code() -> string -- 2-character country code"},
356     {"octets", (PyCFunction)silkPyIPAddr_octets, METH_NOARGS,
357      ("addr.octets() = (o1, o2 ...) -- "
358       "return the octets of addr as a tuple")},
359     {NULL, NULL, 0, NULL}       /* Sentinel */
360 };
361 
362 /* define the object types */
363 static PyTypeObject silkPyIPAddrType = {
364     PyVarObject_HEAD_INIT(NULL, 0)
365     "silk.IPAddr",              /* tp_name */
366     sizeof(silkPyIPAddr),       /* tp_basicsize */
367     0,                          /* tp_itemsize */
368     obj_dealloc,                /* tp_dealloc */
369     0,                          /* tp_vectorcall_offset (Py 3.8) */
370     0,                          /* tp_getattr */
371     0,                          /* tp_setattr */
372     0,                          /* tp_as_async (tp_compare in Py2.x) */
373     (reprfunc)silkPyIPAddr_repr, /* tp_repr */
374     &silkPyIPAddr_number_methods, /* tp_as_number */
375     0,                          /* tp_as_sequence */
376     0,                          /* tp_as_mapping */
377     (hashfunc)silkPyIPAddr_hash, /* tp_hash  */
378     0,                          /* tp_call */
379     (reprfunc)silkPyIPAddr_str, /* tp_str */
380     0,                          /* tp_getattro */
381     0,                          /* tp_setattro */
382     0,                          /* tp_as_buffer */
383 #if PY_MAJOR_VERSION < 3
384     Py_TPFLAGS_HAVE_RICHCOMPARE |
385 #endif
386     Py_TPFLAGS_DEFAULT,         /* tp_flags */
387     silkPyIPAddr_doc,           /* tp_doc */
388     0,                          /* tp_traverse */
389     0,                          /* tp_clear */
390     (richcmpfunc)silkPyIPAddr_richcompare, /* tp_richcompare */
391     0,                          /* tp_weaklistoffset */
392     0,                          /* tp_iter */
393     0,                          /* tp_iternext */
394     silkPyIPAddr_methods,       /* tp_methods */
395     0,                          /* tp_members */
396     0,                          /* tp_getset */
397     0,                          /* tp_base */
398     0,                          /* tp_dict */
399     0,                          /* tp_descr_get */
400     0,                          /* tp_descr_set */
401     0,                          /* tp_dictoffset */
402     0,                          /* tp_init */
403     0,                          /* tp_alloc */
404     silkPyIPAddr_new,           /* tp_new */
405     0,                          /* tp_free */
406     0,                          /* tp_is_gc */
407     0,                          /* tp_bases */
408     0,                          /* tp_mro */
409     0,                          /* tp_cache */
410     0,                          /* tp_subclasses */
411     0,                          /* tp_weaklist */
412     0                           /* tp_del */
413 #if PY_VERSION_HEX >= 0x02060000
414     ,0                          /* tp_version_tag */
415 #endif
416 #if PY_VERSION_HEX >= 0x03040000
417     ,0                          /* tp_finalize */
418 #endif
419 #if PY_VERSION_HEX >= 0x03080000
420     ,0                          /* tp_vectorcall */
421     ,0                          /* tp_print */
422 #endif
423 };
424 
425 static PyTypeObject silkPyIPv4AddrType = {
426     PyVarObject_HEAD_INIT(NULL, 0)
427     "silk.IPv4Addr",            /* tp_name */
428     0,                          /* tp_basicsize */
429     0,                          /* tp_itemsize */
430     0,                          /* tp_dealloc */
431     0,                          /* tp_vectorcall_offset (Py 3.8) */
432     0,                          /* tp_getattr */
433     0,                          /* tp_setattr */
434     0,                          /* tp_as_async (tp_compare in Py2.x) */
435     0,                          /* tp_repr */
436     0,                          /* tp_as_number */
437     0,                          /* tp_as_sequence */
438     0,                          /* tp_as_mapping */
439     0,                          /* tp_hash  */
440     0,                          /* tp_call */
441     0,                          /* tp_str */
442     0,                          /* tp_getattro */
443     0,                          /* tp_setattro */
444     0,                          /* tp_as_buffer */
445     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
446     silkPyIPv4Addr_doc,         /* tp_doc */
447     0,                          /* tp_traverse */
448     0,                          /* tp_clear */
449     0,                          /* tp_richcompare */
450     0,                          /* tp_weaklistoffset */
451     0,                          /* tp_iter */
452     0,                          /* tp_iternext */
453     0,                          /* tp_methods */
454     0,                          /* tp_members */
455     0,                          /* tp_getset */
456     &silkPyIPAddrType,          /* tp_base */
457     0,                          /* tp_dict */
458     0,                          /* tp_descr_get */
459     0,                          /* tp_descr_set */
460     0,                          /* tp_dictoffset */
461     (initproc)silkPyIPv4Addr_init, /* tp_init */
462     0,                          /* tp_alloc */
463     silkPyIPv4Addr_new,         /* tp_new */
464     0,                          /* tp_free */
465     0,                          /* tp_is_gc */
466     0,                          /* tp_bases */
467     0,                          /* tp_mro */
468     0,                          /* tp_cache */
469     0,                          /* tp_subclasses */
470     0,                          /* tp_weaklist */
471     0                           /* tp_del */
472 #if PY_VERSION_HEX >= 0x02060000
473     ,0                          /* tp_version_tag */
474 #endif
475 #if PY_VERSION_HEX >= 0x03040000
476     ,0                          /* tp_finalize */
477 #endif
478 #if PY_VERSION_HEX >= 0x03080000
479     ,0                          /* tp_vectorcall */
480     ,0                          /* tp_print */
481 #endif
482 };
483 
484 static PyTypeObject silkPyIPv6AddrType = {
485     PyVarObject_HEAD_INIT(NULL, 0)
486     "silk.IPv6Addr",            /* tp_name */
487     0,                          /* tp_basicsize */
488     0,                          /* tp_itemsize */
489     0,                          /* tp_dealloc */
490     0,                          /* tp_vectorcall_offset (Py 3.8) */
491     0,                          /* tp_getattr */
492     0,                          /* tp_setattr */
493     0,                          /* tp_as_async (tp_compare in Py2.x) */
494     0,                          /* tp_repr */
495     0,                          /* tp_as_number */
496     0,                          /* tp_as_sequence */
497     0,                          /* tp_as_mapping */
498     0,                          /* tp_hash  */
499     0,                          /* tp_call */
500     0,                          /* tp_str */
501     0,                          /* tp_getattro */
502     0,                          /* tp_setattro */
503     0,                          /* tp_as_buffer */
504     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
505     silkPyIPv6Addr_doc,         /* tp_doc */
506     0,                          /* tp_traverse */
507     0,                          /* tp_clear */
508     0,                          /* tp_richcompare */
509     0,                          /* tp_weaklistoffset */
510     0,                          /* tp_iter */
511     0,                          /* tp_iternext */
512     0,                          /* tp_methods */
513     0,                          /* tp_members */
514     0,                          /* tp_getset */
515     &silkPyIPAddrType,          /* tp_base */
516     0,                          /* tp_dict */
517     0,                          /* tp_descr_get */
518     0,                          /* tp_descr_set */
519     0,                          /* tp_dictoffset */
520     (initproc)silkPyIPv6Addr_init, /* tp_init */
521     0,                          /* tp_alloc */
522 #if SK_ENABLE_IPV6
523     silkPyIPv6Addr_new,         /* tp_new */
524 #else
525     (newfunc)silkPyNotImplemented, /* tp_new */
526 #endif
527     0,                          /* tp_free */
528     0,                          /* tp_is_gc */
529     0,                          /* tp_bases */
530     0,                          /* tp_mro */
531     0,                          /* tp_cache */
532     0,                          /* tp_subclasses */
533     0,                          /* tp_weaklist */
534     0                           /* tp_del */
535 #if PY_VERSION_HEX >= 0x02060000
536     ,0                          /* tp_version_tag */
537 #endif
538 #if PY_VERSION_HEX >= 0x03040000
539     ,0                          /* tp_finalize */
540 #endif
541 #if PY_VERSION_HEX >= 0x03080000
542     ,0                          /* tp_vectorcall */
543     ,0                          /* tp_print */
544 #endif
545 };
546 
547 /* macro and function defintions */
548 #define silkPyIPAddr_Check(op)                  \
549     PyObject_TypeCheck(op, &silkPyIPAddrType)
550 #define silkPyIPv4Addr_Check(op)                \
551     PyObject_TypeCheck(op, &silkPyIPv4AddrType)
552 #define silkPyIPv6Addr_Check(op)                \
553     PyObject_TypeCheck(op, &silkPyIPv6AddrType)
554 
555 static PyObject *
silkPyIPAddr_country_code(silkPyIPAddr * self)556 silkPyIPAddr_country_code(
557     silkPyIPAddr       *self)
558 {
559     char name[3];
560     sk_countrycode_t code;
561     int rv;
562 
563     rv = skCountrySetup(NULL, error_printf);
564     if (rv != 0) {
565         PyErr_SetString(PyExc_RuntimeError, error_buffer);
566         return NULL;
567     }
568 
569     code = skCountryLookupCode(&self->addr);
570     if (code == SK_COUNTRYCODE_INVALID) {
571         Py_RETURN_NONE;
572     }
573 
574     return PyUnicode_FromString(skCountryCodeToName(code, name, sizeof(name)));
575 }
576 
577 static long
silkPyIPAddr_hash(silkPyIPAddr * obj)578 silkPyIPAddr_hash(
579     silkPyIPAddr       *obj)
580 {
581     long retval;
582 #if SK_ENABLE_IPV6
583     if (skipaddrIsV6(&obj->addr)) {
584         uint8_t v6[16];
585         skipaddrGetAsV6(&obj->addr, v6);
586 #if SK_SIZEOF_LONG == 8
587         retval = *(long*)(&v6[8]);
588 #else  /* SK_SIZEOF_LONG */
589         /* Assume long is 4 bytes */
590         retval = *(long*)(&v6[12]);
591 #endif  /* SK_SIZEOF_LONG */
592         return retval;
593     }
594 #endif  /* SK_ENABLE_IPV6 */
595     retval = skipaddrGetV4(&obj->addr);
596     if (retval == -1) {
597         retval = 0;
598     }
599     return retval;
600 }
601 
602 static PyObject *
silkPyIPAddr_int(silkPyIPAddr * obj)603 silkPyIPAddr_int(
604     silkPyIPAddr       *obj)
605 {
606     PyObject *result;
607 
608 #if SK_ENABLE_IPV6
609     if (skipaddrIsV6(&obj->addr)) {
610         char      buf[33];
611         char     *p;
612         int       i;
613         uint32_t *v6;
614 
615         p = buf;
616         v6 = (uint32_t*)obj->addr.ip_ip.ipu_ipv6;
617         for (i = 0; i < 4; i++) {
618             sprintf(p, "%08" PRIx32, ntohl(*v6));
619             p += 8;
620             ++v6;
621         }
622         result = PyLong_FromString(buf, NULL, 16);
623     } else
624 #endif  /* SK_ENABLE_IPV6 */
625     {
626         result = PyLong_FromUnsignedLong(skipaddrGetV4(&obj->addr));
627     }
628 
629     return result;
630 }
631 
632 static PyObject *
silkPyIPAddr_is_ipv6(silkPyIPAddr UNUSED_NOv6 (* self))633 silkPyIPAddr_is_ipv6(
634     silkPyIPAddr        UNUSED_NOv6(*self))
635 {
636 #if SK_ENABLE_IPV6
637     return PyBool_FromLong(skipaddrIsV6(&self->addr));
638 #else
639     Py_RETURN_FALSE;
640 #endif
641 }
642 
643 static PyObject *
silkPyIPAddr_isipv6_deprecated(silkPyIPAddr * self)644 silkPyIPAddr_isipv6_deprecated(
645     silkPyIPAddr       *self)
646 {
647     /* deprecated in SiLK-2.2.0 */
648     PyErr_Warn(PyExc_DeprecationWarning,
649                ("IPAddr.isipv6() is deprecated.  "
650                 "Use IPAddr.is_ipv6() instead."));
651     return silkPyIPAddr_is_ipv6(self);
652 }
653 
654 static PyObject *
silkPyIPAddr_mask(silkPyIPAddr * self,PyObject * mask)655 silkPyIPAddr_mask(
656     silkPyIPAddr       *self,
657     PyObject           *mask)
658 {
659     silkPyIPAddr *retval;
660     skipaddr_t addr;
661     PyTypeObject *type;
662 
663     if (!silkPyIPAddr_Check(mask)) {
664         PyErr_SetString(PyExc_TypeError, "Argument must be an IPAddr");
665         return NULL;
666     }
667 
668     skipaddrCopy(&addr, &self->addr);
669     skipaddrMask(&addr, &((silkPyIPAddr*)mask)->addr);
670 #if SK_ENABLE_IPV6
671     if (skipaddrIsV6(&addr)) {
672         type = &silkPyIPv6AddrType;
673     } else
674 #endif
675     {
676         type = &silkPyIPv4AddrType;
677     }
678     retval = PyObject_New(silkPyIPAddr, type);
679     if (retval == NULL) {
680         return NULL;
681     }
682     skipaddrCopy(&retval->addr, &addr);
683 
684     return (PyObject*)retval;
685 }
686 
687 static PyObject *
silkPyIPAddr_mask_prefix(silkPyIPAddr * self,PyObject * prefix)688 silkPyIPAddr_mask_prefix(
689     silkPyIPAddr       *self,
690     PyObject           *prefix)
691 {
692     silkPyIPAddr *retval;
693     PyTypeObject *type;
694     long p;
695     int max;
696 
697     if (!IS_INT(prefix)) {
698         PyErr_SetString(PyExc_TypeError, "Prefix must be an integer");
699         return NULL;
700     }
701 
702 #if SK_ENABLE_IPV6
703     if (skipaddrIsV6(&self->addr)) {
704         type = &silkPyIPv6AddrType;
705         max = 128;
706     } else
707 #endif
708     {
709         type = &silkPyIPv4AddrType;
710         max = 32;
711     }
712 
713     p = PyInt_AsLong(prefix);
714     if (PyErr_Occurred()) {
715         return NULL;
716     }
717 
718     if (p < 0 || p > max) {
719         return PyErr_Format(PyExc_ValueError,
720                             "Prefix must be between 0 and %d", max);
721     }
722 
723     retval = PyObject_New(silkPyIPAddr, type);
724     if (retval == NULL) {
725         return NULL;
726     }
727 
728     skipaddrCopy(&retval->addr, &self->addr);
729     skipaddrApplyCIDR(&retval->addr, p);
730 
731     return (PyObject*)retval;
732 }
733 
734 static PyObject *
silkPyIPAddr_new(PyTypeObject * type,PyObject * args,PyObject * kwds)735 silkPyIPAddr_new(
736     PyTypeObject       *type,
737     PyObject           *args,
738     PyObject           *kwds)
739 {
740     static char  *kwlist[] = {"address", NULL};
741     silkPyIPAddr *self;
742     PyObject     *o;
743 
744     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &o)) {
745         return NULL;
746     }
747 
748     if (Py_TYPE(o) == &silkPyIPv4AddrType ||
749         Py_TYPE(o) == &silkPyIPv6AddrType)
750     {
751         /* IPv{4,6}Addr objects are immutable, so just incref*/
752         Py_INCREF(o);
753         return o;
754     }
755     if (silkPyIPAddr_Check(o)) {
756         /* Unknown subclass of IPAddr, do a real copy */
757         if (type == &silkPyIPAddrType) {
758 #if SK_ENABLE_IPV6
759             if (skipaddrIsV6(&((silkPyIPAddr*)o)->addr)) {
760                 type = &silkPyIPv6AddrType;
761             } else
762 #endif
763             {
764                 type = &silkPyIPv4AddrType;
765             }
766         }
767     } else if (IS_STRING(o)) {
768         PyObject *bytes = bytes_from_string(o);
769         const char *straddr;
770         const char *c;
771 
772         if (bytes == NULL) {
773             return NULL;
774         }
775 
776         straddr = PyBytes_AS_STRING(bytes);
777         c = strchr(straddr, ':');
778         if (c) {
779             type = &silkPyIPv6AddrType;
780         } else {
781             type = &silkPyIPv4AddrType;
782         }
783         Py_DECREF(bytes);
784     } else if (IS_INT(o)) {
785         /* The IPAddr(int) constructor is deprecated as of SiLK 2.2.0 */
786         int rv = PyErr_Warn(PyExc_DeprecationWarning,
787                             ("IPAddr(int) is deprecated.  Use IPv4Addr(int) "
788                              "or IPv6Addr(int) instead."));
789         if (rv) {
790             return NULL;
791         }
792         type = &silkPyIPv4AddrType;
793 
794     } else {
795         return PyErr_Format(PyExc_TypeError, "Must be a string or IPAddr");
796     }
797 
798     /* Allocate the object */
799     self = (silkPyIPAddr*)type->tp_alloc(type, 0);
800     if (self == NULL) {
801         return NULL;
802     }
803 
804     return (PyObject*)self;
805 }
806 
807 static PyObject *
silkPyIPAddr_octets(silkPyIPAddr * self)808 silkPyIPAddr_octets(
809     silkPyIPAddr       *self)
810 {
811     PyObject *retval;
812     PyObject *octet;
813     int i;
814 
815 #if SK_ENABLE_IPV6
816     if (skipaddrIsV6(&self->addr)) {
817         uint8_t v6[16];
818         retval = PyTuple_New(16);
819         if (retval == NULL) {
820             return NULL;
821         }
822         skipaddrGetV6(&self->addr, v6);
823 
824         for (i = 0; i < 16; i++) {
825             octet = PyInt_FromLong(v6[i]);
826             if (octet == NULL) {
827                 Py_DECREF(retval);
828                 return NULL;
829             }
830             PyTuple_SET_ITEM(retval, i, octet);
831         }
832     } else
833 #endif
834     {
835         uint32_t v4 = skipaddrGetV4(&self->addr);
836         retval = PyTuple_New(4);
837         if (retval == NULL) {
838             return NULL;
839         }
840 
841         for (i = 3; i >= 0; i--) {
842             octet = PyInt_FromLong(v4 & 0xff);
843             if (octet == NULL) {
844                 Py_DECREF(retval);
845                 return NULL;
846             }
847             PyTuple_SET_ITEM(retval, i, octet);
848             v4 >>= 8;
849         }
850     }
851 
852     return retval;
853 }
854 
855 static PyObject *
silkPyIPAddr_padded(silkPyIPAddr * obj)856 silkPyIPAddr_padded(
857     silkPyIPAddr       *obj)
858 {
859     char buf[SKIPADDR_STRLEN];
860 
861     skipaddrString(buf, &obj->addr, SKIPADDR_ZEROPAD);
862     return PyUnicode_FromString(buf);
863 }
864 
865 static PyObject *
silkPyIPAddr_repr(silkPyIPAddr * obj)866 silkPyIPAddr_repr(
867     silkPyIPAddr       *obj)
868 {
869     char buf[SKIPADDR_STRLEN];
870     PyTypeObject *type;
871 
872     type = Py_TYPE(obj);
873     if (type == NULL) {
874         return NULL;
875     }
876 
877     skipaddrString(buf, &obj->addr, SKIPADDR_CANONICAL);
878     return PyUnicode_FromFormat("%s('%s')", type->tp_name, buf);
879 }
880 
881 static PyObject *
silkPyIPAddr_richcompare(silkPyIPAddr * self,PyObject * obj,int cmp)882 silkPyIPAddr_richcompare(
883     silkPyIPAddr       *self,
884     PyObject           *obj,
885     int                 cmp)
886 {
887     int rv;
888     silkPyIPAddr *other;
889 
890     if (!silkPyIPAddr_Check(obj)) {
891         PyErr_SetString(PyExc_TypeError, "Expected silk.IPAddr");
892         return NULL;
893     }
894     other = (silkPyIPAddr*)obj;
895     rv = skipaddrCompare(&self->addr, &other->addr);
896     if (rv < 0) {
897         return PyBool_FromLong(cmp == Py_LT || cmp == Py_LE || cmp == Py_NE);
898     }
899     if (rv > 0) {
900         return PyBool_FromLong(cmp == Py_GT || cmp == Py_GE || cmp == Py_NE);
901     }
902     return PyBool_FromLong(cmp == Py_EQ || cmp == Py_LE || cmp == Py_GE);
903 }
904 
905 static int
silkPyIPAddr_setup(PyObject * mod)906 silkPyIPAddr_setup(
907     PyObject           *mod)
908 {
909     /* Setup number methods */
910     memset(&silkPyIPAddr_number_methods, 0,
911            sizeof(silkPyIPAddr_number_methods));
912     silkPyIPAddr_number_methods.nb_int = (unaryfunc)silkPyIPAddr_int;
913 #if PY_MAJOR_VERSION < 3
914     silkPyIPAddr_number_methods.nb_long = (unaryfunc)silkPyIPAddr_int;
915 #endif
916 
917     /* Initialize type and add to module */
918     if (PyType_Ready(&silkPyIPAddrType) < 0) {
919         return -1;
920     }
921     return PyModule_AddObject(mod, "IPAddr", (PyObject*)&silkPyIPAddrType);
922 }
923 
924 static PyObject *
silkPyIPAddr_str(silkPyIPAddr * obj)925 silkPyIPAddr_str(
926     silkPyIPAddr       *obj)
927 {
928     char buf[SKIPADDR_STRLEN];
929 
930     skipaddrString(buf, &obj->addr, SKIPADDR_CANONICAL);
931     return PyUnicode_FromString(buf);
932 }
933 
934 static PyObject *
silkPyIPAddr_to_ipv4(PyObject * self)935 silkPyIPAddr_to_ipv4(
936     PyObject           *self)
937 {
938 #if SK_ENABLE_IPV6
939     PyObject *obj;
940 
941     obj = PyObject_CallFunctionObjArgs((PyObject*)&silkPyIPv4AddrType,
942                                        self, NULL);
943     if (obj == NULL) {
944         if (PyErr_ExceptionMatches(PyExc_ValueError)) {
945             PyErr_Clear();
946             Py_RETURN_NONE;
947         }
948     }
949 
950     return obj;
951 #else  /* SK_ENABLE_IPV6 */
952     Py_INCREF(self);
953     return self;
954 #endif  /* SK_ENABLE_IPV6 */
955 }
956 
957 #if SK_ENABLE_IPV6
958 static PyObject *
silkPyIPAddr_to_ipv6(PyObject * self)959 silkPyIPAddr_to_ipv6(
960     PyObject           *self)
961 {
962     return PyObject_CallFunctionObjArgs((PyObject*)&silkPyIPv6AddrType,
963                                         self, NULL);
964 }
965 #endif  /* SK_ENABLE_IPV6 */
966 
967 static int
silkPyIPv4Addr_init(silkPyIPAddr * self,PyObject * args,PyObject * kwds)968 silkPyIPv4Addr_init(
969     silkPyIPAddr       *self,
970     PyObject           *args,
971     PyObject           *kwds)
972 {
973     static char  *kwlist[] = {"address", NULL};
974     PyObject     *addr;
975     int           rv;
976 
977     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &addr)) {
978         return -1;
979     }
980 
981     if (addr == (PyObject*)self) {
982         /* We were initialized by new */
983         return 0;
984     }
985 
986     if (IS_STRING(addr)) {
987         PyObject *bytes;
988         bytes = bytes_from_string(addr);
989         if (bytes == NULL) {
990             return -1;
991         }
992         rv = skStringParseIP(&self->addr, PyBytes_AS_STRING(bytes));
993         Py_DECREF(bytes);
994         if (rv != 0) {
995             PyErr_SetString(PyExc_ValueError,
996                             "String is not a valid IP address");
997             return -1;
998         }
999 #if SK_ENABLE_IPV6
1000         if (skipaddrIsV6(&self->addr)) {
1001             PyErr_SetString(PyExc_ValueError,
1002                             "String is not a valid IPv4 address");
1003             return -1;
1004         }
1005 #endif
1006     } else if (IS_INT(addr)) {
1007         uint32_t value;
1008         PyObject *num;
1009 
1010         num = PyLong_FromLong(0);
1011         rv = PyObject_RichCompareBool(addr, num, Py_LT);
1012         Py_DECREF(num);
1013         if (rv) {
1014             /* Negative */
1015             PyErr_SetString(PyExc_ValueError,
1016                             "Illegal IPv4 address (negative)");
1017             return -1;
1018         }
1019         rv = PyObject_RichCompareBool(addr, GLOBALS->maxintipv4, Py_GT);
1020         if (rv) {
1021             PyErr_SetString(PyExc_ValueError,
1022                             "Illegal IPv4 address (integer too large)");
1023             return -1;
1024         }
1025 
1026         value = PyLong_AsUnsignedLong(addr);
1027         skipaddrSetV4(&self->addr, &value);
1028 
1029 #if SK_ENABLE_IPV6
1030     } else if (silkPyIPv6Addr_Check(addr)) {
1031         /* Convert to v4 */
1032         silkPyIPAddr *v6addr = (silkPyIPAddr*)addr;
1033 
1034         if (skipaddrV6toV4(&v6addr->addr, &self->addr)) {
1035             PyErr_SetString(PyExc_ValueError,
1036                             "IP address not convertable to IPv4.");
1037             return -1;
1038         }
1039 #endif  /* SK_ENABLE_IPV6 */
1040 
1041     } else if (silkPyIPv4Addr_Check(addr)) {
1042         /* Copy */
1043         skipaddrCopy(&self->addr, &((silkPyIPAddr*)addr)->addr);
1044     } else {
1045         PyErr_SetString(PyExc_TypeError, "Must be a string or integer");
1046         return -1;
1047     }
1048 
1049     return 0;
1050 }
1051 
1052 static PyObject *
silkPyIPv4Addr_new(PyTypeObject * type,PyObject * args,PyObject * kwds)1053 silkPyIPv4Addr_new(
1054     PyTypeObject       *type,
1055     PyObject           *args,
1056     PyObject           *kwds)
1057 {
1058     return silkPyIPvXAddr_new(&silkPyIPv4AddrType, type, args, kwds);
1059 }
1060 
1061 static int
silkPyIPv6Addr_init(silkPyIPAddr * self,PyObject * args,PyObject * kwds)1062 silkPyIPv6Addr_init(
1063     silkPyIPAddr       *self,
1064     PyObject           *args,
1065     PyObject           *kwds)
1066 {
1067 #if !SK_ENABLE_IPV6
1068     silkPyNotImplemented((PyObject*)self, args, kwds);
1069     return -1;
1070 #else  /* if SK_ENABLE_IPV6 */
1071     static char  *kwlist[] = {"address", NULL};
1072     PyObject     *addr;
1073     int           rv;
1074 
1075     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &addr)) {
1076         return -1;
1077     }
1078 
1079     if (addr == (PyObject*)self) {
1080         /* We were initialized by new */
1081         return 0;
1082     }
1083 
1084     if (IS_STRING(addr)) {
1085         PyObject *bytes = bytes_from_string(addr);
1086         if (bytes == NULL) {
1087             return -1;
1088         }
1089         rv = skStringParseIP(&self->addr, PyBytes_AS_STRING(bytes));
1090         Py_DECREF(bytes);
1091         if (rv != 0) {
1092             PyErr_SetString(PyExc_ValueError,
1093                             "String is not a valid IP address");
1094             return -1;
1095         }
1096         if (!skipaddrIsV6(&self->addr)) {
1097             PyErr_SetString(PyExc_ValueError,
1098                             "String is not a valid IPv6 address");
1099             return -1;
1100         }
1101     } else if (IS_INT(addr)) {
1102         uint8_t   v6[16];
1103         uint32_t *v6_32;
1104         PyObject *next;
1105         PyObject *shift;
1106         PyObject *num;
1107         int i;
1108 
1109         num = PyLong_FromLong(0);
1110         rv = PyObject_RichCompareBool(addr, num, Py_LT);
1111         Py_DECREF(num);
1112         if (rv) {
1113             /* Negative */
1114             PyErr_SetString(PyExc_ValueError,
1115                             "Illegal IPv6 address (negative)");
1116             return -1;
1117         }
1118         rv = PyObject_RichCompareBool(addr, GLOBALS->maxintipv6, Py_GT);
1119         if (rv) {
1120             PyErr_SetString(PyExc_ValueError,
1121                             "Illegal IPv6 address (integer too large)");
1122             return -1;
1123         }
1124 
1125         /* Set IP */
1126         shift = PyLong_FromLong(32);
1127         v6_32 = (uint32_t*)v6 + 3;
1128 
1129         next = addr;
1130         Py_INCREF(next);
1131         for (i = 0; i < 4; i++, v6_32--) {
1132             PyObject *tmp;
1133 
1134             tmp = PyNumber_And(next, GLOBALS->maxintipv4);
1135             *v6_32 = htonl(PyLong_AsUnsignedLong(tmp));
1136             Py_DECREF(tmp);
1137             tmp = next;
1138             next = PyNumber_Rshift(tmp, shift);
1139             Py_DECREF(tmp);
1140         }
1141         Py_DECREF(next);
1142         Py_DECREF(shift);
1143         skipaddrSetV6(&self->addr, v6);
1144 
1145     } else if (silkPyIPv4Addr_Check(addr)) {
1146         /* Convert to v6 */
1147         silkPyIPAddr *v4addr = (silkPyIPAddr*)addr;
1148 
1149         if (skipaddrIsV6(&v4addr->addr)) {
1150             skipaddrCopy(&self->addr, &v4addr->addr);
1151         } else {
1152             skipaddrV4toV6(&v4addr->addr, &self->addr);
1153         }
1154 
1155     } else if (silkPyIPv6Addr_Check(addr)) {
1156         /* Copy */
1157         skipaddrCopy(&self->addr, &((silkPyIPAddr*)addr)->addr);
1158     } else {
1159         PyErr_SetString(PyExc_TypeError, "Must be a string or integer");
1160         return -1;
1161     }
1162 
1163     return 0;
1164 #endif  /* else of !SK_ENABLE_IPV6 */
1165 }
1166 
1167 #if SK_ENABLE_IPV6
1168 static PyObject *
silkPyIPv6Addr_new(PyTypeObject * type,PyObject * args,PyObject * kwds)1169 silkPyIPv6Addr_new(
1170     PyTypeObject       *type,
1171     PyObject           *args,
1172     PyObject           *kwds)
1173 {
1174     return silkPyIPvXAddr_new(&silkPyIPv6AddrType, type, args, kwds);
1175 }
1176 #endif  /* SK_ENABLE_IPV6 */
1177 
1178 static PyObject *
silkPyIPvXAddr_new(PyTypeObject * basetype,PyTypeObject * type,PyObject * args,PyObject * kwds)1179 silkPyIPvXAddr_new(
1180     PyTypeObject       *basetype,
1181     PyTypeObject       *type,
1182     PyObject           *args,
1183     PyObject           *kwds)
1184 {
1185     static char  *kwlist[] = {"address", NULL};
1186     PyObject   *self;
1187     PyObject   *o;
1188 
1189     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &o)) {
1190         return NULL;
1191     }
1192 
1193     if (type == basetype && Py_TYPE(o) == basetype) {
1194         Py_INCREF(o);
1195         return o;
1196     }
1197 
1198     self = type->tp_alloc(type, 0);
1199     return self;
1200 }
1201 
1202 
1203 /*
1204  *************************************************************************
1205  *   IPWildcard
1206  *************************************************************************
1207  */
1208 
1209 typedef struct silkPyIPWildcard_st {
1210     PyObject_HEAD
1211     skIPWildcard_t  wildcard;
1212     PyObject       *name;
1213 } silkPyIPWildcard;
1214 
1215 typedef struct silkPyIPWildcardIter_st {
1216     PyObject_HEAD
1217     silkPyIPWildcard       *wildcard;
1218     skIPWildcardIterator_t  iter;
1219 } silkPyIPWildcardIter;
1220 
1221 /* function prototypes */
1222 static void
1223 silkPyIPWildcardIter_dealloc(
1224     silkPyIPWildcardIter   *self);
1225 static PyObject *
1226 silkPyIPWildcardIter_iternext(
1227     silkPyIPWildcardIter   *self);
1228 static int
1229 silkPyIPWildcard_contains(
1230     silkPyIPWildcard   *self,
1231     PyObject           *obj);
1232 static void
1233 silkPyIPWildcard_dealloc(
1234     silkPyIPWildcard   *obj);
1235 static PyObject *
1236 silkPyIPWildcard_is_ipv6(
1237     silkPyIPWildcard    UNUSED_NOv6(*self));
1238 static PyObject *
1239 silkPyIPWildcard_isipv6_deprecated(
1240     silkPyIPWildcard   *self);
1241 static PyObject *
1242 silkPyIPWildcard_iter(
1243     silkPyIPWildcard   *self);
1244 static PyObject *
1245 silkPyIPWildcard_new(
1246     PyTypeObject       *type,
1247     PyObject           *args,
1248     PyObject           *kwds);
1249 static PyObject *
1250 silkPyIPWildcard_repr(
1251     silkPyIPWildcard   *obj);
1252 static PyObject *
1253 silkPyIPWildcard_str(
1254     silkPyIPWildcard   *obj);
1255 
1256 /* define docs and methods */
1257 #define silkPyIPWildcard_doc                    \
1258     "IPWildcard(string) -> IP Wildcard address"
1259 
1260 static PyMethodDef silkPyIPWildcard_methods[] = {
1261     {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
1262     {"isipv6", (PyCFunction)silkPyIPWildcard_isipv6_deprecated, METH_NOARGS,
1263      ("wild.isipv6() -> bool -- return whether wild is an IPv6 wildcard."
1264       " DEPRECATED Use wild.is_ipv6() instead.")},
1265     {"is_ipv6", (PyCFunction)silkPyIPWildcard_is_ipv6, METH_NOARGS,
1266      "wild.is_ipv6() -> bool -- return whether wild is an IPv6 wildcard"},
1267     {NULL, NULL, 0, NULL}       /* Sentinel */
1268 };
1269 
1270 static PySequenceMethods silkPyIPWildcard_sequence_methods = {
1271     0,                          /* sq_length */
1272     0,                          /* sq_concat */
1273     0,                          /* sq_repeat */
1274     0,                          /* sq_item */
1275     0,                          /* sq_slice */
1276     0,                          /* sq_ass_item */
1277     0,                          /* sq_ass_slice */
1278     (objobjproc)silkPyIPWildcard_contains, /* sq_contains */
1279     0,                          /* sq_inplace_concat */
1280     0                           /* sq_inplace_repeat */
1281 };
1282 
1283 /* define the object types */
1284 static PyTypeObject silkPyIPWildcardType = {
1285     PyVarObject_HEAD_INIT(NULL, 0)
1286     "silk.IPWildcard",          /* tp_name */
1287     sizeof(silkPyIPWildcard),   /* tp_basicsize */
1288     0,                          /* tp_itemsize */
1289     (destructor)silkPyIPWildcard_dealloc, /* tp_dealloc */
1290     0,                          /* tp_vectorcall_offset (Py 3.8) */
1291     0,                          /* tp_getattr */
1292     0,                          /* tp_setattr */
1293     0,                          /* tp_as_async (tp_compare in Py2.x) */
1294     (reprfunc)silkPyIPWildcard_repr, /* tp_repr */
1295     0,                          /* tp_as_number */
1296     &silkPyIPWildcard_sequence_methods, /* tp_as_sequence */
1297     0,                          /* tp_as_mapping */
1298     0,                          /* tp_hash  */
1299     0,                          /* tp_call */
1300     (reprfunc)silkPyIPWildcard_str, /* tp_str */
1301     0,                          /* tp_getattro */
1302     0,                          /* tp_setattro */
1303     0,                          /* tp_as_buffer */
1304     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1305                                 /* tp_flags */
1306     silkPyIPWildcard_doc,       /* tp_doc */
1307     0,                          /* tp_traverse */
1308     0,                          /* tp_clear */
1309     0,                          /* tp_richcompare */
1310     0,                          /* tp_weaklistoffset */
1311     (getiterfunc)silkPyIPWildcard_iter, /* tp_iter */
1312     0,                          /* tp_iternext */
1313     silkPyIPWildcard_methods,   /* tp_methods */
1314     0,                          /* tp_members */
1315     0,                          /* tp_getset */
1316     0,                          /* tp_base */
1317     0,                          /* tp_dict */
1318     0,                          /* tp_descr_get */
1319     0,                          /* tp_descr_set */
1320     0,                          /* tp_dictoffset */
1321     0,                          /* tp_init */
1322     0,                          /* tp_alloc */
1323     silkPyIPWildcard_new,       /* tp_new */
1324     0,                          /* tp_free */
1325     0,                          /* tp_is_gc */
1326     0,                          /* tp_bases */
1327     0,                          /* tp_mro */
1328     0,                          /* tp_cache */
1329     0,                          /* tp_subclasses */
1330     0,                          /* tp_weaklist */
1331     0                           /* tp_del */
1332 #if PY_VERSION_HEX >= 0x02060000
1333     ,0                          /* tp_version_tag */
1334 #endif
1335 #if PY_VERSION_HEX >= 0x03040000
1336     ,0                          /* tp_finalize */
1337 #endif
1338 #if PY_VERSION_HEX >= 0x03080000
1339     ,0                          /* tp_vectorcall */
1340     ,0                          /* tp_print */
1341 #endif
1342 };
1343 
1344 static PyTypeObject silkPyIPWildcardIterType = {
1345     PyVarObject_HEAD_INIT(NULL, 0)
1346     "silk.pysilk.IPWildcardIter", /* tp_name */
1347     sizeof(silkPyIPWildcardIter), /* tp_basicsize */
1348     0,                          /* tp_itemsize */
1349     (destructor)silkPyIPWildcardIter_dealloc, /* tp_dealloc */
1350     0,                          /* tp_vectorcall_offset (Py 3.8) */
1351     0,                          /* tp_getattr */
1352     0,                          /* tp_setattr */
1353     0,                          /* tp_as_async (tp_compare in Py2.x) */
1354     0,                          /* tp_repr */
1355     0,                          /* tp_as_number */
1356     0,                          /* tp_as_sequence */
1357     0,                          /* tp_as_mapping */
1358     0,                          /* tp_hash  */
1359     0,                          /* tp_call */
1360     0,                          /* tp_str */
1361     0,                          /* tp_getattro */
1362     0,                          /* tp_setattro */
1363     0,                          /* tp_as_buffer */
1364     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
1365     "IP Wildcard iterator object", /* tp_doc */
1366     0,                          /* tp_traverse */
1367     0,                          /* tp_clear */
1368     0,                          /* tp_richcompare */
1369     0,                          /* tp_weaklistoffset */
1370     iter_iter,                  /* tp_iter */
1371     (iternextfunc)silkPyIPWildcardIter_iternext, /* tp_iternext */
1372     0,                          /* tp_methods */
1373     0,                          /* tp_members */
1374     0,                          /* tp_getset */
1375     0,                          /* tp_base */
1376     0,                          /* tp_dict */
1377     0,                          /* tp_descr_get */
1378     0,                          /* tp_descr_set */
1379     0,                          /* tp_dictoffset */
1380     0,                          /* tp_init */
1381     0,                          /* tp_alloc */
1382     0,                          /* tp_new */
1383     0,                          /* tp_free */
1384     0,                          /* tp_is_gc */
1385     0,                          /* tp_bases */
1386     0,                          /* tp_mro */
1387     0,                          /* tp_cache */
1388     0,                          /* tp_subclasses */
1389     0,                          /* tp_weaklist */
1390     0                           /* tp_del */
1391 #if PY_VERSION_HEX >= 0x02060000
1392     ,0                          /* tp_version_tag */
1393 #endif
1394 #if PY_VERSION_HEX >= 0x03040000
1395     ,0                          /* tp_finalize */
1396 #endif
1397 #if PY_VERSION_HEX >= 0x03080000
1398     ,0                          /* tp_vectorcall */
1399     ,0                          /* tp_print */
1400 #endif
1401 };
1402 
1403 /* macro and function defintions */
1404 #define silkPyIPWildcard_Check(op)                      \
1405     PyObject_TypeCheck(op, &silkPyIPWildcardType)
1406 #define silkPyIPWildcardIter_Check(op)                  \
1407     PyObject_TypeCheck(op, &silkPyIPWildcardIterType)
1408 
1409 static void
silkPyIPWildcardIter_dealloc(silkPyIPWildcardIter * self)1410 silkPyIPWildcardIter_dealloc(
1411     silkPyIPWildcardIter   *self)
1412 {
1413     Py_XDECREF(self->wildcard);
1414     Py_TYPE(self)->tp_free((PyObject*)self);
1415 }
1416 
1417 static PyObject *
silkPyIPWildcardIter_iternext(silkPyIPWildcardIter * self)1418 silkPyIPWildcardIter_iternext(
1419     silkPyIPWildcardIter   *self)
1420 {
1421     silkPyIPAddr       *addr;
1422     skIteratorStatus_t  rv;
1423     skipaddr_t          raw_addr;
1424 
1425     rv = skIPWildcardIteratorNext(&self->iter, &raw_addr);
1426     if (rv == SK_ITERATOR_NO_MORE_ENTRIES) {
1427         PyErr_SetNone(PyExc_StopIteration);
1428         return NULL;
1429     }
1430     addr = (silkPyIPAddr*)silkPyIPv4AddrType.tp_alloc(&silkPyIPv4AddrType, 0);
1431     if (addr == NULL) {
1432         return NULL;
1433     }
1434     addr->addr = raw_addr;
1435 
1436     return (PyObject*)addr;
1437 }
1438 
1439 static int
silkPyIPWildcard_contains(silkPyIPWildcard * self,PyObject * obj)1440 silkPyIPWildcard_contains(
1441     silkPyIPWildcard   *self,
1442     PyObject           *obj)
1443 {
1444     int           retval;
1445     silkPyIPAddr *silkaddr;
1446 
1447     if (IS_STRING(obj)) {
1448         obj = PyObject_CallFunctionObjArgs((PyObject*)&silkPyIPAddrType,
1449                                            obj, NULL);
1450         if (obj == NULL) {
1451             return -1;
1452         }
1453     } else if (silkPyIPAddr_Check(obj)) {
1454         Py_INCREF(obj);
1455     } else {
1456         PyErr_SetString(PyExc_TypeError, "Must be a string or silk.IPAddr");
1457         return -1;
1458     }
1459 
1460     silkaddr = (silkPyIPAddr*)obj;
1461     retval = skIPWildcardCheckIp(&self->wildcard, &silkaddr->addr);
1462     Py_DECREF(obj);
1463 
1464     return retval ? 1 : 0;
1465 }
1466 
1467 static void
silkPyIPWildcard_dealloc(silkPyIPWildcard * obj)1468 silkPyIPWildcard_dealloc(
1469     silkPyIPWildcard   *obj)
1470 {
1471     Py_XDECREF(obj->name);
1472     Py_TYPE(obj)->tp_free((PyObject*)obj);
1473 }
1474 
1475 static PyObject *
silkPyIPWildcard_is_ipv6(silkPyIPWildcard UNUSED_NOv6 (* self))1476 silkPyIPWildcard_is_ipv6(
1477     silkPyIPWildcard    UNUSED_NOv6(*self))
1478 {
1479 #if SK_ENABLE_IPV6
1480     return PyBool_FromLong(skIPWildcardIsV6(&self->wildcard));
1481 #else
1482     Py_RETURN_FALSE;
1483 #endif
1484 }
1485 
1486 static PyObject *
silkPyIPWildcard_isipv6_deprecated(silkPyIPWildcard * self)1487 silkPyIPWildcard_isipv6_deprecated(
1488     silkPyIPWildcard   *self)
1489 {
1490     /* deprecated in SiLK 3.0.0.  Function is undocumented. */
1491     PyErr_Warn(PyExc_DeprecationWarning,
1492                ("IPWildcard.isipv6() is deprecated.  "
1493                 "Use IPWildcard.is_ipv6() instead."));
1494     return silkPyIPWildcard_is_ipv6(self);
1495 }
1496 
1497 static PyObject *
silkPyIPWildcard_iter(silkPyIPWildcard * self)1498 silkPyIPWildcard_iter(
1499     silkPyIPWildcard   *self)
1500 {
1501     silkPyIPWildcardIter *iter;
1502 
1503     iter = (silkPyIPWildcardIter*)silkPyIPWildcardIterType.tp_alloc(
1504         &silkPyIPWildcardIterType, 0);
1505     if (iter) {
1506         ASSERT_RESULT(skIPWildcardIteratorBind(&iter->iter, &self->wildcard),
1507                       int, 0);
1508         Py_INCREF(self);
1509         iter->wildcard = self;
1510     }
1511     return (PyObject*)iter;
1512 }
1513 
1514 static PyObject *
silkPyIPWildcard_new(PyTypeObject * type,PyObject * args,PyObject * kwds)1515 silkPyIPWildcard_new(
1516     PyTypeObject       *type,
1517     PyObject           *args,
1518     PyObject           *kwds)
1519 {
1520     static char *kwlist[] = {"wildcard", NULL};
1521     silkPyIPWildcard *self;
1522 
1523     if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist,
1524                                     &silkPyIPWildcardType, &self))
1525     {
1526         Py_INCREF(self);
1527         return (PyObject*)self;
1528     } else {
1529         PyErr_Clear();
1530     }
1531 
1532     self = (silkPyIPWildcard*)type->tp_alloc(type, 0);
1533     if (self != NULL) {
1534         Py_ssize_t   len;
1535         const char  *wildcard;
1536         int          rv;
1537 
1538         if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist,
1539                                          &wildcard, &len))
1540         {
1541             Py_DECREF(self);
1542             return NULL;
1543         }
1544         rv = skStringParseIPWildcard(&self->wildcard, wildcard);
1545         if (rv != 0) {
1546             Py_DECREF(self);
1547             return PyErr_Format(PyExc_ValueError,
1548                                 "Illegal IP wildcard: %s", wildcard);
1549         }
1550         self->name = PyUnicode_DecodeASCII(wildcard, len, "strict");
1551         if (self->name == NULL) {
1552             Py_DECREF(self);
1553             return NULL;
1554         }
1555     }
1556 
1557     return (PyObject*)self;
1558 }
1559 
1560 static PyObject *
silkPyIPWildcard_repr(silkPyIPWildcard * obj)1561 silkPyIPWildcard_repr(
1562     silkPyIPWildcard   *obj)
1563 {
1564     PyObject *format;
1565     PyObject *arg;
1566     PyObject *retval;
1567 
1568     format = PyUnicode_FromString("silk.IPWildcard(\"%s\")");
1569     if (format == NULL) {
1570         return NULL;
1571     }
1572     arg = Py_BuildValue("(O)", obj->name);
1573     if (arg == NULL) {
1574         Py_DECREF(format);
1575         return NULL;
1576     }
1577     retval = PyUnicode_Format(format, arg);
1578     Py_DECREF(format);
1579     Py_DECREF(arg);
1580 
1581     return retval;
1582 }
1583 
1584 static PyObject *
silkPyIPWildcard_str(silkPyIPWildcard * obj)1585 silkPyIPWildcard_str(
1586     silkPyIPWildcard   *obj)
1587 {
1588     Py_INCREF(obj->name);
1589     return obj->name;
1590 }
1591 
1592 
1593 /*
1594  *************************************************************************
1595  *   IPSet
1596  *************************************************************************
1597  */
1598 
1599 typedef struct silkPyIPSet_st {
1600     PyObject_HEAD
1601     skipset_t  *ipset;
1602 } silkPyIPSet;
1603 
1604 typedef struct silkPyIPSetIter_st {
1605     PyObject_HEAD
1606     silkPyIPSet *set;
1607     skipset_iterator_t iter;
1608     unsigned is_cidr : 1;
1609 } silkPyIPSetIter;
1610 
1611 /* function prototypes */
1612 static void
1613 silkPyIPSetIter_dealloc(
1614     silkPyIPSetIter    *self);
1615 static PyObject *
1616 silkPyIPSetIter_iternext(
1617     silkPyIPSetIter    *self);
1618 static PyObject *
1619 silkPyIPSet_add(
1620     silkPyIPSet        *self,
1621     PyObject           *obj);
1622 static PyObject *
1623 silkPyIPSet_add_range(
1624     silkPyIPSet        *self,
1625     PyObject           *args,
1626     PyObject           *kwds);
1627 static PyObject *
1628 silkPyIPSet_cardinality(
1629     silkPyIPSet        *self);
1630 static PyObject *
1631 silkPyIPSet_cidr_iter(
1632     silkPyIPSet        *self);
1633 static PyObject *
1634 silkPyIPSet_clear(
1635     silkPyIPSet        *self);
1636 static int
1637 silkPyIPSet_contains(
1638     silkPyIPSet        *self,
1639     PyObject           *obj);
1640 static PyObject *
1641 silkPyIPSet_convert(
1642     silkPyIPSet        *self,
1643     PyObject           *obj);
1644 static void
1645 silkPyIPSet_dealloc(
1646     silkPyIPSet        *obj);
1647 static PyObject *
1648 silkPyIPSet_difference_update(
1649     silkPyIPSet        *self,
1650     silkPyIPSet        *obj);
1651 static PyObject *
1652 silkPyIPSet_discard(
1653     silkPyIPSet        *self,
1654     PyObject           *obj);
1655 static int
1656 silkPyIPSet_init(
1657     silkPyIPSet        *self,
1658     PyObject           *args,
1659     PyObject           *kwds);
1660 static PyObject *
1661 silkPyIPSet_intersection_update(
1662     silkPyIPSet        *self,
1663     silkPyIPSet        *obj);
1664 static PyObject *
1665 silkPyIPSet_isdisjoint(
1666     silkPyIPSet        *self,
1667     PyObject           *obj);
1668 static PyObject *
1669 silkPyIPSet_is_ipv6(
1670     silkPyIPSet        *self);
1671 static PyObject *
1672 silkPyIPSet_iter(
1673     silkPyIPSet        *self);
1674 static Py_ssize_t
1675 silkPyIPSet_len(
1676     silkPyIPSet        *self);
1677 static PyObject *
1678 silkPyIPSet_save(
1679     silkPyIPSet        *self,
1680     PyObject           *args,
1681     PyObject           *kwds);
1682 static PyObject *
1683 silkPyIPSet_union_update(
1684     silkPyIPSet        *self,
1685     silkPyIPSet        *obj);
1686 
1687 /* define docs and methods */
1688 #define silkPyIPSet_doc                         \
1689     "IPSetBase() -> empty IPset\n"              \
1690     "IPSetBase(filename) -> IPset from file"
1691 
1692 static PyMethodDef silkPyIPSet_methods[] = {
1693     {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
1694     {"cardinality", (PyCFunction)silkPyIPSet_cardinality, METH_NOARGS,
1695      "ipset.cardinality() -> long -- number of IP Addresses in the IPSet"},
1696     {"intersection_update", (PyCFunction)silkPyIPSet_intersection_update,
1697      METH_O,
1698      ("Return the intersection of two IPSets as a new IPSet.\n"
1699       "\n"
1700       "(i.e. all elements that are in both IPSets.)")},
1701     {"update", (PyCFunction)silkPyIPSet_union_update,
1702      METH_O,
1703      ("Update the IPSet with the union of itself and another.")},
1704     {"difference_update", (PyCFunction)silkPyIPSet_difference_update,
1705      METH_O,
1706      ("Remove all elements of another IPSet from this IPSet.")},
1707     {"clear", (PyCFunction)silkPyIPSet_clear, METH_NOARGS,
1708      ("Remove all elements from this IPSet.")},
1709     {"save", (PyCFunction)silkPyIPSet_save, METH_KEYWORDS | METH_VARARGS,
1710      "ipset.save(filename[, compression]) -- Saves the set to a file."},
1711     {"cidr_iter", (PyCFunction)silkPyIPSet_cidr_iter, METH_NOARGS,
1712      "Return an iterator over IPAddr/prefix tuples."},
1713     {"add", (PyCFunction)silkPyIPSet_add, METH_O,
1714      ("Add an element to an IPSet.  The element may be an IP address, an\n"
1715       "IP wildcard, or the string representation of either.\n"
1716       "\n"
1717       "This has no effect for any element already present.")},
1718     {"add_range", (PyCFunction)silkPyIPSet_add_range,
1719      METH_KEYWORDS | METH_VARARGS,
1720      ("Add all IPs between start and end, inclusive, to an IPSet.  Each\n"
1721       "argument may be an IP address or the string representation of an\n"
1722       "IP address\n"
1723       "\n"
1724       "This has no effect when all elements are already present.")},
1725     {"discard", (PyCFunction)silkPyIPSet_discard, METH_O,
1726      ("Discard an element to an IPSet.  The element may be an IP address, an\n"
1727       "IP wildcard, or the string representation of either.\n"
1728       "\n"
1729       "This has no effect for any element not present in the IPset.")},
1730     {"isdisjoint", (PyCFunction)silkPyIPSet_isdisjoint, METH_O,
1731      "Return whether the IPSet has any elements in common with the argument"},
1732     {"is_ipv6", (PyCFunction)silkPyIPSet_is_ipv6, METH_NOARGS,
1733      "Return whether the IPSet is an IPv6 set."},
1734     {"convert", (PyCFunction)silkPyIPSet_convert, METH_VARARGS,
1735      ("Convert the current IPSet to IPv4 or IPv6 if the argument is 4 or 6.\n"
1736       "Converting an IPv6 set to IPv4 will throw a ValueError if there are\n"
1737       "addresses in the set that cannot be represented in IPv4.")},
1738     {NULL, NULL, 0, NULL}       /* Sentinel */
1739 };
1740 
1741 static PySequenceMethods silkPyIPSet_sequence_methods = {
1742 #if PY_VERSION_HEX < 0x02050000
1743     (inquiry)silkPyIPSet_len,   /* sq_length */
1744 #else
1745     (lenfunc)silkPyIPSet_len,   /* sq_length */
1746 #endif
1747     0,                          /* sq_concat */
1748     0,                          /* sq_repeat */
1749     0,                          /* sq_item */
1750     0,                          /* sq_slice */
1751     0,                          /* sq_ass_item */
1752     0,                          /* sq_ass_slice */
1753     (objobjproc)silkPyIPSet_contains, /* sq_contains */
1754     0,                          /* sq_inplace_concat */
1755     0                           /* sq_inplace_repeat */
1756 };
1757 
1758 /* define the object types */
1759 static PyTypeObject silkPyIPSetType = {
1760     PyVarObject_HEAD_INIT(NULL, 0)
1761     "silk.pysilk.IPSetBase",    /* tp_name */
1762     sizeof(silkPyIPSet),        /* tp_basicsize */
1763     0,                          /* tp_itemsize */
1764     (destructor)silkPyIPSet_dealloc, /* tp_dealloc */
1765     0,                          /* tp_vectorcall_offset (Py 3.8) */
1766     0,                          /* tp_getattr */
1767     0,                          /* tp_setattr */
1768     0,                          /* tp_as_async (tp_compare in Py2.x) */
1769     0,                          /* tp_repr */
1770     0,                          /* tp_as_number */
1771     &silkPyIPSet_sequence_methods, /* tp_as_sequence */
1772     0,                          /* tp_as_mapping */
1773     0,                          /* tp_hash  */
1774     0,                          /* tp_call */
1775     0,                          /* tp_str */
1776     0,                          /* tp_getattro */
1777     0,                          /* tp_setattro */
1778     0,                          /* tp_as_buffer */
1779     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
1780     silkPyIPSet_doc,            /* tp_doc */
1781     0,                          /* tp_traverse */
1782     0,                          /* tp_clear */
1783     0,                          /* tp_richcompare */
1784     0,                          /* tp_weaklistoffset */
1785     (getiterfunc)silkPyIPSet_iter, /* tp_iter */
1786     0,                          /* tp_iternext */
1787     silkPyIPSet_methods,        /* tp_methods */
1788     0,                          /* tp_members */
1789     0,                          /* tp_getset */
1790     0,                          /* tp_base */
1791     0,                          /* tp_dict */
1792     0,                          /* tp_descr_get */
1793     0,                          /* tp_descr_set */
1794     0,                          /* tp_dictoffset */
1795     (initproc)silkPyIPSet_init, /* tp_init */
1796     0,                          /* tp_alloc */
1797     0,                          /* tp_new */
1798     0,                          /* tp_free */
1799     0,                          /* tp_is_gc */
1800     0,                          /* tp_bases */
1801     0,                          /* tp_mro */
1802     0,                          /* tp_cache */
1803     0,                          /* tp_subclasses */
1804     0,                          /* tp_weaklist */
1805     0                           /* tp_del */
1806 #if PY_VERSION_HEX >= 0x02060000
1807     ,0                          /* tp_version_tag */
1808 #endif
1809 #if PY_VERSION_HEX >= 0x03040000
1810     ,0                          /* tp_finalize */
1811 #endif
1812 #if PY_VERSION_HEX >= 0x03080000
1813     ,0                          /* tp_vectorcall */
1814     ,0                          /* tp_print */
1815 #endif
1816 };
1817 
1818 static PyTypeObject silkPyIPSetIterType = {
1819     PyVarObject_HEAD_INIT(NULL, 0)
1820     "silk.pysilk.IPSetIter",    /* tp_name */
1821     sizeof(silkPyIPSetIter),    /* tp_basicsize */
1822     0,                          /* tp_itemsize */
1823     (destructor)silkPyIPSetIter_dealloc, /* tp_dealloc */
1824     0,                          /* tp_vectorcall_offset (Py 3.8) */
1825     0,                          /* tp_getattr */
1826     0,                          /* tp_setattr */
1827     0,                          /* tp_as_async (tp_compare in Py2.x) */
1828     0,                          /* tp_repr */
1829     0,                          /* tp_as_number */
1830     0,                          /* tp_as_sequence */
1831     0,                          /* tp_as_mapping */
1832     0,                          /* tp_hash  */
1833     0,                          /* tp_call */
1834     0,                          /* tp_str */
1835     0,                          /* tp_getattro */
1836     0,                          /* tp_setattro */
1837     0,                          /* tp_as_buffer */
1838     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
1839     "IP Set iterator object",   /* tp_doc */
1840     0,                          /* tp_traverse */
1841     0,                          /* tp_clear */
1842     0,                          /* tp_richcompare */
1843     0,                          /* tp_weaklistoffset */
1844     iter_iter,                  /* tp_iter */
1845     (iternextfunc)silkPyIPSetIter_iternext, /* tp_iternext */
1846     0,                          /* tp_methods */
1847     0,                          /* tp_members */
1848     0,                          /* tp_getset */
1849     0,                          /* tp_base */
1850     0,                          /* tp_dict */
1851     0,                          /* tp_descr_get */
1852     0,                          /* tp_descr_set */
1853     0,                          /* tp_dictoffset */
1854     0,                          /* tp_init */
1855     0,                          /* tp_alloc */
1856     0,                          /* tp_new */
1857     0,                          /* tp_free */
1858     0,                          /* tp_is_gc */
1859     0,                          /* tp_bases */
1860     0,                          /* tp_mro */
1861     0,                          /* tp_cache */
1862     0,                          /* tp_subclasses */
1863     0,                          /* tp_weaklist */
1864     0                           /* tp_del */
1865 #if PY_VERSION_HEX >= 0x02060000
1866     ,0                          /* tp_version_tag */
1867 #endif
1868 #if PY_VERSION_HEX >= 0x03040000
1869     ,0                          /* tp_finalize */
1870 #endif
1871 #if PY_VERSION_HEX >= 0x03080000
1872     ,0                          /* tp_vectorcall */
1873     ,0                          /* tp_print */
1874 #endif
1875 };
1876 
1877 
1878 /* macro and function defintions */
1879 #define silkPyIPSet_Check(op)                   \
1880     PyObject_TypeCheck(op, &silkPyIPSetType)
1881 #define silkPyIPSetIter_Check(op)                       \
1882     PyObject_TypeCheck(op, &silkPyIPSetIterType)
1883 
1884 static void
silkPyIPSetIter_dealloc(silkPyIPSetIter * self)1885 silkPyIPSetIter_dealloc(
1886     silkPyIPSetIter    *self)
1887 {
1888     Py_XDECREF(self->set);
1889     Py_TYPE(self)->tp_free((PyObject*)self);
1890 }
1891 
1892 static PyObject *
silkPyIPSetIter_iternext(silkPyIPSetIter * self)1893 silkPyIPSetIter_iternext(
1894     silkPyIPSetIter    *self)
1895 {
1896     silkPyIPAddr       *addr;
1897     int                 rv;
1898     PyObject           *retval;
1899     skipaddr_t          raw_addr;
1900     uint32_t            raw_prefix;
1901 
1902     rv = skIPSetIteratorNext(&self->iter, &raw_addr, &raw_prefix);
1903     if (rv == SK_ITERATOR_NO_MORE_ENTRIES) {
1904         PyErr_SetNone(PyExc_StopIteration);
1905         return NULL;
1906     }
1907 
1908     addr = (silkPyIPAddr*)silkPyIPAddrType.tp_alloc(&silkPyIPAddrType, 0);
1909     if (addr == NULL) {
1910         return NULL;
1911     }
1912     addr->addr = raw_addr;
1913 
1914     if (!self->is_cidr) {
1915         retval = (PyObject*)addr;
1916     } else {
1917         PyObject       *pair;
1918         PyObject       *len;
1919 
1920         len = PyInt_FromLong(raw_prefix);
1921         if (len == NULL) {
1922             Py_DECREF(addr);
1923             return NULL;
1924         }
1925         pair = PyTuple_New(2);
1926         if (pair == NULL) {
1927             Py_DECREF(addr);
1928             Py_DECREF(len);
1929         }
1930         PyTuple_SET_ITEM(pair, 0, (PyObject*)addr);
1931         PyTuple_SET_ITEM(pair, 1, len);
1932 
1933         retval = pair;
1934     }
1935 
1936     return retval;
1937 }
1938 
1939 static PyObject *
silkPyIPSet_add(silkPyIPSet * self,PyObject * obj)1940 silkPyIPSet_add(
1941     silkPyIPSet        *self,
1942     PyObject           *obj)
1943 {
1944     int           rv;
1945 
1946     if (silkPyIPAddr_Check(obj)) {
1947         silkPyIPAddr *addr = (silkPyIPAddr*)obj;
1948 
1949         rv = skIPSetInsertAddress(self->ipset, &addr->addr, 0);
1950     } else if (silkPyIPWildcard_Check(obj)) {
1951         silkPyIPWildcard *wild;
1952 
1953         assert(silkPyIPWildcard_Check(obj));
1954 
1955         wild = (silkPyIPWildcard*)obj;
1956 
1957         rv = skIPSetInsertIPWildcard(self->ipset, &wild->wildcard);
1958     } else {
1959         PyErr_SetString(PyExc_TypeError,
1960                         "Must be a silk.IPAddr or a silk.IPWildcard");
1961         return NULL;
1962     }
1963 
1964     if (rv == SKIPSET_ERR_ALLOC) {
1965         return PyErr_NoMemory();
1966     }
1967     if (rv == SKIPSET_ERR_IPV6) {
1968         PyErr_SetString(PyExc_ValueError,
1969                         "Must only include IPv4 addresses");
1970         return NULL;
1971     }
1972     assert(rv == SKIPSET_OK);
1973 
1974     Py_INCREF(self);
1975     return (PyObject*)self;
1976 }
1977 
1978 static PyObject *
silkPyIPSet_add_range(silkPyIPSet * self,PyObject * args,PyObject * kwds)1979 silkPyIPSet_add_range(
1980     silkPyIPSet        *self,
1981     PyObject           *args,
1982     PyObject           *kwds)
1983 {
1984     static char  *kwlist[] = {"start", "end", NULL};
1985     PyObject     *start_obj;
1986     PyObject     *end_obj;
1987     silkPyIPAddr *start_addr;
1988     silkPyIPAddr *end_addr;
1989     int           rv;
1990 
1991     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
1992                                      &start_obj, &end_obj))
1993     {
1994         return NULL;
1995     }
1996     if (!silkPyIPAddr_Check(start_obj)) {
1997         PyErr_SetString(PyExc_TypeError,
1998                         "The start argument must be a silk.IPAddr");
1999         return NULL;
2000     }
2001     if (!silkPyIPAddr_Check(end_obj)) {
2002         PyErr_SetString(PyExc_TypeError,
2003                         "The end argument must be a silk.IPAddr");
2004         return NULL;
2005     }
2006 
2007     start_addr = (silkPyIPAddr*)start_obj;
2008     end_addr =  (silkPyIPAddr*)end_obj;
2009 
2010     rv = skIPSetInsertRange(self->ipset, &start_addr->addr, &end_addr->addr);
2011     if (rv == SKIPSET_ERR_ALLOC) {
2012         return PyErr_NoMemory();
2013     }
2014     if (rv == SKIPSET_ERR_IPV6) {
2015         PyErr_SetString(PyExc_ValueError,
2016                         "Must only include IPv4 addresses");
2017         return NULL;
2018     }
2019     if (rv == SKIPSET_ERR_BADINPUT) {
2020         PyErr_SetString(PyExc_ValueError,
2021                         "The start of range must not be greater than the end");
2022         return NULL;
2023     }
2024     assert(rv == SKIPSET_OK);
2025 
2026     Py_INCREF(self);
2027     return (PyObject*)self;
2028 }
2029 
2030 static PyObject *
silkPyIPSet_cardinality(silkPyIPSet * self)2031 silkPyIPSet_cardinality(
2032     silkPyIPSet        *self)
2033 {
2034     uint64_t count;
2035     double count_d;
2036 
2037     skIPSetClean(self->ipset);
2038     count = skIPSetCountIPs(self->ipset, &count_d);
2039     if (count == UINT64_MAX) {
2040         return PyLong_FromDouble(count_d);
2041     }
2042     return PyLong_FromUnsignedLongLong(count);
2043 }
2044 
2045 static PyObject *
silkPyIPSet_cidr_iter(silkPyIPSet * self)2046 silkPyIPSet_cidr_iter(
2047     silkPyIPSet        *self)
2048 {
2049     silkPyIPSetIter *iter;
2050 
2051     iter = (silkPyIPSetIter*)silkPyIPSetIterType.tp_alloc(
2052         &silkPyIPSetIterType, 0);
2053     if (iter) {
2054         skIPSetClean(self->ipset);
2055         if (skIPSetIteratorBind(&iter->iter, self->ipset, 1,SK_IPV6POLICY_MIX))
2056         {
2057             Py_DECREF(iter);
2058             return PyErr_NoMemory();
2059         }
2060         Py_INCREF(self);
2061         iter->set = self;
2062         iter->is_cidr = 1;
2063     }
2064     return (PyObject*)iter;
2065 }
2066 
2067 static PyObject *
silkPyIPSet_clear(silkPyIPSet * self)2068 silkPyIPSet_clear(
2069     silkPyIPSet        *self)
2070 {
2071     skIPSetRemoveAll(self->ipset);
2072 
2073     Py_INCREF(self);
2074     return (PyObject*)self;
2075 }
2076 
2077 static int
silkPyIPSet_contains(silkPyIPSet * self,PyObject * obj)2078 silkPyIPSet_contains(
2079     silkPyIPSet        *self,
2080     PyObject           *obj)
2081 {
2082     int           retval;
2083     silkPyIPAddr *silkaddr;
2084 
2085     if (IS_STRING(obj)) {
2086         obj = PyObject_CallFunctionObjArgs((PyObject*)&silkPyIPAddrType,
2087                                            obj, NULL);
2088         if (obj == NULL) {
2089             return -1;
2090         }
2091     } else if (silkPyIPAddr_Check(obj)) {
2092         Py_INCREF(obj);
2093     } else {
2094         PyErr_SetString(PyExc_TypeError, "Must be a string or silk.IPAddr");
2095         return -1;
2096     }
2097 
2098     silkaddr = (silkPyIPAddr*)obj;
2099     retval = skIPSetCheckAddress(self->ipset, &silkaddr->addr);
2100     Py_DECREF(obj);
2101 
2102     return retval ? 1 : 0;
2103 }
2104 
2105 static PyObject *
silkPyIPSet_convert(silkPyIPSet * self,PyObject * args)2106 silkPyIPSet_convert(
2107     silkPyIPSet        *self,
2108     PyObject           *args)
2109 {
2110     int rv;
2111     int version;
2112 
2113     if (!PyArg_ParseTuple(args, "i", &version)) {
2114         return NULL;
2115     }
2116     if (version != 4 && version != 6) {
2117         PyErr_SetString(PyExc_ValueError, "Version must be 4 or 6");
2118         return NULL;
2119     }
2120 
2121     rv = skIPSetConvert(self->ipset, version);
2122     if (rv == 0) {
2123         Py_INCREF(self);
2124         return (PyObject*)self;
2125     }
2126     if (rv == SKIPSET_ERR_IPV6) {
2127 #if SK_ENABLE_IPV6
2128         PyErr_SetString(
2129             PyExc_ValueError,
2130             "IPSet cannot be converted to v4, as it contains v6 addresses");
2131 #else
2132         PyErr_SetString(PyExc_ValueError,
2133                         "This build of SiLK does not support IPv6");
2134 #endif
2135         return NULL;
2136     }
2137     return PyErr_Format(PyExc_RuntimeError,
2138                         "Unexpected error converting IPSet: %d", rv);
2139 }
2140 
2141 static void
silkPyIPSet_dealloc(silkPyIPSet * obj)2142 silkPyIPSet_dealloc(
2143     silkPyIPSet        *obj)
2144 {
2145     if (obj->ipset) {
2146         skIPSetDestroy(&obj->ipset);
2147     }
2148     Py_TYPE(obj)->tp_free((PyObject*)obj);
2149 }
2150 
2151 static PyObject *
silkPyIPSet_difference_update(silkPyIPSet * self,silkPyIPSet * obj)2152 silkPyIPSet_difference_update(
2153     silkPyIPSet        *self,
2154     silkPyIPSet        *obj)
2155 {
2156     if (!silkPyIPSet_Check(obj)) {
2157         PyErr_SetString(PyExc_NotImplementedError,
2158                         "Argument must be a silk.IPSet");
2159         return NULL;
2160     }
2161 
2162     skIPSetClean(self->ipset);
2163     skIPSetClean(obj->ipset);
2164     skIPSetSubtract(self->ipset, obj->ipset);
2165 
2166     Py_INCREF(self);
2167     return (PyObject*)self;
2168 }
2169 
2170 static PyObject *
silkPyIPSet_discard(silkPyIPSet * self,PyObject * obj)2171 silkPyIPSet_discard(
2172     silkPyIPSet        *self,
2173     PyObject           *obj)
2174 {
2175     int rv;
2176 
2177     if (silkPyIPAddr_Check(obj)) {
2178         silkPyIPAddr *addr = (silkPyIPAddr*)obj;
2179 
2180         rv = skIPSetRemoveAddress(self->ipset, &addr->addr, 0);
2181     } else if (silkPyIPWildcard_Check(obj)) {
2182         silkPyIPWildcard *wild;
2183 
2184         assert(silkPyIPWildcard_Check(obj));
2185 
2186         wild = (silkPyIPWildcard*)obj;
2187 
2188         rv = skIPSetRemoveIPWildcard(self->ipset, &wild->wildcard);
2189     } else {
2190         PyErr_SetString(PyExc_TypeError,
2191                         "Must be a silk.IPAddr or a silk.IPWildcard");
2192         return NULL;
2193     }
2194 
2195     if (rv == SKIPSET_ERR_ALLOC) {
2196         return PyErr_NoMemory();
2197     }
2198     assert(rv == SKIPSET_OK);
2199 
2200     Py_INCREF(self);
2201     return (PyObject*)self;
2202 }
2203 
2204 static int
silkPyIPSet_init(silkPyIPSet * self,PyObject * args,PyObject * kwds)2205 silkPyIPSet_init(
2206     silkPyIPSet        *self,
2207     PyObject           *args,
2208     PyObject           *kwds)
2209 {
2210     static char *kwlist[] = {"filename", NULL};
2211     char         errbuf[2 * PATH_MAX];
2212     skstream_t  *stream = NULL;
2213     char        *fname = NULL;
2214     int          rv;
2215 
2216     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|et", kwlist,
2217                                      Py_FileSystemDefaultEncoding, &fname))
2218     {
2219         return -1;
2220     }
2221 
2222     if (fname) {
2223         if ((rv = skStreamCreate(&stream, SK_IO_READ, SK_CONTENT_SILK))
2224             || (rv = skStreamBind(stream, fname))
2225             || (rv = skStreamOpen(stream)))
2226         {
2227             skStreamLastErrMessage(stream, rv, errbuf, sizeof(errbuf));
2228             PyErr_Format(PyExc_IOError, "Unable to read IPSet from %s: %s",
2229                          fname, errbuf);
2230             skStreamDestroy(&stream);
2231             PyMem_Free(fname);
2232             return -1;
2233         }
2234         rv = skIPSetRead(&self->ipset, stream);
2235         if (rv) {
2236             if (SKIPSET_ERR_FILEIO == rv) {
2237                 skStreamLastErrMessage(stream,
2238                                        skStreamGetLastReturnValue(stream),
2239                                        errbuf, sizeof(errbuf));
2240             } else {
2241                 strncpy(errbuf, skIPSetStrerror(rv), sizeof(errbuf));
2242             }
2243             PyErr_Format(PyExc_IOError, "Unable to read IPSet from %s: %s",
2244                          fname, errbuf);
2245             skStreamDestroy(&stream);
2246             PyMem_Free(fname);
2247             return -1;
2248         }
2249         skStreamDestroy(&stream);
2250         PyMem_Free(fname);
2251     } else {
2252         rv = skIPSetCreate(&self->ipset, 0);
2253         if (rv == SKIPSET_ERR_ALLOC) {
2254             PyErr_NoMemory();
2255             return -1;
2256         }
2257         assert(rv == SKIPSET_OK);
2258     }
2259 
2260     return 0;
2261 }
2262 
2263 static PyObject *
silkPyIPSet_is_ipv6(silkPyIPSet * self)2264 silkPyIPSet_is_ipv6(
2265     silkPyIPSet        *self)
2266 {
2267     return PyBool_FromLong(skIPSetIsV6(self->ipset));
2268 }
2269 
2270 static PyObject *
silkPyIPSet_intersection_update(silkPyIPSet * self,silkPyIPSet * obj)2271 silkPyIPSet_intersection_update(
2272     silkPyIPSet        *self,
2273     silkPyIPSet        *obj)
2274 {
2275     if (!silkPyIPSet_Check(obj)) {
2276         PyErr_SetString(PyExc_NotImplementedError,
2277                         "Argument must be a silk.IPSet");
2278         return NULL;
2279     }
2280 
2281     skIPSetClean(self->ipset);
2282     skIPSetClean(obj->ipset);
2283     skIPSetIntersect(self->ipset, obj->ipset);
2284 
2285     Py_INCREF(self);
2286     return (PyObject*)self;
2287 }
2288 
2289 static PyObject *
silkPyIPSet_isdisjoint(silkPyIPSet * self,PyObject * obj)2290 silkPyIPSet_isdisjoint(
2291     silkPyIPSet        *self,
2292     PyObject           *obj)
2293 {
2294     int disjoint;
2295 
2296     if (silkPyIPSet_Check(obj)) {
2297         disjoint = !skIPSetCheckIPSet(
2298             self->ipset, ((silkPyIPSet*)obj)->ipset);
2299     } else if (silkPyIPWildcard_Check(obj)) {
2300         disjoint = !skIPSetCheckIPWildcard(
2301             self->ipset, &((silkPyIPWildcard*)obj)->wildcard);
2302     } else {
2303         PyErr_SetString(PyExc_TypeError, "Expected an IPSet or an IPWildcard");
2304         return NULL;
2305     }
2306     if (disjoint) {
2307         Py_RETURN_TRUE;
2308     }
2309     Py_RETURN_FALSE;
2310 }
2311 
2312 static PyObject *
silkPyIPSet_iter(silkPyIPSet * self)2313 silkPyIPSet_iter(
2314     silkPyIPSet        *self)
2315 {
2316     silkPyIPSetIter *iter;
2317 
2318     iter = (silkPyIPSetIter*)silkPyIPSetIterType.tp_alloc(
2319         &silkPyIPSetIterType, 0);
2320     if (iter) {
2321         skIPSetClean(self->ipset);
2322         if (skIPSetIteratorBind(&iter->iter, self->ipset, 0,SK_IPV6POLICY_MIX))
2323         {
2324             Py_DECREF(iter);
2325             return PyErr_NoMemory();
2326         }
2327         Py_INCREF(self);
2328         iter->set = self;
2329     }
2330     return (PyObject*)iter;
2331 }
2332 
2333 static Py_ssize_t
silkPyIPSet_len(silkPyIPSet * self)2334 silkPyIPSet_len(
2335     silkPyIPSet        *self)
2336 {
2337     uint64_t count;
2338     double count_d;
2339 
2340     skIPSetClean(self->ipset);
2341     count = skIPSetCountIPs(self->ipset, &count_d);
2342     if (count > PY_SSIZE_T_MAX) {
2343         PyErr_SetString(PyExc_OverflowError, "IPSet too long for integer");
2344         return -1;
2345     }
2346     return (Py_ssize_t)count;
2347 }
2348 
2349 static PyObject *
silkPyIPSet_save(silkPyIPSet * self,PyObject * args,PyObject * kwds)2350 silkPyIPSet_save(
2351     silkPyIPSet        *self,
2352     PyObject           *args,
2353     PyObject           *kwds)
2354 {
2355     int rv;
2356     skstream_t *stream;
2357 
2358     if ((stream = open_silkfile_write(args, kwds)) == NULL) {
2359         return NULL;
2360     }
2361 
2362     skIPSetClean(self->ipset);
2363     rv = skIPSetWrite(self->ipset, stream);
2364     skStreamDestroy(&stream);
2365     if (rv != SKIPSET_OK) {
2366         PyErr_SetString(PyExc_IOError, skIPSetStrerror(rv));
2367         return NULL;
2368     }
2369 
2370     Py_RETURN_NONE;
2371 }
2372 
2373 static PyObject *
silkPyIPSet_union_update(silkPyIPSet * self,silkPyIPSet * obj)2374 silkPyIPSet_union_update(
2375     silkPyIPSet        *self,
2376     silkPyIPSet        *obj)
2377 {
2378     int rv;
2379 
2380     if (!silkPyIPSet_Check(obj)) {
2381         PyErr_SetString(PyExc_NotImplementedError,
2382                         "Argument must be a silk.IPSet");
2383         return NULL;
2384     }
2385 
2386     skIPSetClean(self->ipset);
2387     skIPSetClean(obj->ipset);
2388     rv = skIPSetUnion(self->ipset, obj->ipset);
2389     if (rv != 0) {
2390         return PyErr_NoMemory();
2391     }
2392 
2393     Py_INCREF(self);
2394     return (PyObject*)self;
2395 }
2396 
2397 
2398 /* *************************************************************************
2399  *   Prefix Map
2400  *************************************************************************
2401  */
2402 
2403 typedef struct silkPyPmap_st {
2404     PyObject_HEAD
2405     skPrefixMap_t *map;
2406 } silkPyPmap;
2407 
2408 typedef struct silkPyPmapIter_st {
2409     PyObject_HEAD
2410     silkPyPmap *map;
2411     skPrefixMapIterator_t iter;
2412 } silkPyPmapIter;
2413 
2414 /* function prototypes */
2415 static void
2416 silkPyPmapIter_dealloc(
2417     silkPyPmapIter     *self);
2418 static PyObject *
2419 silkPyPmapIter_iternext(
2420     silkPyPmapIter     *self);
2421 static void
2422 silkPyPmap_dealloc(
2423     silkPyPmap         *obj);
2424 static PyObject *
2425 silkPyPmap_get_content(
2426     silkPyPmap         *self,
2427     void        UNUSED(*cbdata));
2428 static PyObject *
2429 silkPyPmap_get_name(
2430     silkPyPmap         *self,
2431     void        UNUSED(*cbdata));
2432 static PyObject *
2433 silkPyPmap_get_num_values(
2434     silkPyPmap         *self,
2435     void        UNUSED(*cbdata));
2436 static PyObject *
2437 silkPyPmap_get_value_string(
2438     silkPyPmap         *self,
2439     PyObject           *value);
2440 static int
2441 silkPyPmap_init(
2442     silkPyPmap         *self,
2443     PyObject           *args,
2444     PyObject           *kwds);
2445 static PyObject *
2446 silkPyPmap_iter(
2447     silkPyPmap         *self);
2448 static PyObject *
2449 silkPyPmap_subscript(
2450     silkPyPmap         *self,
2451     PyObject           *sub);
2452 
2453 /* define docs and methods */
2454 #define silkPyPmap_doc                                  \
2455     "PMapBase(filename) -> Prefix map from file"
2456 
2457 static PyMethodDef silkPyPmap_methods[] = {
2458     {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
2459     {"get_value_string", (PyCFunction)silkPyPmap_get_value_string, METH_O,
2460      ("Get the string associated with an integer value")},
2461     {NULL, NULL, 0, NULL}       /* Sentinel */
2462 };
2463 
2464 static PyGetSetDef silkPyPmap_getsetters[] = {
2465     {"content", (getter)silkPyPmap_get_content, NULL, "Content type", NULL},
2466     {"name", (getter)silkPyPmap_get_name, NULL, "Prefix map name", NULL},
2467     {"num_values", (getter)silkPyPmap_get_num_values, NULL,
2468      "Prefix map number of values", NULL},
2469     {NULL, NULL, NULL, NULL, NULL}
2470 };
2471 
2472 static PyMappingMethods silkPyPmap_mapping_methods = {
2473     0,
2474     (binaryfunc)silkPyPmap_subscript,
2475     0
2476 };
2477 
2478 /* define the object types */
2479 static PyTypeObject silkPyPmapType = {
2480     PyVarObject_HEAD_INIT(NULL, 0)
2481     "silk.pysilk.PMapBase",     /* tp_name */
2482     sizeof(silkPyPmap),         /* tp_basicsize */
2483     0,                          /* tp_itemsize */
2484     (destructor)silkPyPmap_dealloc, /* tp_dealloc */
2485     0,                          /* tp_vectorcall_offset (Py 3.8) */
2486     0,                          /* tp_getattr */
2487     0,                          /* tp_setattr */
2488     0,                          /* tp_as_async (tp_compare in Py2.x) */
2489     0,                          /* tp_repr */
2490     0,                          /* tp_as_number */
2491     0,                          /* tp_as_sequence */
2492     &silkPyPmap_mapping_methods, /* tp_as_mapping */
2493     0,                          /* tp_hash  */
2494     0,                          /* tp_call */
2495     0,                          /* tp_str */
2496     0,                          /* tp_getattro */
2497     0,                          /* tp_setattro */
2498     0,                          /* tp_as_buffer */
2499     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
2500     silkPyPmap_doc,             /* tp_doc */
2501     0,                          /* tp_traverse */
2502     0,                          /* tp_clear */
2503     0,                          /* tp_richcompare */
2504     0,                          /* tp_weaklistoffset */
2505     (getiterfunc)silkPyPmap_iter, /* tp_iter */
2506     0,                          /* tp_iternext */
2507     silkPyPmap_methods,         /* tp_methods */
2508     0,                          /* tp_members */
2509     silkPyPmap_getsetters,      /* tp_getset */
2510     0,                          /* tp_base */
2511     0,                          /* tp_dict */
2512     0,                          /* tp_descr_get */
2513     0,                          /* tp_descr_set */
2514     0,                          /* tp_dictoffset */
2515     (initproc)silkPyPmap_init,  /* tp_init */
2516     0,                          /* tp_alloc */
2517     0,                          /* tp_new */
2518     0,                          /* tp_free */
2519     0,                          /* tp_is_gc */
2520     0,                          /* tp_bases */
2521     0,                          /* tp_mro */
2522     0,                          /* tp_cache */
2523     0,                          /* tp_subclasses */
2524     0,                          /* tp_weaklist */
2525     0                           /* tp_del */
2526 #if PY_VERSION_HEX >= 0x02060000
2527     ,0                          /* tp_version_tag */
2528 #endif
2529 #if PY_VERSION_HEX >= 0x03040000
2530     ,0                          /* tp_finalize */
2531 #endif
2532 #if PY_VERSION_HEX >= 0x03080000
2533     ,0                          /* tp_vectorcall */
2534     ,0                          /* tp_print */
2535 #endif
2536 };
2537 
2538 static PyTypeObject silkPyPmapIterType = {
2539     PyVarObject_HEAD_INIT(NULL, 0)
2540     "silk.pysilk.PMapBaseIter", /* tp_name */
2541     sizeof(silkPyPmapIterType), /* tp_basicsize */
2542     0,                          /* tp_itemsize */
2543     (destructor)silkPyPmapIter_dealloc, /* tp_dealloc */
2544     0,                          /* tp_vectorcall_offset (Py 3.8) */
2545     0,                          /* tp_getattr */
2546     0,                          /* tp_setattr */
2547     0,                          /* tp_as_async (tp_compare in Py2.x) */
2548     0,                          /* tp_repr */
2549     0,                          /* tp_as_number */
2550     0,                          /* tp_as_sequence */
2551     0,                          /* tp_as_mapping */
2552     0,                          /* tp_hash  */
2553     0,                          /* tp_call */
2554     0,                          /* tp_str */
2555     0,                          /* tp_getattro */
2556     0,                          /* tp_setattro */
2557     0,                          /* tp_as_buffer */
2558     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
2559     "Prefix map iterator object", /* tp_doc */
2560     0,                          /* tp_traverse */
2561     0,                          /* tp_clear */
2562     0,                          /* tp_richcompare */
2563     0,                          /* tp_weaklistoffset */
2564     iter_iter,                  /* tp_iter */
2565     (iternextfunc)silkPyPmapIter_iternext, /* tp_iternext */
2566     0,                          /* tp_methods */
2567     0,                          /* tp_members */
2568     0,                          /* tp_getset */
2569     0,                          /* tp_base */
2570     0,                          /* tp_dict */
2571     0,                          /* tp_descr_get */
2572     0,                          /* tp_descr_set */
2573     0,                          /* tp_dictoffset */
2574     0,                          /* tp_init */
2575     0,                          /* tp_alloc */
2576     0,                          /* tp_new */
2577     0,                          /* tp_free */
2578     0,                          /* tp_is_gc */
2579     0,                          /* tp_bases */
2580     0,                          /* tp_mro */
2581     0,                          /* tp_cache */
2582     0,                          /* tp_subclasses */
2583     0,                          /* tp_weaklist */
2584     0                           /* tp_del */
2585 #if PY_VERSION_HEX >= 0x02060000
2586     ,0                          /* tp_version_tag */
2587 #endif
2588 #if PY_VERSION_HEX >= 0x03040000
2589     ,0                          /* tp_finalize */
2590 #endif
2591 #if PY_VERSION_HEX >= 0x03080000
2592     ,0                          /* tp_vectorcall */
2593     ,0                          /* tp_print */
2594 #endif
2595 };
2596 
2597 /* macro and function defintions */
2598 #define silkPyPmap_Check(op)                    \
2599     PyObject_TypeCheck(op, &silkPyPmapType)
2600 #define silkPyPmapIter_Check(op)                \
2601     PyObject_TypeCheck(op, &silkPyPmapIterType)
2602 
2603 static void
silkPyPmapIter_dealloc(silkPyPmapIter * self)2604 silkPyPmapIter_dealloc(
2605     silkPyPmapIter     *self)
2606 {
2607     Py_XDECREF(self->map);
2608     Py_TYPE(self)->tp_free((PyObject*)self);
2609 }
2610 
2611 static PyObject *
silkPyPmapIter_iternext(silkPyPmapIter * self)2612 silkPyPmapIter_iternext(
2613     silkPyPmapIter     *self)
2614 {
2615     skIteratorStatus_t    rv;
2616     PyObject             *retval;
2617     PyObject             *startval = NULL;
2618     PyObject             *endval = NULL;
2619     union {
2620         skipaddr_t             addr;
2621         skPrefixMapProtoPort_t pp;
2622     } start, end;
2623     uint32_t              value;
2624     skPrefixMapContent_t  content;
2625 
2626     rv = skPrefixMapIteratorNext(&self->iter, &start, &end, &value);
2627     if (rv == SK_ITERATOR_NO_MORE_ENTRIES) {
2628         PyErr_SetNone(PyExc_StopIteration);
2629         return NULL;
2630     }
2631 
2632     content = skPrefixMapGetContentType(self->map->map);
2633     switch (content) {
2634       case SKPREFIXMAP_CONT_ADDR_V4:
2635       case SKPREFIXMAP_CONT_ADDR_V6:
2636         {
2637             PyTypeObject *type =
2638                 (content == SKPREFIXMAP_CONT_ADDR_V4) ?
2639                 &silkPyIPv4AddrType : &silkPyIPv6AddrType;
2640 
2641             startval = type->tp_alloc(type, 0);
2642             if (startval == NULL) {
2643                 return NULL;
2644             }
2645             endval = type->tp_alloc(type, 0);
2646             if (endval == NULL) {
2647                 Py_DECREF(startval);
2648                 return NULL;
2649             }
2650             skipaddrCopy(&((silkPyIPAddr*)startval)->addr, &start.addr);
2651             skipaddrCopy(&((silkPyIPAddr*)endval)->addr, &end.addr);
2652         }
2653         break;
2654       case SKPREFIXMAP_CONT_PROTO_PORT:
2655         {
2656             startval = Py_BuildValue("BH", start.pp.proto, start.pp.port);
2657             if (startval == NULL) {
2658                 return NULL;
2659             }
2660             endval = Py_BuildValue("BH", end.pp.proto, end.pp.port);
2661             if (endval == NULL) {
2662                 Py_DECREF(startval);
2663                 return NULL;
2664             }
2665         }
2666         break;
2667     }
2668     assert(startval && endval);
2669 
2670     retval = Py_BuildValue("NNk", startval, endval, value);
2671     if (retval == NULL) {
2672         Py_DECREF(startval);
2673         Py_DECREF(endval);
2674     }
2675 
2676     return retval;
2677 }
2678 
2679 static void
silkPyPmap_dealloc(silkPyPmap * obj)2680 silkPyPmap_dealloc(
2681     silkPyPmap         *obj)
2682 {
2683     if (obj->map) {
2684         skPrefixMapDelete(obj->map);
2685     }
2686     Py_TYPE(obj)->tp_free((PyObject*)obj);
2687 }
2688 
2689 static PyObject *
silkPyPmap_get_content(silkPyPmap * self,void UNUSED (* cbdata))2690 silkPyPmap_get_content(
2691     silkPyPmap         *self,
2692     void        UNUSED(*cbdata))
2693 {
2694     return PyUnicode_FromString(skPrefixMapGetContentName(
2695                                     skPrefixMapGetContentType(self->map)));
2696 }
2697 
2698 static PyObject *
silkPyPmap_get_name(silkPyPmap * self,void UNUSED (* cbdata))2699 silkPyPmap_get_name(
2700     silkPyPmap         *self,
2701     void        UNUSED(*cbdata))
2702 {
2703     const char *name = skPrefixMapGetMapName(self->map);
2704     if (name == NULL) {
2705         Py_RETURN_NONE;
2706     }
2707 
2708     return PyUnicode_FromString(name);
2709 }
2710 
2711 static PyObject *
silkPyPmap_get_num_values(silkPyPmap * self,void UNUSED (* cbdata))2712 silkPyPmap_get_num_values(
2713     silkPyPmap         *self,
2714     void        UNUSED(*cbdata))
2715 {
2716     return PyInt_FromLong(skPrefixMapDictionaryGetWordCount(self->map));
2717 }
2718 
2719 static PyObject *
silkPyPmap_get_value_string(silkPyPmap * self,PyObject * value)2720 silkPyPmap_get_value_string(
2721     silkPyPmap         *self,
2722     PyObject           *value)
2723 {
2724     uint32_t  val;
2725     uint32_t  size;
2726     char     *buf;
2727     int       rv;
2728     PyObject *retval;
2729 
2730     if (!IS_INT(value)) {
2731         PyErr_SetString(PyExc_TypeError, "Expected an integer");
2732         return NULL;
2733     }
2734 
2735     val = PyLong_AsUnsignedLong(value);
2736     if (PyErr_Occurred()) {
2737         return NULL;
2738     }
2739 
2740     size = skPrefixMapDictionaryGetMaxWordSize(self->map) + 1;
2741     buf = (char*)malloc(size);
2742     if (buf == NULL) {
2743         return PyErr_NoMemory();
2744     }
2745 
2746     rv = skPrefixMapDictionaryGetEntry(self->map, val, buf, size);
2747     assert(rv < (int32_t)size);
2748 
2749     retval = PyUnicode_DecodeASCII(buf, rv, "strict");
2750     free(buf);
2751 
2752     return retval;
2753 }
2754 
2755 static int
silkPyPmap_init(silkPyPmap * self,PyObject * args,PyObject * kwds)2756 silkPyPmap_init(
2757     silkPyPmap         *self,
2758     PyObject           *args,
2759     PyObject           *kwds)
2760 {
2761     static char      *kwlist[] = {"filename", NULL};
2762     char              errbuf[2 * PATH_MAX];
2763     skstream_t       *stream = NULL;
2764     char             *fname;
2765     int               rv;
2766 
2767     if (!PyArg_ParseTupleAndKeywords(args, kwds, "et", kwlist,
2768                                      Py_FileSystemDefaultEncoding, &fname))
2769     {
2770         return -1;
2771     }
2772 
2773     if ((rv = skStreamCreate(&stream, SK_IO_READ, SK_CONTENT_SILK))
2774         || (rv = skStreamBind(stream, fname))
2775         || (rv = skStreamOpen(stream)))
2776     {
2777         skStreamLastErrMessage(stream, rv, errbuf, sizeof(errbuf));
2778         PyErr_Format(PyExc_IOError, "Unable to read prefix map from %s: %s",
2779                      fname, errbuf);
2780         skStreamDestroy(&stream);
2781         PyMem_Free(fname);
2782         return -1;
2783     }
2784     rv = (int)skPrefixMapRead(&self->map, stream);
2785     if (rv) {
2786         if (SKPREFIXMAP_ERR_IO == rv) {
2787             skStreamLastErrMessage(stream,
2788                                    skStreamGetLastReturnValue(stream),
2789                                    errbuf, sizeof(errbuf));
2790         } else {
2791             strncpy(errbuf, skPrefixMapStrerror(rv), sizeof(errbuf));
2792         }
2793         PyErr_Format(PyExc_IOError, "Unable to read prefix map from %s: %s",
2794                      fname, errbuf);
2795         skStreamDestroy(&stream);
2796         PyMem_Free(fname);
2797         return -1;
2798     }
2799     skStreamDestroy(&stream);
2800     PyMem_Free(fname);
2801 
2802     return 0;
2803 }
2804 
2805 static PyObject *
silkPyPmap_iter(silkPyPmap * self)2806 silkPyPmap_iter(
2807     silkPyPmap         *self)
2808 {
2809     int             rv;
2810     silkPyPmapIter *iter;
2811 
2812     iter = (silkPyPmapIter*)silkPyPmapIterType.tp_alloc(
2813         &silkPyPmapIterType, 0);
2814     if (iter) {
2815         rv = skPrefixMapIteratorBind(&iter->iter, self->map);
2816         if (rv != 0) {
2817             Py_DECREF(iter);
2818             PyErr_SetString(PyExc_RuntimeError,
2819                             "Failed to create prefix map iterator");
2820             return NULL;
2821         }
2822         Py_INCREF(self);
2823         iter->map = self;
2824     }
2825     return (PyObject*)iter;
2826 }
2827 
2828 static PyObject *
silkPyPmap_subscript(silkPyPmap * self,PyObject * sub)2829 silkPyPmap_subscript(
2830     silkPyPmap         *self,
2831     PyObject           *sub)
2832 {
2833     void *key = NULL;
2834     uint32_t value;
2835     skPrefixMapProtoPort_t protoport;
2836     skPrefixMapContent_t content;
2837     PyObject *tuple;
2838     int32_t i32;
2839     int rv;
2840 
2841     content = skPrefixMapGetContentType(self->map);
2842 
2843     switch (content) {
2844       case SKPREFIXMAP_CONT_ADDR_V4:
2845       case SKPREFIXMAP_CONT_ADDR_V6:
2846         if (!silkPyIPAddr_Check(sub)) {
2847             PyErr_SetString(PyExc_TypeError, "Expected an IPAddr");
2848             return NULL;
2849         }
2850         key = &((silkPyIPAddr*)sub)->addr;
2851         break;
2852       case SKPREFIXMAP_CONT_PROTO_PORT:
2853         if (!PySequence_Check(sub) || PySequence_Size(sub) != 2) {
2854             PyErr_SetString(PyExc_TypeError, "Expected a (proto, port) pair");
2855             return NULL;
2856         }
2857         tuple = PySequence_Tuple(sub);
2858         if (tuple == NULL) {
2859             return NULL;
2860         }
2861         rv = PyArg_ParseTuple(tuple, "bi;Expected a (proto, port) pair",
2862                               &protoport.proto, &i32);
2863         Py_DECREF(tuple);
2864         if (!rv) {
2865             return NULL;
2866         }
2867         if (i32 < 0 || i32 > 0xFFFF) {
2868             PyErr_SetString(PyExc_ValueError, "Port is out of bounds");
2869             return NULL;
2870         }
2871         protoport.port = i32;
2872         key = &protoport;
2873         break;
2874     }
2875 
2876     value = skPrefixMapFindValue(self->map, key);
2877 
2878     return PyLong_FromUnsignedLong(value);
2879 }
2880 
2881 
2882 /*
2883  *************************************************************************
2884  *   Bag
2885  *************************************************************************
2886  */
2887 
2888 typedef struct silkPyBag_st {
2889     PyObject_HEAD
2890     skBag_t *bag;
2891     unsigned is_ipaddr : 1;
2892 } silkPyBag;
2893 
2894 typedef struct silkPyBagIter_st {
2895     PyObject_HEAD
2896     silkPyBag       *bag;
2897     skBagIterator_t *iter;
2898     unsigned         ipaddr : 1;
2899 } silkPyBagIter;
2900 
2901 /* function prototypes */
2902 static void
2903 silkPyBagIter_dealloc(
2904     silkPyBagIter      *self);
2905 static PyObject *
2906 silkPyBagIter_iternext(
2907     silkPyBagIter      *self);
2908 static PyObject *
2909 silkPyBag__get_custom_type(
2910     PyObject    UNUSED(*self));
2911 static PyObject *
2912 silkPyBag__get_ipv4_type(
2913     PyObject    UNUSED(*self));
2914 static PyObject *
2915 silkPyBag__get_ipv6_type(
2916     PyObject    UNUSED(*self));
2917 static int
2918 silkPyBag_ass_subscript(
2919     silkPyBag          *self,
2920     PyObject           *sub,
2921     PyObject           *value);
2922 static PyObject *
2923 silkPyBag_clear(
2924     silkPyBag          *self);
2925 static Py_ssize_t
2926 silkPyBag_count(
2927     silkPyBag          *self);
2928 static void
2929 silkPyBag_dealloc(
2930     silkPyBag          *obj);
2931 static PyObject *
2932 silkPyBag_decr(
2933     silkPyBag          *self,
2934     PyObject           *args,
2935     PyObject           *kwds);
2936 static PyObject *
2937 silkPyBag_field_types(
2938     PyObject    UNUSED(*self));
2939 static PyObject *
2940 silkPyBag_get_info(
2941     silkPyBag          *self);
2942 static PyObject *
2943 silkPyBag_iadd(
2944     silkPyBag          *self,
2945     silkPyBag          *other);
2946 #if 0
2947 static skBagErr_t
2948 silkPyBag_iadd_bounds(
2949     const skBagTypedKey_t       UNUSED(*key),
2950     skBagTypedCounter_t                *in_out_counter,
2951     const skBagTypedCounter_t   UNUSED(*in_counter),
2952     void                        UNUSED(*cb_data));
2953 #endif
2954 static PyObject *
2955 silkPyBag_incr(
2956     silkPyBag          *self,
2957     PyObject           *args,
2958     PyObject           *kwds);
2959 static int
2960 silkPyBag_init(
2961     silkPyBag          *self,
2962     PyObject           *args,
2963     PyObject           *kwds);
2964 static PyObject *
2965 silkPyBag_iter(
2966     silkPyBag          *self);
2967 static PyObject *
2968 silkPyBag_iter_helper(
2969     silkPyBag          *self,
2970     int                 sorted);
2971 static int
2972 silkPyBag_modify(
2973     silkPyBag          *self,
2974     PyObject           *sub,
2975     PyObject           *value,
2976     silkBagModFn        fn);
2977 static PyObject *
2978 silkPyBag_save(
2979     silkPyBag          *self,
2980     PyObject           *args,
2981     PyObject           *kwds);
2982 static PyObject *
2983 silkPyBag_set_info(
2984     silkPyBag          *self,
2985     PyObject           *args,
2986     PyObject           *kwds);
2987 static int
2988 silkPyBag_setup(
2989     PyObject           *mod);
2990 static PyObject *
2991 silkPyBag_sorted_iter(
2992     silkPyBag          *self);
2993 static PyObject *
2994 silkPyBag_subscript(
2995     silkPyBag          *self,
2996     PyObject           *sub);
2997 static PyObject *
2998 silkPyBag_type_merge(
2999     PyObject    UNUSED(*self),
3000     PyObject           *args);
3001 
3002 /* define docs and methods */
3003 #define silkPyBag_doc                           \
3004     "BagBase(filename) -> Bag from file"
3005 
3006 static PyNumberMethods silkPyBag_number_methods;
3007 
3008 static PyMappingMethods silkPyBag_mapping_methods = {
3009 #if PY_VERSION_HEX < 0x02050000
3010     (inquiry)silkPyBag_count,   /* mp_length */
3011 #else
3012     (lenfunc)silkPyBag_count,   /* mp_length */
3013 #endif
3014     (binaryfunc)silkPyBag_subscript,       /* mp_subscript */
3015     (objobjargproc)silkPyBag_ass_subscript /* mp_ass_subscript */
3016 };
3017 
3018 static PyMethodDef silkPyBag_methods[] = {
3019     {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
3020     {"incr", (PyCFunction)silkPyBag_incr, METH_KEYWORDS | METH_VARARGS,
3021      ("bag.incr(key, value) -- increments bag[key] by value")},
3022     {"decr", (PyCFunction)silkPyBag_decr, METH_KEYWORDS | METH_VARARGS,
3023      ("bag.decr(key, value) -- decrements bag[key] by value")},
3024     {"save", (PyCFunction)silkPyBag_save, METH_KEYWORDS | METH_VARARGS,
3025      "bag.save(filename[, compression]) -- saves the bag to a file"},
3026     {"clear", (PyCFunction)silkPyBag_clear, METH_NOARGS,
3027      "bag.clear() -- empties the bag"},
3028     {"sorted_iter", (PyCFunction)silkPyBag_sorted_iter, METH_NOARGS,
3029      ("bag.sorted_iter() -- returns an iterator whose values are "
3030       "sorted by key")},
3031     {"get_info", (PyCFunction)silkPyBag_get_info, METH_NOARGS,
3032      "get_info() -- returns (key_type, key_len, counter_type, counter_len)"},
3033     {"set_info", (PyCFunction)silkPyBag_set_info,
3034      METH_KEYWORDS | METH_VARARGS,
3035      ("set_info([key_type][, key_len][, counter_type][, counter_len]) --\n\t"
3036       "returns the result of bag.get_info()")},
3037     {"field_types", (PyCFunction)silkPyBag_field_types,
3038      METH_NOARGS | METH_STATIC,
3039      "field_types() -> Tuple of valid field types for Bag keys and counters"},
3040     {"type_merge", (PyCFunction)silkPyBag_type_merge,
3041      METH_VARARGS | METH_STATIC,
3042      "type_merge(keytype_a, keytype_b) -> key_type of merged output"},
3043     {"_get_custom_type", (PyCFunction)silkPyBag__get_custom_type,
3044      METH_NOARGS | METH_STATIC, NULL},
3045     {"_get_ipv4_type", (PyCFunction)silkPyBag__get_ipv4_type,
3046      METH_NOARGS | METH_STATIC, NULL},
3047     {"_get_ipv6_type", (PyCFunction)silkPyBag__get_ipv6_type,
3048      METH_NOARGS | METH_STATIC, NULL},
3049     {NULL, NULL, 0, NULL}       /* Sentinel */
3050 };
3051 
3052 
3053 /* define the object types */
3054 static PyTypeObject silkPyBagType = {
3055     PyVarObject_HEAD_INIT(NULL, 0)
3056     "silk.pysilk.BagBase",      /* tp_name */
3057     sizeof(silkPyBag),          /* tp_basicsize */
3058     0,                          /* tp_itemsize */
3059     (destructor)silkPyBag_dealloc, /* tp_dealloc */
3060     0,                          /* tp_vectorcall_offset (Py 3.8) */
3061     0,                          /* tp_getattr */
3062     0,                          /* tp_setattr */
3063     0,                          /* tp_as_async (tp_compare in Py2.x) */
3064     0,                          /* tp_repr */
3065     &silkPyBag_number_methods,  /* tp_as_number */
3066     0,                          /* tp_as_sequence */
3067     &silkPyBag_mapping_methods, /* tp_as_mapping */
3068     0,                          /* tp_hash  */
3069     0,                          /* tp_call */
3070     0,                          /* tp_str */
3071     0,                          /* tp_getattro */
3072     0,                          /* tp_setattro */
3073     0,                          /* tp_as_buffer */
3074 #if PY_MAJOR_VERSION < 3
3075     Py_TPFLAGS_CHECKTYPES |
3076 #endif
3077     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
3078     silkPyBag_doc,              /* tp_doc */
3079     0,                          /* tp_traverse */
3080     0,                          /* tp_clear */
3081     0,                          /* tp_richcompare */
3082     0,                          /* tp_weaklistoffset */
3083     (getiterfunc)silkPyBag_iter, /* tp_iter */
3084     0,                          /* tp_iternext */
3085     silkPyBag_methods,          /* tp_methods */
3086     0,                          /* tp_members */
3087     0,                          /* tp_getset */
3088     0,                          /* tp_base */
3089     0,                          /* tp_dict */
3090     0,                          /* tp_descr_get */
3091     0,                          /* tp_descr_set */
3092     0,                          /* tp_dictoffset */
3093     (initproc)silkPyBag_init,   /* tp_init */
3094     0,                          /* tp_alloc */
3095     0,                          /* tp_new */
3096     0,                          /* tp_free */
3097     0,                          /* tp_is_gc */
3098     0,                          /* tp_bases */
3099     0,                          /* tp_mro */
3100     0,                          /* tp_cache */
3101     0,                          /* tp_subclasses */
3102     0,                          /* tp_weaklist */
3103     0                           /* tp_del */
3104 #if PY_VERSION_HEX >= 0x02060000
3105     ,0                          /* tp_version_tag */
3106 #endif
3107 #if PY_VERSION_HEX >= 0x03040000
3108     ,0                          /* tp_finalize */
3109 #endif
3110 #if PY_VERSION_HEX >= 0x03080000
3111     ,0                          /* tp_vectorcall */
3112     ,0                          /* tp_print */
3113 #endif
3114 };
3115 
3116 static PyTypeObject silkPyBagIterType = {
3117     PyVarObject_HEAD_INIT(NULL, 0)
3118     "silk.pysilk.BagBaseIter",  /* tp_name */
3119     sizeof(silkPyBagIterType),  /* tp_basicsize */
3120     0,                          /* tp_itemsize */
3121     (destructor)silkPyBagIter_dealloc, /* tp_dealloc */
3122     0,                          /* tp_vectorcall_offset (Py 3.8) */
3123     0,                          /* tp_getattr */
3124     0,                          /* tp_setattr */
3125     0,                          /* tp_as_async (tp_compare in Py2.x) */
3126     0,                          /* tp_repr */
3127     0,                          /* tp_as_number */
3128     0,                          /* tp_as_sequence */
3129     0,                          /* tp_as_mapping */
3130     0,                          /* tp_hash  */
3131     0,                          /* tp_call */
3132     0,                          /* tp_str */
3133     0,                          /* tp_getattro */
3134     0,                          /* tp_setattro */
3135     0,                          /* tp_as_buffer */
3136     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
3137     "Bag iterator object",      /* tp_doc */
3138     0,                          /* tp_traverse */
3139     0,                          /* tp_clear */
3140     0,                          /* tp_richcompare */
3141     0,                          /* tp_weaklistoffset */
3142     iter_iter,                  /* tp_iter */
3143     (iternextfunc)silkPyBagIter_iternext, /* tp_iternext */
3144     0,                          /* tp_methods */
3145     0,                          /* tp_members */
3146     0,                          /* tp_getset */
3147     0,                          /* tp_base */
3148     0,                          /* tp_dict */
3149     0,                          /* tp_descr_get */
3150     0,                          /* tp_descr_set */
3151     0,                          /* tp_dictoffset */
3152     0,                          /* tp_init */
3153     0,                          /* tp_alloc */
3154     0,                          /* tp_new */
3155     0,                          /* tp_free */
3156     0,                          /* tp_is_gc */
3157     0,                          /* tp_bases */
3158     0,                          /* tp_mro */
3159     0,                          /* tp_cache */
3160     0,                          /* tp_subclasses */
3161     0,                          /* tp_weaklist */
3162     0                           /* tp_del */
3163 #if PY_VERSION_HEX >= 0x02060000
3164     ,0                          /* tp_version_tag */
3165 #endif
3166 #if PY_VERSION_HEX >= 0x03040000
3167     ,0                          /* tp_finalize */
3168 #endif
3169 #if PY_VERSION_HEX >= 0x03080000
3170     ,0                          /* tp_vectorcall */
3171     ,0                          /* tp_print */
3172 #endif
3173 };
3174 
3175 /* macro and function defintions */
3176 #define silkPyBag_Check(op)                     \
3177     PyObject_TypeCheck(op, &silkPyBagType)
3178 #define silkPyBagIter_Check(op)                 \
3179     PyObject_TypeCheck(op, &silkPyBagIterType)
3180 
3181 #define IS_IPV4_KEY(k)                          \
3182     ((k) == SKBAG_FIELD_SIPv4                   \
3183      || (k) == SKBAG_FIELD_DIPv4                \
3184      || (k) == SKBAG_FIELD_NHIPv4               \
3185      || (k) == SKBAG_FIELD_ANY_IPv4)
3186 
3187 #define IS_IPV6_KEY(k)                          \
3188     ((k) == SKBAG_FIELD_SIPv6                   \
3189      || (k) == SKBAG_FIELD_DIPv6                \
3190      || (k) == SKBAG_FIELD_NHIPv6               \
3191      || (k) == SKBAG_FIELD_ANY_IPv6)
3192 
3193 #define IS_IP_KEY(k) (IS_IPV4_KEY(k) || IS_IPV6_KEY(k))
3194 
3195 static void
silkPyBagIter_dealloc(silkPyBagIter * self)3196 silkPyBagIter_dealloc(
3197     silkPyBagIter      *self)
3198 {
3199     Py_XDECREF(self->bag);
3200     skBagIteratorDestroy(self->iter);
3201     Py_TYPE(self)->tp_free((PyObject*)self);
3202 }
3203 
3204 static PyObject *
silkPyBagIter_iternext(silkPyBagIter * self)3205 silkPyBagIter_iternext(
3206     silkPyBagIter      *self)
3207 {
3208     skBagErr_t           rv;
3209     PyObject            *retkey;
3210     PyObject            *retval;
3211     skBagTypedKey_t      key;
3212     skBagTypedCounter_t  counter;
3213 
3214     counter.type = SKBAG_COUNTER_U64;
3215     key.type = self->ipaddr ? SKBAG_KEY_IPADDR : SKBAG_KEY_U32;
3216 
3217     rv = skBagIteratorNextTyped(self->iter, &key, &counter);
3218     if (rv == SKBAG_ERR_KEY_NOT_FOUND) {
3219         PyErr_SetNone(PyExc_StopIteration);
3220         return NULL;
3221     }
3222     if (rv == SKBAG_ERR_MODIFIED) {
3223         PyErr_SetString(PyExc_RuntimeError,
3224                         "Underlying Bag changed during iteration");
3225         return NULL;
3226     }
3227     if (self->ipaddr) {
3228         PyTypeObject *type = (skipaddrIsV6(&key.val.addr)
3229                               ? &silkPyIPv6AddrType : &silkPyIPv4AddrType);
3230         retkey = type->tp_alloc(type, 0);
3231         if (retkey == NULL) {
3232             return NULL;
3233         }
3234         skipaddrCopy(&((silkPyIPAddr*)retkey)->addr, &key.val.addr);
3235     } else {
3236         retkey = PyLong_FromUnsignedLong(key.val.u32);
3237         if (retkey == NULL) {
3238             return NULL;
3239         }
3240     }
3241 
3242     retval = Py_BuildValue("OK", retkey, counter.val.u64);
3243     Py_DECREF(retkey);
3244     return retval;
3245 }
3246 
3247 static PyObject *
silkPyBag__get_custom_type(PyObject UNUSED (* self))3248 silkPyBag__get_custom_type(
3249     PyObject    UNUSED(*self))
3250 {
3251     char buf[SKBAG_MAX_FIELD_BUFLEN];
3252 
3253     skBagFieldTypeAsString(SKBAG_FIELD_CUSTOM, buf, sizeof(buf));
3254     return PyUnicode_FromString(buf);
3255 }
3256 
3257 static PyObject *
silkPyBag__get_ipv4_type(PyObject UNUSED (* self))3258 silkPyBag__get_ipv4_type(
3259     PyObject    UNUSED(*self))
3260 {
3261     char buf[SKBAG_MAX_FIELD_BUFLEN];
3262 
3263     skBagFieldTypeAsString(SKBAG_FIELD_ANY_IPv4, buf, sizeof(buf));
3264     return PyUnicode_FromString(buf);
3265 }
3266 
3267 static PyObject *
silkPyBag__get_ipv6_type(PyObject UNUSED (* self))3268 silkPyBag__get_ipv6_type(
3269     PyObject    UNUSED(*self))
3270 {
3271     char buf[SKBAG_MAX_FIELD_BUFLEN];
3272 
3273     skBagFieldTypeAsString(SKBAG_FIELD_ANY_IPv6, buf, sizeof(buf));
3274     return PyUnicode_FromString(buf);
3275 }
3276 
3277 static int
silkPyBag_ass_subscript(silkPyBag * self,PyObject * sub,PyObject * value)3278 silkPyBag_ass_subscript(
3279     silkPyBag          *self,
3280     PyObject           *sub,
3281     PyObject           *value)
3282 {
3283     /* skBagCounterSet will ignore the extra NULL passed to it */
3284     return silkPyBag_modify(self, sub, value, (silkBagModFn)skBagCounterSet);
3285 }
3286 
3287 static PyObject *
silkPyBag_clear(silkPyBag * self)3288 silkPyBag_clear(
3289     silkPyBag          *self)
3290 {
3291     skBagErr_t rv;
3292     skBagFieldType_t key, value;
3293     size_t keylen, valuelen;
3294     skBag_t *bag;
3295 
3296     key = skBagKeyFieldType(self->bag);
3297     keylen = skBagKeyFieldLength(self->bag);
3298     value = skBagCounterFieldType(self->bag);
3299     valuelen = skBagCounterFieldLength(self->bag);
3300 
3301     rv = skBagCreateTyped(&bag, key, value, keylen, valuelen);
3302     if (rv == SKBAG_ERR_MEMORY) {
3303         return PyErr_NoMemory();
3304     }
3305     assert(rv == SKBAG_OK);
3306     skBagAutoConvertDisable(bag);
3307 
3308     skBagDestroy(&self->bag);
3309     self->bag = bag;
3310 
3311     Py_RETURN_NONE;
3312 }
3313 
3314 static Py_ssize_t
silkPyBag_count(silkPyBag * self)3315 silkPyBag_count(
3316     silkPyBag          *self)
3317 {
3318     uint64_t count = skBagCountKeys(self->bag);
3319     return (Py_ssize_t)count;
3320 }
3321 
3322 static void
silkPyBag_dealloc(silkPyBag * obj)3323 silkPyBag_dealloc(
3324     silkPyBag          *obj)
3325 {
3326     if (obj->bag) {
3327         skBagDestroy(&obj->bag);
3328     }
3329     Py_TYPE(obj)->tp_free((PyObject*)obj);
3330 }
3331 
3332 static PyObject *
silkPyBag_decr(silkPyBag * self,PyObject * args,PyObject * kwds)3333 silkPyBag_decr(
3334     silkPyBag          *self,
3335     PyObject           *args,
3336     PyObject           *kwds)
3337 {
3338     static char *kwlist[] = {"key", "value", NULL};
3339     PyObject *sub;
3340     PyObject *value;
3341 
3342     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &sub, &value)) {
3343         return NULL;
3344     }
3345 
3346     if (silkPyBag_modify(self, sub, value, skBagCounterSubtract)) {
3347         return NULL;
3348     }
3349 
3350     Py_RETURN_NONE;
3351 }
3352 
3353 static PyObject *
silkPyBag_field_types(PyObject UNUSED (* self))3354 silkPyBag_field_types(
3355     PyObject    UNUSED(*self))
3356 {
3357     char buf[SKBAG_MAX_FIELD_BUFLEN];
3358     skBagFieldTypeIterator_t iter;
3359     Py_ssize_t count;
3360     PyObject *retval;
3361 
3362     /* First, count thee types */
3363     skBagFieldTypeIteratorBind(&iter);
3364     count = 0;
3365     while (skBagFieldTypeIteratorNext(&iter, NULL, NULL, NULL, 0) == SKBAG_OK)
3366     {
3367         count++;
3368     }
3369 
3370     /* Create the tuple */
3371     retval = PyTuple_New(count);
3372     if (retval == NULL) {
3373         return NULL;
3374     }
3375 
3376     /* Then fill in the tuple */
3377     skBagFieldTypeIteratorReset(&iter);
3378     count = 0;
3379     while (skBagFieldTypeIteratorNext(&iter, NULL, NULL, buf, sizeof(buf))
3380            == SKBAG_OK)
3381     {
3382         PyObject *name = PyUnicode_InternFromString(buf);
3383         if (name == NULL) {
3384             Py_DECREF(retval);
3385             return NULL;
3386         }
3387         PyTuple_SET_ITEM(retval, count, name);
3388         count++;
3389     }
3390 
3391     return retval;
3392 }
3393 
3394 static PyObject *
silkPyBag_get_info(silkPyBag * self)3395 silkPyBag_get_info(
3396     silkPyBag          *self)
3397 {
3398     char buf[80];
3399     unsigned int key_len;
3400     unsigned int counter_len;
3401     PyObject *key_name;
3402     PyObject *counter_name;
3403 
3404     skBagKeyFieldName(self->bag, buf, sizeof(buf));
3405     key_len = skBagKeyFieldLength(self->bag);
3406     key_name = PyUnicode_FromString(buf);
3407     if (key_name == NULL) {
3408         return NULL;
3409     }
3410     skBagCounterFieldName(self->bag, buf, sizeof(buf));
3411     counter_len = skBagCounterFieldLength(self->bag);
3412     counter_name = PyUnicode_FromString(buf);
3413     if (counter_name == NULL) {
3414         Py_DECREF(key_name);
3415         return NULL;
3416     }
3417     return Py_BuildValue("{sN sI sN sI}",
3418                          "key_type", key_name, "key_len", key_len,
3419                          "counter_type", counter_name,
3420                          "counter_len", counter_len);
3421 }
3422 
3423 static PyObject *
silkPyBag_iadd(silkPyBag * self,silkPyBag * other)3424 silkPyBag_iadd(
3425     silkPyBag          *self,
3426     silkPyBag          *other)
3427 {
3428     skBagErr_t rv;
3429 
3430     if (!silkPyBag_Check(self) || !silkPyBag_Check(other)) {
3431         Py_INCREF(Py_NotImplemented);
3432         return Py_NotImplemented;
3433     }
3434 
3435     rv = skBagAddBag(self->bag, other->bag, NULL, NULL);
3436     switch (rv) {
3437       case SKBAG_OK:
3438         break;
3439       case SKBAG_ERR_MEMORY:
3440         PyErr_NoMemory();
3441         return NULL;
3442       case SKBAG_ERR_OP_BOUNDS:
3443         PyErr_SetString(PyExc_ValueError, skBagStrerror(rv));
3444         return NULL;
3445       case SKBAG_ERR_KEY_RANGE:
3446         PyErr_SetString(PyExc_ValueError, skBagStrerror(rv));
3447         return NULL;
3448       case SKBAG_ERR_INPUT:
3449       case SKBAG_ERR_KEY_NOT_FOUND:
3450         /* Fall through */
3451       default:
3452         skAbortBadCase(rv);
3453     }
3454     self->is_ipaddr = (skBagKeyFieldLength(self->bag) == 16
3455                        || IS_IP_KEY(skBagKeyFieldType(self->bag)));
3456 
3457     Py_INCREF(self);
3458     return (PyObject*)self;
3459 }
3460 
3461 #if 0
3462 /* Clamp bag values for iadd to SKBAG_COUNTER_MAX without errors. */
3463 static skBagErr_t
3464 silkPyBag_iadd_bounds(
3465     const skBagTypedKey_t       UNUSED(*key),
3466     skBagTypedCounter_t                *in_out_counter,
3467     const skBagTypedCounter_t   UNUSED(*in_counter),
3468     void                        UNUSED(*cb_data))
3469 {
3470     in_out_counter->type = SKBAG_COUNTER_U64;
3471     in_out_counter->val.u64 = SKBAG_COUNTER_MAX;
3472     return SKBAG_OK;
3473 }
3474 #endif
3475 
3476 static PyObject *
silkPyBag_incr(silkPyBag * self,PyObject * args,PyObject * kwds)3477 silkPyBag_incr(
3478     silkPyBag          *self,
3479     PyObject           *args,
3480     PyObject           *kwds)
3481 {
3482     static char *kwlist[] = {"key", "value", NULL};
3483     PyObject *sub;
3484     PyObject *value;
3485 
3486     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &sub, &value)) {
3487         return NULL;
3488     }
3489 
3490     if (silkPyBag_modify(self, sub, value, skBagCounterAdd)) {
3491         return NULL;
3492     }
3493 
3494     Py_RETURN_NONE;
3495 }
3496 
3497 static int
silkPyBag_init(silkPyBag * self,PyObject * args,PyObject * kwds)3498 silkPyBag_init(
3499     silkPyBag          *self,
3500     PyObject           *args,
3501     PyObject           *kwds)
3502 {
3503     static char *kwlist[] = {"copy", "filename", "key_type", "counter_type",
3504                              "key_len", "counter_len", NULL};
3505     char          errbuf[2 * PATH_MAX];
3506     skstream_t   *stream       = NULL;
3507     char         *fname        = NULL;
3508     silkPyBag    *copy         = NULL;
3509     char         *key          = NULL;
3510     char         *counter      = NULL;
3511     unsigned int  key_size     = 0;
3512     unsigned int  counter_size = 0;
3513     skBagErr_t    bagerr;
3514     int           rv;
3515 
3516     if (!PyArg_ParseTupleAndKeywords(
3517             args, kwds, "|O!etssII", kwlist, &silkPyBagType,
3518             (PyObject*)&copy, Py_FileSystemDefaultEncoding, &fname,
3519             &key, &counter, &key_size, &counter_size))
3520     {
3521         return -1;
3522     }
3523 
3524     if ((copy && fname)
3525         || (copy && (key || counter))
3526         || (fname && (key || counter)))
3527     {
3528         PyErr_SetString(PyExc_ValueError, "Illegal argument combination");
3529         return -1;
3530     }
3531 
3532     if (fname) {
3533         if ((rv = skStreamCreate(&stream, SK_IO_READ, SK_CONTENT_SILK))
3534             || (rv = skStreamBind(stream, fname))
3535             || (rv = skStreamOpen(stream)))
3536         {
3537             skStreamLastErrMessage(stream, rv, errbuf, sizeof(errbuf));
3538             PyErr_Format(PyExc_IOError, "Unable to read Bag from %s: %s",
3539                          fname, errbuf);
3540             skStreamDestroy(&stream);
3541             PyMem_Free(fname);
3542             return -1;
3543         }
3544         bagerr = skBagRead(&self->bag, stream);
3545         if (bagerr) {
3546             if (SKBAG_ERR_READ == bagerr) {
3547                 skStreamLastErrMessage(stream,
3548                                        skStreamGetLastReturnValue(stream),
3549                                        errbuf, sizeof(errbuf));
3550             } else {
3551                 strncpy(errbuf, skBagStrerror(bagerr), sizeof(errbuf));
3552             }
3553             PyErr_Format(PyExc_IOError, "Unable to read Bag from %s: %s",
3554                          fname, errbuf);
3555             skStreamDestroy(&stream);
3556             PyMem_Free(fname);
3557             return -1;
3558         }
3559         skStreamDestroy(&stream);
3560         PyMem_Free(fname);
3561         self->is_ipaddr = skBagKeyFieldLength(self->bag) == 16
3562                           || IS_IP_KEY(skBagKeyFieldType(self->bag));
3563     } else if (copy) {
3564         bagerr = skBagCopy(&self->bag, copy->bag);
3565         self->is_ipaddr = copy->is_ipaddr;
3566     } else {
3567         skBagFieldType_t key_type, counter_type;
3568         if (!key) {
3569             key_type = SKBAG_FIELD_CUSTOM;
3570         } else {
3571             bagerr = skBagFieldTypeLookup(key, &key_type, NULL);
3572             if (bagerr != SKBAG_OK) {
3573                 PyErr_Format(PyExc_ValueError,
3574                              "'%s' is not a valid key type", key);
3575                 return -1;
3576             }
3577         }
3578         if (key_type == SKBAG_FIELD_CUSTOM && key_size == 0) {
3579             key_size = 4;
3580         }
3581         if (!counter) {
3582             counter_type = SKBAG_FIELD_CUSTOM;
3583         } else {
3584             bagerr = skBagFieldTypeLookup(counter, &counter_type, NULL);
3585             if (bagerr != SKBAG_OK) {
3586                 PyErr_Format(PyExc_ValueError,
3587                              "'%s' is not a valid counter type", counter);
3588                 return -1;
3589             }
3590         }
3591         if (counter_type == SKBAG_FIELD_CUSTOM && counter_size == 0) {
3592             counter_size = 8;
3593         }
3594 
3595         bagerr = skBagCreateTyped(&self->bag, key_type, counter_type,
3596                                   key_size, counter_size);
3597         if (bagerr == SKBAG_ERR_INPUT) {
3598             PyErr_Format(PyExc_ValueError,
3599                          "Illegal arguments to Bag constructor");
3600             return -1;
3601         }
3602         skBagAutoConvertDisable(self->bag);
3603         self->is_ipaddr = (counter_size == 16 || IS_IP_KEY(key_type));
3604     }
3605 
3606     if (bagerr == SKBAG_ERR_MEMORY) {
3607         PyErr_NoMemory();
3608         return -1;
3609     }
3610     assert(bagerr == SKBAG_OK);
3611 
3612     return 0;
3613 }
3614 
3615 static PyObject *
silkPyBag_iter(silkPyBag * self)3616 silkPyBag_iter(
3617     silkPyBag          *self)
3618 {
3619     return silkPyBag_iter_helper(self, 0);
3620 }
3621 
3622 static PyObject *
silkPyBag_iter_helper(silkPyBag * self,int sorted)3623 silkPyBag_iter_helper(
3624     silkPyBag          *self,
3625     int                 sorted)
3626 {
3627     skBagErr_t     rv;
3628     silkPyBagIter *iter;
3629 
3630     iter = (silkPyBagIter*)silkPyBagIterType.tp_alloc(
3631         &silkPyBagIterType, 0);
3632     if (iter) {
3633         if (sorted) {
3634             rv = skBagIteratorCreate(self->bag, &iter->iter);
3635         } else {
3636             rv = skBagIteratorCreateUnsorted(self->bag, &iter->iter);
3637         }
3638         if (rv == SKBAG_ERR_MEMORY) {
3639             Py_DECREF(iter);
3640             return PyErr_NoMemory();
3641         }
3642         if (rv != SKBAG_OK) {
3643             Py_DECREF(iter);
3644             PyErr_SetString(PyExc_RuntimeError,
3645                             "Failed to create bag iterator");
3646             return NULL;
3647         }
3648         Py_INCREF(self);
3649         iter->bag = self;
3650         iter->ipaddr = self->is_ipaddr;
3651     }
3652     return (PyObject*)iter;
3653 }
3654 
3655 static int
silkPyBag_modify(silkPyBag * self,PyObject * sub,PyObject * value,silkBagModFn fn)3656 silkPyBag_modify(
3657     silkPyBag          *self,
3658     PyObject           *sub,
3659     PyObject           *value,
3660     silkBagModFn        fn)
3661 {
3662     skBagTypedCounter_t bagvalue;
3663     skBagTypedKey_t     key;
3664     skBagErr_t          rv;
3665 
3666     if (!IS_INT(value)) {
3667         PyErr_SetString(PyExc_TypeError, "Expected an integer value");
3668         return -1;
3669     }
3670     bagvalue.val.u64 = LONG_AS_UNSIGNED_LONGLONG(value);
3671     if (PyErr_Occurred()) {
3672         return -1;
3673     }
3674     bagvalue.type = SKBAG_COUNTER_U64;
3675 
3676     if (IS_INT(sub)) {
3677         if (self->is_ipaddr) {
3678             PyErr_SetString(PyExc_TypeError, "Expected an IPAddr index");
3679             return -1;
3680         }
3681         /* long long is 64-bits on 32 and 64-bit arches, so use it for
3682          * consistency. */
3683         key.val.u64 = LONG_AS_UNSIGNED_LONGLONG(sub);
3684         if (PyErr_Occurred()) {
3685             if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
3686                 PyErr_Clear();
3687                 PyErr_SetString(PyExc_IndexError, "Index out of range");
3688             }
3689             return -1;
3690         }
3691         if (key.val.u64 > 0xffffffff) {
3692             PyErr_SetString(PyExc_IndexError, "Index out of range");
3693             return -1;
3694         }
3695         key.val.u32 = key.val.u64;
3696         key.type = SKBAG_KEY_U32;
3697     } else if (silkPyIPAddr_Check(sub)) {
3698         silkPyIPAddr *addr;
3699         if (!self->is_ipaddr) {
3700             PyErr_SetString(PyExc_TypeError, "Expected an integer index");
3701             return -1;
3702         }
3703         addr = (silkPyIPAddr*)sub;
3704         skipaddrCopy(&key.val.addr, &addr->addr);
3705         key.type = SKBAG_KEY_IPADDR;
3706     } else {
3707         PyErr_SetString(PyExc_TypeError, "Expected an integer or IP address");
3708         return -1;
3709     }
3710 
3711     rv = fn(self->bag, &key, &bagvalue, NULL);
3712     switch (rv) {
3713       case SKBAG_OK:
3714         break;
3715       case SKBAG_ERR_INPUT:
3716       case SKBAG_ERR_KEY_RANGE:
3717         PyErr_SetString(PyExc_IndexError, "Address out of range");
3718         return -1;
3719       case SKBAG_ERR_MEMORY:
3720         PyErr_NoMemory();
3721         return -1;
3722       case SKBAG_ERR_OP_BOUNDS:
3723         PyErr_SetString(PyExc_ValueError, skBagStrerror(rv));
3724         return -1;
3725       case SKBAG_ERR_KEY_NOT_FOUND:
3726         /* Fall through */
3727       default:
3728         skAbortBadCase(rv);
3729     }
3730 
3731     return 0;
3732 }
3733 
3734 static PyObject *
silkPyBag_save(silkPyBag * self,PyObject * args,PyObject * kwds)3735 silkPyBag_save(
3736     silkPyBag          *self,
3737     PyObject           *args,
3738     PyObject           *kwds)
3739 {
3740     skBagErr_t rv;
3741     skstream_t *stream;
3742 
3743     if ((stream = open_silkfile_write(args, kwds)) == NULL) {
3744         return NULL;
3745     }
3746 
3747     rv = skBagWrite(self->bag, stream);
3748     skStreamDestroy(&stream);
3749     if (rv != SKBAG_OK) {
3750         PyErr_SetString(PyExc_IOError, skBagStrerror(rv));
3751         return NULL;
3752     }
3753 
3754     Py_RETURN_NONE;
3755 }
3756 
3757 static PyObject *
silkPyBag_set_info(silkPyBag * self,PyObject * args,PyObject * kwds)3758 silkPyBag_set_info(
3759     silkPyBag          *self,
3760     PyObject           *args,
3761     PyObject           *kwds)
3762 {
3763     static char *kwlist[] = {"key_type", "key_len",
3764                              "counter_type", "counter_len", NULL};
3765     size_t key_len = SKBAG_OCTETS_NO_CHANGE;
3766     size_t counter_len = SKBAG_OCTETS_NO_CHANGE;
3767     unsigned int key_len_tmp = UINT_MAX;
3768     unsigned int counter_len_tmp = UINT_MAX;
3769     char *key_name = NULL;
3770     char *counter_name = NULL;
3771     skBagFieldType_t key_type;
3772     skBagFieldType_t counter_type;
3773     skBagErr_t err;
3774 
3775     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sIsI", kwlist,
3776                                      &key_name, &key_len_tmp,
3777                                      &counter_name, &counter_len_tmp))
3778     {
3779         return NULL;
3780     }
3781 
3782     /* key_len_tmp and counter_len_tmp are unsigned ints, since there
3783      * were no conversion functions to size_t until Python 2.6 */
3784     if (key_len_tmp != UINT_MAX) {
3785         key_len = key_len_tmp;
3786     }
3787     if (counter_len_tmp != UINT_MAX) {
3788         counter_len = counter_len_tmp;
3789     }
3790     if (key_name) {
3791         err = skBagFieldTypeLookup(key_name, &key_type, NULL);
3792         if (err != SKBAG_OK) {
3793             assert(err == SKBAG_ERR_INPUT);
3794             return PyErr_Format(PyExc_ValueError,
3795                                 "'%s' is not a valid key type", key_name);
3796         }
3797     } else {
3798         key_type = skBagKeyFieldType(self->bag);
3799     }
3800 
3801     if (counter_name) {
3802         err = skBagFieldTypeLookup(counter_name, &counter_type, NULL);
3803         if (err != SKBAG_OK) {
3804             assert(err == SKBAG_ERR_INPUT);
3805             return PyErr_Format(PyExc_ValueError,
3806                                 "'%s' is not a valid counter type",
3807                                 counter_name);
3808         }
3809     } else {
3810         counter_type = skBagCounterFieldType(self->bag);
3811     }
3812 
3813     err = skBagModify(self->bag, key_type, counter_type,
3814                       key_len, counter_len);
3815     if (err != SKBAG_OK) {
3816         PyErr_SetString(PyExc_ValueError,
3817                         "Illegal value was passed to Bag.set_info");
3818         return NULL;
3819     }
3820 
3821     self->is_ipaddr = (counter_len == 16 || IS_IP_KEY(key_type));
3822 
3823     return silkPyBag_get_info(self);
3824 }
3825 
3826 static int
silkPyBag_setup(PyObject * mod)3827 silkPyBag_setup(
3828     PyObject           *mod)
3829 {
3830     /* Setup number methods */
3831     memset(&silkPyBag_number_methods, 0, sizeof(silkPyBag_number_methods));
3832     silkPyBag_number_methods.nb_inplace_add = (binaryfunc)silkPyBag_iadd;
3833 
3834     /* Initialize type and add to module */
3835     silkPyBagType.tp_new = PyType_GenericNew;
3836     if (PyType_Ready(&silkPyBagType) < 0) {
3837         return -1;
3838     }
3839     return PyModule_AddObject(mod, "BagBase", (PyObject*)&silkPyBagType);
3840 }
3841 
3842 static PyObject *
silkPyBag_sorted_iter(silkPyBag * self)3843 silkPyBag_sorted_iter(
3844     silkPyBag          *self)
3845 {
3846     return silkPyBag_iter_helper(self, 1);
3847 }
3848 
3849 static PyObject *
silkPyBag_subscript(silkPyBag * self,PyObject * sub)3850 silkPyBag_subscript(
3851     silkPyBag          *self,
3852     PyObject           *sub)
3853 {
3854     skBagTypedKey_t     key;
3855     skBagTypedCounter_t value;
3856     skBagErr_t          rv;
3857 
3858     if (IS_INT(sub)) {
3859         if (self->is_ipaddr) {
3860             PyErr_SetString(PyExc_TypeError, "Expected an IPAddr index");
3861             return NULL;
3862         }
3863         /* long long is 64-bits on 32 and 64-bit arches, so use it for
3864          * consistency. */
3865         key.val.u64 = LONG_AS_UNSIGNED_LONGLONG(sub);
3866         if (PyErr_Occurred()) {
3867             if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
3868                 PyErr_Clear();
3869                 PyErr_SetString(PyExc_IndexError, "Index out of range");
3870             }
3871             return NULL;
3872         }
3873         if (key.val.u64 > 0xffffffff) {
3874             PyErr_SetString(PyExc_IndexError, "Index out of range");
3875             return NULL;
3876         }
3877         key.val.u32 = key.val.u64;
3878         key.type = SKBAG_KEY_U32;
3879     } else if (silkPyIPAddr_Check(sub)) {
3880         silkPyIPAddr *addr;
3881         if (!self->is_ipaddr) {
3882             PyErr_SetString(PyExc_TypeError, "Expected an integer index");
3883             return NULL;
3884         }
3885         addr = (silkPyIPAddr*)sub;
3886         skipaddrCopy(&key.val.addr, &addr->addr);
3887         key.type = SKBAG_KEY_IPADDR;
3888     } else {
3889         PyErr_SetString(PyExc_TypeError, "Expected an integer or IP address");
3890         return NULL;
3891     }
3892 
3893     value.type = SKBAG_COUNTER_U64;
3894     rv = skBagCounterGet(self->bag, &key, &value);
3895 
3896     assert(rv != SKBAG_ERR_KEY_NOT_FOUND);
3897     if (rv == SKBAG_ERR_KEY_RANGE) {
3898         PyErr_SetString(PyExc_IndexError, "Index out of range");
3899         return NULL;
3900     }
3901     if (rv != SKBAG_OK) {
3902         PyErr_SetString(PyExc_ValueError, skBagStrerror(rv));
3903         return NULL;
3904     }
3905     assert(value.type == SKBAG_COUNTER_U64);
3906 
3907     return PyLong_FromUnsignedLongLong(value.val.u64);
3908 }
3909 
3910 static PyObject *
silkPyBag_type_merge(PyObject UNUSED (* self),PyObject * args)3911 silkPyBag_type_merge(
3912     PyObject    UNUSED(*self),
3913     PyObject           *args)
3914 {
3915     char *a, *b;
3916     skBagFieldType_t a_type, b_type, c_type;
3917     skBagErr_t rv;
3918     char buf[SKBAG_MAX_FIELD_BUFLEN];
3919 
3920     if (!PyArg_ParseTuple(args, "ss", &a, &b)) {
3921         return NULL;
3922     }
3923     rv = skBagFieldTypeLookup(a, &a_type, NULL);
3924     if (rv != SKBAG_OK) {
3925         PyErr_Format(PyExc_ValueError, "'%s' is not a valid key type", a);
3926     }
3927     rv = skBagFieldTypeLookup(b, &b_type, NULL);
3928     if (rv != SKBAG_OK) {
3929         PyErr_Format(PyExc_ValueError, "'%s' is not a valid key type", b);
3930     }
3931     c_type = skBagFieldTypeMerge(a_type, b_type);
3932     skBagFieldTypeAsString(c_type, buf, sizeof(buf));
3933     return PyUnicode_FromString(buf);
3934 }
3935 
3936 
3937 /*
3938  *************************************************************************
3939  *   TCP Flags
3940  *************************************************************************
3941  */
3942 
3943 typedef struct silkPyTCPFlags_st {
3944     PyObject_HEAD
3945     uint8_t val;
3946 } silkPyTCPFlags;
3947 
3948 /* function prototypes */
3949 static PyObject *
3950 silkPyTCPFlags_and(
3951     silkPyTCPFlags     *a,
3952     silkPyTCPFlags     *b);
3953 static PyObject *
3954 silkPyTCPFlags_getflag(
3955     silkPyTCPFlags     *obj,
3956     void               *bit);
3957 static PyObject *
3958 silkPyTCPFlags_getflag_deprecated(
3959     silkPyTCPFlags     *obj,
3960     void               *bit);
3961 static long
3962 silkPyTCPFlags_hash(
3963     silkPyTCPFlags     *obj);
3964 static int
3965 silkPyTCPFlags_init(
3966     silkPyTCPFlags     *self,
3967     PyObject           *args,
3968     PyObject           *kwds);
3969 static PyObject *
3970 silkPyTCPFlags_int(
3971     silkPyTCPFlags     *obj);
3972 static silkPyTCPFlags *
3973 silkPyTCPFlags_invert(
3974     silkPyTCPFlags     *obj);
3975 static PyObject *
3976 silkPyTCPFlags_matches(
3977     silkPyTCPFlags     *self,
3978     PyObject           *arg);
3979 static PyObject *
3980 silkPyTCPFlags_new(
3981     PyTypeObject           *type,
3982     PyObject        UNUSED(*args),
3983     PyObject        UNUSED(*kwds));
3984 static int
3985 silkPyTCPFlags_nonzero(
3986     silkPyTCPFlags     *a);
3987 static PyObject *
3988 silkPyTCPFlags_or(
3989     silkPyTCPFlags     *a,
3990     silkPyTCPFlags     *b);
3991 static PyObject *
3992 silkPyTCPFlags_padded(
3993     silkPyTCPFlags     *obj);
3994 static PyObject *
3995 silkPyTCPFlags_repr(
3996     silkPyTCPFlags     *obj);
3997 static PyObject *
3998 silkPyTCPFlags_richcompare(
3999     silkPyTCPFlags     *self,
4000     PyObject           *obj,
4001     int                 cmp);
4002 static int
4003 silkPyTCPFlags_setup(
4004     PyObject           *mod);
4005 static PyObject *
4006 silkPyTCPFlags_str(
4007     silkPyTCPFlags     *obj);
4008 static PyObject *
4009 silkPyTCPFlags_xor(
4010     silkPyTCPFlags     *a,
4011     silkPyTCPFlags     *b);
4012 
4013 /* define docs and methods */
4014 #define silkPyTCPFlags_doc                                              \
4015     "TCPFlags(string)   -> TCPFlags based on flag string\n"             \
4016     "TCPFlags(int)      -> TCPFlags based on integer representation\n"  \
4017     "TCPFlags(TCPFlags) -> Copy of TCPFlags"
4018 
4019 static PyNumberMethods silkPyTCPFlags_number_methods;
4020 
4021 static PyMethodDef silkPyTCPFlags_methods[] = {
4022     {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
4023     {"matches", (PyCFunction)silkPyTCPFlags_matches, METH_O,
4024      "Return whether the flags match the high/mask flagstring"},
4025     {"padded", (PyCFunction)silkPyTCPFlags_padded, METH_NOARGS,
4026      "Returns the flags string padded with spaces, so flags line up"},
4027     {NULL, NULL, 0, NULL}       /* Sentinel */
4028 };
4029 
4030 static uint8_t flags_array[] = {
4031     FIN_FLAG, SYN_FLAG, RST_FLAG, PSH_FLAG,
4032     ACK_FLAG, URG_FLAG, ECE_FLAG, CWR_FLAG};
4033 
4034 static PyGetSetDef silkPyTCPFlags_getsetters[] = {
4035     {"fin", (getter)silkPyTCPFlags_getflag, NULL,
4036      "True if the FIN flag is set; False otherwise", (void*)&flags_array[0]},
4037     {"syn", (getter)silkPyTCPFlags_getflag, NULL,
4038      "True if the SYN flag is set; False otherwise", (void*)&flags_array[1]},
4039     {"rst", (getter)silkPyTCPFlags_getflag, NULL,
4040      "True if the RST flag is set; False otherwise", (void*)&flags_array[2]},
4041     {"psh", (getter)silkPyTCPFlags_getflag, NULL,
4042      "True if the PSH flag is set; False otherwise", (void*)&flags_array[3]},
4043     {"ack", (getter)silkPyTCPFlags_getflag, NULL,
4044      "True if the ACK flag is set; False otherwise", (void*)&flags_array[4]},
4045     {"urg", (getter)silkPyTCPFlags_getflag, NULL,
4046      "True if the URG flag is set; False otherwise", (void*)&flags_array[5]},
4047     {"ece", (getter)silkPyTCPFlags_getflag, NULL,
4048      "True if the ECE flag is set; False otherwise", (void*)&flags_array[6]},
4049     {"cwr", (getter)silkPyTCPFlags_getflag, NULL,
4050      "True if the CWR flag is set; False otherwise", (void*)&flags_array[7]},
4051 
4052     {"FIN", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
4053      ("True if the FIN flag is set; False otherwise."
4054       " DEPRECATED Use flag.fin instead"), (void*)&flags_array[0]},
4055     {"SYN", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
4056      ("True if the SYN flag is set; False otherwise."
4057       " DEPRECATED Use flag.syn instead"), (void*)&flags_array[1]},
4058     {"RST", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
4059      ("True if the RST flag is set; False otherwise."
4060       " DEPRECATED Use flag.rst instead"), (void*)&flags_array[2]},
4061     {"PSH", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
4062      ("True if the PSH flag is set; False otherwise."
4063       " DEPRECATED Use flag.psh instead"), (void*)&flags_array[3]},
4064     {"ACK", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
4065      ("True if the ACK flag is set; False otherwise."
4066       " DEPRECATED Use flag.ack instead"), (void*)&flags_array[4]},
4067     {"URG", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
4068      ("True if the URG flag is set; False otherwise."
4069       " DEPRECATED Use flag.urg instead"), (void*)&flags_array[5]},
4070     {"ECE", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
4071      ("True if the ECE flag is set; False otherwise."
4072       " DEPRECATED Use flag.ece instead"), (void*)&flags_array[6]},
4073     {"CWR", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
4074      ("True if the CWR flag is set; False otherwise."
4075       " DEPRECATED Use flag.cwr instead"), (void*)&flags_array[7]},
4076     {NULL, NULL, NULL, NULL, NULL}
4077 };
4078 
4079 /* define the object types */
4080 static PyTypeObject silkPyTCPFlagsType = {
4081     PyVarObject_HEAD_INIT(NULL, 0)
4082     "silk.TCPFlags",            /* tp_name */
4083     sizeof(silkPyTCPFlags),     /* tp_basicsize */
4084     0,                          /* tp_itemsize */
4085     obj_dealloc,                /* tp_dealloc */
4086     0,                          /* tp_vectorcall_offset (Py 3.8) */
4087     0,                          /* tp_getattr */
4088     0,                          /* tp_setattr */
4089     0,                          /* tp_as_async (tp_compare in Py2.x) */
4090     (reprfunc)silkPyTCPFlags_repr, /* tp_repr */
4091     &silkPyTCPFlags_number_methods, /* tp_as_number */
4092     0,                          /* tp_as_sequence */
4093     0,                          /* tp_as_mapping */
4094     (hashfunc)silkPyTCPFlags_hash, /* tp_hash  */
4095     0,                          /* tp_call */
4096     (reprfunc)silkPyTCPFlags_str, /* tp_str */
4097     0,                          /* tp_getattro */
4098     0,                          /* tp_setattro */
4099     0,                          /* tp_as_buffer */
4100 #if PY_MAJOR_VERSION < 3
4101     Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_RICHCOMPARE |
4102 #endif
4103     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
4104     silkPyTCPFlags_doc,         /* tp_doc */
4105     0,                          /* tp_traverse */
4106     0,                          /* tp_clear */
4107     (richcmpfunc)silkPyTCPFlags_richcompare, /* tp_richcompare */
4108     0,                          /* tp_weaklistoffset */
4109     0,                          /* tp_iter */
4110     0,                          /* tp_iternext */
4111     silkPyTCPFlags_methods,     /* tp_methods */
4112     0,                          /* tp_members */
4113     silkPyTCPFlags_getsetters,  /* tp_getset */
4114     0,                          /* tp_base */
4115     0,                          /* tp_dict */
4116     0,                          /* tp_descr_get */
4117     0,                          /* tp_descr_set */
4118     0,                          /* tp_dictoffset */
4119     (initproc)silkPyTCPFlags_init, /* tp_init */
4120     0,                          /* tp_alloc */
4121     silkPyTCPFlags_new,         /* tp_new */
4122     0,                          /* tp_free */
4123     0,                          /* tp_is_gc */
4124     0,                          /* tp_bases */
4125     0,                          /* tp_mro */
4126     0,                          /* tp_cache */
4127     0,                          /* tp_subclasses */
4128     0,                          /* tp_weaklist */
4129     0                           /* tp_del */
4130 #if PY_VERSION_HEX >= 0x02060000
4131     ,0                          /* tp_version_tag */
4132 #endif
4133 #if PY_VERSION_HEX >= 0x03040000
4134     ,0                          /* tp_finalize */
4135 #endif
4136 #if PY_VERSION_HEX >= 0x03080000
4137     ,0                          /* tp_vectorcall */
4138     ,0                          /* tp_print */
4139 #endif
4140 };
4141 
4142 /* macro and function defintions */
4143 #define silkPyTCPFlags_Check(op)                \
4144     PyObject_TypeCheck(op, &silkPyTCPFlagsType)
4145 
4146 static PyObject *
silkPyTCPFlags_and(silkPyTCPFlags * a,silkPyTCPFlags * b)4147 silkPyTCPFlags_and(
4148     silkPyTCPFlags     *a,
4149     silkPyTCPFlags     *b)
4150 {
4151     PyObject *new_obj;
4152 
4153     if (!silkPyTCPFlags_Check(a) || !silkPyTCPFlags_Check(b)) {
4154         Py_INCREF(Py_NotImplemented);
4155         return Py_NotImplemented;
4156     }
4157 
4158     new_obj = silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType, 0);
4159     if (new_obj != NULL) {
4160         ((silkPyTCPFlags*)new_obj)->val = a->val & b->val;
4161     }
4162     return new_obj;
4163 }
4164 
4165 static PyObject *
silkPyTCPFlags_getflag(silkPyTCPFlags * obj,void * bit)4166 silkPyTCPFlags_getflag(
4167     silkPyTCPFlags     *obj,
4168     void               *bit)
4169 {
4170     return PyBool_FromLong(obj->val & *(uint8_t*)bit);
4171 }
4172 
4173 static PyObject *
silkPyTCPFlags_getflag_deprecated(silkPyTCPFlags * obj,void * bit)4174 silkPyTCPFlags_getflag_deprecated(
4175     silkPyTCPFlags     *obj,
4176     void               *bit)
4177 {
4178     /* Deprecated as of SiLK 3.0.0. */
4179     PyErr_Warn(PyExc_DeprecationWarning,
4180                ("Use of upper-case flag check attributes for "
4181                 "TCPFlags is deprecated"));
4182     return PyBool_FromLong(obj->val & *(uint8_t*)bit);
4183 }
4184 
4185 static long
silkPyTCPFlags_hash(silkPyTCPFlags * obj)4186 silkPyTCPFlags_hash(
4187     silkPyTCPFlags     *obj)
4188 {
4189     return obj->val;
4190 }
4191 
4192 static int
silkPyTCPFlags_init(silkPyTCPFlags * self,PyObject * args,PyObject * kwds)4193 silkPyTCPFlags_init(
4194     silkPyTCPFlags     *self,
4195     PyObject           *args,
4196     PyObject           *kwds)
4197 {
4198     static char *kwlist[] = {"value", NULL};
4199     PyObject *val;
4200 
4201     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &val)) {
4202         return -1;
4203     }
4204 
4205     if (silkPyTCPFlags_Check(val)) {
4206         silkPyTCPFlags *oflags = (silkPyTCPFlags*)val;
4207         self->val = oflags->val;
4208     } else if (IS_INT(val)) {
4209         long intval = PyLong_AsLong(val);
4210         if (intval < 0 || intval > (long)UINT8_MAX) {
4211             PyErr_Format(PyExc_ValueError,
4212                          "Illegal TCP flag value: %ld", intval);
4213             return -1;
4214         }
4215         self->val = intval;
4216     } else if (IS_STRING(val)) {
4217         PyObject *bytes = bytes_from_string(val);
4218         char *strval;
4219 
4220         if (bytes == NULL) {
4221             return -1;
4222         }
4223         strval = PyBytes_AS_STRING(bytes);
4224         if (skStringParseTCPFlags(&self->val, strval)) {
4225             PyErr_Format(PyExc_ValueError,
4226                          "Illegal TCP flag value: %s", strval);
4227             Py_DECREF(bytes);
4228             return -1;
4229         }
4230         Py_DECREF(bytes);
4231     } else {
4232         obj_error("Illegal value: %s", val);
4233         return -1;
4234     }
4235 
4236     return 0;
4237 }
4238 
4239 static PyObject *
silkPyTCPFlags_int(silkPyTCPFlags * obj)4240 silkPyTCPFlags_int(
4241     silkPyTCPFlags     *obj)
4242 {
4243     return PyInt_FromLong(obj->val);
4244 }
4245 
4246 static silkPyTCPFlags *
silkPyTCPFlags_invert(silkPyTCPFlags * obj)4247 silkPyTCPFlags_invert(
4248     silkPyTCPFlags     *obj)
4249 {
4250     silkPyTCPFlags *new_obj =
4251         (silkPyTCPFlags*)silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType, 0);
4252 
4253     if (new_obj != NULL) {
4254         new_obj->val = ~obj->val;
4255     }
4256     return new_obj;
4257 }
4258 
4259 static PyObject *
silkPyTCPFlags_matches(silkPyTCPFlags * self,PyObject * arg)4260 silkPyTCPFlags_matches(
4261     silkPyTCPFlags     *self,
4262     PyObject           *arg)
4263 {
4264     char *repr;
4265     PyObject *bytes;
4266     uint8_t high, mask;
4267     int rv;
4268 
4269     if (!IS_STRING(arg)) {
4270         PyErr_SetString(PyExc_TypeError, "Expected string");
4271         return NULL;
4272     }
4273 
4274     bytes = bytes_from_string(arg);
4275     repr = PyBytes_AS_STRING(bytes);
4276     rv = skStringParseTCPFlagsHighMask(&high, &mask, repr);
4277     Py_DECREF(bytes);
4278     if (rv == SKUTILS_ERR_SHORT) {
4279         mask = high;
4280     } else if (rv != 0) {
4281         PyErr_SetString(PyExc_ValueError, "Illegal flag/mask");
4282         return NULL;
4283     }
4284 
4285     return PyBool_FromLong((self->val & mask) == high);
4286 }
4287 
4288 static PyObject *
silkPyTCPFlags_new(PyTypeObject * type,PyObject UNUSED (* args),PyObject UNUSED (* kwds))4289 silkPyTCPFlags_new(
4290     PyTypeObject           *type,
4291     PyObject        UNUSED(*args),
4292     PyObject        UNUSED(*kwds))
4293 {
4294     silkPyTCPFlags *self;
4295 
4296     self = (silkPyTCPFlags*)type->tp_alloc(type, 0);
4297 
4298     if (self != NULL) {
4299         self->val = 0;
4300     }
4301 
4302     return (PyObject*)self;
4303 }
4304 
4305 static int
silkPyTCPFlags_nonzero(silkPyTCPFlags * a)4306 silkPyTCPFlags_nonzero(
4307     silkPyTCPFlags     *a)
4308 {
4309     return a->val ? 1 : 0;
4310 }
4311 
4312 static PyObject *
silkPyTCPFlags_or(silkPyTCPFlags * a,silkPyTCPFlags * b)4313 silkPyTCPFlags_or(
4314     silkPyTCPFlags     *a,
4315     silkPyTCPFlags     *b)
4316 {
4317     PyObject *new_obj;
4318 
4319     if (!silkPyTCPFlags_Check(a) || !silkPyTCPFlags_Check(b)) {
4320         Py_INCREF(Py_NotImplemented);
4321         return Py_NotImplemented;
4322     }
4323 
4324     new_obj = silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType, 0);
4325     if (new_obj != NULL) {
4326         ((silkPyTCPFlags*)new_obj)->val = a->val | b->val;
4327     }
4328     return new_obj;
4329 }
4330 
4331 static PyObject *
silkPyTCPFlags_padded(silkPyTCPFlags * obj)4332 silkPyTCPFlags_padded(
4333     silkPyTCPFlags     *obj)
4334 {
4335     char flags[SK_TCPFLAGS_STRLEN];
4336 
4337     skTCPFlagsString(obj->val, flags, SK_PADDED_FLAGS);
4338 
4339     return PyUnicode_FromString(flags);
4340 }
4341 
4342 static PyObject *
silkPyTCPFlags_repr(silkPyTCPFlags * obj)4343 silkPyTCPFlags_repr(
4344     silkPyTCPFlags     *obj)
4345 {
4346     char flags[SK_TCPFLAGS_STRLEN];
4347 
4348     skTCPFlagsString(obj->val, flags, SK_PADDED_FLAGS);
4349 
4350     return PyUnicode_FromFormat("silk.TCPFlags('%s')", flags);
4351 }
4352 
4353 static PyObject *
silkPyTCPFlags_richcompare(silkPyTCPFlags * self,PyObject * obj,int cmp)4354 silkPyTCPFlags_richcompare(
4355     silkPyTCPFlags     *self,
4356     PyObject           *obj,
4357     int                 cmp)
4358 {
4359     if (cmp != Py_EQ && cmp != Py_NE) {
4360         Py_INCREF(Py_NotImplemented);
4361         return Py_NotImplemented;
4362     }
4363 
4364     if (!silkPyTCPFlags_Check(obj)) {
4365         PyErr_SetString(PyExc_TypeError, "Expected silk.TCPFlags");
4366         return NULL;
4367     }
4368 
4369     if (self->val == ((silkPyTCPFlags*)obj)->val) {
4370         if (cmp == Py_EQ) {
4371             Py_RETURN_TRUE;
4372         } else {
4373             Py_RETURN_FALSE;
4374         }
4375     }
4376     if (cmp == Py_NE) {
4377         Py_RETURN_TRUE;
4378     }
4379 
4380     Py_RETURN_FALSE;
4381 }
4382 
4383 static int
silkPyTCPFlags_setup(PyObject * mod)4384 silkPyTCPFlags_setup(
4385     PyObject           *mod)
4386 {
4387     /* Setup number methods */
4388     memset(&silkPyTCPFlags_number_methods, 0,
4389            sizeof(silkPyTCPFlags_number_methods));
4390 #if PY_MAJOR_VERSION >= 3
4391     silkPyTCPFlags_number_methods.nb_bool =
4392         (inquiry)silkPyTCPFlags_nonzero;
4393 #else
4394     silkPyTCPFlags_number_methods.nb_nonzero =
4395         (inquiry)silkPyTCPFlags_nonzero;
4396 #endif
4397     silkPyTCPFlags_number_methods.nb_invert =
4398         (unaryfunc)silkPyTCPFlags_invert;
4399     silkPyTCPFlags_number_methods.nb_and = (binaryfunc)silkPyTCPFlags_and;
4400     silkPyTCPFlags_number_methods.nb_xor = (binaryfunc)silkPyTCPFlags_xor;
4401     silkPyTCPFlags_number_methods.nb_or = (binaryfunc)silkPyTCPFlags_or;
4402     silkPyTCPFlags_number_methods.nb_int = (unaryfunc)silkPyTCPFlags_int;
4403 
4404     /* Initialize type and add to module */
4405     if (PyType_Ready(&silkPyTCPFlagsType) < 0) {
4406         return -1;
4407     }
4408     return PyModule_AddObject(mod, "TCPFlags",
4409                               (PyObject*)&silkPyTCPFlagsType);
4410 }
4411 
4412 static PyObject *
silkPyTCPFlags_str(silkPyTCPFlags * obj)4413 silkPyTCPFlags_str(
4414     silkPyTCPFlags     *obj)
4415 {
4416     char flags[SK_TCPFLAGS_STRLEN];
4417 
4418     skTCPFlagsString(obj->val, flags, 0);
4419 
4420     return PyUnicode_FromString(flags);
4421 }
4422 
4423 static PyObject *
silkPyTCPFlags_xor(silkPyTCPFlags * a,silkPyTCPFlags * b)4424 silkPyTCPFlags_xor(
4425     silkPyTCPFlags     *a,
4426     silkPyTCPFlags     *b)
4427 {
4428     PyObject *new_obj;
4429 
4430     if (!silkPyTCPFlags_Check(a) || !silkPyTCPFlags_Check(b)) {
4431         Py_INCREF(Py_NotImplemented);
4432         return Py_NotImplemented;
4433     }
4434 
4435     new_obj = silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType, 0);
4436     if (new_obj != NULL) {
4437         ((silkPyTCPFlags*)new_obj)->val = a->val ^ b->val;
4438     }
4439     return new_obj;
4440 }
4441 
4442 
4443 /*
4444  *************************************************************************
4445  *   RWRec
4446  *************************************************************************
4447  */
4448 
4449 typedef struct silkPyRawRWRec_st {
4450     PyObject_HEAD
4451     rwRec rec;
4452 } silkPyRawRWRec;
4453 
4454 typedef struct silkPyRWRec_st {
4455     PyObject_HEAD
4456     silkPyRawRWRec *raw;
4457 } silkPyRWRec;
4458 
4459 /* function prototypes */
4460 static PyObject *
4461 silkPyRWRec_application_get(
4462     silkPyRWRec        *obj,
4463     void        UNUSED(*closure));
4464 static int
4465 silkPyRWRec_application_set(
4466     silkPyRWRec        *obj,
4467     PyObject           *value,
4468     void        UNUSED(*closure));
4469 static PyObject *
4470 silkPyRWRec_bytes_get(
4471     silkPyRWRec        *obj,
4472     void        UNUSED(*closure));
4473 static int
4474 silkPyRWRec_bytes_set(
4475     silkPyRWRec        *obj,
4476     PyObject           *value,
4477     void        UNUSED(*closure));
4478 static PyObject *
4479 silkPyRWRec_classname_get(
4480     silkPyRWRec        *obj,
4481     void        UNUSED(*closure));
4482 static PyObject *
4483 silkPyRWRec_classtype_get(
4484     silkPyRWRec        *obj,
4485     void        UNUSED(*closure));
4486 static PyObject *
4487 silkPyRWRec_classtype_id_get(
4488     silkPyRWRec        *obj,
4489     void        UNUSED(*closure));
4490 static int
4491 silkPyRWRec_classtype_id_set(
4492     silkPyRWRec        *obj,
4493     PyObject           *value,
4494     void        UNUSED(*closure));
4495 static int
4496 silkPyRWRec_classtype_set(
4497     silkPyRWRec        *obj,
4498     PyObject           *value,
4499     void        UNUSED(*closure));
4500 static void
4501 silkPyRWRec_dealloc(
4502     silkPyRWRec        *obj);
4503 static PyObject *
4504 silkPyRWRec_dip_get(
4505     silkPyRWRec        *obj,
4506     void        UNUSED(*closure));
4507 static int
4508 silkPyRWRec_dip_set(
4509     silkPyRWRec        *obj,
4510     PyObject           *value,
4511     void        UNUSED(*closure));
4512 static PyObject *
4513 silkPyRWRec_dport_get(
4514     silkPyRWRec        *obj,
4515     void        UNUSED(*closure));
4516 static int
4517 silkPyRWRec_dport_set(
4518     silkPyRWRec        *obj,
4519     PyObject           *value,
4520     void        UNUSED(*closure));
4521 static PyObject *
4522 silkPyRWRec_duration_get(
4523     silkPyRWRec        *obj,
4524     void        UNUSED(*closure));
4525 static PyObject *
4526 silkPyRWRec_duration_secs_get(
4527     silkPyRWRec        *obj,
4528     void        UNUSED(*closure));
4529 static int
4530 silkPyRWRec_duration_secs_set(
4531     silkPyRWRec        *obj,
4532     PyObject           *value,
4533     void        UNUSED(*closure));
4534 static int
4535 silkPyRWRec_duration_set(
4536     silkPyRWRec        *obj,
4537     PyObject           *value,
4538     void        UNUSED(*closure));
4539 static PyObject *
4540 silkPyRWRec_etime_epoch_secs_get(
4541     silkPyRWRec        *obj,
4542     void        UNUSED(*closure));
4543 static int
4544 silkPyRWRec_etime_epoch_secs_set(
4545     silkPyRWRec        *obj,
4546     PyObject           *value,
4547     void        UNUSED(*closure));
4548 static PyObject *
4549 silkPyRWRec_etime_get(
4550     silkPyRWRec        *obj,
4551     void        UNUSED(*closure));
4552 static int
4553 silkPyRWRec_etime_set(
4554     silkPyRWRec        *obj,
4555     PyObject           *value,
4556     void        UNUSED(*closure));
4557 static PyObject *
4558 silkPyRWRec_finnoack_get(
4559     silkPyRWRec        *obj,
4560     void        UNUSED(*closure));
4561 static int
4562 silkPyRWRec_finnoack_set(
4563     silkPyRWRec        *obj,
4564     PyObject           *value,
4565     void        UNUSED(*closure));
4566 static PyObject *
4567 silkPyRWRec_icmpcode_get(
4568     silkPyRWRec        *obj,
4569     void        UNUSED(*closure));
4570 static int
4571 silkPyRWRec_icmpcode_set(
4572     silkPyRWRec        *obj,
4573     PyObject           *value,
4574     void        UNUSED(*closure));
4575 static PyObject *
4576 silkPyRWRec_icmptype_get(
4577     silkPyRWRec        *obj,
4578     void        UNUSED(*closure));
4579 static int
4580 silkPyRWRec_icmptype_set(
4581     silkPyRWRec        *obj,
4582     PyObject           *value,
4583     void        UNUSED(*closure));
4584 static PyObject *
4585 silkPyRWRec_new(
4586     PyTypeObject       *type,
4587     PyObject           *args,
4588     PyObject           *kwds);
4589 static int
4590 silkPyRWRec_init(
4591     silkPyRWRec        *self,
4592     PyObject           *args,
4593     PyObject           *kwds);
4594 static PyObject *
4595 silkPyRWRec_initial_tcpflags_get(
4596     silkPyRWRec        *obj,
4597     void               *deprecated);
4598 static int
4599 silkPyRWRec_initial_tcpflags_set(
4600     silkPyRWRec        *obj,
4601     PyObject           *value,
4602     void               *deprecated);
4603 static PyObject *
4604 silkPyRWRec_input_get(
4605     silkPyRWRec        *obj,
4606     void        UNUSED(*closure));
4607 static int
4608 silkPyRWRec_input_set(
4609     silkPyRWRec        *obj,
4610     PyObject           *value,
4611     void        UNUSED(*closure));
4612 static PyObject *
4613 silkPyRWRec_is_icmp(
4614     silkPyRWRec        *obj);
4615 static PyObject *
4616 silkPyRWRec_is_ipv6(
4617     silkPyRWRec         UNUSED_NOv6(*obj));
4618 static PyObject *
4619 silkPyRWRec_is_web(
4620     silkPyRWRec        *obj);
4621 static PyObject *
4622 silkPyRWRec_nhip_get(
4623     silkPyRWRec        *obj,
4624     void        UNUSED(*closure));
4625 static int
4626 silkPyRWRec_nhip_set(
4627     silkPyRWRec        *obj,
4628     PyObject           *value,
4629     void        UNUSED(*closure));
4630 static PyObject *
4631 silkPyRWRec_output_get(
4632     silkPyRWRec        *obj,
4633     void        UNUSED(*closure));
4634 static int
4635 silkPyRWRec_output_set(
4636     silkPyRWRec        *obj,
4637     PyObject           *value,
4638     void        UNUSED(*closure));
4639 static PyObject *
4640 silkPyRWRec_packets_get(
4641     silkPyRWRec        *obj,
4642     void        UNUSED(*closure));
4643 static int
4644 silkPyRWRec_packets_set(
4645     silkPyRWRec        *obj,
4646     PyObject           *value,
4647     void        UNUSED(*closure));
4648 static PyObject *
4649 silkPyRWRec_protocol_get(
4650     silkPyRWRec        *obj,
4651     void        UNUSED(*closure));
4652 static int
4653 silkPyRWRec_protocol_set(
4654     silkPyRWRec        *obj,
4655     PyObject           *value,
4656     void        UNUSED(*closure));
4657 static PyObject *
4658 silkPyRWRec_richcompare(
4659     silkPyRWRec        *self,
4660     PyObject           *obj,
4661     int                 cmp);
4662 static PyObject *
4663 silkPyRWRec_sensor_get(
4664     silkPyRWRec        *obj,
4665     void        UNUSED(*closure));
4666 static PyObject *
4667 silkPyRWRec_sensor_id_get(
4668     silkPyRWRec        *obj,
4669     void        UNUSED(*closure));
4670 static PyObject *
4671 silkPyRWRec_to_ipv4(
4672     silkPyRWRec        *obj);
4673 #if SK_ENABLE_IPV6
4674 static PyObject *
4675 silkPyRWRec_to_ipv6(
4676     silkPyRWRec        *obj);
4677 #endif
4678 static int
4679 silkPyRWRec_sensor_id_set(
4680     silkPyRWRec        *obj,
4681     PyObject           *value,
4682     void        UNUSED(*closure));
4683 static int
4684 silkPyRWRec_sensor_set(
4685     silkPyRWRec        *obj,
4686     PyObject           *value,
4687     void        UNUSED(*closure));
4688 static PyObject *
4689 silkPyRWRec_session_tcpflags_get(
4690     silkPyRWRec        *obj,
4691     void               *deprecated);
4692 static int
4693 silkPyRWRec_session_tcpflags_set(
4694     silkPyRWRec        *obj,
4695     PyObject           *value,
4696     void               *deprecated);
4697 static PyObject *
4698 silkPyRWRec_sip_get(
4699     silkPyRWRec        *obj,
4700     void        UNUSED(*closure));
4701 static int
4702 silkPyRWRec_sip_set(
4703     silkPyRWRec        *obj,
4704     PyObject           *value,
4705     void        UNUSED(*closure));
4706 static PyObject *
4707 silkPyRWRec_sport_get(
4708     silkPyRWRec        *obj,
4709     void        UNUSED(*closure));
4710 static int
4711 silkPyRWRec_sport_set(
4712     silkPyRWRec        *obj,
4713     PyObject           *value,
4714     void        UNUSED(*closure));
4715 static PyObject *
4716 silkPyRWRec_stime_epoch_secs_get(
4717     silkPyRWRec        *obj,
4718     void        UNUSED(*closure));
4719 static int
4720 silkPyRWRec_stime_epoch_secs_set(
4721     silkPyRWRec        *obj,
4722     PyObject           *value,
4723     void        UNUSED(*closure));
4724 static PyObject *
4725 silkPyRWRec_stime_get(
4726     silkPyRWRec        *obj,
4727     void        UNUSED(*closure));
4728 static int
4729 silkPyRWRec_stime_set(
4730     silkPyRWRec        *obj,
4731     PyObject           *value,
4732     void        UNUSED(*closure));
4733 static PyObject *
4734 silkPyRWRec_tcpflags_get(
4735     silkPyRWRec        *obj,
4736     void        UNUSED(*closure));
4737 static int
4738 silkPyRWRec_tcpflags_set(
4739     silkPyRWRec        *obj,
4740     PyObject           *value,
4741     void        UNUSED(*closure));
4742 static PyObject *
4743 silkPyRWRec_timeout_killed_get(
4744     silkPyRWRec        *obj,
4745     void        UNUSED(*closure));
4746 static int
4747 silkPyRWRec_timeout_killed_set(
4748     silkPyRWRec        *obj,
4749     PyObject           *value,
4750     void        UNUSED(*closure));
4751 static PyObject *
4752 silkPyRWRec_timeout_started_get(
4753     silkPyRWRec        *obj,
4754     void        UNUSED(*closure));
4755 static int
4756 silkPyRWRec_timeout_started_set(
4757     silkPyRWRec        *obj,
4758     PyObject           *value,
4759     void        UNUSED(*closure));
4760 static PyObject *
4761 silkPyRWRec_typename_get(
4762     silkPyRWRec        *obj,
4763     void        UNUSED(*closure));
4764 static PyObject *
4765 silkPyRWRec_uniform_packets_get(
4766     silkPyRWRec        *obj,
4767     void        UNUSED(*closure));
4768 static int
4769 silkPyRWRec_uniform_packets_set(
4770     silkPyRWRec        *obj,
4771     PyObject           *value,
4772     void        UNUSED(*closure));
4773 static int
4774 silkPyRawRWRec_init(
4775     silkPyRawRWRec     *self,
4776     PyObject           *args,
4777     PyObject           *kwds);
4778 static PyObject *
4779 silkPyRawRWRec_new(
4780     PyTypeObject           *type,
4781     PyObject        UNUSED(*args),
4782     PyObject        UNUSED(*kwds));
4783 
4784 /* define docs and methods */
4785 static PyMethodDef silkPyRWRec_methods[] = {
4786     {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
4787     {"is_icmp", (PyCFunction)silkPyRWRec_is_icmp, METH_NOARGS,
4788      "Returns whether the record is an ICMP record"},
4789     {"is_ipv6", (PyCFunction)silkPyRWRec_is_ipv6, METH_NOARGS,
4790      "Returns whether record uses IPv6 addresses"},
4791     {"is_web", (PyCFunction)silkPyRWRec_is_web, METH_NOARGS,
4792      "Returns whether record can be stored in a SiLK WWW file format"},
4793     {"to_ipv4", (PyCFunction)silkPyRWRec_to_ipv4, METH_NOARGS,
4794      "Returns a new raw copy of the record converted to IPv4"},
4795     {"to_ipv6", (PyCFunction)
4796 #if SK_ENABLE_IPV6
4797      silkPyRWRec_to_ipv6, METH_NOARGS,
4798 #else
4799      silkPyNotImplemented, METH_VARARGS | METH_KEYWORDS,
4800 #endif
4801      "Returns a new raw copy of the record converted to IPv6"},
4802     {NULL, NULL, 0, NULL}       /* Sentinel */
4803 };
4804 
4805 static PyGetSetDef silkPyRWRec_getseters[] = {
4806     {"application",
4807      (getter)silkPyRWRec_application_get, (setter)silkPyRWRec_application_set,
4808      "\"service\" port set by the collector", NULL},
4809     {"bytes",
4810      (getter)silkPyRWRec_bytes_get,       (setter)silkPyRWRec_bytes_set,
4811      "Count of bytes", NULL},
4812     {"classname",
4813      (getter)silkPyRWRec_classname_get,   NULL,
4814      "class name (read-only)", NULL},
4815     {"classtype",
4816      (getter)silkPyRWRec_classtype_get,   (setter)silkPyRWRec_classtype_set,
4817      "class name, type name pair", NULL},
4818     {"classtype_id",
4819      (getter)silkPyRWRec_classtype_id_get,(setter)silkPyRWRec_classtype_id_set,
4820      "class, type pair ID", NULL},
4821     {"dip",
4822      (getter)silkPyRWRec_dip_get,         (setter)silkPyRWRec_dip_set,
4823      "destination IP", NULL},
4824     {"dport",
4825      (getter)silkPyRWRec_dport_get,       (setter)silkPyRWRec_dport_set,
4826      "Destination port", NULL},
4827     {"duration",
4828      (getter)silkPyRWRec_duration_get,    (setter)silkPyRWRec_duration_set,
4829      "duration of flow as datetime.timedelta", NULL},
4830     {"duration_secs",
4831      (getter)silkPyRWRec_duration_secs_get,
4832      (setter)silkPyRWRec_duration_secs_set,
4833      "duration of flow in seconds", NULL},
4834     {"etime",
4835      (getter)silkPyRWRec_etime_get,       (setter)silkPyRWRec_etime_set,
4836      "end time of flow as datetime.timedelta", NULL},
4837     {"etime_epoch_secs",
4838      (getter)silkPyRWRec_etime_epoch_secs_get,
4839      (setter)silkPyRWRec_etime_epoch_secs_set,
4840      "end time of flow as a number of seconds since the epoch time", NULL},
4841     {"finnoack",
4842      (getter)silkPyRWRec_finnoack_get,    (setter)silkPyRWRec_finnoack_set,
4843      "FIN followed by not ACK", NULL},
4844     {"icmpcode",
4845      (getter)silkPyRWRec_icmpcode_get,    (setter)silkPyRWRec_icmpcode_set,
4846      "ICMP code", NULL},
4847     {"icmptype",
4848      (getter)silkPyRWRec_icmptype_get,    (setter)silkPyRWRec_icmptype_set,
4849      "ICMP type", NULL},
4850     {"initflags", /* Deprecated in SiLK 3.0.0 */
4851      (getter)silkPyRWRec_initial_tcpflags_get,
4852      (setter)silkPyRWRec_initial_tcpflags_set,
4853      "TCP flags of first packet. DEPRECATED Use initial_tcpflags instead",
4854       deprecated_true},
4855     {"initial_tcpflags",
4856      (getter)silkPyRWRec_initial_tcpflags_get,
4857      (setter)silkPyRWRec_initial_tcpflags_set,
4858      "TCP flags of first packet", NULL},
4859     {"input",
4860      (getter)silkPyRWRec_input_get,       (setter)silkPyRWRec_input_set,
4861      "router incoming SNMP interface", NULL},
4862     {"nhip",
4863      (getter)silkPyRWRec_nhip_get,        (setter)silkPyRWRec_nhip_set,
4864      "router next hop IP", NULL},
4865     {"output",
4866      (getter)silkPyRWRec_output_get,      (setter)silkPyRWRec_output_set,
4867      "router outgoing SNMP interface", NULL},
4868     {"packets",
4869      (getter)silkPyRWRec_packets_get,     (setter)silkPyRWRec_packets_set,
4870      "count of packets", NULL},
4871     {"protocol",
4872      (getter)silkPyRWRec_protocol_get,    (setter)silkPyRWRec_protocol_set,
4873      "IP protocol", NULL},
4874     {"restflags", /* Deprecated,SiLK 3.0.0 */
4875      (getter)silkPyRWRec_session_tcpflags_get,
4876      (setter)silkPyRWRec_session_tcpflags_set,
4877      ("TCP flags on non-initial packets."
4878       " DEPRECATED Use session_tcpflags instead"), deprecated_true},
4879     {"sensor",
4880      (getter)silkPyRWRec_sensor_get,      (setter)silkPyRWRec_sensor_set,
4881      "sensor name", NULL},
4882     {"sensor_id",
4883      (getter)silkPyRWRec_sensor_id_get,   (setter)silkPyRWRec_sensor_id_set,
4884      "sensor ID", NULL},
4885     {"session_tcpflags",
4886      (getter)silkPyRWRec_session_tcpflags_get,
4887      (setter)silkPyRWRec_session_tcpflags_set,
4888      "TCP flags on non-initial packets", NULL},
4889     {"sip",
4890      (getter)silkPyRWRec_sip_get,         (setter)silkPyRWRec_sip_set,
4891      "source IP", NULL},
4892     {"sport",
4893      (getter)silkPyRWRec_sport_get,       (setter)silkPyRWRec_sport_set,
4894      "source port", NULL},
4895     {"stime",
4896      (getter)silkPyRWRec_stime_get,       (setter)silkPyRWRec_stime_set,
4897      "start time of flow as datetime.datetime", NULL},
4898     {"stime_epoch_secs",
4899      (getter)silkPyRWRec_stime_epoch_secs_get,
4900      (setter)silkPyRWRec_stime_epoch_secs_set,
4901      "start time of flow as a number of seconds since the epoch time", NULL},
4902     {"tcpflags",
4903      (getter)silkPyRWRec_tcpflags_get,    (setter)silkPyRWRec_tcpflags_set,
4904      "OR of all tcpflags", NULL},
4905     {"timeout_killed",
4906      (getter)silkPyRWRec_timeout_killed_get,
4907      (setter)silkPyRWRec_timeout_killed_set,
4908      "flow ended prematurely due to timeout by the collector", NULL},
4909     {"timeout_started",
4910      (getter)silkPyRWRec_timeout_started_get,
4911      (setter)silkPyRWRec_timeout_started_set,
4912      "flow is a continuation of a flow timed-out by the collector", NULL},
4913     {"typename",
4914      (getter)silkPyRWRec_typename_get,    NULL,
4915      "type name (read-only)", NULL},
4916     {"uniform_packets",
4917      (getter)silkPyRWRec_uniform_packets_get,
4918      (setter)silkPyRWRec_uniform_packets_set,
4919      "flow contained only packets of uniform size", NULL},
4920     {NULL, NULL, NULL, NULL, NULL}
4921 };
4922 
4923 /* define the object types */
4924 static PyTypeObject silkPyRawRWRecType = {
4925     PyVarObject_HEAD_INIT(NULL, 0)
4926     "silk.pysilk.RWRawRec",     /* tp_name */
4927     sizeof(silkPyRawRWRec),     /* tp_basicsize */
4928     0,                          /* tp_itemsize */
4929     obj_dealloc,                /* tp_dealloc */
4930     0,                          /* tp_vectorcall_offset (Py 3.8) */
4931     0,                          /* tp_getattr */
4932     0,                          /* tp_setattr */
4933     0,                          /* tp_as_async (tp_compare in Py2.x) */
4934     0,                          /* tp_repr */
4935     0,                          /* tp_as_number */
4936     0,                          /* tp_as_sequence */
4937     0,                          /* tp_as_mapping */
4938     0,                          /* tp_hash  */
4939     0,                          /* tp_call */
4940     0,                          /* tp_str */
4941     0,                          /* tp_getattro */
4942     0,                          /* tp_setattro */
4943     0,                          /* tp_as_buffer */
4944     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
4945     "Raw RW Record",            /* tp_doc */
4946     0,                          /* tp_traverse */
4947     0,                          /* tp_clear */
4948     0,                          /* tp_richcompare */
4949     0,                          /* tp_weaklistoffset */
4950     0,                          /* tp_iter */
4951     0,                          /* tp_iternext */
4952     0,                          /* tp_methods */
4953     0,                          /* tp_members */
4954     0,                          /* tp_getset */
4955     0,                          /* tp_base */
4956     0,                          /* tp_dict */
4957     0,                          /* tp_descr_get */
4958     0,                          /* tp_descr_set */
4959     0,                          /* tp_dictoffset */
4960     (initproc)silkPyRawRWRec_init, /* tp_init */
4961     0,                          /* tp_alloc */
4962     silkPyRawRWRec_new,         /* tp_new */
4963     0,                          /* tp_free */
4964     0,                          /* tp_is_gc */
4965     0,                          /* tp_bases */
4966     0,                          /* tp_mro */
4967     0,                          /* tp_cache */
4968     0,                          /* tp_subclasses */
4969     0,                          /* tp_weaklist */
4970     0                           /* tp_del */
4971 #if PY_VERSION_HEX >= 0x02060000
4972     ,0                          /* tp_version_tag */
4973 #endif
4974 #if PY_VERSION_HEX >= 0x03040000
4975     ,0                          /* tp_finalize */
4976 #endif
4977 #if PY_VERSION_HEX >= 0x03080000
4978     ,0                          /* tp_vectorcall */
4979     ,0                          /* tp_print */
4980 #endif
4981 };
4982 
4983 static PyTypeObject silkPyRWRecType = {
4984     PyVarObject_HEAD_INIT(NULL, 0)
4985     "silk.pysilk.RWRecBase",    /* tp_name */
4986     sizeof(silkPyRWRec),        /* tp_basicsize */
4987     0,                          /* tp_itemsize */
4988     (destructor)silkPyRWRec_dealloc, /* tp_dealloc */
4989     0,                          /* tp_vectorcall_offset (Py 3.8) */
4990     0,                          /* tp_getattr */
4991     0,                          /* tp_setattr */
4992     0,                          /* tp_as_async (tp_compare in Py2.x) */
4993     0,                          /* tp_repr */
4994     0,                          /* tp_as_number */
4995     0,                          /* tp_as_sequence */
4996     0,                          /* tp_as_mapping */
4997     0,                          /* tp_hash  */
4998     0,                          /* tp_call */
4999     0,                          /* tp_str */
5000     0,                          /* tp_getattro */
5001     0,                          /* tp_setattro */
5002     0,                          /* tp_as_buffer */
5003 #if PY_MAJOR_VERSION < 3
5004     Py_TPFLAGS_HAVE_RICHCOMPARE |
5005 #endif
5006     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
5007     "Base RW Record",           /* tp_doc */
5008     0,                          /* tp_traverse */
5009     0,                          /* tp_clear */
5010     (richcmpfunc)silkPyRWRec_richcompare, /* tp_richcompare */
5011     0,                          /* tp_weaklistoffset */
5012     0,                          /* tp_iter */
5013     0,                          /* tp_iternext */
5014     silkPyRWRec_methods,        /* tp_methods */
5015     0,                          /* tp_members */
5016     silkPyRWRec_getseters,      /* tp_getset */
5017     0,                          /* tp_base */
5018     0,                          /* tp_dict */
5019     0,                          /* tp_descr_get */
5020     0,                          /* tp_descr_set */
5021     0,                          /* tp_dictoffset */
5022     (initproc)silkPyRWRec_init, /* tp_init */
5023     0,                          /* tp_alloc */
5024     silkPyRWRec_new,            /* tp_new */
5025     0,                          /* tp_free */
5026     0,                          /* tp_is_gc */
5027     0,                          /* tp_bases */
5028     0,                          /* tp_mro */
5029     0,                          /* tp_cache */
5030     0,                          /* tp_subclasses */
5031     0,                          /* tp_weaklist */
5032     0                           /* tp_del */
5033 #if PY_VERSION_HEX >= 0x02060000
5034     ,0                          /* tp_version_tag */
5035 #endif
5036 #if PY_VERSION_HEX >= 0x03040000
5037     ,0                          /* tp_finalize */
5038 #endif
5039 #if PY_VERSION_HEX >= 0x03080000
5040     ,0                          /* tp_vectorcall */
5041     ,0                          /* tp_print */
5042 #endif
5043 };
5044 
5045 /* macro and function defintions */
5046 #define silkPyRawRWRec_Check(op)                \
5047     PyObject_TypeCheck(op, &silkPyRawRWRecType)
5048 #define silkPyRWRec_Check(op)                   \
5049     PyObject_TypeCheck(op, &silkPyRWRecType)
5050 
5051 static PyObject *
silkPyRWRec_application_get(silkPyRWRec * obj,void UNUSED (* closure))5052 silkPyRWRec_application_get(
5053     silkPyRWRec        *obj,
5054     void        UNUSED(*closure))
5055 {
5056     return PyInt_FromLong(rwRecGetApplication(&obj->raw->rec));
5057 }
5058 
5059 static int
silkPyRWRec_application_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5060 silkPyRWRec_application_set(
5061     silkPyRWRec        *obj,
5062     PyObject           *value,
5063     void        UNUSED(*closure))
5064 {
5065     long val;
5066 
5067     if (!IS_INT(value)) {
5068         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5069         return -1;
5070     }
5071 
5072     val = PyLong_AsLong(value);
5073     if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
5074         PyErr_SetString(PyExc_ValueError,
5075                         "The application value must be a 16-bit integer");
5076         return -1;
5077     }
5078 
5079     rwRecSetApplication(&obj->raw->rec, val);
5080     return 0;
5081 }
5082 
5083 static PyObject *
silkPyRWRec_to_ipv4(silkPyRWRec * obj)5084 silkPyRWRec_to_ipv4(
5085     silkPyRWRec        *obj)
5086 {
5087     silkPyRawRWRec *copy = (silkPyRawRWRec*)PyObject_CallFunctionObjArgs(
5088         (PyObject *)&silkPyRawRWRecType, obj->raw, NULL);
5089     if (copy == NULL) {
5090         return NULL;
5091     }
5092 #if SK_ENABLE_IPV6
5093     if (rwRecIsIPv6(&copy->rec) && rwRecConvertToIPv4(&copy->rec)) {
5094         Py_DECREF(copy);
5095         Py_RETURN_NONE;
5096     }
5097 #endif  /* SK_ENABLE_IPV6 */
5098     return (PyObject *)copy;
5099 }
5100 
5101 #if SK_ENABLE_IPV6
5102 static PyObject *
silkPyRWRec_to_ipv6(silkPyRWRec * obj)5103 silkPyRWRec_to_ipv6(
5104     silkPyRWRec        *obj)
5105 {
5106     silkPyRawRWRec *copy = (silkPyRawRWRec*)PyObject_CallFunctionObjArgs(
5107         (PyObject *)&silkPyRawRWRecType, obj->raw, NULL);
5108     if (copy == NULL) {
5109         return NULL;
5110     }
5111     rwRecConvertToIPv6(&copy->rec);
5112     return (PyObject *)copy;
5113 }
5114 #endif  /* SK_ENABLE_IPV6 */
5115 
5116 static PyObject *
silkPyRWRec_bytes_get(silkPyRWRec * obj,void UNUSED (* closure))5117 silkPyRWRec_bytes_get(
5118     silkPyRWRec        *obj,
5119     void        UNUSED(*closure))
5120 {
5121     return PyLong_FromUnsignedLong(rwRecGetBytes(&obj->raw->rec));
5122 }
5123 
5124 static int
silkPyRWRec_bytes_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5125 silkPyRWRec_bytes_set(
5126     silkPyRWRec        *obj,
5127     PyObject           *value,
5128     void        UNUSED(*closure))
5129 {
5130     unsigned long val;
5131 
5132     if (!IS_INT(value)) {
5133         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5134         return -1;
5135     }
5136 
5137     val = PyLong_AsUnsignedLong(value);
5138     if (PyErr_Occurred() || val > UINT32_MAX) {
5139         PyErr_SetString(PyExc_ValueError,
5140                         "The bytes value must be a 32-bit integer");
5141         return -1;
5142     }
5143 
5144     rwRecSetBytes(&obj->raw->rec, val);
5145     return 0;
5146 }
5147 
5148 static PyObject *
silkPyRWRec_classname_get(silkPyRWRec * obj,void UNUSED (* closure))5149 silkPyRWRec_classname_get(
5150     silkPyRWRec        *obj,
5151     void        UNUSED(*closure))
5152 {
5153     char              class_name[SK_MAX_STRLEN_FLOWTYPE+1];
5154     sk_flowtype_id_t  flowtype = rwRecGetFlowType(&obj->raw->rec);
5155 
5156     CHECK_SITE(NULL);
5157 
5158     sksiteFlowtypeGetClass(class_name, sizeof(class_name), flowtype);
5159 
5160     return PyUnicode_InternFromString(class_name);
5161 }
5162 
5163 static PyObject *
silkPyRWRec_classtype_get(silkPyRWRec * obj,void UNUSED (* closure))5164 silkPyRWRec_classtype_get(
5165     silkPyRWRec        *obj,
5166     void        UNUSED(*closure))
5167 {
5168     char              class_name[SK_MAX_STRLEN_FLOWTYPE+1];
5169     char              type_name[SK_MAX_STRLEN_FLOWTYPE+1];
5170     sk_flowtype_id_t  flowtype = rwRecGetFlowType(&obj->raw->rec);
5171     PyObject         *pair     = PyTuple_New(2);
5172 
5173     if (pair == NULL) {
5174         return NULL;
5175     }
5176 
5177     CHECK_SITE(NULL);
5178 
5179     sksiteFlowtypeGetClass(class_name, sizeof(class_name), flowtype);
5180     sksiteFlowtypeGetType(type_name, sizeof(type_name), flowtype);
5181 
5182     PyTuple_SET_ITEM(pair, 0, PyUnicode_InternFromString(class_name));
5183     PyTuple_SET_ITEM(pair, 1, PyUnicode_InternFromString(type_name));
5184 
5185     return pair;
5186 }
5187 
5188 static PyObject *
silkPyRWRec_classtype_id_get(silkPyRWRec * obj,void UNUSED (* closure))5189 silkPyRWRec_classtype_id_get(
5190     silkPyRWRec        *obj,
5191     void        UNUSED(*closure))
5192 {
5193     return PyInt_FromLong(rwRecGetFlowType(&obj->raw->rec));
5194 }
5195 
5196 static int
silkPyRWRec_classtype_id_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5197 silkPyRWRec_classtype_id_set(
5198     silkPyRWRec        *obj,
5199     PyObject           *value,
5200     void        UNUSED(*closure))
5201 {
5202     long val;
5203 
5204     if (!IS_INT(value)) {
5205         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5206         return -1;
5207     }
5208 
5209     val = PyLong_AsLong(value);
5210     if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
5211         PyErr_SetString(PyExc_ValueError,
5212                         "The classtype_id value must be an 8-bit integer");
5213         return -1;
5214     }
5215 
5216     rwRecSetFlowType(&obj->raw->rec, val);
5217     return 0;
5218 }
5219 
5220 static int
silkPyRWRec_classtype_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5221 silkPyRWRec_classtype_set(
5222     silkPyRWRec        *obj,
5223     PyObject           *value,
5224     void        UNUSED(*closure))
5225 {
5226     char *class_name, *type_name;
5227     sk_flowtype_id_t flowtype;
5228 
5229 
5230     if (!PyArg_ParseTuple(value, "ss", &class_name, &type_name)) {
5231         return -1;
5232     }
5233 
5234     CHECK_SITE(-1);
5235 
5236     flowtype = sksiteFlowtypeLookupByClassType(class_name, type_name);
5237 
5238     if (flowtype == SK_INVALID_FLOWTYPE) {
5239         PyErr_SetString(PyExc_ValueError, "Invalid (class_name, type) pair");
5240         return -1;
5241     }
5242 
5243     rwRecSetFlowType(&obj->raw->rec, flowtype);
5244     return 0;
5245 }
5246 
5247 static void
silkPyRWRec_dealloc(silkPyRWRec * obj)5248 silkPyRWRec_dealloc(
5249     silkPyRWRec        *obj)
5250 {
5251     Py_XDECREF((PyObject*)obj->raw);
5252     Py_TYPE(obj)->tp_free(obj);
5253 }
5254 
5255 static PyObject *
silkPyRWRec_dip_get(silkPyRWRec * obj,void UNUSED (* closure))5256 silkPyRWRec_dip_get(
5257     silkPyRWRec        *obj,
5258     void        UNUSED(*closure))
5259 {
5260     silkPyIPAddr *addr;
5261     PyTypeObject *type;
5262 
5263 #if SK_ENABLE_IPV6
5264     if (rwRecIsIPv6(&obj->raw->rec)) {
5265         type = &silkPyIPv6AddrType;
5266     } else
5267 #endif
5268     {
5269         type = &silkPyIPv4AddrType;
5270     }
5271 
5272     addr = PyObject_New(silkPyIPAddr, type);
5273     if (addr != NULL) {
5274         rwRecMemGetDIP(&obj->raw->rec, &addr->addr);
5275     }
5276 
5277     return (PyObject*)addr;
5278 }
5279 
5280 static int
silkPyRWRec_dip_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5281 silkPyRWRec_dip_set(
5282     silkPyRWRec        *obj,
5283     PyObject           *value,
5284     void        UNUSED(*closure))
5285 {
5286     if (IS_STRING(value)) {
5287         skipaddr_t  addr;
5288         PyObject   *bytes;
5289         char       *repr;
5290         int         rv;
5291 
5292         bytes = bytes_from_string(value);
5293         if (bytes == NULL) {
5294             return -1;
5295         }
5296         repr = PyBytes_AS_STRING(bytes);
5297         rv = skStringParseIP(&addr, repr);
5298         if (rv != 0) {
5299             PyErr_Format(PyExc_ValueError, "Illegal IP address: %s", repr);
5300             Py_DECREF(bytes);
5301             return -1;
5302         }
5303         Py_DECREF(bytes);
5304         rwRecMemSetDIP(&obj->raw->rec, &addr);
5305         return 0;
5306     }
5307 
5308     if (silkPyIPAddr_Check(value)) {
5309         silkPyIPAddr *addr = (silkPyIPAddr*)value;
5310         rwRecMemSetDIP(&obj->raw->rec, &addr->addr);
5311         return 0;
5312     }
5313 
5314     PyErr_SetString(PyExc_TypeError, "The dip must be a valid IP address");
5315     return -1;
5316 }
5317 
5318 static PyObject *
silkPyRWRec_dport_get(silkPyRWRec * obj,void UNUSED (* closure))5319 silkPyRWRec_dport_get(
5320     silkPyRWRec        *obj,
5321     void        UNUSED(*closure))
5322 {
5323     return PyInt_FromLong(rwRecGetDPort(&obj->raw->rec));
5324 }
5325 
5326 static int
silkPyRWRec_dport_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5327 silkPyRWRec_dport_set(
5328     silkPyRWRec        *obj,
5329     PyObject           *value,
5330     void        UNUSED(*closure))
5331 {
5332     long val;
5333 
5334     if (!IS_INT(value)) {
5335         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5336         return -1;
5337     }
5338 
5339     val = PyLong_AsLong(value);
5340     if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
5341         PyErr_SetString(PyExc_ValueError,
5342                         "The dport value must be a 16-bit integer");
5343         return -1;
5344     }
5345 
5346     rwRecSetDPort(&obj->raw->rec, val);
5347     return 0;
5348 }
5349 
5350 static PyObject *
silkPyRWRec_duration_get(silkPyRWRec * obj,void UNUSED (* closure))5351 silkPyRWRec_duration_get(
5352     silkPyRWRec        *obj,
5353     void        UNUSED(*closure))
5354 {
5355     return PyObject_CallFunction(GLOBALS->timedelta, "IIII", 0, 0, 0,
5356                                  rwRecGetElapsed(&obj->raw->rec));
5357 }
5358 
5359 static PyObject *
silkPyRWRec_duration_secs_get(silkPyRWRec * obj,void UNUSED (* closure))5360 silkPyRWRec_duration_secs_get(
5361     silkPyRWRec        *obj,
5362     void        UNUSED(*closure))
5363 {
5364     double elapsed = ((double)rwRecGetElapsed(&obj->raw->rec)) / 1.0e3;
5365 
5366     return PyFloat_FromDouble(elapsed);
5367 }
5368 
5369 static int
silkPyRWRec_duration_secs_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5370 silkPyRWRec_duration_secs_set(
5371     silkPyRWRec        *obj,
5372     PyObject           *value,
5373     void        UNUSED(*closure))
5374 {
5375     const char *errstr = ("The duration_secs value must be a positive "
5376                           "number not greater than 4294967.295");
5377     PyObject *pyfloat_val;
5378     PyObject *pyint_val;
5379     int64_t long_val;
5380 
5381     if (!PyNumber_Check(value)) {
5382         PyErr_SetString(PyExc_TypeError, errstr);
5383         return -1;
5384     }
5385 
5386     pyfloat_val = PyNumber_Multiply(value, GLOBALS->thousand);
5387     if (pyfloat_val == NULL) {
5388         return -1;
5389     }
5390 
5391     pyint_val = PyNumber_Long(pyfloat_val);
5392     Py_DECREF(pyfloat_val);
5393     if (pyint_val == NULL) {
5394         return -1;
5395     }
5396     long_val = PyLong_AsLongLong(pyint_val);
5397     Py_DECREF(pyint_val);
5398     if (long_val < 0) {
5399         PyErr_SetString(PyExc_ValueError, errstr);
5400         return -1;
5401     }
5402 
5403     if (long_val > UINT32_MAX) {
5404         PyErr_SetString(PyExc_ValueError,
5405                         ("The total duration must be not greater than "
5406                          "4294967.295 seconds"));
5407         return -1;
5408     }
5409 
5410     rwRecSetElapsed(&obj->raw->rec, long_val);
5411     return 0;
5412 }
5413 
5414 static int
silkPyRWRec_duration_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5415 silkPyRWRec_duration_set(
5416     silkPyRWRec        *obj,
5417     PyObject           *value,
5418     void        UNUSED(*closure))
5419 {
5420     PyObject *days;
5421     PyObject *secs;
5422     PyObject *usecs;
5423     uint32_t millisecs;
5424 
5425     if (!PyDelta_Check(value)) {
5426         PyErr_SetString(PyExc_TypeError,
5427                         "The duration value must be a datetime.timedelta");
5428         return -1;
5429     }
5430     if (PyObject_RichCompareBool(value, GLOBALS->minelapsed, Py_LT) ||
5431         PyObject_RichCompareBool(value, GLOBALS->maxelapsed, Py_GT))
5432     {
5433         PyErr_SetString(PyExc_ValueError,
5434                         ("The duration must be in the range [0,4294967295] "
5435                          "milliseconds"));
5436         return -1;
5437     }
5438     days = PyObject_GetAttrString(value, "days");
5439     secs = PyObject_GetAttrString(value, "seconds");
5440     usecs = PyObject_GetAttrString(value, "microseconds");
5441     millisecs = PyLong_AsLong(days) * 1000 * 3600 * 24 +
5442                 PyLong_AsLong(secs) * 1000 +
5443                 PyLong_AsLong(usecs) / 1000;
5444     Py_DECREF(secs);
5445     Py_DECREF(usecs);
5446 
5447     rwRecSetElapsed(&obj->raw->rec, millisecs);
5448     return 0;
5449 }
5450 
5451 static PyObject *
silkPyRWRec_etime_epoch_secs_get(silkPyRWRec * obj,void UNUSED (* closure))5452 silkPyRWRec_etime_epoch_secs_get(
5453     silkPyRWRec        *obj,
5454     void        UNUSED(*closure))
5455 {
5456     double duration = (double)(rwRecGetStartTime(&obj->raw->rec) +
5457                                rwRecGetElapsed(&obj->raw->rec)) / 1.0e3;
5458 
5459     return PyFloat_FromDouble(duration);
5460 }
5461 
5462 static int
silkPyRWRec_etime_epoch_secs_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5463 silkPyRWRec_etime_epoch_secs_set(
5464     silkPyRWRec        *obj,
5465     PyObject           *value,
5466     void        UNUSED(*closure))
5467 {
5468     PyObject *s_time, *dur;
5469     int       retval;
5470 
5471     s_time = silkPyRWRec_stime_epoch_secs_get(obj, NULL);
5472     if (s_time == NULL) {
5473         return -1;
5474     }
5475 
5476     if (PyObject_RichCompareBool(value, s_time, Py_LT)) {
5477         PyErr_SetString(PyExc_ValueError,
5478                         "etime may not be less than stime");
5479         Py_DECREF(s_time);
5480         return -1;
5481     }
5482     dur = PyNumber_Subtract(value, s_time);
5483     Py_DECREF(s_time);
5484     if (dur == NULL) {
5485         return -1;
5486     }
5487 
5488     retval = silkPyRWRec_duration_secs_set(obj, dur, NULL);
5489     Py_DECREF(dur);
5490 
5491     return retval;
5492 }
5493 
5494 static PyObject *
silkPyRWRec_etime_get(silkPyRWRec * obj,void UNUSED (* closure))5495 silkPyRWRec_etime_get(
5496     silkPyRWRec        *obj,
5497     void        UNUSED(*closure))
5498 {
5499     PyObject *s_time, *dur;
5500     PyObject *retval;
5501 
5502     s_time = silkPyRWRec_stime_get(obj, NULL);
5503     if (s_time == NULL) {
5504         return NULL;
5505     }
5506     dur = silkPyRWRec_duration_get(obj, NULL);
5507     if (dur == NULL) {
5508         Py_DECREF(s_time);
5509         return NULL;
5510     }
5511 
5512     retval = PyNumber_Add(s_time, dur);
5513 
5514     Py_DECREF(s_time);
5515     Py_DECREF(dur);
5516 
5517     return retval;
5518 }
5519 
5520 static int
silkPyRWRec_etime_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5521 silkPyRWRec_etime_set(
5522     silkPyRWRec        *obj,
5523     PyObject           *value,
5524     void        UNUSED(*closure))
5525 {
5526     PyObject *s_time, *dur;
5527     int       retval;
5528 
5529     s_time = silkPyRWRec_stime_get(obj, NULL);
5530     if (s_time == NULL) {
5531         return -1;
5532     }
5533 
5534     if (PyObject_RichCompareBool(value, s_time, Py_LT)) {
5535         PyErr_SetString(PyExc_ValueError,
5536                         "etime may not be less than stime");
5537         Py_DECREF(s_time);
5538         return -1;
5539     }
5540     dur = PyNumber_Subtract(value, s_time);
5541     Py_DECREF(s_time);
5542     if (dur == NULL) {
5543         return -1;
5544     }
5545 
5546     retval = silkPyRWRec_duration_set(obj, dur, NULL);
5547     Py_DECREF(dur);
5548 
5549     return retval;
5550 }
5551 
5552 static PyObject *
silkPyRWRec_finnoack_get(silkPyRWRec * obj,void UNUSED (* closure))5553 silkPyRWRec_finnoack_get(
5554     silkPyRWRec        *obj,
5555     void        UNUSED(*closure))
5556 {
5557     uint8_t state;
5558 
5559     state = rwRecGetTcpState(&obj->raw->rec);
5560     return PyBool_FromLong(state & SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK);
5561 }
5562 
5563 static int
silkPyRWRec_finnoack_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5564 silkPyRWRec_finnoack_set(
5565     silkPyRWRec        *obj,
5566     PyObject           *value,
5567     void        UNUSED(*closure))
5568 {
5569     int     rv;
5570     uint8_t state;
5571 
5572     rv = PyObject_IsTrue(value);
5573     if (rv == -1) {
5574         return -1;
5575     }
5576     state = rwRecGetTcpState(&obj->raw->rec);
5577     if (rv) {
5578         state |= SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK;
5579     } else {
5580         state &= ~SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK;
5581     }
5582     rwRecSetTcpState(&obj->raw->rec, state);
5583 
5584     return 0;
5585 }
5586 
5587 static PyObject *
silkPyRWRec_icmpcode_get(silkPyRWRec * obj,void UNUSED (* closure))5588 silkPyRWRec_icmpcode_get(
5589     silkPyRWRec        *obj,
5590     void        UNUSED(*closure))
5591 {
5592     return PyInt_FromLong(rwRecGetIcmpCode(&obj->raw->rec));
5593 }
5594 
5595 static int
silkPyRWRec_icmpcode_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5596 silkPyRWRec_icmpcode_set(
5597     silkPyRWRec        *obj,
5598     PyObject           *value,
5599     void        UNUSED(*closure))
5600 {
5601     long val;
5602 
5603     if (!IS_INT(value)) {
5604         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5605         return -1;
5606     }
5607 
5608     val = PyLong_AsLong(value);
5609     if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
5610         PyErr_SetString(PyExc_ValueError,
5611                         "The icmpcode value must be a 8-bit integer");
5612         return -1;
5613     }
5614 
5615     rwRecSetIcmpCode(&obj->raw->rec, (uint8_t)val);
5616     return 0;
5617 }
5618 
5619 static PyObject *
silkPyRWRec_icmptype_get(silkPyRWRec * obj,void UNUSED (* closure))5620 silkPyRWRec_icmptype_get(
5621     silkPyRWRec        *obj,
5622     void        UNUSED(*closure))
5623 {
5624     return PyInt_FromLong(rwRecGetIcmpType(&obj->raw->rec));
5625 }
5626 
5627 static int
silkPyRWRec_icmptype_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5628 silkPyRWRec_icmptype_set(
5629     silkPyRWRec        *obj,
5630     PyObject           *value,
5631     void        UNUSED(*closure))
5632 {
5633     long val;
5634 
5635     if (!IS_INT(value)) {
5636         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5637         return -1;
5638     }
5639 
5640     val = PyLong_AsLong(value);
5641     if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
5642         PyErr_SetString(PyExc_ValueError,
5643                         "The icmptype value must be a 8-bit integer");
5644         return -1;
5645     }
5646 
5647     rwRecSetIcmpType(&obj->raw->rec, (uint8_t)val);
5648     return 0;
5649 }
5650 
5651 static PyObject *
silkPyRWRec_new(PyTypeObject * type,PyObject UNUSED (* args),PyObject UNUSED (* kwds))5652 silkPyRWRec_new(
5653     PyTypeObject           *type,
5654     PyObject        UNUSED(*args),
5655     PyObject        UNUSED(*kwds))
5656 {
5657     silkPyRWRec *self;
5658     PyObject *newrawrec = GLOBALS->newrawrec;
5659 
5660     self = (silkPyRWRec *)type->tp_alloc(type, 0);
5661     if (self != NULL) {
5662         self->raw = (silkPyRawRWRec *)newrawrec;
5663         Py_INCREF(newrawrec);
5664     }
5665     return (PyObject *)self;
5666 }
5667 
5668 static int
silkPyRWRec_init(silkPyRWRec * self,PyObject * args,PyObject * kwds)5669 silkPyRWRec_init(
5670     silkPyRWRec        *self,
5671     PyObject           *args,
5672     PyObject           *kwds)
5673 {
5674     static char *kwlist[] = {"clone", "copy", NULL};
5675     silkPyRawRWRec *clne = NULL;
5676     silkPyRWRec    *copy  = NULL;
5677 
5678     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!", kwlist,
5679                                      &silkPyRawRWRecType, (PyObject **)&clne,
5680                                      &silkPyRWRecType, (PyObject **)&copy))
5681     {
5682         return -1;
5683     }
5684 
5685     if (clne && copy) {
5686         PyErr_SetString(PyExc_RuntimeError, "Cannot clone and copy");
5687         return -1;
5688     }
5689 
5690     Py_XDECREF((PyObject*)self->raw);
5691     if (clne) {
5692         Py_INCREF(clne);
5693         self->raw = clne;
5694     } else if (copy) {
5695         self->raw = (silkPyRawRWRec*)PyObject_CallFunctionObjArgs(
5696             (PyObject*)&silkPyRawRWRecType, copy->raw, NULL);
5697     } else {
5698         self->raw = (silkPyRawRWRec*)PyObject_CallFunctionObjArgs(
5699             (PyObject*)&silkPyRawRWRecType, NULL);
5700     }
5701 
5702     if (self->raw == NULL) {
5703         return -1;
5704     }
5705 
5706     return 0;
5707 }
5708 
5709 static PyObject *
silkPyRWRec_initial_tcpflags_get(silkPyRWRec * obj,void * deprecated)5710 silkPyRWRec_initial_tcpflags_get(
5711     silkPyRWRec        *obj,
5712     void               *deprecated)
5713 {
5714     silkPyTCPFlags *flags;
5715 
5716     if (deprecated == deprecated_true) {
5717         /* Deprecated in SiLK 3.0.0 */
5718         int rv = PyErr_Warn(PyExc_DeprecationWarning,
5719                             ("'initflags' is deprecated in favor of"
5720                              " 'initial_tcpflags'."));
5721         if (rv) {
5722             return NULL;
5723         }
5724     }
5725 
5726     if (!(rwRecGetTcpState(&obj->raw->rec) & SK_TCPSTATE_EXPANDED)) {
5727         Py_RETURN_NONE;
5728     }
5729     flags = (silkPyTCPFlags*)silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType,
5730                                                           0);
5731     if (flags != NULL) {
5732         flags->val = rwRecGetInitFlags(&obj->raw->rec);
5733     }
5734 
5735     return (PyObject*)flags;
5736 }
5737 
5738 static int
silkPyRWRec_initial_tcpflags_set(silkPyRWRec * obj,PyObject * value,void * deprecated)5739 silkPyRWRec_initial_tcpflags_set(
5740     silkPyRWRec        *obj,
5741     PyObject           *value,
5742     void               *deprecated)
5743 {
5744     uint8_t state;
5745     uint8_t flagval;
5746     silkPyTCPFlags *flags;
5747 
5748     if (deprecated == deprecated_true) {
5749         /* Deprecated in SiLK 3.0.0 */
5750         int rv = PyErr_Warn(PyExc_DeprecationWarning,
5751                             ("'initflags' is deprecated in favor of"
5752                              " 'initial_tcpflags'."));
5753         if (rv) {
5754             return -1;
5755         }
5756     }
5757 
5758     if (rwRecGetProto(&obj->raw->rec) != IPPROTO_TCP) {
5759         PyErr_SetString(
5760             PyExc_AttributeError,
5761             "Cannot set initial_tcpflags when protocol is not TCP");
5762         return -1;
5763     }
5764 
5765     flags = (silkPyTCPFlags *)PyObject_CallFunctionObjArgs(
5766         (PyObject *)&silkPyTCPFlagsType, value, NULL);
5767     if (flags == NULL) {
5768         return -1;
5769     }
5770     flagval = flags->val;
5771     Py_DECREF(flags);
5772 
5773     state = rwRecGetTcpState(&obj->raw->rec);
5774     rwRecSetInitFlags(&obj->raw->rec, flagval);
5775     if (! (state & SK_TCPSTATE_EXPANDED)) {
5776         rwRecSetTcpState(&obj->raw->rec, state | SK_TCPSTATE_EXPANDED);
5777         rwRecSetRestFlags(&obj->raw->rec, 0);
5778     }
5779     rwRecSetFlags(&obj->raw->rec, rwRecGetRestFlags(&obj->raw->rec) | flagval);
5780     return 0;
5781 }
5782 
5783 static PyObject *
silkPyRWRec_input_get(silkPyRWRec * obj,void UNUSED (* closure))5784 silkPyRWRec_input_get(
5785     silkPyRWRec        *obj,
5786     void        UNUSED(*closure))
5787 {
5788     return  PyInt_FromLong(rwRecGetInput(&obj->raw->rec));
5789 }
5790 
5791 static int
silkPyRWRec_input_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5792 silkPyRWRec_input_set(
5793     silkPyRWRec        *obj,
5794     PyObject           *value,
5795     void        UNUSED(*closure))
5796 {
5797     long val;
5798 
5799     if (!IS_INT(value)) {
5800         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5801         return -1;
5802     }
5803 
5804     val = PyLong_AsLong(value);
5805     if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
5806         PyErr_SetString(PyExc_ValueError,
5807                         "The input value must be a 16-bit integer");
5808         return -1;
5809     }
5810 
5811     rwRecSetInput(&obj->raw->rec, val);
5812     return 0;
5813 }
5814 
5815 static PyObject *
silkPyRWRec_is_icmp(silkPyRWRec * obj)5816 silkPyRWRec_is_icmp(
5817     silkPyRWRec        *obj)
5818 {
5819     return PyBool_FromLong(rwRecIsICMP(&obj->raw->rec));
5820 }
5821 
5822 static PyObject *
silkPyRWRec_is_ipv6(silkPyRWRec UNUSED_NOv6 (* obj))5823 silkPyRWRec_is_ipv6(
5824     silkPyRWRec         UNUSED_NOv6(*obj))
5825 {
5826     return PyBool_FromLong(rwRecIsIPv6(&obj->raw->rec));
5827 }
5828 
5829 static PyObject *
silkPyRWRec_is_web(silkPyRWRec * obj)5830 silkPyRWRec_is_web(
5831     silkPyRWRec        *obj)
5832 {
5833     return PyBool_FromLong(rwRecIsWeb(&obj->raw->rec));
5834 }
5835 
5836 static PyObject *
silkPyRWRec_nhip_get(silkPyRWRec * obj,void UNUSED (* closure))5837 silkPyRWRec_nhip_get(
5838     silkPyRWRec        *obj,
5839     void        UNUSED(*closure))
5840 {
5841     silkPyIPAddr *addr;
5842     PyTypeObject *type;
5843 
5844 #if SK_ENABLE_IPV6
5845     if (rwRecIsIPv6(&obj->raw->rec)) {
5846         type = &silkPyIPv6AddrType;
5847     } else
5848 #endif
5849     {
5850         type = &silkPyIPv4AddrType;
5851     }
5852 
5853     addr = PyObject_New(silkPyIPAddr, type);
5854     if (addr != NULL) {
5855         rwRecMemGetNhIP(&obj->raw->rec, &addr->addr);
5856     }
5857     return (PyObject*)addr;
5858 }
5859 
5860 static int
silkPyRWRec_nhip_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5861 silkPyRWRec_nhip_set(
5862     silkPyRWRec        *obj,
5863     PyObject           *value,
5864     void        UNUSED(*closure))
5865 {
5866     if (IS_STRING(value)) {
5867         skipaddr_t  addr;
5868         PyObject   *bytes;
5869         char       *repr;
5870         int         rv;
5871 
5872         bytes = bytes_from_string(value);
5873         if (bytes == NULL) {
5874             return -1;
5875         }
5876         repr = PyBytes_AS_STRING(bytes);
5877         rv   = skStringParseIP(&addr, repr);
5878         if (rv != 0) {
5879             PyErr_Format(PyExc_ValueError, "Illegal IP address: %s", repr);
5880             Py_DECREF(bytes);
5881             return -1;
5882         }
5883         Py_DECREF(bytes);
5884         rwRecMemSetNhIP(&obj->raw->rec, &addr);
5885         return 0;
5886     }
5887 
5888     if (silkPyIPAddr_Check(value)) {
5889         silkPyIPAddr *addr = (silkPyIPAddr*)value;
5890         rwRecMemSetNhIP(&obj->raw->rec, &addr->addr);
5891         return 0;
5892     }
5893 
5894     PyErr_SetString(PyExc_TypeError, "The nhip must be a valid IP address");
5895     return -1;
5896 }
5897 
5898 static PyObject *
silkPyRWRec_output_get(silkPyRWRec * obj,void UNUSED (* closure))5899 silkPyRWRec_output_get(
5900     silkPyRWRec        *obj,
5901     void        UNUSED(*closure))
5902 {
5903     return PyInt_FromLong(rwRecGetOutput(&obj->raw->rec));
5904 }
5905 
5906 static int
silkPyRWRec_output_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5907 silkPyRWRec_output_set(
5908     silkPyRWRec        *obj,
5909     PyObject           *value,
5910     void        UNUSED(*closure))
5911 {
5912     long val;
5913 
5914     if (!IS_INT(value)) {
5915         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5916         return -1;
5917     }
5918 
5919     val = PyLong_AsLong(value);
5920     if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
5921         PyErr_SetString(PyExc_ValueError,
5922                         "The output value must be a 16-bit integer");
5923         return -1;
5924     }
5925 
5926     rwRecSetOutput(&obj->raw->rec, val);
5927     return 0;
5928 }
5929 
5930 static PyObject *
silkPyRWRec_packets_get(silkPyRWRec * obj,void UNUSED (* closure))5931 silkPyRWRec_packets_get(
5932     silkPyRWRec        *obj,
5933     void        UNUSED(*closure))
5934 {
5935     return PyLong_FromUnsignedLong(rwRecGetPkts(&obj->raw->rec));
5936 }
5937 
5938 static int
silkPyRWRec_packets_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5939 silkPyRWRec_packets_set(
5940     silkPyRWRec        *obj,
5941     PyObject           *value,
5942     void        UNUSED(*closure))
5943 {
5944     unsigned long val;
5945 
5946     if (!IS_INT(value)) {
5947         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5948         return -1;
5949     }
5950 
5951     val = PyLong_AsUnsignedLong(value);
5952     if (PyErr_Occurred() || val > UINT32_MAX) {
5953         PyErr_SetString(PyExc_ValueError,
5954                         "The packets value must be a 32-bit integer");
5955         return -1;
5956     }
5957 
5958     rwRecSetPkts(&obj->raw->rec, val);
5959     return 0;
5960 }
5961 
5962 static PyObject *
silkPyRWRec_protocol_get(silkPyRWRec * obj,void UNUSED (* closure))5963 silkPyRWRec_protocol_get(
5964     silkPyRWRec        *obj,
5965     void        UNUSED(*closure))
5966 {
5967     return PyInt_FromLong(rwRecGetProto(&obj->raw->rec));
5968 }
5969 
5970 static int
silkPyRWRec_protocol_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))5971 silkPyRWRec_protocol_set(
5972     silkPyRWRec        *obj,
5973     PyObject           *value,
5974     void        UNUSED(*closure))
5975 {
5976     long val;
5977 
5978     if (!IS_INT(value)) {
5979         PyErr_SetString(PyExc_TypeError, "Expected an integer");
5980         return -1;
5981     }
5982 
5983     val = PyLong_AsLong(value);
5984     if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
5985         PyErr_SetString(PyExc_ValueError,
5986                         "The protocol value must be an 8-bit integer");
5987         return -1;
5988     }
5989 
5990     rwRecSetProto(&obj->raw->rec, val);
5991     if (val != IPPROTO_TCP) {
5992         /* Initial and session flags are not allowed for non-TCP. */
5993         uint8_t state = rwRecGetTcpState(&obj->raw->rec);
5994         rwRecSetTcpState(&obj->raw->rec, state & ~SK_TCPSTATE_EXPANDED);
5995         rwRecSetInitFlags(&obj->raw->rec, 0);
5996         rwRecSetRestFlags(&obj->raw->rec, 0);
5997     }
5998     return 0;
5999 }
6000 
6001 static PyObject *
silkPyRWRec_richcompare(silkPyRWRec * self,PyObject * obj,int cmp)6002 silkPyRWRec_richcompare(
6003     silkPyRWRec        *self,
6004     PyObject           *obj,
6005     int                 cmp)
6006 {
6007     int rv;
6008 
6009     if ((cmp != Py_EQ && cmp != Py_NE) ||
6010         !silkPyRWRec_Check(obj))
6011     {
6012         Py_INCREF(Py_NotImplemented);
6013         return Py_NotImplemented;
6014     }
6015 
6016     rv = memcmp(&self->raw->rec, &((silkPyRWRec*)obj)->raw->rec,
6017                 sizeof(self->raw->rec));
6018     rv = (rv == 0) ? 1 : 0;
6019     if (cmp == Py_NE) {
6020         rv = !rv;
6021     }
6022 
6023     return PyBool_FromLong(rv);
6024 }
6025 
6026 static PyObject *
silkPyRWRec_sensor_get(silkPyRWRec * obj,void UNUSED (* closure))6027 silkPyRWRec_sensor_get(
6028     silkPyRWRec        *obj,
6029     void        UNUSED(*closure))
6030 {
6031     char name[SK_MAX_STRLEN_SENSOR+1];
6032 
6033     CHECK_SITE(NULL);
6034 
6035     sksiteSensorGetName(name, sizeof(name), rwRecGetSensor(&obj->raw->rec));
6036     return PyUnicode_InternFromString(name);
6037 }
6038 
6039 static PyObject *
silkPyRWRec_sensor_id_get(silkPyRWRec * obj,void UNUSED (* closure))6040 silkPyRWRec_sensor_id_get(
6041     silkPyRWRec        *obj,
6042     void        UNUSED(*closure))
6043 {
6044     return PyInt_FromLong(rwRecGetSensor(&obj->raw->rec));
6045 }
6046 
6047 static int
silkPyRWRec_sensor_id_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6048 silkPyRWRec_sensor_id_set(
6049     silkPyRWRec        *obj,
6050     PyObject           *value,
6051     void        UNUSED(*closure))
6052 {
6053     long val;
6054 
6055     if (!IS_INT(value)) {
6056         PyErr_SetString(PyExc_TypeError, "Expected an integer");
6057         return -1;
6058     }
6059 
6060     val = PyLong_AsLong(value);
6061     if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
6062         PyErr_SetString(PyExc_ValueError,
6063                         "The sensor_id value must be a 16-bit integer");
6064         return -1;
6065     }
6066 
6067     rwRecSetSensor(&obj->raw->rec, val);
6068     return 0;
6069 }
6070 
6071 static int
silkPyRWRec_sensor_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6072 silkPyRWRec_sensor_set(
6073     silkPyRWRec        *obj,
6074     PyObject           *value,
6075     void        UNUSED(*closure))
6076 {
6077     char *repr;
6078     sk_sensor_id_t sensor;
6079     PyObject *bytes;
6080 
6081     bytes = bytes_from_string(value);
6082     if (bytes == NULL) {
6083         PyErr_SetString(PyExc_TypeError, "The sensor value must be a string");
6084         return -1;
6085     }
6086     repr = PyBytes_AS_STRING(bytes);
6087 
6088     if (init_site(NULL)) {
6089         Py_DECREF(bytes);
6090         return -1;
6091     }
6092 
6093     sensor = sksiteSensorLookup(repr);
6094     Py_DECREF(bytes);
6095     if (sensor == SK_INVALID_SENSOR) {
6096         PyErr_SetString(PyExc_ValueError, "Invalid sensor name");
6097         return -1;
6098     }
6099 
6100     rwRecSetSensor(&obj->raw->rec, sensor);
6101     return 0;
6102 }
6103 
6104 static PyObject *
silkPyRWRec_session_tcpflags_get(silkPyRWRec * obj,void * deprecated)6105 silkPyRWRec_session_tcpflags_get(
6106     silkPyRWRec        *obj,
6107     void               *deprecated)
6108 {
6109     silkPyTCPFlags *flags;
6110 
6111     if (deprecated == deprecated_true) {
6112         /* Deprecated in SiLK 3.0.0 */
6113         int rv = PyErr_Warn(PyExc_DeprecationWarning,
6114                             ("'restflags' is deprecated in favor of"
6115                              " 'session_tcpflags'."));
6116         if (rv) {
6117             return NULL;
6118         }
6119     }
6120 
6121     if (!(rwRecGetTcpState(&obj->raw->rec) & SK_TCPSTATE_EXPANDED)) {
6122         Py_RETURN_NONE;
6123     }
6124     flags = (silkPyTCPFlags*)silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType,
6125                                                           0);
6126     if (flags != NULL) {
6127         flags->val = rwRecGetRestFlags(&obj->raw->rec);
6128     }
6129 
6130     return (PyObject*)flags;
6131 }
6132 
6133 static int
silkPyRWRec_session_tcpflags_set(silkPyRWRec * obj,PyObject * value,void * deprecated)6134 silkPyRWRec_session_tcpflags_set(
6135     silkPyRWRec        *obj,
6136     PyObject           *value,
6137     void               *deprecated)
6138 {
6139     uint8_t state;
6140     uint8_t flagval;
6141     silkPyTCPFlags *flags;
6142 
6143     if (deprecated == deprecated_true) {
6144         /* Deprecated in SiLK 3.0.0 */
6145         int rv = PyErr_Warn(PyExc_DeprecationWarning,
6146                             ("'restflags' is deprecated in favor of"
6147                              " 'session_tcpflags'."));
6148         if (rv) {
6149             return -1;
6150         }
6151     }
6152 
6153     if (rwRecGetProto(&obj->raw->rec) != IPPROTO_TCP) {
6154         PyErr_SetString(
6155             PyExc_AttributeError,
6156             "Cannot set session_tcpflags when protocol is not TCP");
6157         return -1;
6158     }
6159 
6160     flags = (silkPyTCPFlags *)PyObject_CallFunctionObjArgs(
6161         (PyObject *)&silkPyTCPFlagsType, value, NULL);
6162     if (flags == NULL) {
6163         return -1;
6164     }
6165     flagval = flags->val;
6166     Py_DECREF(flags);
6167 
6168     state = rwRecGetTcpState(&obj->raw->rec);
6169     rwRecSetRestFlags(&obj->raw->rec, flagval);
6170     if (! (state & SK_TCPSTATE_EXPANDED)) {
6171         rwRecSetTcpState(&obj->raw->rec, state | SK_TCPSTATE_EXPANDED);
6172         rwRecSetInitFlags(&obj->raw->rec, 0);
6173     }
6174     rwRecSetFlags(&obj->raw->rec, rwRecGetInitFlags(&obj->raw->rec) | flagval);
6175     return 0;
6176 }
6177 
6178 static PyObject *
silkPyRWRec_sip_get(silkPyRWRec * obj,void UNUSED (* closure))6179 silkPyRWRec_sip_get(
6180     silkPyRWRec        *obj,
6181     void        UNUSED(*closure))
6182 {
6183     silkPyIPAddr *addr;
6184     PyTypeObject *type;
6185 
6186 #if SK_ENABLE_IPV6
6187     if (rwRecIsIPv6(&obj->raw->rec)) {
6188         type = &silkPyIPv6AddrType;
6189     } else
6190 #endif
6191     {
6192         type = &silkPyIPv4AddrType;
6193     }
6194 
6195     addr = PyObject_New(silkPyIPAddr, type);
6196     if (addr != NULL) {
6197         rwRecMemGetSIP(&obj->raw->rec, &addr->addr);
6198     }
6199     return (PyObject*)addr;
6200 }
6201 
6202 static int
silkPyRWRec_sip_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6203 silkPyRWRec_sip_set(
6204     silkPyRWRec        *obj,
6205     PyObject           *value,
6206     void        UNUSED(*closure))
6207 {
6208     if (IS_STRING(value)) {
6209         skipaddr_t  addr;
6210         PyObject   *bytes;
6211         char       *repr;
6212         int         rv;
6213 
6214         bytes = bytes_from_string(value);
6215         if (bytes == NULL) {
6216             return -1;
6217         }
6218         repr = PyBytes_AS_STRING(bytes);
6219         rv   = skStringParseIP(&addr, repr);
6220         if (rv != 0) {
6221             PyErr_Format(PyExc_ValueError, "Illegal IP address: %s", repr);
6222             Py_DECREF(bytes);
6223             return -1;
6224         }
6225         Py_DECREF(bytes);
6226         rwRecMemSetSIP(&obj->raw->rec, &addr);
6227         return 0;
6228     }
6229 
6230     if (silkPyIPAddr_Check(value)) {
6231         silkPyIPAddr *addr = (silkPyIPAddr*)value;
6232         rwRecMemSetSIP(&obj->raw->rec, &addr->addr);
6233         return 0;
6234     }
6235 
6236     PyErr_SetString(PyExc_TypeError, "The sip must be a valid IP address");
6237     return -1;
6238 }
6239 
6240 static PyObject *
silkPyRWRec_sport_get(silkPyRWRec * obj,void UNUSED (* closure))6241 silkPyRWRec_sport_get(
6242     silkPyRWRec        *obj,
6243     void        UNUSED(*closure))
6244 {
6245     return PyInt_FromLong(rwRecGetSPort(&obj->raw->rec));
6246 }
6247 
6248 static int
silkPyRWRec_sport_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6249 silkPyRWRec_sport_set(
6250     silkPyRWRec        *obj,
6251     PyObject           *value,
6252     void        UNUSED(*closure))
6253 {
6254     long val;
6255 
6256     if (!IS_INT(value)) {
6257         PyErr_SetString(PyExc_TypeError, "Expected an integer");
6258         return -1;
6259     }
6260 
6261     val = PyLong_AsLong(value);
6262     if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
6263         PyErr_SetString(PyExc_ValueError,
6264                         "The sport value must be a 16-bit integer");
6265         return -1;
6266     }
6267 
6268     rwRecSetSPort(&obj->raw->rec, val);
6269     return 0;
6270 }
6271 
6272 static PyObject *
silkPyRWRec_stime_epoch_secs_get(silkPyRWRec * obj,void UNUSED (* closure))6273 silkPyRWRec_stime_epoch_secs_get(
6274     silkPyRWRec        *obj,
6275     void        UNUSED(*closure))
6276 {
6277     double s_time = ((double)rwRecGetStartTime(&obj->raw->rec)) / 1.0e3;
6278 
6279     return PyFloat_FromDouble(s_time);
6280 }
6281 
6282 static int
silkPyRWRec_stime_epoch_secs_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6283 silkPyRWRec_stime_epoch_secs_set(
6284     silkPyRWRec        *obj,
6285     PyObject           *value,
6286     void        UNUSED(*closure))
6287 {
6288     const char *errstr = ("The stime_epoch_secs value must be a "
6289                           "positive number");
6290     PyObject *pyfloat_val;
6291     PyObject *pyint_val;
6292     int64_t long_val;
6293 
6294     if (!PyNumber_Check(value)) {
6295         PyErr_SetString(PyExc_TypeError, errstr);
6296         return -1;
6297     }
6298 
6299     pyfloat_val = PyNumber_Multiply(value, GLOBALS->thousand);
6300     if (pyfloat_val == NULL) {
6301         return -1;
6302     }
6303 
6304     pyint_val = PyNumber_Long(pyfloat_val);
6305     Py_DECREF(pyfloat_val);
6306     if (pyint_val == NULL) {
6307         PyErr_SetString(PyExc_TypeError, errstr);
6308         return -1;
6309     }
6310     long_val = PyLong_AsLongLong(pyint_val);
6311     Py_DECREF(pyint_val);
6312     if (long_val < 0) {
6313         PyErr_SetString(PyExc_ValueError, errstr);
6314         return -1;
6315     }
6316     if (long_val > MAX_EPOCH) {
6317         PyErr_SetString(PyExc_ValueError,
6318                         "Maximum stime is 03:14:07, Jan 19, 2038");
6319         return -1;
6320     }
6321 
6322     rwRecSetStartTime(&obj->raw->rec, long_val);
6323     return 0;
6324 }
6325 
6326 static PyObject *
silkPyRWRec_stime_get(silkPyRWRec * obj,void UNUSED (* closure))6327 silkPyRWRec_stime_get(
6328     silkPyRWRec        *obj,
6329     void        UNUSED(*closure))
6330 {
6331     PyObject *delta;
6332     PyObject *final;
6333     imaxdiv_t d = imaxdiv(rwRecGetStartTime(&obj->raw->rec), 1000);
6334 
6335     delta = PyObject_CallFunction(GLOBALS->timedelta, "ILIL",
6336                                   0, d.quot, 0, d.rem);
6337     if (delta == NULL) {
6338         return NULL;
6339     }
6340     final = PyNumber_Add(GLOBALS->epochtime, delta);
6341     Py_DECREF(delta);
6342     return final;
6343 }
6344 
6345 static int
silkPyRWRec_stime_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6346 silkPyRWRec_stime_set(
6347     silkPyRWRec        *obj,
6348     PyObject           *value,
6349     void        UNUSED(*closure))
6350 {
6351     sktime_t t;
6352     int rv;
6353 
6354     rv = silkPyDatetimeToSktime(&t, value);
6355 
6356     if (rv == 0) {
6357         rwRecSetStartTime(&obj->raw->rec, t);
6358     }
6359     return rv;
6360 }
6361 
6362 static PyObject *
silkPyRWRec_tcpflags_get(silkPyRWRec * obj,void UNUSED (* closure))6363 silkPyRWRec_tcpflags_get(
6364     silkPyRWRec        *obj,
6365     void        UNUSED(*closure))
6366 {
6367     silkPyTCPFlags *flags;
6368 
6369     flags = (silkPyTCPFlags*)silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType,
6370                                                           0);
6371     if (flags != NULL) {
6372         flags->val = rwRecGetFlags(&obj->raw->rec);
6373     }
6374 
6375     return (PyObject*)flags;
6376 }
6377 
6378 static int
silkPyRWRec_tcpflags_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6379 silkPyRWRec_tcpflags_set(
6380     silkPyRWRec        *obj,
6381     PyObject           *value,
6382     void        UNUSED(*closure))
6383 {
6384     uint8_t flagval;
6385     uint8_t state;
6386     silkPyTCPFlags *flags;
6387 
6388     state = rwRecGetTcpState(&obj->raw->rec) & ~SK_TCPSTATE_EXPANDED;
6389 
6390     flags = (silkPyTCPFlags *)PyObject_CallFunctionObjArgs(
6391         (PyObject *)&silkPyTCPFlagsType, value, NULL);
6392     if (flags == NULL) {
6393         return -1;
6394     }
6395     flagval = flags->val;
6396     Py_DECREF(flags);
6397 
6398     rwRecSetFlags(&obj->raw->rec, flagval);
6399     rwRecSetInitFlags(&obj->raw->rec, 0);
6400     rwRecSetInitFlags(&obj->raw->rec, 0);
6401     rwRecSetTcpState(&obj->raw->rec, state);
6402     return 0;
6403 }
6404 
6405 static PyObject *
silkPyRWRec_timeout_killed_get(silkPyRWRec * obj,void UNUSED (* closure))6406 silkPyRWRec_timeout_killed_get(
6407     silkPyRWRec        *obj,
6408     void        UNUSED(*closure))
6409 {
6410     uint8_t state;
6411 
6412     state = rwRecGetTcpState(&obj->raw->rec);
6413     return PyBool_FromLong(state & SK_TCPSTATE_TIMEOUT_KILLED);
6414 }
6415 
6416 static int
silkPyRWRec_timeout_killed_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6417 silkPyRWRec_timeout_killed_set(
6418     silkPyRWRec        *obj,
6419     PyObject           *value,
6420     void        UNUSED(*closure))
6421 {
6422     int     rv;
6423     uint8_t state;
6424 
6425     rv = PyObject_IsTrue(value);
6426     if (rv == -1) {
6427         return -1;
6428     }
6429     state = rwRecGetTcpState(&obj->raw->rec);
6430     if (rv) {
6431         state |= SK_TCPSTATE_TIMEOUT_KILLED;
6432     } else {
6433         state &= ~SK_TCPSTATE_TIMEOUT_KILLED;
6434     }
6435     rwRecSetTcpState(&obj->raw->rec, state);
6436 
6437     return 0;
6438 }
6439 
6440 static PyObject *
silkPyRWRec_timeout_started_get(silkPyRWRec * obj,void UNUSED (* closure))6441 silkPyRWRec_timeout_started_get(
6442     silkPyRWRec        *obj,
6443     void        UNUSED(*closure))
6444 {
6445     uint8_t state;
6446 
6447     state = rwRecGetTcpState(&obj->raw->rec);
6448     return PyBool_FromLong(state & SK_TCPSTATE_TIMEOUT_STARTED);
6449 }
6450 
6451 static int
silkPyRWRec_timeout_started_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6452 silkPyRWRec_timeout_started_set(
6453     silkPyRWRec        *obj,
6454     PyObject           *value,
6455     void        UNUSED(*closure))
6456 {
6457     int     rv;
6458     uint8_t state;
6459 
6460     rv = PyObject_IsTrue(value);
6461     if (rv == -1) {
6462         return -1;
6463     }
6464     state = rwRecGetTcpState(&obj->raw->rec);
6465     if (rv) {
6466         state |= SK_TCPSTATE_TIMEOUT_STARTED;
6467     } else {
6468         state &= ~SK_TCPSTATE_TIMEOUT_STARTED;
6469     }
6470     rwRecSetTcpState(&obj->raw->rec, state);
6471 
6472     return 0;
6473 }
6474 
6475 static PyObject *
silkPyRWRec_typename_get(silkPyRWRec * obj,void UNUSED (* closure))6476 silkPyRWRec_typename_get(
6477     silkPyRWRec        *obj,
6478     void        UNUSED(*closure))
6479 {
6480     char              type_name[SK_MAX_STRLEN_FLOWTYPE+1];
6481     sk_flowtype_id_t  flowtype = rwRecGetFlowType(&obj->raw->rec);
6482 
6483     CHECK_SITE(NULL);
6484 
6485     sksiteFlowtypeGetType(type_name, sizeof(type_name), flowtype);
6486     return PyUnicode_InternFromString(type_name);
6487 }
6488 
6489 static PyObject *
silkPyRWRec_uniform_packets_get(silkPyRWRec * obj,void UNUSED (* closure))6490 silkPyRWRec_uniform_packets_get(
6491     silkPyRWRec        *obj,
6492     void        UNUSED(*closure))
6493 {
6494     uint8_t state;
6495 
6496     state = rwRecGetTcpState(&obj->raw->rec);
6497     return PyBool_FromLong(state & SK_TCPSTATE_UNIFORM_PACKET_SIZE);
6498 }
6499 
6500 static int
silkPyRWRec_uniform_packets_set(silkPyRWRec * obj,PyObject * value,void UNUSED (* closure))6501 silkPyRWRec_uniform_packets_set(
6502     silkPyRWRec        *obj,
6503     PyObject           *value,
6504     void        UNUSED(*closure))
6505 {
6506     int     rv;
6507     uint8_t state;
6508 
6509     rv = PyObject_IsTrue(value);
6510     if (rv == -1) {
6511         return -1;
6512     }
6513     state = rwRecGetTcpState(&obj->raw->rec);
6514     if (rv) {
6515         state |= SK_TCPSTATE_UNIFORM_PACKET_SIZE;
6516     } else {
6517         state &= ~SK_TCPSTATE_UNIFORM_PACKET_SIZE;
6518     }
6519     rwRecSetTcpState(&obj->raw->rec, state);
6520 
6521     return 0;
6522 }
6523 
6524 static int
silkPyRawRWRec_init(silkPyRawRWRec * self,PyObject * args,PyObject * kwds)6525 silkPyRawRWRec_init(
6526     silkPyRawRWRec     *self,
6527     PyObject           *args,
6528     PyObject           *kwds)
6529 {
6530     static char *kwlist[] = {"rec", NULL};
6531     PyObject *copy = NULL;
6532 
6533     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!", kwlist,
6534                                      &silkPyRawRWRecType, &copy))
6535     {
6536         return -1;
6537     }
6538 
6539     if (copy) {
6540         RWREC_COPY(&self->rec, &((silkPyRawRWRec*)copy)->rec);
6541     }
6542     return 0;
6543 }
6544 
6545 static PyObject *
silkPyRawRWRec_new(PyTypeObject * type,PyObject UNUSED (* args),PyObject UNUSED (* kwds))6546 silkPyRawRWRec_new(
6547     PyTypeObject           *type,
6548     PyObject        UNUSED(*args),
6549     PyObject        UNUSED(*kwds))
6550 {
6551     silkPyRawRWRec *self;
6552 
6553     self = (silkPyRawRWRec*)type->tp_alloc(type, 0);
6554 
6555     if (self != NULL) {
6556         RWREC_CLEAR(&self->rec);
6557     }
6558 
6559     return (PyObject*)self;
6560 }
6561 
6562 
6563 /*
6564  *************************************************************************
6565  *   SiLK File
6566  *************************************************************************
6567  */
6568 
6569 typedef struct silkPySilkFile_st {
6570     PyObject_HEAD
6571     skstream_t *io;
6572 } silkPySilkFile;
6573 
6574 /* function prototypes */
6575 static PyObject *
6576 silkPySilkFile_close(
6577     silkPySilkFile     *obj);
6578 static void
6579 silkPySilkFile_dealloc(
6580     silkPySilkFile     *obj);
6581 static PyObject *
6582 silkPySilkFile_get_mode(
6583     silkPySilkFile         *obj,
6584     void            UNUSED(*closure));
6585 static PyObject *
6586 silkPySilkFile_get_name(
6587     silkPySilkFile         *obj,
6588     void            UNUSED(*closure));
6589 static int
6590 silkPySilkFile_init(
6591     silkPySilkFile     *self,
6592     PyObject           *args,
6593     PyObject           *kwds);
6594 static PyObject *
6595 silkPySilkFile_invocations(
6596     silkPySilkFile     *obj);
6597 static PyObject *
6598 silkPySilkFile_notes(
6599     silkPySilkFile     *obj);
6600 static PyObject *
6601 silkPySilkFile_read(
6602     silkPySilkFile     *obj);
6603 static PyObject *
6604 silkPySilkFile_write(
6605     silkPySilkFile     *obj,
6606     PyObject           *rec);
6607 static PyObject *
6608 silkPySilkFile_skip(
6609     silkPySilkFile     *obj,
6610     PyObject           *value);
6611 
6612 /* define docs and methods */
6613 static PyMethodDef silkPySilkFile_methods[] = {
6614     {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
6615     {"read", (PyCFunction)silkPySilkFile_read, METH_NOARGS,
6616      "Read a RWRec from a RW File"},
6617     {"write", (PyCFunction)silkPySilkFile_write, METH_O,
6618      "Write a RWRec to a RW File"},
6619     {"skip", (PyCFunction)silkPySilkFile_skip, METH_O,
6620      "Skip some number of RWRecs in a RW File;"
6621      " return number of records skipped"},
6622     {"close", (PyCFunction)silkPySilkFile_close, METH_NOARGS,
6623      "Close an RW File"},
6624     {"notes", (PyCFunction)silkPySilkFile_notes, METH_NOARGS,
6625      "Get the file's annotations"},
6626     {"invocations", (PyCFunction)silkPySilkFile_invocations, METH_NOARGS,
6627      "Get the file's invocations"},
6628     {NULL, NULL, 0, NULL}       /* Sentinel */
6629 };
6630 
6631 static PyGetSetDef silkPySilkFile_getseters[] = {
6632     {"name", (getter)silkPySilkFile_get_name, NULL,
6633      "name of file associated with SilkFile", NULL},
6634     {"mode", (getter)silkPySilkFile_get_mode, NULL,
6635      "mode associated with SilkFile", NULL},
6636     {NULL, NULL, NULL, NULL, NULL}    /* Sentinel */
6637 };
6638 
6639 /* define the object types */
6640 static PyTypeObject silkPySilkFileType = {
6641     PyVarObject_HEAD_INIT(NULL, 0)
6642     "silk.pysilk.SilkFileBase", /* tp_name */
6643     sizeof(silkPySilkFile),         /* tp_basicsize */
6644     0,                          /* tp_itemsize */
6645     (destructor)silkPySilkFile_dealloc, /* tp_dealloc */
6646     0,                          /* tp_vectorcall_offset (Py 3.8) */
6647     0,                          /* tp_getattr */
6648     0,                          /* tp_setattr */
6649     0,                          /* tp_as_async (tp_compare in Py2.x) */
6650     0,                          /* tp_repr */
6651     0,                          /* tp_as_number */
6652     0,                          /* tp_as_sequence */
6653     0,                          /* tp_as_mapping */
6654     0,                          /* tp_hash  */
6655     0,                          /* tp_call */
6656     0,                          /* tp_str */
6657     0,                          /* tp_getattro */
6658     0,                          /* tp_setattro */
6659     0,                          /* tp_as_buffer */
6660     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
6661     "Base Silk File",           /* tp_doc */
6662     0,                          /* tp_traverse */
6663     0,                          /* tp_clear */
6664     0,                          /* tp_richcompare */
6665     0,                          /* tp_weaklistoffset */
6666     0,                          /* tp_iter */
6667     0,                          /* tp_iternext */
6668     silkPySilkFile_methods,     /* tp_methods */
6669     0,                          /* tp_members */
6670     silkPySilkFile_getseters,   /* tp_getset */
6671     0,                          /* tp_base */
6672     0,                          /* tp_dict */
6673     0,                          /* tp_descr_get */
6674     0,                          /* tp_descr_set */
6675     0,                          /* tp_dictoffset */
6676     (initproc)silkPySilkFile_init, /* tp_init */
6677     0,                          /* tp_alloc */
6678     0,                          /* tp_new */
6679     0,                          /* tp_free */
6680     0,                          /* tp_is_gc */
6681     0,                          /* tp_bases */
6682     0,                          /* tp_mro */
6683     0,                          /* tp_cache */
6684     0,                          /* tp_subclasses */
6685     0,                          /* tp_weaklist */
6686     0                           /* tp_del */
6687 #if PY_VERSION_HEX >= 0x02060000
6688     ,0                          /* tp_version_tag */
6689 #endif
6690 #if PY_VERSION_HEX >= 0x03040000
6691     ,0                          /* tp_finalize */
6692 #endif
6693 #if PY_VERSION_HEX >= 0x03080000
6694     ,0                          /* tp_vectorcall */
6695     ,0                          /* tp_print */
6696 #endif
6697 };
6698 
6699 /* macro and function defintions */
6700 #define silkPySilkFile_Check(op) \
6701     PyObject_TypeCheck(op, &silkPySilkFileType)
6702 
6703 static PyObject *
throw_ioerror(silkPySilkFile * obj,int errcode)6704 throw_ioerror(
6705     silkPySilkFile     *obj,
6706     int                 errcode)
6707 {
6708     skStreamPrintLastErr(obj->io, errcode, error_printf);
6709     PyErr_SetString(PyExc_IOError, error_buffer);
6710     return NULL;
6711 }
6712 
6713 static PyObject *
silkPySilkFile_close(silkPySilkFile * obj)6714 silkPySilkFile_close(
6715     silkPySilkFile     *obj)
6716 {
6717     int rv;
6718 
6719     rv = skStreamClose(obj->io);
6720     if (rv == 0) {
6721         Py_RETURN_NONE;
6722     }
6723 
6724     return throw_ioerror(obj, rv);
6725 }
6726 
6727 static void
silkPySilkFile_dealloc(silkPySilkFile * obj)6728 silkPySilkFile_dealloc(
6729     silkPySilkFile     *obj)
6730 {
6731     if (obj->io) {
6732         skStreamDestroy(&obj->io);
6733     }
6734     Py_TYPE(obj)->tp_free(obj);
6735 }
6736 
6737 static PyObject *
silkPySilkFile_get_mode(silkPySilkFile * obj,void UNUSED (* closure))6738 silkPySilkFile_get_mode(
6739     silkPySilkFile         *obj,
6740     void            UNUSED(*closure))
6741 {
6742     return PyInt_FromLong(skStreamGetMode(obj->io));
6743 }
6744 
6745 static PyObject *
silkPySilkFile_get_name(silkPySilkFile * obj,void UNUSED (* closure))6746 silkPySilkFile_get_name(
6747     silkPySilkFile         *obj,
6748     void            UNUSED(*closure))
6749 {
6750     const char *name = skStreamGetPathname(obj->io);
6751     if (name) {
6752         return PyUnicode_FromString(name);
6753     }
6754     Py_RETURN_NONE;
6755 }
6756 
6757 static int
silkPySilkFile_init(silkPySilkFile * self,PyObject * args,PyObject * kwds)6758 silkPySilkFile_init(
6759     silkPySilkFile     *self,
6760     PyObject           *args,
6761     PyObject           *kwds)
6762 {
6763     char             *filename;
6764     int               mode;
6765     int               format      = NOT_SET;
6766     int               policy      = NOT_SET;
6767     int               compr       = NOT_SET;
6768     int               file_des    = NOT_SET;
6769     PyObject         *annotations = NULL;
6770     PyObject         *invocations = NULL;
6771     sk_file_header_t *hdr;
6772     int               rv;
6773 
6774     static char *kwlist[] = {"filename", "mode", "compression",
6775                              "format", "policy", "invocations",
6776                              "notes", "_fileno", NULL};
6777 
6778     if (!PyArg_ParseTupleAndKeywords(args, kwds, "si|iiiO!O!i", kwlist,
6779                                      &filename, &mode, &compr,
6780                                      &format, &policy,
6781                                      &PyList_Type, &invocations,
6782                                      &PyList_Type, &annotations,
6783                                      &file_des))
6784     {
6785         return -1;
6786     }
6787 
6788     if (mode != SK_IO_READ && mode != SK_IO_WRITE && mode != SK_IO_APPEND) {
6789         PyErr_SetString(PyExc_ValueError, "Illegal mode");
6790         Py_DECREF(self);
6791         return -1;
6792     }
6793     if (self->io) {
6794         skStreamDestroy(&self->io);
6795     }
6796     rv = skStreamCreate(&self->io, (skstream_mode_t)mode,SK_CONTENT_SILK_FLOW);
6797     if (rv != 0) {
6798         throw_ioerror(self, rv);
6799         return -1;
6800     }
6801 
6802     rv = skStreamBind(self->io, filename);
6803     if (rv != 0) {
6804         throw_ioerror(self, rv);
6805         return -1;
6806     }
6807 
6808     hdr = skStreamGetSilkHeader(self->io);
6809 
6810     if (policy != NOT_SET) {
6811         rv = skStreamSetIPv6Policy(self->io, (sk_ipv6policy_t)policy);
6812         if (rv != 0) {
6813             throw_ioerror(self, rv);
6814             return -1;
6815         }
6816     }
6817 
6818     if (compr != NOT_SET) {
6819         if (mode != SK_IO_WRITE) {
6820             PyErr_SetString(PyExc_ValueError,
6821                             "Cannot set compression unless in WRITE mode");
6822             return -1;
6823         }
6824         rv = skHeaderSetCompressionMethod(hdr, compr);
6825         if (rv != 0) {
6826             throw_ioerror(self, rv);
6827             return -1;
6828         }
6829     }
6830 
6831     if (format != NOT_SET) {
6832         if (mode != SK_IO_WRITE) {
6833             PyErr_SetString(PyExc_ValueError,
6834                             "Cannot set file format unless in WRITE mode");
6835             return -1;
6836         }
6837         rv = skHeaderSetFileFormat(hdr, format);
6838         if (rv != 0) {
6839             throw_ioerror(self, rv);
6840             return -1;
6841         }
6842     }
6843 
6844     if (annotations != NULL) {
6845         if (mode != SK_IO_WRITE) {
6846             PyErr_SetString(PyExc_ValueError,
6847                             "Cannot set annotations unless in WRITE mode");
6848             return -1;
6849         }
6850         if (hdr != NULL) {
6851             ssize_t len = PyList_GET_SIZE(annotations);
6852             ssize_t i;
6853 
6854             for (i = 0; i < len; i++) {
6855                 PyObject *bytes;
6856                 PyObject *item = PyList_GET_ITEM(annotations, i);
6857 
6858                 if (!IS_STRING(item)) {
6859                     PyErr_SetString(PyExc_TypeError,
6860                                     "Annotation was not a string");
6861                     return -1;
6862                 }
6863                 bytes = bytes_from_string(item);
6864                 if (bytes == NULL) {
6865                     return -1;
6866                 }
6867 
6868                 rv = skHeaderAddAnnotation(hdr, PyBytes_AS_STRING(bytes));
6869                 Py_DECREF(bytes);
6870                 if (rv != 0) {
6871                     throw_ioerror(self, rv);
6872                 }
6873             }
6874         }
6875     }
6876 
6877     if (invocations != NULL) {
6878         if (mode != SK_IO_WRITE) {
6879             PyErr_SetString(PyExc_ValueError,
6880                             "Cannot set invocations unless in WRITE mode");
6881             return -1;
6882         }
6883         if (hdr != NULL) {
6884             ssize_t len = PyList_GET_SIZE(invocations);
6885             ssize_t i;
6886 
6887             for (i = 0; i < len; i++) {
6888                 PyObject *item = PyList_GET_ITEM(invocations, i);
6889                 char     *value;
6890                 PyObject *bytes;
6891 
6892                 if (!IS_STRING(item)) {
6893                     PyErr_SetString(PyExc_TypeError,
6894                                     "Invocation was not a string");
6895                     return -1;
6896                 }
6897 
6898                 bytes = bytes_from_string(item);
6899                 if (bytes == NULL) {
6900                     return -1;
6901                 }
6902                 value = PyBytes_AS_STRING(bytes);
6903                 rv = skHeaderAddInvocation(hdr, 0, 1, &value);
6904                 Py_DECREF(bytes);
6905                 if (rv != 0) {
6906                     throw_ioerror(self, rv);
6907                 }
6908             }
6909         }
6910     }
6911 
6912     if (file_des == NOT_SET) {
6913         rv = skStreamOpen(self->io);
6914     } else {
6915         rv = skStreamFDOpen(self->io, file_des);
6916     }
6917     if (rv != 0) {
6918         throw_ioerror(self, rv);
6919         return -1;
6920     }
6921 
6922     if (mode == SK_IO_WRITE) {
6923         rv = skStreamWriteSilkHeader(self->io);
6924         if (rv != 0) {
6925             throw_ioerror(self, rv);
6926             return -1;
6927         }
6928     } else {
6929         rv = skStreamReadSilkHeader(self->io, NULL);
6930         if (rv != 0) {
6931             throw_ioerror(self, rv);
6932             return -1;
6933         }
6934     }
6935 
6936     return 0;
6937 }
6938 
6939 static PyObject *
silkPySilkFile_invocations(silkPySilkFile * obj)6940 silkPySilkFile_invocations(
6941     silkPySilkFile     *obj)
6942 {
6943     sk_file_header_t     *hdr;
6944     sk_header_entry_t    *entry;
6945     sk_hentry_iterator_t  iter;
6946     PyObject             *list;
6947     PyObject             *invoc;
6948     int                   rv;
6949 
6950     list = PyList_New(0);
6951     if (list == NULL) {
6952         return NULL;
6953     }
6954     hdr = skStreamGetSilkHeader(obj->io);
6955     if (hdr != NULL) {
6956         skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_INVOCATION_ID);
6957         while ((entry = skHeaderIteratorNext(&iter)) != NULL) {
6958             invoc = PyUnicode_FromString(
6959                 skHentryInvocationGetInvocation(entry));
6960             if (invoc == NULL) {
6961                 Py_DECREF(list);
6962                 return NULL;
6963             }
6964             rv = PyList_Append(list, invoc);
6965             Py_DECREF(invoc);
6966             if (rv != 0) {
6967                 Py_DECREF(list);
6968                 return NULL;
6969             }
6970         }
6971     }
6972 
6973     return list;
6974 }
6975 
6976 static PyObject *
silkPySilkFile_notes(silkPySilkFile * obj)6977 silkPySilkFile_notes(
6978     silkPySilkFile     *obj)
6979 {
6980     sk_file_header_t     *hdr;
6981     sk_header_entry_t    *entry;
6982     sk_hentry_iterator_t  iter;
6983     PyObject             *list;
6984     PyObject             *annot;
6985     int                   rv;
6986 
6987     list = PyList_New(0);
6988     if (list == NULL) {
6989         return NULL;
6990     }
6991     hdr = skStreamGetSilkHeader(obj->io);
6992     if (hdr != NULL) {
6993         skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_ANNOTATION_ID);
6994         while ((entry = skHeaderIteratorNext(&iter)) != NULL) {
6995             annot = PyUnicode_FromString(
6996                 skHentryAnnotationGetNote(entry));
6997             if (annot == NULL) {
6998                 Py_DECREF(list);
6999                 return NULL;
7000             }
7001             rv = PyList_Append(list, annot);
7002             Py_DECREF(annot);
7003             if (rv != 0) {
7004                 Py_DECREF(list);
7005                 return NULL;
7006             }
7007         }
7008     }
7009 
7010     return list;
7011 }
7012 
7013 static PyObject *
silkPySilkFile_read(silkPySilkFile * obj)7014 silkPySilkFile_read(
7015     silkPySilkFile     *obj)
7016 {
7017     PyObject *pyrec;
7018     int rv;
7019 
7020     pyrec = silkPyRawRWRecType.tp_alloc(&silkPyRawRWRecType, 0);
7021     if (pyrec == NULL) {
7022         return NULL;
7023     }
7024 
7025     rv = skStreamReadRecord(obj->io, &((silkPyRawRWRec*)pyrec)->rec);
7026     if (rv != 0) {
7027         Py_DECREF(pyrec);
7028         if (rv == SKSTREAM_ERR_EOF) {
7029             Py_RETURN_NONE;
7030         }
7031         return throw_ioerror(obj, rv);
7032     }
7033 
7034     return pyrec;
7035 }
7036 
7037 static PyObject *
silkPySilkFile_write(silkPySilkFile * obj,PyObject * rec)7038 silkPySilkFile_write(
7039     silkPySilkFile     *obj,
7040     PyObject           *rec)
7041 {
7042     int rv;
7043 
7044     if (!silkPyRWRec_Check(rec)) {
7045         PyErr_SetString(PyExc_TypeError, "Argument not a RWRec");
7046         return NULL;
7047     }
7048 
7049     rv = skStreamWriteRecord(obj->io, &((silkPyRWRec*)rec)->raw->rec);
7050     if (rv == 0) {
7051         Py_RETURN_NONE;
7052     }
7053 
7054     return throw_ioerror(obj, rv);
7055 }
7056 
7057 static PyObject *
silkPySilkFile_skip(silkPySilkFile * obj,PyObject * value)7058 silkPySilkFile_skip(
7059     silkPySilkFile     *obj,
7060     PyObject           *value)
7061 {
7062     size_t skipped = 0;
7063     uint64_t val;
7064     int rv;
7065 
7066     if (!IS_INT(value)) {
7067         PyErr_SetString(PyExc_TypeError, "Expected an integer");
7068         return NULL;
7069     }
7070 
7071     val = LONG_AS_UNSIGNED_LONGLONG(value);
7072     if (PyErr_Occurred()) {
7073         return NULL;
7074     }
7075 
7076     rv = skStreamSkipRecords(obj->io, val, &skipped);
7077     if (rv == 0 || rv == SKSTREAM_ERR_EOF) {
7078         return PyLong_FromUnsignedLongLong(skipped);
7079     }
7080 
7081     return throw_ioerror(obj, rv);
7082 }
7083 
7084 
7085 /*
7086  *************************************************************************
7087  *   RepoIter
7088  *************************************************************************
7089  */
7090 
7091 typedef struct silkPyRepoIter_st {
7092     PyObject_HEAD
7093     sksite_repo_iter_t *iter;
7094 } silkPyRepoIter;
7095 
7096 /* function prototypes */
7097 static void
7098 silkPyRepoIter_dealloc(
7099     silkPyRepoIter     *self);
7100 static int
7101 silkPyRepoIter_init(
7102     silkPyRepoIter     *self,
7103     PyObject           *args,
7104     PyObject           *kwds);
7105 static PyObject *
7106 silkPyRepoIter_iternext(
7107     silkPyRepoIter     *self);
7108 
7109 /* define the object types */
7110 static PyTypeObject silkPyRepoIterType ={
7111     PyVarObject_HEAD_INIT(NULL, 0)
7112     "silk.pysilk.RepoIter",    /* tp_name */
7113     sizeof(silkPyRepoIterType), /* tp_basicsize */
7114     0,                          /* tp_itemsize */
7115     (destructor)silkPyRepoIter_dealloc, /* tp_dealloc */
7116     0,                          /* tp_vectorcall_offset (Py 3.8) */
7117     0,                          /* tp_getattr */
7118     0,                          /* tp_setattr */
7119     0,                          /* tp_as_async (tp_compare in Py2.x) */
7120     0,                          /* tp_repr */
7121     0,                          /* tp_as_number */
7122     0,                          /* tp_as_sequence */
7123     0,                          /* tp_as_mapping */
7124     0,                          /* tp_hash  */
7125     0,                          /* tp_call */
7126     0,                          /* tp_str */
7127     0,                          /* tp_getattro */
7128     0,                          /* tp_setattro */
7129     0,                          /* tp_as_buffer */
7130     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
7131     "SiLK repo file iterator object", /* tp_doc */
7132     0,                          /* tp_traverse */
7133     0,                          /* tp_clear */
7134     0,                          /* tp_richcompare */
7135     0,                          /* tp_weaklistoffset */
7136     iter_iter,                  /* tp_iter */
7137     (iternextfunc)silkPyRepoIter_iternext, /* tp_iternext */
7138     0,                          /* tp_methods */
7139     0,                          /* tp_members */
7140     0,                          /* tp_getset */
7141     0,                          /* tp_base */
7142     0,                          /* tp_dict */
7143     0,                          /* tp_descr_get */
7144     0,                          /* tp_descr_set */
7145     0,                          /* tp_dictoffset */
7146     (initproc)silkPyRepoIter_init, /* tp_init */
7147     0,                          /* tp_alloc */
7148     0,                          /* tp_new */
7149     0,                          /* tp_free */
7150     0,                          /* tp_is_gc */
7151     0,                          /* tp_bases */
7152     0,                          /* tp_mro */
7153     0,                          /* tp_cache */
7154     0,                          /* tp_subclasses */
7155     0,                          /* tp_weaklist */
7156     0                           /* tp_del */
7157 #if PY_VERSION_HEX >= 0x02060000
7158     ,0                          /* tp_version_tag */
7159 #endif
7160 #if PY_VERSION_HEX >= 0x03040000
7161     ,0                          /* tp_finalize */
7162 #endif
7163 #if PY_VERSION_HEX >= 0x03080000
7164     ,0                          /* tp_vectorcall */
7165     ,0                          /* tp_print */
7166 #endif
7167 };
7168 
7169 /* macro and function defintions */
7170 #define silkPyRepoIter_Check(op)                \
7171     PyObject_TypeCheck(op, &silkPyRepoIterType)
7172 
7173 static void
silkPyRepoIter_dealloc(silkPyRepoIter * self)7174 silkPyRepoIter_dealloc(
7175     silkPyRepoIter     *self)
7176 {
7177     sksiteRepoIteratorDestroy(&self->iter);
7178     Py_TYPE(self)->tp_free((PyObject*)self);
7179 }
7180 
7181 static int
silkPyRepoIter_init(silkPyRepoIter * self,PyObject * args,PyObject * kwds)7182 silkPyRepoIter_init(
7183     silkPyRepoIter     *self,
7184     PyObject           *args,
7185     PyObject           *kwds)
7186 {
7187     static char *kwlist[] = {"start", "end", "flowtypes",
7188                              "sensors", "missing", NULL};
7189     PyObject *start     = NULL;
7190     PyObject *end       = NULL;
7191     PyObject *flowtypes = NULL;
7192     PyObject *sensors   = NULL;
7193     PyObject *missing   = NULL;
7194     PyObject *fast      = NULL;
7195     sk_vector_t *ft_vec     = NULL;
7196     sk_vector_t *sensor_vec = NULL;
7197     sktime_t starttime, endtime;
7198     sk_flowtype_iter_t ft_iter;
7199     sk_flowtype_id_t ft;
7200     uint32_t flags;
7201     unsigned int start_precision;
7202     unsigned int end_precision;
7203     int rv;
7204 
7205     CHECK_SITE(-1);
7206 
7207     ft_vec = skVectorNew(sizeof(sk_flowtype_id_t));
7208     if (ft_vec == NULL) {
7209         PyErr_NoMemory();
7210         return -1;
7211     }
7212 
7213     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOO", kwlist,
7214                                      &start, &end, &flowtypes,
7215                                      &sensors, &missing))
7216     {
7217         goto error;
7218     }
7219 
7220     /* Calculate starttime */
7221     if (PyDate_Check(start)) {
7222         rv = silkPyDatetimeToSktime(&starttime, start);
7223         if (rv != 0) {
7224             goto error;
7225         }
7226         start_precision = (PyDateTime_Check(start)
7227                            ? SK_PARSED_DATETIME_HOUR
7228                            : SK_PARSED_DATETIME_DAY);
7229     } else if (IS_STRING(start)) {
7230         PyObject *bytes = bytes_from_string(start);
7231         if (bytes == NULL) {
7232             goto error;
7233         }
7234         rv = skStringParseDatetime(&starttime, PyBytes_AS_STRING(bytes),
7235                                    &start_precision);
7236         Py_DECREF(bytes);
7237         if (rv != 0) {
7238             PyErr_SetString(PyExc_ValueError, skStringParseStrerror(rv));
7239             goto error;
7240         }
7241     } else {
7242         PyErr_SetString(PyExc_TypeError,
7243                         "start must be a string or a "
7244                         "datetime.date[time] object");
7245         goto error;
7246     }
7247     starttime -= starttime % 3600000;
7248 
7249     /* Calculate endtime */
7250     if (end == NULL || end == Py_None) {
7251         end = NULL;
7252     } else if (PyDate_Check(end)) {
7253         rv = silkPyDatetimeToSktime(&endtime, end);
7254         if (rv != 0) {
7255             goto error;
7256         }
7257         end_precision = (PyDateTime_Check(end)
7258                          ? SK_PARSED_DATETIME_HOUR
7259                          : SK_PARSED_DATETIME_DAY);
7260     } else if (IS_STRING(end)) {
7261         PyObject *bytes = bytes_from_string(end);
7262         if (bytes == NULL) {
7263             goto error;
7264         }
7265         rv = skStringParseDatetime(&endtime, PyBytes_AS_STRING(bytes),
7266                                    &end_precision);
7267         Py_DECREF(bytes);
7268         if (rv != 0) {
7269             PyErr_SetString(PyExc_ValueError, skStringParseStrerror(rv));
7270             goto error;
7271         }
7272     } else {
7273         PyErr_SetString(PyExc_TypeError,
7274                         "end must be a string or a "
7275                         "datetime.date[time] object");
7276         goto error;
7277     }
7278 
7279     /* End-time mashup */
7280     if (end) {
7281         if (end_precision & SK_PARSED_DATETIME_EPOCH) {
7282             /* when end-time is specified as an epoch, use it as-is */
7283 
7284         } else if (SK_PARSED_DATETIME_GET_PRECISION(start_precision)
7285                    == SK_PARSED_DATETIME_DAY)
7286         {
7287             /* when no starting hour given, we look at the full days,
7288              * regardless of the precision of the ending time; go to
7289              * the last hour of the ending day. */
7290             if (skDatetimeCeiling(&endtime, &endtime, start_precision)) {
7291                 PyErr_SetString(PyExc_ValueError,
7292                                 "Could not determine end time");
7293                 goto error;
7294             }
7295             endtime -= endtime % 3600000;
7296         } else if (SK_PARSED_DATETIME_GET_PRECISION(end_precision)
7297                    < SK_PARSED_DATETIME_HOUR)
7298         {
7299             /* starting time has an hour but ending time does not; use
7300              * same hour for ending time */
7301 #if  SK_ENABLE_LOCALTIME
7302             time_t t;
7303             struct tm work_tm;
7304             int work_hour;
7305 
7306             /* get starting hour */
7307             t = starttime / 1000;
7308             localtime_r(&t, &work_tm);
7309             work_hour = work_tm.tm_hour;
7310             /* break apart end time */
7311             t = endtime / 1000;
7312             localtime_r(&t, &work_tm);
7313             /* set end hour to start hour and re-combine */
7314             work_tm.tm_hour = work_hour;
7315             t = mktime(&work_tm);
7316             endtime = sktimeCreate((t - (t % 3600)), 0);
7317 #else
7318             endtime = endtime - (endtime % 86400000) + (starttime % 86400000);
7319 #endif
7320         } else {
7321             endtime -= endtime % 3600000;
7322         }
7323 
7324     } else if ((SK_PARSED_DATETIME_GET_PRECISION(start_precision)
7325                    >= SK_PARSED_DATETIME_HOUR)
7326                || (start_precision & SK_PARSED_DATETIME_EPOCH))
7327     {
7328         /* no ending time was given and the starting time contains an
7329          * hour or the starting time was expressed as epoch seconds;
7330          * we only look at that single hour */
7331         endtime = starttime;
7332 
7333     } else {
7334         /* no ending time was given and the starting time was to the
7335          * day; look at that entire day */
7336         if (skDatetimeCeiling(&endtime, &starttime, start_precision)) {
7337             PyErr_SetString(PyExc_ValueError,
7338                             "Could not determine end time");
7339             goto error;
7340         }
7341         endtime -= endtime % 3600000;
7342     }
7343 
7344     if (starttime > endtime) {
7345         PyErr_SetString(PyExc_ValueError,
7346                         "start must be less or equal to end");
7347         goto error;
7348     }
7349 
7350     /* Calculate flowtypes */
7351     if (flowtypes == NULL || flowtypes == Py_None) {
7352         sksiteFlowtypeIterator(&ft_iter);
7353         while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
7354             rv = skVectorAppendValue(ft_vec, &ft);
7355             if (rv != 0) {
7356                 PyErr_NoMemory();
7357                 goto error;
7358             }
7359         }
7360     } else if (PySequence_Check(flowtypes)) {
7361         Py_ssize_t len;
7362         PyObject **items;
7363         fast = PySequence_Fast(flowtypes, "flowtypes must be a sequence");
7364         if (fast == NULL) {
7365             goto error;
7366         }
7367         len = PySequence_Fast_GET_SIZE(fast);
7368         items = PySequence_Fast_ITEMS(fast);
7369         for (/*empty*/; len; len--, items++) {
7370             const char *class_name, *type_name;
7371             if (!PyArg_ParseTuple(*items, "ss", &class_name, &type_name)) {
7372                 goto error;
7373             }
7374             ft = sksiteFlowtypeLookupByClassType(class_name, type_name);
7375             if (ft == SK_INVALID_FLOWTYPE) {
7376                 PyErr_Format(PyExc_ValueError,
7377                              "Invalid (class, type) pair ('%s', '%s')",
7378                              class_name, type_name);
7379                 return -1;
7380             }
7381             rv = skVectorAppendValue(ft_vec, &ft);
7382             if (rv != 0) {
7383                 PyErr_NoMemory();
7384                 goto error;
7385             }
7386         }
7387         Py_CLEAR(fast);
7388     } else {
7389         PyErr_SetString(
7390             PyExc_TypeError,
7391             "flowtypes should be a sequence of (class, type) pairs");
7392         goto error;
7393     }
7394 
7395     /* Calculate sensors */
7396     if (sensors && PySequence_Check(sensors)) {
7397         Py_ssize_t len;
7398         PyObject **items;
7399         sk_sensor_id_t sensor;
7400 
7401         sensor_vec = skVectorNew(sizeof(sk_sensor_id_t));
7402         if (sensor_vec == NULL) {
7403             PyErr_NoMemory();
7404             goto error;
7405         }
7406 
7407         fast = PySequence_Fast(sensors, "sensors must be a sequence");
7408         if (fast == NULL) {
7409             goto error;
7410         }
7411         len = PySequence_Fast_GET_SIZE(fast);
7412         items = PySequence_Fast_ITEMS(fast);
7413         for (/*empty*/; len; len--, items++) {
7414             PyObject *bytes;
7415             if (!IS_STRING(*items)) {
7416                 PyErr_SetString(PyExc_TypeError,
7417                                 "sensors must be strings");
7418                 goto error;
7419             }
7420             bytes = bytes_from_string(*items);
7421             if (bytes == NULL) {
7422                 goto error;
7423             }
7424             sensor = sksiteSensorLookup(PyBytes_AS_STRING(bytes));
7425             if (sensor == SK_INVALID_SENSOR) {
7426                 PyErr_SetString(PyExc_ValueError, "Invalid sensor name");
7427                 goto error;
7428             }
7429             rv = skVectorAppendValue(sensor_vec, &sensor);
7430             if (rv != 0) {
7431                 PyErr_NoMemory();
7432                 goto error;
7433             }
7434         }
7435         Py_CLEAR(fast);
7436     } else if (sensors != NULL && sensors != Py_None) {
7437         PyErr_SetString(PyExc_TypeError,
7438                         "sensors should be a sequence of strings");
7439         goto error;
7440     }
7441 
7442     if (missing && PyObject_IsTrue(missing)) {
7443         flags = RETURN_MISSING;
7444     } else {
7445         flags = 0;
7446     }
7447 
7448     rv = sksiteRepoIteratorCreate(
7449         &self->iter, ft_vec, sensor_vec, starttime, endtime, flags);
7450     if (rv != 0) {
7451         PyErr_NoMemory();
7452         goto error;
7453     }
7454 
7455     rv = 0;
7456 
7457   cleanup:
7458     Py_XDECREF(fast);
7459     if (ft_vec) {
7460         skVectorDestroy(ft_vec);
7461     }
7462     if (sensor_vec) {
7463         skVectorDestroy(sensor_vec);
7464     }
7465 
7466     return rv;
7467 
7468   error:
7469     rv = -1;
7470     goto cleanup;
7471 }
7472 
7473 static PyObject *
silkPyRepoIter_iternext(silkPyRepoIter * self)7474 silkPyRepoIter_iternext(
7475     silkPyRepoIter     *self)
7476 {
7477     char path[PATH_MAX];
7478     int missing;
7479     int rv;
7480 
7481     rv = sksiteRepoIteratorNextPath(self->iter, path, sizeof(path), &missing);
7482     if (rv == SK_ITERATOR_NO_MORE_ENTRIES) {
7483         PyErr_SetNone(PyExc_StopIteration);
7484         return NULL;
7485     }
7486 
7487     return Py_BuildValue("sO", path, missing ? Py_False : Py_True);
7488 }
7489 
7490 
7491 /*
7492  *************************************************************************
7493  *   Misc Globals
7494  *************************************************************************
7495  */
7496 
7497 /* function prototypes */
7498 static PyObject *silk_class_info(void);
7499 static PyObject *silk_flowtype_info(void);
7500 static PyObject *silk_get_rootdir(void);
7501 static PyObject *silk_get_siteconf(void);
7502 static PyObject *silk_have_site_config(void);
7503 static PyObject *
7504 silk_init_country_codes(
7505     PyObject    UNUSED(*self),
7506     PyObject           *args);
7507 static int
7508 silk_init_set_envvar(
7509     const char         *value,
7510     const char         *envvar);
7511 static PyObject *
7512 silk_init_site(
7513     PyObject    UNUSED(*self),
7514     PyObject           *args,
7515     PyObject           *kwds);
7516 static PyObject *silk_get_compression_methods(void);
7517 static PyObject *silk_get_timezone_support(void);
7518 static PyObject *silk_initial_tcpflags_enabled(void);
7519 static PyObject *silk_ipset_supports_ipv6(void);
7520 static PyObject *silk_ipv6_enabled(void);
7521 static silkPyRawRWRec *
7522 silk_raw_rwrec_copy(
7523     PyObject    UNUSED(*self),
7524     PyObject           *c_rec);
7525 static PyObject *silk_sensor_info(void);
7526 static PyObject *
7527 silk_set_rootdir(
7528     PyObject    UNUSED(*self),
7529     PyObject           *args);
7530 static PyObject *silk_version(void);
7531 
7532 static PyMethodDef silk_methods[] = {
7533     {"get_compression_methods", (PyCFunction)silk_get_compression_methods,
7534      METH_NOARGS,
7535      ("Return a list of strings containing the compression methods"
7536       " enabled at compile-time")},
7537     {"get_timezone_support", (PyCFunction)silk_get_timezone_support,
7538      METH_NOARGS,
7539      ("Return whether \"UTC\" or the \"local\" timezone was selected"
7540       " at compile-time")},
7541     {"ipv6_enabled", (PyCFunction)silk_ipv6_enabled,
7542      METH_NOARGS,
7543      ("Return whether IPv6 was enabled at compile-time")},
7544     {"ipset_supports_ipv6", (PyCFunction)silk_ipset_supports_ipv6,
7545      METH_NOARGS,
7546      ("Return whether IPv6-support for IPsets was enabled at compile-time")},
7547     {"initial_tcpflags_enabled", (PyCFunction)silk_initial_tcpflags_enabled,
7548      METH_NOARGS,
7549      ("Return whether initial tcpflags were enabled at compile-time")},
7550     {"init_site", (PyCFunction)silk_init_site,
7551      METH_VARARGS | METH_KEYWORDS,
7552      ("init_site([siteconf][, rootdir])\n"
7553       "Initialize the silk site.\n"
7554       "When siteconf is None, PySiLK uses the file named by the environment\n"
7555       "variable " SILK_CONFIG_FILE_ENVAR ", if available, or the file\n"
7556       "'silk.conf' in the rootdir, the directories '$SILK_PATH/share/silk/'\n"
7557       "and '$SILK_PATH/share/', and the 'share/silk/' and 'share/'\n"
7558       "directories parallel to the application's directory.\n"
7559       "When rootdir is not supplied, SiLK's default value is used.\n"
7560       "Throw an exception if the site is already initialized.")},
7561     {"have_site_config", (PyCFunction)silk_have_site_config,
7562      METH_NOARGS,
7563      ("Return whether the site configuration file has been loaded")},
7564     {"get_site_config", (PyCFunction)silk_get_siteconf,
7565      METH_NOARGS,
7566      ("Return the current site configuration file; None if not set")},
7567     {"set_data_rootdir", (PyCFunction)silk_set_rootdir,
7568      METH_VARARGS,
7569      ("Change the data root directory to the given path")},
7570     {"get_data_rootdir", (PyCFunction)silk_get_rootdir,
7571      METH_NOARGS,
7572      ("Return the current root directory")},
7573     {"sensor_info", (PyCFunction)silk_sensor_info,
7574      METH_NOARGS,
7575      ("Returns a list of information for configured sensors")},
7576     {"class_info", (PyCFunction)silk_class_info,
7577      METH_NOARGS,
7578      ("Return a list of information for configured classes")},
7579     {"flowtype_info", (PyCFunction)silk_flowtype_info,
7580      METH_NOARGS,
7581      ("Return a list of information for configured flowtypes")},
7582     {"silk_version", (PyCFunction)silk_version,
7583      METH_NOARGS,
7584      ("Return the version of SiLK that PySilk was linked against")},
7585     {"init_country_codes", (PyCFunction)silk_init_country_codes,
7586      METH_VARARGS,
7587      ("Initialize the country codes from the given file (can be left blank)")},
7588     {"_raw_rwrec_copy", (PyCFunction)silk_raw_rwrec_copy,
7589      METH_O,
7590      ("Create a RawRWRec from a C rwrec PyCObject, copying the value")},
7591     {NULL, NULL, 0, NULL}       /* Sentinel */
7592 };
7593 
7594 static PyObject *
silk_class_info(void)7595 silk_class_info(
7596     void)
7597 {
7598     CHECK_SITE(NULL);
7599 
7600     Py_INCREF(GLOBALS->classes);
7601     return GLOBALS->classes;
7602 }
7603 
7604 static PyObject *
silk_flowtype_info(void)7605 silk_flowtype_info(
7606     void)
7607 {
7608     CHECK_SITE(NULL);
7609 
7610     Py_INCREF(GLOBALS->flowtypes);
7611     return GLOBALS->flowtypes;
7612 }
7613 
7614 static PyObject *
silk_get_rootdir(void)7615 silk_get_rootdir(
7616     void)
7617 {
7618     char rootdir[PATH_MAX];
7619 
7620     sksiteGetRootDir(rootdir, sizeof(rootdir));
7621     return PyUnicode_InternFromString(rootdir);
7622 }
7623 
7624 static PyObject *
silk_get_siteconf(void)7625 silk_get_siteconf(
7626     void)
7627 {
7628     char siteconf[PATH_MAX];
7629 
7630     sksiteGetConfigPath(siteconf, sizeof(siteconf));
7631     return PyUnicode_InternFromString(siteconf);
7632 }
7633 
7634 static PyObject *
silk_have_site_config(void)7635 silk_have_site_config(
7636     void)
7637 {
7638     Py_INCREF(GLOBALS->havesite);
7639     return GLOBALS->havesite;
7640 }
7641 
7642 static PyObject *
silk_init_country_codes(PyObject UNUSED (* self),PyObject * args)7643 silk_init_country_codes(
7644     PyObject    UNUSED(*self),
7645     PyObject           *args)
7646 {
7647     int   rv;
7648     char *filename = NULL;
7649 
7650     rv = PyArg_ParseTuple(args, "|et",
7651                           Py_FileSystemDefaultEncoding, &filename);
7652     if (!rv) {
7653         return NULL;
7654     }
7655 
7656     skCountryTeardown();
7657     rv = skCountrySetup(filename, error_printf);
7658     PyMem_Free(filename);
7659     if (rv != 0) {
7660         PyErr_SetString(PyExc_RuntimeError, error_buffer);
7661         return NULL;
7662     }
7663 
7664     Py_RETURN_NONE;
7665 }
7666 
7667 static int
silk_init_set_envvar(const char * value,const char * envvar)7668 silk_init_set_envvar(
7669     const char         *value,
7670     const char         *envvar)
7671 {
7672     static char env_buf[101 + PATH_MAX];
7673     PyObject *os;
7674     int rv;
7675 
7676     if (value == NULL) {
7677         return 0;
7678     }
7679 
7680     /* setenv() does not exist on Solaris 9, so we use putenv()
7681      * instead */
7682     rv = snprintf(env_buf, sizeof(env_buf),
7683                   "%s=%s", envvar, value);
7684     if (rv >= (int)sizeof(env_buf) || putenv(env_buf) != 0) {
7685         PyErr_SetString(PyExc_RuntimeError,
7686                         ("Could not set " SILK_CONFIG_FILE_ENVAR));
7687         return -1;
7688     }
7689 
7690     /* Attempt to add the environment variable to Python's
7691      * environment list as well */
7692     os = PyImport_ImportModule("os");
7693     if (os != NULL) {
7694         PyObject *env = PyObject_GetAttrString(os, "environ");
7695         if (env != NULL) {
7696             PyObject *s = PyUnicode_Decode(value,
7697                                            strlen(value),
7698                                            Py_FileSystemDefaultEncoding,
7699                                            "strict");
7700             if (s != NULL) {
7701                 PyMapping_SetItemString(env, (char*)envvar, s);
7702                 Py_DECREF(s);
7703             }
7704             Py_DECREF(env);
7705         }
7706         Py_DECREF(os);
7707     }
7708 
7709     return 0;
7710 }
7711 
7712 static PyObject *
silk_init_site(PyObject UNUSED (* self),PyObject * args,PyObject * kwds)7713 silk_init_site(
7714     PyObject    UNUSED(*self),
7715     PyObject           *args,
7716     PyObject           *kwds)
7717 {
7718     static char *kwlist[] = {"siteconf", "rootdir", NULL};
7719     char *siteconf = NULL;
7720     char *rootdir  = NULL;
7721     int   rv;
7722 
7723     rv = PyArg_ParseTupleAndKeywords(args, kwds, "|etet", kwlist,
7724                                      Py_FileSystemDefaultEncoding, &siteconf,
7725                                      Py_FileSystemDefaultEncoding, &rootdir);
7726     if (!rv) {
7727         goto error;
7728     }
7729 
7730     if (GLOBALS->site_configured) {
7731         PyErr_SetString(PyExc_RuntimeError, "Site already initialized");
7732         goto error;
7733     }
7734 
7735     if (siteconf) {
7736         ASSERT_RESULT(sksiteSetConfigPath(siteconf), int, 0);
7737     }
7738 
7739     if (rootdir) {
7740         if (!skDirExists(rootdir)) {
7741             PyErr_Format(PyExc_IOError,
7742                          "The directory %s does not exist", rootdir);
7743             goto error;
7744         }
7745         rv = sksiteSetRootDir(rootdir);
7746         if (rv != 0) {
7747             PyErr_SetString(PyExc_ValueError, "Illegal root directory");
7748             goto error;
7749         }
7750     }
7751 
7752     if (init_site(siteconf) != 0) {
7753         goto error;
7754     }
7755 
7756     /* These are needed for subprocess calls to silk */
7757     if (silk_init_set_envvar(siteconf, SILK_CONFIG_FILE_ENVAR)) {
7758         goto error;
7759     }
7760     if (silk_init_set_envvar(rootdir, SILK_DATA_ROOTDIR_ENVAR)) {
7761         goto error;
7762     }
7763 
7764     Py_INCREF(GLOBALS->havesite);
7765     return GLOBALS->havesite;
7766 
7767   error:
7768     PyMem_Free(siteconf);
7769     PyMem_Free(rootdir);
7770 
7771     return NULL;
7772 }
7773 
7774 static PyObject *
silk_initial_tcpflags_enabled(void)7775 silk_initial_tcpflags_enabled(
7776     void)
7777 {
7778     Py_RETURN_TRUE;
7779 }
7780 
7781 static PyObject *
silk_ipset_supports_ipv6(void)7782 silk_ipset_supports_ipv6(
7783     void)
7784 {
7785 #if SK_ENABLE_IPV6
7786     Py_RETURN_TRUE;
7787 #else
7788     Py_RETURN_FALSE;
7789 #endif
7790 }
7791 
7792 static PyObject *
silk_ipv6_enabled(void)7793 silk_ipv6_enabled(
7794     void)
7795 {
7796 #if SK_ENABLE_IPV6
7797     Py_RETURN_TRUE;
7798 #else
7799     Py_RETURN_FALSE;
7800 #endif
7801 }
7802 
7803 static PyObject *
silk_get_timezone_support(void)7804 silk_get_timezone_support(
7805     void)
7806 {
7807 #if SK_ENABLE_LOCALTIME
7808     return STRING_FROM_STRING("local");
7809 #else
7810     return STRING_FROM_STRING("UTC");
7811 #endif
7812 }
7813 
7814 static PyObject *
silk_get_compression_methods(void)7815 silk_get_compression_methods(
7816     void)
7817 {
7818     const char *compmethods[] = {
7819         "NO_COMPRESSION",
7820 #if SK_ENABLE_ZLIB
7821         "ZLIB",
7822 #endif
7823 #if SK_ENABLE_LZO
7824         "LZO1X",
7825 #endif
7826 #if SK_ENABLE_SNAPPY
7827         "SNAPPY",
7828 #endif
7829         NULL
7830     };
7831     PyObject *list;
7832     PyObject *val;
7833     size_t i;
7834     int rv;
7835 
7836     list = PyList_New(0);
7837     if (NULL == list) {
7838         return NULL;
7839     }
7840 
7841     for (i = 0; compmethods[i] != NULL; ++i) {
7842         val = STRING_FROM_STRING(compmethods[i]);
7843         if (NULL == val) {
7844             goto ERROR;
7845         }
7846         rv = PyList_Append(list, val);
7847         Py_DECREF(val);
7848         if (rv != 0) {
7849             goto ERROR;
7850         }
7851     }
7852 
7853     return list;
7854 
7855   ERROR:
7856     Py_DECREF(list);
7857     return NULL;
7858 }
7859 
7860 static silkPyRawRWRec *
silk_raw_rwrec_copy(PyObject UNUSED (* self),PyObject * c_rec)7861 silk_raw_rwrec_copy(
7862     PyObject    UNUSED(*self),
7863     PyObject           *c_rec)
7864 {
7865     silkPyRawRWRec *pyrec;
7866     rwRec       *rec;
7867 
7868     if (!COBJ_CHECK(c_rec)) {
7869         PyErr_SetString(PyExc_TypeError, "Illegal argument type");
7870         return NULL;
7871     }
7872 
7873     pyrec = (silkPyRawRWRec*)silkPyRawRWRecType.tp_alloc(
7874         &silkPyRawRWRecType, 0);
7875     if (pyrec != NULL) {
7876         rec = (rwRec*)COBJ_PTR(c_rec);
7877         if (rec != NULL) {
7878             RWREC_COPY(&pyrec->rec, rec);
7879         }
7880     }
7881 
7882     return pyrec;
7883 }
7884 
7885 static PyObject *
silk_sensor_info(void)7886 silk_sensor_info(
7887     void)
7888 {
7889     CHECK_SITE(NULL);
7890 
7891     Py_INCREF(GLOBALS->sensors);
7892     return GLOBALS->sensors;
7893 }
7894 
7895 static PyObject *
silk_set_rootdir(PyObject UNUSED (* self),PyObject * args)7896 silk_set_rootdir(
7897     PyObject    UNUSED(*self),
7898     PyObject           *args)
7899 {
7900     int   rv;
7901     char *rootdir = NULL;
7902 
7903     CHECK_SITE(NULL);
7904 
7905     rv = PyArg_ParseTuple(args, "|et",
7906                           Py_FileSystemDefaultEncoding, &rootdir);
7907     if (!rv) {
7908         return NULL;
7909     }
7910     if (!skDirExists(rootdir)) {
7911         PyErr_Format(PyExc_IOError,
7912                      "The directory %s does not exist", rootdir);
7913         PyMem_Free(rootdir);
7914         return NULL;
7915     }
7916     rv = sksiteSetRootDir(rootdir);
7917     PyMem_Free(rootdir);
7918     if (rv != 0) {
7919         PyErr_SetString(PyExc_ValueError, "Illegal root directory");
7920         return NULL;
7921     }
7922 
7923     Py_RETURN_NONE;
7924 }
7925 
7926 static PyObject *
silk_version(void)7927 silk_version(
7928     void)
7929 {
7930     return PyUnicode_InternFromString(SK_PACKAGE_VERSION);
7931 }
7932 
7933 
7934 /*
7935  *************************************************************************
7936  *   SUPPORT FUNCTIONS
7937  *************************************************************************
7938  */
7939 
7940 static PyObject *
any_obj_error(PyObject * exc,const char * format,PyObject * obj)7941 any_obj_error(
7942     PyObject           *exc,
7943     const char         *format,
7944     PyObject           *obj)
7945 {
7946     PyObject *pformat = PyUnicode_FromString(format);
7947     PyObject *msg = PyUnicode_Format(pformat, obj);
7948     PyErr_SetObject(exc, msg);
7949     Py_DECREF(pformat);
7950     Py_DECREF(msg);
7951     return NULL;
7952 }
7953 
7954 #ifndef TEST_PRINTF_FORMATS
7955 static int
error_printf(const char * fmt,...)7956 error_printf(
7957     const char         *fmt,
7958     ...)
7959 {
7960     int rv;
7961 
7962     va_list args;
7963     va_start(args, fmt);
7964     rv = vsnprintf(error_buffer, sizeof(error_buffer), fmt, args);
7965     error_buffer[sizeof(error_buffer) - 1] = '\0';
7966     va_end(args);
7967 
7968     return rv;
7969 }
7970 #endif  /* TEST_PRINTF_FORMATS */
7971 
7972 
7973 static int
init_classes(void)7974 init_classes(
7975     void)
7976 {
7977     sk_class_iter_t iter;
7978     sk_class_id_t   class_id;
7979     char            name[SK_MAX_STRLEN_FLOWTYPE+1];
7980     PyObject       *list;
7981     PyObject       *dict;
7982     PyObject       *classes;
7983     PyObject       *val;
7984     PyObject       *class_data;
7985     int             rv;
7986 
7987     classes = PyDict_New();
7988     if (classes == NULL) {
7989         goto error;
7990     }
7991     class_id = sksiteClassGetDefault();
7992     if (class_id == SK_INVALID_CLASS) {
7993         val = Py_None;
7994         Py_INCREF(val);
7995     } else {
7996         val = PyInt_FromLong(sksiteClassGetDefault());
7997         if (val == NULL) {
7998             goto error;
7999         }
8000     }
8001     rv = PyDict_SetItemString(classes, "default", val);
8002     Py_DECREF(val);
8003     if (rv != 0) {
8004         goto error;
8005     }
8006 
8007     class_data = PyDict_New();
8008     if (class_data == NULL) {
8009         goto error;
8010     }
8011     rv = PyDict_SetItemString(classes, "data", class_data);
8012     Py_DECREF(class_data);
8013     if (rv != 0) {
8014         goto error;
8015     }
8016 
8017     sksiteClassIterator(&iter);
8018     while (sksiteClassIteratorNext(&iter, &class_id)) {
8019         sk_sensor_iter_t    sensor_iter;
8020         sk_sensor_id_t      sensor;
8021         sk_flowtype_iter_t  flowtype_iter;
8022         sk_flowtype_id_t    flowtype;
8023 
8024         dict = PyDict_New();
8025         if (dict == NULL) {
8026             goto error;
8027         }
8028         val = PyInt_FromLong(class_id);
8029         if (val == NULL) {
8030             Py_DECREF(dict);
8031             goto error;
8032         }
8033         rv = PyDict_SetItem(class_data, val, dict);
8034         Py_DECREF(dict);
8035         if (rv != 0) {
8036             Py_DECREF(val);
8037             goto error;
8038         }
8039         rv = PyDict_SetItemString(dict, "id", val);
8040         Py_DECREF(val);
8041         if (rv != 0) {
8042             goto error;
8043         }
8044 
8045         sksiteClassGetName(name, sizeof(name), class_id);
8046         val = PyUnicode_InternFromString(name);
8047         if (val == NULL) {
8048             goto error;
8049         }
8050         rv = PyDict_SetItemString(dict, "name", val);
8051         Py_DECREF(val);
8052         if (rv != 0) {
8053             goto error;
8054         }
8055 
8056         list = PyList_New(0);
8057         if (list == NULL) {
8058             goto error;
8059         }
8060         rv = PyDict_SetItemString(dict, "sensors", list);
8061         Py_DECREF(list);
8062         if (rv != 0) {
8063             goto error;
8064         }
8065         sksiteClassSensorIterator(class_id, &sensor_iter);
8066         while (sksiteSensorIteratorNext(&sensor_iter, &sensor)) {
8067             val = PyInt_FromLong(sensor);
8068             if (val == NULL) {
8069                 goto error;
8070             }
8071             rv = PyList_Append(list, val);
8072             Py_DECREF(val);
8073             if (rv != 0) {
8074                 goto error;
8075             }
8076         }
8077 
8078         list = PyList_New(0);
8079         if (list == NULL) {
8080             goto error;
8081         }
8082         rv = PyDict_SetItemString(dict, "flowtypes", list);
8083         Py_DECREF(list);
8084         if (rv != 0) {
8085             goto error;
8086         }
8087         sksiteClassFlowtypeIterator(class_id, &flowtype_iter);
8088         while (sksiteFlowtypeIteratorNext(&flowtype_iter, &flowtype)) {
8089             val = PyInt_FromLong(flowtype);
8090             if (val == NULL) {
8091                 goto error;
8092             }
8093             rv = PyList_Append(list, val);
8094             Py_DECREF(val);
8095             if (rv != 0) {
8096                 goto error;
8097             }
8098         }
8099 
8100         list = PyList_New(0);
8101         if (list == NULL) {
8102             goto error;
8103         }
8104         rv = PyDict_SetItemString(dict, "default_flowtypes", list);
8105         Py_DECREF(list);
8106         if (rv != 0) {
8107             goto error;
8108         }
8109         sksiteClassDefaultFlowtypeIterator(class_id, &flowtype_iter);
8110         while (sksiteFlowtypeIteratorNext(&flowtype_iter, &flowtype)) {
8111             val = PyInt_FromLong(flowtype);
8112             if (val == NULL) {
8113                 goto error;
8114             }
8115             rv = PyList_Append(list, val);
8116             Py_DECREF(val);
8117             if (rv != 0) {
8118                 goto error;
8119             }
8120         }
8121     }
8122 
8123     GLOBALS->classes = classes;
8124     return 0;
8125 
8126   error:
8127     Py_XDECREF(classes);
8128 
8129     return -1;
8130 }
8131 
8132 static int
init_flowtypes(void)8133 init_flowtypes(
8134     void)
8135 {
8136     sk_flowtype_iter_t   flowtype_iter;
8137     sk_flowtype_id_t     flowtype;
8138     char                 name[SK_MAX_STRLEN_SENSOR+1];
8139     PyObject            *dict;
8140     PyObject            *flowtypes;
8141     int                  rv;
8142 
8143     flowtypes = PyDict_New();
8144     if (flowtypes == NULL) {
8145         goto error;
8146     }
8147 
8148     sksiteFlowtypeIterator(&flowtype_iter);
8149     while (sksiteFlowtypeIteratorNext(&flowtype_iter, &flowtype)) {
8150         sk_class_id_t class_id;
8151         PyObject     *val;
8152 
8153         dict = PyDict_New();
8154         if (dict == NULL) {
8155             goto error;
8156         }
8157         val = PyInt_FromLong(flowtype);
8158         if (val == NULL) {
8159             Py_DECREF(dict);
8160             goto error;
8161         }
8162         rv = PyDict_SetItem(flowtypes, val, dict);
8163         Py_DECREF(dict);
8164         if (rv != 0) {
8165             Py_DECREF(val);
8166             goto error;
8167         }
8168         rv = PyDict_SetItemString(dict, "id", val);
8169         Py_DECREF(val);
8170         if (rv != 0) {
8171             goto error;
8172         }
8173 
8174         sksiteFlowtypeGetName(name, sizeof(name), flowtype);
8175         val = PyUnicode_InternFromString(name);
8176         if (val == NULL) {
8177             goto error;
8178         }
8179         rv = PyDict_SetItemString(dict, "name", val);
8180         Py_DECREF(val);
8181         if (rv != 0) {
8182             goto error;
8183         }
8184 
8185         sksiteFlowtypeGetType(name, sizeof(name), flowtype);
8186         val = PyUnicode_InternFromString(name);
8187         if (val == NULL) {
8188             goto error;
8189         }
8190         rv = PyDict_SetItemString(dict, "type", val);
8191         Py_DECREF(val);
8192         if (rv != 0) {
8193             goto error;
8194         }
8195 
8196         class_id = sksiteFlowtypeGetClassID(flowtype);
8197         val = PyInt_FromLong(class_id);
8198         if (val == NULL) {
8199             goto error;
8200         }
8201         rv = PyDict_SetItemString(dict, "class", val);
8202         Py_DECREF(val);
8203         if (rv != 0) {
8204             goto error;
8205         }
8206     }
8207 
8208     GLOBALS->flowtypes = flowtypes;
8209     return 0;
8210 
8211   error:
8212     Py_XDECREF(flowtypes);
8213 
8214     return -1;
8215 }
8216 
8217 static int
init_sensors(void)8218 init_sensors(
8219     void)
8220 {
8221     sk_sensor_iter_t   sensor_iter;
8222     sk_sensor_id_t     sensor;
8223     char               name[SK_MAX_STRLEN_SENSOR+1];
8224     PyObject          *list;
8225     PyObject          *dict;
8226     PyObject          *sensors;
8227     int                rv;
8228 
8229     sensors = PyDict_New();
8230     if (sensors == NULL) {
8231         goto error;
8232     }
8233 
8234     sksiteSensorIterator(&sensor_iter);
8235     while (sksiteSensorIteratorNext(&sensor_iter, &sensor)) {
8236         sk_class_iter_t   class_iter;
8237         sk_class_id_t     class_id;
8238         PyObject         *val;
8239         const char       *desc;
8240 
8241         dict = PyDict_New();
8242         if (dict == NULL) {
8243             goto error;
8244         }
8245         val = PyInt_FromLong(sensor);
8246         if (val == NULL) {
8247             Py_DECREF(dict);
8248             goto error;
8249         }
8250         rv = PyDict_SetItem(sensors, val, dict);
8251         Py_DECREF(dict);
8252         if (rv != 0) {
8253             Py_DECREF(val);
8254             goto error;
8255         }
8256         rv = PyDict_SetItemString(dict, "id", val);
8257         Py_DECREF(val);
8258         if (rv != 0) {
8259             goto error;
8260         }
8261 
8262         sksiteSensorGetName(name, sizeof(name), sensor);
8263         val = PyUnicode_InternFromString(name);
8264         if (val == NULL) {
8265             goto error;
8266         }
8267         rv = PyDict_SetItemString(dict, "name", val);
8268         Py_DECREF(val);
8269         if (rv != 0) {
8270             goto error;
8271         }
8272 
8273         desc = sksiteSensorGetDescription(sensor);
8274         if (desc) {
8275             val = PyUnicode_FromString(desc);
8276             if (val == NULL) {
8277                 goto error;
8278             }
8279             rv = PyDict_SetItemString(dict, "description", val);
8280             Py_DECREF(val);
8281             if (rv != 0) {
8282                 goto error;
8283             }
8284         }
8285 
8286         list = PyList_New(0);
8287         if (list == NULL) {
8288             goto error;
8289         }
8290         rv = PyDict_SetItemString(dict, "classes", list);
8291         Py_DECREF(list);
8292         if (rv != 0) {
8293             goto error;
8294         }
8295         sksiteSensorClassIterator(sensor, &class_iter);
8296         while (sksiteClassIteratorNext(&class_iter, &class_id)) {
8297             val = PyInt_FromLong(class_id);
8298             if (val == NULL) {
8299                 goto error;
8300             }
8301             rv = PyList_Append(list, val);
8302             Py_DECREF(val);
8303             if (rv != 0) {
8304                 goto error;
8305             }
8306         }
8307     }
8308 
8309     GLOBALS->sensors = sensors;
8310     return 0;
8311 
8312   error:
8313     Py_XDECREF(sensors);
8314 
8315     return -1;
8316 }
8317 
8318 static int
init_silkfile_module(PyObject * mod)8319 init_silkfile_module(
8320     PyObject           *mod)
8321 {
8322     int rv;
8323 
8324     PyModule_AddIntConstant(mod, "IGNORE", SK_IPV6POLICY_IGNORE);
8325     PyModule_AddIntConstant(mod, "ASV4", SK_IPV6POLICY_ASV4);
8326     PyModule_AddIntConstant(mod, "MIX", SK_IPV6POLICY_MIX);
8327     PyModule_AddIntConstant(mod, "FORCE", SK_IPV6POLICY_FORCE);
8328     PyModule_AddIntConstant(mod, "ONLY", SK_IPV6POLICY_ONLY);
8329 
8330     PyModule_AddIntConstant(mod, "READ", SK_IO_READ);
8331     PyModule_AddIntConstant(mod, "WRITE", SK_IO_WRITE);
8332     PyModule_AddIntConstant(mod, "APPEND", SK_IO_APPEND);
8333 
8334     PyModule_AddIntConstant(mod, "DEFAULT", NOT_SET);
8335     PyModule_AddIntConstant(mod, "NO_COMPRESSION", SK_COMPMETHOD_NONE);
8336     PyModule_AddIntConstant(mod, "ZLIB", SK_COMPMETHOD_ZLIB);
8337     PyModule_AddIntConstant(mod, "LZO1X", SK_COMPMETHOD_LZO1X);
8338     PyModule_AddIntConstant(mod, "SNAPPY", SK_COMPMETHOD_SNAPPY);
8339 
8340     PyModule_AddObject(mod, "BAG_COUNTER_MAX",
8341                        PyLong_FromUnsignedLongLong(SKBAG_COUNTER_MAX));
8342 
8343     silkPySilkFileType.tp_new = PyType_GenericNew;
8344     if (PyType_Ready(&silkPySilkFileType) < 0) {
8345         return -1;
8346     }
8347     rv = PyModule_AddObject(mod, "SilkFileBase",
8348                             (PyObject*)&silkPySilkFileType);
8349     if (rv != 0) {
8350         return -1;
8351     }
8352 
8353     return 0;
8354 }
8355 
8356 static int
init_site(const char * site_file)8357 init_site(
8358     const char         *site_file)
8359 {
8360     int rv;
8361     int siterv;
8362     int retval = 0;
8363 
8364     if (GLOBALS->site_configured) {
8365         return 0;
8366     }
8367 
8368     siterv = sksiteConfigure(0);
8369     if (siterv == 0) {
8370         GLOBALS->havesite = Py_True;
8371     } else if (siterv == -2) {
8372         GLOBALS->havesite = Py_False;
8373         if (site_file) {
8374             Py_INCREF(GLOBALS->havesite);
8375             PyErr_Format(PyExc_IOError,
8376                          "could not read site file %s", site_file);
8377             retval = -1;
8378         }
8379     } else {
8380         GLOBALS->havesite = Py_False;
8381         PyErr_SetString(PyExc_RuntimeError,
8382                         "error parsing site configuration file");
8383         retval = -1;
8384     }
8385     Py_INCREF(GLOBALS->havesite);
8386     rv = PyModule_AddObject(GLOBALS->silkmod, "_havesite", GLOBALS->havesite);
8387     if (rv != 0) {
8388         return -1;
8389     }
8390 
8391     rv = init_sensors();
8392     if (rv != 0) {
8393         return -1;
8394     }
8395     rv = PyModule_AddObject(GLOBALS->silkmod, "_sensors", GLOBALS->sensors);
8396     if (rv != 0) {
8397         return -1;
8398     }
8399 
8400     rv = init_classes();
8401     if (rv != 0) {
8402         return -1;
8403     }
8404     rv = PyModule_AddObject(GLOBALS->silkmod, "_classes", GLOBALS->classes);
8405     if (rv != 0) {
8406         return -1;
8407     }
8408 
8409     rv = init_flowtypes();
8410     if (rv != 0) {
8411         return -1;
8412     }
8413     rv = PyModule_AddObject(GLOBALS->silkmod, "_flowtypes",
8414                             GLOBALS->flowtypes);
8415     if (rv != 0) {
8416         return -1;
8417     }
8418 
8419     if (siterv == 0) {
8420         GLOBALS->site_configured = 1;
8421     }
8422 
8423     return retval;
8424 }
8425 
8426 static PyObject *
iter_iter(PyObject * self)8427 iter_iter(
8428     PyObject           *self)
8429 {
8430     Py_INCREF(self);
8431     return self;
8432 }
8433 
8434 static void
obj_dealloc(PyObject * obj)8435 obj_dealloc(
8436     PyObject           *obj)
8437 {
8438     Py_TYPE(obj)->tp_free(obj);
8439 }
8440 
8441 static PyObject *
obj_error(const char * format,PyObject * obj)8442 obj_error(
8443     const char         *format,
8444     PyObject           *obj)
8445 {
8446     return any_obj_error(PyExc_ValueError, format, obj);
8447 }
8448 
8449 static skstream_t *
open_silkfile_write(PyObject * args,PyObject * kwds)8450 open_silkfile_write(
8451     PyObject           *args,
8452     PyObject           *kwds)
8453 {
8454     static char *kwlist[] = {"filename", "compression", NULL};
8455 
8456     PyObject *name;
8457     PyObject *bytes;
8458     char errbuf[2 * PATH_MAX];
8459     skstream_t *stream = NULL;
8460     int compr = NOT_SET;
8461     const char *fname;
8462     sk_file_header_t *hdr;
8463     int rv;
8464 
8465     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i", kwlist,
8466                                      &name, &compr))
8467     {
8468         return NULL;
8469     }
8470 
8471     if (!IS_STRING(name)) {
8472         PyErr_SetString(PyExc_TypeError, "Filename required");
8473         return NULL;
8474     }
8475 #if PY_MAJOR_VERSION < 3
8476     if (PyBytes_Check(name)) {
8477         bytes = name;
8478         Py_INCREF(bytes);
8479     } else
8480 #endif
8481     {
8482         bytes = PyUnicode_AsEncodedString(name, Py_FileSystemDefaultEncoding,
8483                                           "strict");
8484         if (bytes == NULL) {
8485             return NULL;
8486         }
8487     }
8488 
8489     fname = PyBytes_AS_STRING(bytes);
8490     if ((rv = skStreamCreate(&stream, SK_IO_WRITE, SK_CONTENT_SILK))
8491         || (rv = skStreamBind(stream, fname))
8492         || (rv = skStreamOpen(stream)))
8493     {
8494         skStreamLastErrMessage(stream, rv, errbuf, sizeof(errbuf));
8495         PyErr_Format(PyExc_IOError, "Unable to open %s for writing: %s",
8496                      fname, errbuf);
8497         skStreamDestroy(&stream);
8498         Py_DECREF(bytes);
8499         return NULL;
8500     }
8501 
8502     if (compr != NOT_SET) {
8503         hdr = skStreamGetSilkHeader(stream);
8504         rv = skHeaderSetCompressionMethod(hdr, compr);
8505         if (rv != 0) {
8506             skStreamLastErrMessage(stream, rv, errbuf, sizeof(errbuf));
8507             PyErr_Format(PyExc_IOError,
8508                          "Unable to open set compression on %s: %s",
8509                          fname, errbuf);
8510             skStreamDestroy(&stream);
8511             Py_DECREF(bytes);
8512             return NULL;
8513         }
8514     }
8515 
8516     Py_DECREF(bytes);
8517 
8518     return stream;
8519 }
8520 
8521 static PyObject *
reduce_error(PyObject * obj)8522 reduce_error(
8523     PyObject           *obj)
8524 {
8525     if (Py_TYPE(obj) && Py_TYPE(obj)->tp_name) {
8526         PyErr_Format(PyExc_TypeError, "can't pickle %s objects",
8527                      Py_TYPE(obj)->tp_name);
8528     } else {
8529         PyErr_SetString(PyExc_TypeError, "This object cannot be pickled");
8530     }
8531     return NULL;
8532 }
8533 
8534 static int
silkPyDatetimeToSktime(sktime_t * silktime,PyObject * datetime)8535 silkPyDatetimeToSktime(
8536     sktime_t           *silktime,
8537     PyObject           *datetime)
8538 {
8539     PyObject *delta = NULL;
8540     PyObject *days = NULL;
8541     PyObject *secs = NULL;
8542     PyObject *usecs = NULL;
8543     int64_t millisecs;
8544     int retval = -1;
8545 
8546     if (!PyDateTime_Check(datetime)) {
8547         if (PyDate_Check(datetime)) {
8548             datetime = PyDateTime_FromDateAndTime(
8549                 PyDateTime_GET_YEAR(datetime),
8550                 PyDateTime_GET_MONTH(datetime),
8551                 PyDateTime_GET_DAY(datetime),
8552                 0, 0, 0, 0);
8553             if (datetime == NULL) {
8554                 return -1;
8555             }
8556         } else {
8557             PyErr_SetString(PyExc_TypeError, "Expected a datetime.date");
8558             return -1;
8559         }
8560     } else {
8561         Py_INCREF(datetime);
8562     }
8563     if (PyObject_RichCompareBool(datetime, GLOBALS->epochtime, Py_LT)) {
8564         PyErr_SetString(PyExc_ValueError, "Minimum time is Jan 1, 1970");
8565         Py_DECREF(datetime);
8566         return -1;
8567     }
8568     if (PyObject_RichCompareBool(datetime, GLOBALS->maxtime, Py_GT)) {
8569         PyErr_SetString(PyExc_ValueError,
8570                         "Maximum time is 03:14:07, Jan 19, 2038");
8571         Py_DECREF(datetime);
8572         return -1;
8573     }
8574     delta = PyNumber_Subtract(datetime, GLOBALS->epochtime);
8575     Py_DECREF(datetime);
8576     days = PyObject_GetAttrString(delta, "days");
8577     secs = PyObject_GetAttrString(delta, "seconds");
8578     usecs = PyObject_GetAttrString(delta, "microseconds");
8579     millisecs = (int64_t)PyLong_AsLong(days) * 1000 * 24 * 3600 +
8580                 (int64_t)PyLong_AsLong(secs) * 1000 +
8581                 PyLong_AsLong(usecs) / 1000;
8582     if (!PyErr_Occurred()) {
8583         *silktime = millisecs;
8584         retval = 0;
8585     }
8586     Py_XDECREF(delta);
8587     Py_XDECREF(days);
8588     Py_XDECREF(secs);
8589     Py_XDECREF(usecs);
8590 
8591     return retval;
8592 }
8593 
8594 #if !SK_ENABLE_IPV6
8595 static PyObject *
silkPyNotImplemented(PyObject UNUSED (* self),PyObject UNUSED (* args),PyObject UNUSED (* kwds))8596 silkPyNotImplemented(
8597     PyObject    UNUSED(*self),
8598     PyObject    UNUSED(*args),
8599     PyObject    UNUSED(*kwds))
8600 {
8601     return PyErr_Format(PyExc_NotImplementedError,
8602                         "SiLK was not built with IPv6 support.");
8603 }
8604 #endif  /* !SK_ENABLE_IPV6 */
8605 
8606 
8607 static PyObject *
initpysilkbase(char * name)8608 initpysilkbase(
8609     char*               name)
8610 {
8611 #if PY_MAJOR_VERSION >= 3
8612     /* Module information for Python 3.0 */
8613     static struct PyModuleDef pysilk_module_static = {
8614         PyModuleDef_HEAD_INIT,
8615         NULL,                       /* m_name */
8616         NULL,                       /* m_doc */
8617         sizeof(silkpy_globals_t),   /* m_size */
8618         silk_methods,               /* m_methods */
8619         NULL,                       /* m_reaload (unused) */
8620         NULL,                       /* m_traverse */
8621         NULL,                       /* m_clear */
8622         NULL                        /* m_free */
8623     };
8624 #endif
8625 
8626     PyObject         *silkmod;
8627     PyObject         *tmp;
8628     silkpy_globals_t *globals;
8629 
8630     PyDateTime_IMPORT;
8631 
8632 #if PY_MAJOR_VERSION >= 3
8633     pysilk_module = &pysilk_module_static;
8634     pysilk_module->m_name = name;
8635     silkmod = PyModule_Create(pysilk_module);
8636     if (silkmod == NULL) {
8637         skAppPrintErr("Could not create module silk");
8638         goto err;
8639     }
8640     globals = (silkpy_globals_t*)PyModule_GetState(silkmod);
8641 #else
8642     /* Globals are in the static global variable */
8643     globals = &silkpy_globals_static;
8644     silkmod = Py_InitModule3(name, silk_methods, "SiLK extension module");
8645     if (silkmod == NULL) {
8646         skAppPrintErr("Could not create module silk");
8647         goto err;
8648     }
8649 #endif  /* #else of #if PY_MAJOR_VERSION >= 3 */
8650 
8651     memset(globals, 0, sizeof(*globals));
8652     globals->silkmod = silkmod;
8653     globals->havesite = Py_False;
8654     Py_INCREF(globals->havesite);
8655 
8656     if (init_silkfile_module(silkmod)) {
8657         goto err;
8658     }
8659 
8660     if (silkPyIPAddr_setup(silkmod) != 0) {
8661         goto err;
8662     }
8663 
8664     if (PyType_Ready(&silkPyIPv4AddrType) < 0) {
8665         goto err;
8666     }
8667     ASSERT_RESULT(PyModule_AddObject(silkmod, "IPv4Addr",
8668                                      (PyObject*)&silkPyIPv4AddrType),
8669                   int, 0);
8670 
8671     if (PyType_Ready(&silkPyIPv6AddrType) < 0) {
8672         goto err;
8673     }
8674     ASSERT_RESULT(PyModule_AddObject(silkmod, "IPv6Addr",
8675                                      (PyObject*)&silkPyIPv6AddrType),
8676                   int, 0);
8677 
8678     if (PyType_Ready(&silkPyIPWildcardType) < 0) {
8679         goto err;
8680     }
8681     ASSERT_RESULT(PyModule_AddObject(silkmod, "IPWildcard",
8682                                      (PyObject*)&silkPyIPWildcardType),
8683                   int, 0);
8684 
8685     silkPyIPWildcardIterType.tp_new = PyType_GenericNew;
8686     if (PyType_Ready(&silkPyIPWildcardIterType) < 0) {
8687         goto err;
8688     }
8689     ASSERT_RESULT(PyModule_AddObject(silkmod, "IPWildcardIter",
8690                                      (PyObject*)&silkPyIPWildcardIterType),
8691                   int, 0);
8692 
8693     silkPyIPSetType.tp_new = PyType_GenericNew;
8694     if (PyType_Ready(&silkPyIPSetType) < 0) {
8695         goto err;
8696     }
8697     ASSERT_RESULT(PyModule_AddObject(silkmod, "IPSetBase",
8698                                      (PyObject*)&silkPyIPSetType),
8699                   int, 0);
8700 
8701     silkPyIPSetIterType.tp_new = PyType_GenericNew;
8702     if (PyType_Ready(&silkPyIPSetIterType) < 0) {
8703         goto err;
8704     }
8705     ASSERT_RESULT(PyModule_AddObject(silkmod, "IPSetIter",
8706                                      (PyObject*)&silkPyIPSetIterType),
8707                   int, 0);
8708 
8709     silkPyPmapType.tp_new = PyType_GenericNew;
8710     if (PyType_Ready(&silkPyPmapType) < 0) {
8711         goto err;
8712     }
8713     ASSERT_RESULT(PyModule_AddObject(silkmod, "PMapBase",
8714                                      (PyObject*)&silkPyPmapType),
8715                   int, 0);
8716 
8717     silkPyPmapIterType.tp_new = PyType_GenericNew;
8718     if (PyType_Ready(&silkPyPmapIterType) < 0) {
8719         goto err;
8720     }
8721     ASSERT_RESULT(PyModule_AddObject(silkmod, "PMapBaseIter",
8722                                      (PyObject*)&silkPyPmapIterType),
8723                   int, 0);
8724 
8725     if (silkPyBag_setup(silkmod) != 0) {
8726         goto err;
8727     }
8728 
8729     silkPyBagIterType.tp_new = PyType_GenericNew;
8730     if (PyType_Ready(&silkPyBagIterType) < 0) {
8731         goto err;
8732     }
8733     ASSERT_RESULT(PyModule_AddObject(silkmod, "BagBaseIter",
8734                                      (PyObject*)&silkPyBagIterType),
8735                   int, 0);
8736 
8737     silkPyRepoIterType.tp_new = PyType_GenericNew;
8738     if (PyType_Ready(&silkPyRepoIterType) < 0) {
8739         goto err;
8740     }
8741     ASSERT_RESULT(PyModule_AddObject(silkmod, "RepoIter",
8742                                      (PyObject*)&silkPyRepoIterType),
8743                   int, 0);
8744 
8745     if (silkPyTCPFlags_setup(silkmod)) {
8746         goto err;
8747     }
8748 
8749     if (PyType_Ready(&silkPyRawRWRecType) < 0) {
8750         goto err;
8751     }
8752     ASSERT_RESULT(PyModule_AddObject(silkmod, "RawRWRec",
8753                                      (PyObject*)&silkPyRawRWRecType),
8754                   int, 0);
8755 
8756     silkPyRWRecType.tp_new = PyType_GenericNew;
8757     if (PyType_Ready(&silkPyRWRecType) < 0) {
8758         goto err;
8759     }
8760     ASSERT_RESULT(PyModule_AddObject(silkmod, "RWRecBase",
8761                                      (PyObject*)&silkPyRWRecType),
8762                   int, 0);
8763 
8764     tmp = PyImport_ImportModule("datetime");
8765     if (tmp == NULL) {
8766         skAppPrintErr("Failed to import datetime module");
8767         goto err;
8768     }
8769 
8770     globals->timedelta = PyObject_GetAttrString(tmp, "timedelta");
8771     assert(globals->timedelta != NULL);
8772     ASSERT_RESULT(PyModule_AddObject(silkmod, "_timedelta", globals->timedelta),
8773                   int, 0);
8774 
8775     globals->datetime = PyObject_GetAttrString(tmp, "datetime");
8776     assert(globals->datetime != NULL);
8777     ASSERT_RESULT(PyModule_AddObject(silkmod, "_datetime", globals->datetime),
8778                   int, 0);
8779 
8780     Py_DECREF(tmp);
8781 
8782     globals->maxelapsed = PyObject_CallFunction(globals->timedelta,
8783                                                 "iiik", 0, 0, 0, UINT32_MAX);
8784     assert(globals->maxelapsed != NULL);
8785     ASSERT_RESULT(PyModule_AddObject(silkmod, "_maxelapsed",
8786                                      globals->maxelapsed),
8787                   int, 0);
8788 
8789     globals->minelapsed = PyObject_CallObject(globals->timedelta, NULL);
8790     assert(globals->minelapsed != NULL);
8791     ASSERT_RESULT(PyModule_AddObject(silkmod, "_minelapsed",
8792                                      globals->minelapsed),
8793                   int, 0);
8794 
8795     globals->epochtime = PyObject_CallFunction(globals->datetime, "iii",
8796                                               1970, 1, 1);
8797     assert(globals->epochtime != NULL);
8798     ASSERT_RESULT(PyModule_AddObject(silkmod, "_epochtime",
8799                                      globals->epochtime),
8800                   int, 0);
8801 
8802     globals->maxtime = PyObject_CallFunction(
8803         globals->datetime, "iiiiii", 2038, 1, 19, 3, 14, 7);
8804     assert(globals->maxtime != NULL);
8805     ASSERT_RESULT(PyModule_AddObject(silkmod, "_maxtime",
8806                                      globals->maxtime),
8807                   int, 0);
8808 
8809     globals->thousand = PyFloat_FromDouble(1000.0);
8810     assert(globals->thousand != NULL);
8811     ASSERT_RESULT(PyModule_AddObject(silkmod, "_thousand", globals->thousand),
8812                   int, 0);
8813 
8814     globals->maxintipv4 = PyLong_FromString("0xffffffff", NULL, 0);
8815     assert(globals->maxintipv4 != NULL);
8816     ASSERT_RESULT(PyModule_AddObject(globals->silkmod, "_maxintipv4",
8817                                      globals->maxintipv4),
8818                   int, 0);
8819 
8820 #if SK_ENABLE_IPV6
8821     globals->maxintipv6 =
8822         PyLong_FromString("0xffffffffffffffffffffffffffffffff", NULL, 0);
8823     assert(globals->maxintipv6 != NULL);
8824     ASSERT_RESULT(PyModule_AddObject(silkmod, "_maxintipv6",
8825                                      globals->maxintipv6),
8826                   int, 0);
8827 #endif  /* SK_ENABLE_IPV6 */
8828 
8829     globals->newrawrec = PyObject_CallFunctionObjArgs(
8830         (PyObject *)&silkPyRawRWRecType, NULL);
8831     ASSERT_RESULT(PyModule_AddObject(silkmod, "_newrawrec",
8832                                      globals->newrawrec),
8833                   int, 0);
8834 
8835     return silkmod;
8836 
8837   err:
8838     if (silkmod) {
8839         Py_DECREF(silkmod);
8840     }
8841 #if PY_MAJOR_VERSION >= 3
8842     return NULL;
8843 #else /* PY_MAJOR_VERSION < 3 */
8844     if (PyErr_Occurred()) {
8845         PyErr_Print();
8846     }
8847     exit(EXIT_FAILURE);
8848 #endif  /* PY_MAJOR_VERSION */
8849 }
8850 
8851 PyMODINIT_FUNC
PYSILK_INIT(void)8852 PYSILK_INIT(
8853     void)
8854 {
8855     PyObject *nameobj;
8856 
8857     nameobj = BYTES_FROM_XCHAR(Py_GetProgramName());
8858 
8859     if (nameobj == NULL) {
8860         skAppRegister("PySiLK_program");
8861     } else {
8862         skAppRegister(PyBytes_AS_STRING(nameobj));
8863         Py_DECREF(nameobj);
8864     }
8865     INIT_RETURN(initpysilkbase(STR(PYSILK_NAME)));
8866 }
8867 
8868 PyMODINIT_FUNC
PYSILK_PIN_INIT(void)8869 PYSILK_PIN_INIT(
8870     void)
8871 {
8872     INIT_RETURN(initpysilkbase("silk." STR(PYSILK_PIN_NAME)));
8873 }
8874 
8875 
8876 /*
8877 ** Local Variables:
8878 ** mode:c
8879 ** indent-tabs-mode:nil
8880 ** c-basic-offset:4
8881 ** End:
8882 */
8883