1 /*
2 * ufdbbase.c - URLfilterDB
3 *
4 * ufdbGuard is copyrighted (C) 2005-2020 by URLfilterDB with all rights reserved.
5 *
6 * Parts of ufdbGuard are based on squidGuard.
7 * This module is NOT based on squidGuard.
8 *
9 * RCS $Id: ufdbbase.c,v 1.138 2020/08/29 15:53:49 root Exp root $
10 */
11
12 #undef _FORTIFY_SOURCE
13
14 #define UFDB_MALLOC_DEBUG 0
15
16
17 #include "ufdb.h"
18 #include "ufdblib.h"
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #if UFDB_DPDK_SUPPORT
26 #include "rte_malloc.h"
27 #endif
28 #if HAVE_MEMALIGN
29 #include <malloc.h>
30 #endif
31 #include <ctype.h>
32 #include <signal.h>
33 #include <errno.h>
34 #if HAVE_SYS_SYSCALL_H
35 #include <sys/syscall.h>
36 #endif
37 #include <sys/time.h>
38 #include <sys/types.h>
39
40 #if UFDB_DP_DEV
41 #include "cvmx.h"
42 #include "cvmx-bootmem.h"
43 #include "cvmx-malloc.h"
44 #endif
45
46 #if !UFDB_BARE_METAL_SUPPORT
47 #include <sys/socket.h>
48 #include <sys/stat.h>
49 #include <pwd.h>
50 #endif
51
52 #if HAVE_PCRE_COMPILE
53 #include <pcre.h>
54 #endif
55
56 #if HAVE_PR_SET_TRACER
57 #include <sys/prctl.h>
58 #endif
59
60 #if !defined(UFDB_API_NO_THREADS) && UFDB_PTHREAD_SUPPORT
61 #include <pthread.h>
62 #endif
63
64
65 #if UFDB_DP_DEV
66 #include "dpmalloc.h"
UFDBmallocInit(ufdb_config_t * config)67 void UFDBmallocInit( ufdb_config_t * config )
68 {
69 ufdbMallocInitDPdevelopment();
70 }
71
72 #elif UFDB_BARE_METAL_SUPPORT && __OCTEON__
73
74 #include "dpmalloc.h"
75 UFDB_SHARED static ufdb_malloc_t malloc_wrapper = NULL;
76 UFDB_SHARED static ufdb_free_t free_wrapper = NULL;
77
UFDBmallocInit(ufdb_config_t * config)78 void UFDBmallocInit( ufdb_config_t * config )
79 {
80 if (config->ufdb_alloc == NULL)
81 ufdbLogFatalError( "UFDBmallocInit: ufdb_alloc is NULL" );
82 else
83 malloc_wrapper = config->ufdb_alloc;
84
85 if (config->ufdb_free == NULL)
86 ufdbLogFatalError( "UFDBmallocInit: ufdb_free is NULL" );
87 else
88 free_wrapper = config->ufdb_free;
89
90 if (ufdbGV.debug)
91 ufdbLogMessage( "UFDBmallocInit: wrapper functions malloc %p free %p", malloc_wrapper, free_wrapper );
92 }
93 #endif
94
95
96 #ifdef __cplusplus
97 extern "C" {
98 #endif
99
100 #if HAVE_SETRESUID
101 int setresuid( uid_t ruid, uid_t euid, uid_t suid );
102 int getresuid( uid_t * ruid, uid_t * euid, uid_t * suid );
103 #endif
104
105
106 UFDB_SHARED static unsigned long cpu_mask = 0UL;
107 #define UFDB_MAX_CPUS 64
108
109
110 #if defined(__GLIBC__)
111 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 4) || HAVE_PCRE_COMPILE
112 #define NEED_REGEXEC_MUTEX 0
113 #else
114 #define NEED_REGEXEC_MUTEX 1
115 #endif
116 #else
117 #define NEED_REGEXEC_MUTEX 0
118 #endif
119
120 #if UFDB_REGEX_SUPPORT && NEED_REGEXEC_MUTEX
121 ufdb_mutex ufdb_regexec_mutex = ufdb_mutex_initializer;
122 #endif
123
124 #ifdef UFDB_DEBUG
125 ufdb_mutex ufdb_malloc_mutex = ufdb_mutex_initializer;
126 #endif
127
128
129 #if UFDB_DP_DEV
130 UFDB_SHARED static cvmx_arena_list_t alist = NULL;
131
ufdbMallocInitDPdevelopment(void)132 void ufdbMallocInitDPdevelopment( void )
133 {
134 #define MYMEMSIZE (700 * 1024 * 1024)
135
136 // allocate an arena and assign it to memory allocator
137 void * mm;
138
139 mm = cvmx_bootmem_alloc( MYMEMSIZE, 4096 );
140 if (mm == NULL)
141 {
142 ufdbLogFatalError( "initDP: cvmx_bootmem_alloc failed" );
143 exit( 1 );
144 }
145
146 if (cvmx_add_arena( &alist, mm, MYMEMSIZE ) != 0)
147 {
148 ufdbLogFatalError( "initDP: cvmx_add_arena failed" );
149 exit( 1 );
150 }
151 }
152 #endif
153
154
155 UFDB_GCC_MALLOC_ATTR
ufdbMalloc(size_t elsize)156 void * ufdbMalloc( size_t elsize )
157 {
158 void * p;
159
160 #if UFDB_MALLOC_DEBUG
161 if (ufdbGV.debug)
162 ufdbLogMessage( " ufdbMalloc %'ld", (long) elsize );
163 #endif
164
165 #if UFDB_DPDK_SUPPORT
166 p = rte_malloc( NULL, elsize, 0 );
167 #elif UFDB_DP_DEV
168 p = cvmx_malloc( alist, elsize );
169 #elif UFDB_BARE_METAL_SUPPORT && __OCTEON__
170 p = malloc_wrapper( (uint32_t) elsize );
171 if (ufdbGV.debug)
172 ufdbLogMessage( "ufdbMalloc: malloc_wrapper(%ld) -> %p", (long)elsize, p );
173 #else
174 p = (void *) malloc( elsize );
175 #endif
176 if (p == NULL && elsize > 0)
177 {
178 ufdbGV.memoryAllocationErrors++;
179 ufdbLogFatalError( "cannot allocate %'ld bytes memory", (long) elsize );
180 }
181
182 #if UFDB_MALLOC_DEBUG
183 if (ufdbGV.debug)
184 ufdbLogMessage( " ufdbMalloc %'ld -> 0x%08lx", (long) elsize, (long) p );
185 #endif
186
187 return p;
188 }
189
190
191 #define UFDB_HUGEPAGESIZE (2*1024*1024)
192
ufdbMallocAligned(size_t alignment,size_t elsize)193 void * UFDB_GCC_MALLOC_ATTR ufdbMallocAligned( size_t alignment, size_t elsize )
194 {
195 void * p;
196
197 #if UFDB_MALLOC_DEBUG
198 if (ufdbGV.debug)
199 ufdbLogMessage( " ufdbMallocAligned %'ld, %'ld", alignment, elsize );
200 #endif
201
202 if (alignment < UFDB_HUGEPAGESIZE && (elsize > ((size_t) (UFDB_HUGEPAGESIZE * 0.9))))
203 alignment = UFDB_HUGEPAGESIZE; // the kernel may use a hugepage
204 else if (alignment < 4096 && elsize > 3600)
205 alignment = 4096;
206 else
207 {
208 alignment = (alignment + (UFDB_CACHELINE_SIZE-1)) & ~(UFDB_CACHELINE_SIZE-1);
209 }
210
211 #if UFDB_DPDK_SUPPORT
212 p = rte_malloc( NULL, elsize, (unsigned int) alignment );
213 #elif UFDB_DP_DEV
214 p = cvmx_memalign( alist, alignment, elsize );
215 #elif UFDB_BARE_METAL_SUPPORT && __OCTEON__
216 if (ufdbGV.debug)
217 ufdbLogMessage( "ufdbMallocAligned: going to call malloc_wrapper(%ld) wrapper=%p", (long)elsize, malloc_wrapper );
218 p = malloc_wrapper( (uint32_t) elsize );
219 if (ufdbGV.debug)
220 ufdbLogMessage( "ufdbMallocAligned: malloc_wrapper(%ld) -> %p", (long)elsize, p );
221 #else
222
223 int retval;
224 #if HAVE_POSIX_MEMALIGN
225 p = NULL;
226 retval = posix_memalign( &p, alignment, elsize );
227 #elif HAVE_MEMALIGN
228 retval = 0;
229 p = memalign( alignment, elsize );
230 #elif HAVE_ALIGNED_ALLOC
231 retval = 0;
232 p = aligned_alloc( alignment, elsize );
233 #else
234 retval = 0;
235 p = malloc( elsize );
236 #endif
237
238 #if UFDB_MALLOC_DEBUG
239 if (ufdbGV.debug)
240 ufdbLogMessage( " ufdbMallocAligned(%ld):%d %'ld -> %p",
241 alignment, retval, elsize, p );
242 #endif
243
244 if (retval == 0 && p != NULL)
245 return p;
246
247 p = (void *) ufdbMalloc( elsize );
248 #endif
249
250 if (p == NULL && elsize > 0)
251 {
252 ufdbGV.memoryAllocationErrors++;
253 ufdbLogFatalError( "cannot allocate %'ld bytes %'ld-aligned memory", elsize, alignment );
254 }
255
256 #if UFDB_MALLOC_DEBUG
257 if (ufdbGV.debug)
258 ufdbLogMessage( " ufdbMallocAligned not-aligned %'ld -> %p", elsize, p );
259 #endif
260
261 return p;
262 }
263
264
ufdbCalloc(size_t n,size_t num)265 void * ufdbCalloc( size_t n, size_t num )
266 {
267 void * p;
268
269 #if UFDB_MALLOC_DEBUG
270 if (ufdbGV.debug)
271 ufdbLogMessage( " ufdbCalloc %ld %'ld", (long) n, (long) num );
272 #endif
273
274 p = (void *) ufdbMalloc( n * num );
275 if (p == NULL && n > 0)
276 ufdbLogFatalError( "cannot allocate %ld bytes zeroed memory", (long) (n*num) );
277 else
278 memset( p, 0, n * num );
279
280 #if UFDB_MALLOC_DEBUG
281 if (ufdbGV.debug)
282 ufdbLogMessage( " ufdbCalloc %ld %ld = %'ld -> 0x%08lx",
283 (long) n, (long) num, (long) n*num, (long) p );
284 #endif
285
286 return p;
287 }
288
289
290 // realloc is only used to parse 1.2 tables and in ufdbGenTable and may be problematic on bare metal
291 #if UFDB_DP_DEV || !UFDB_BARE_METAL_SUPPORT
ufdbRealloc(void * ptr,size_t elsize)292 void * ufdbRealloc( void * ptr, size_t elsize )
293 {
294 void * p;
295
296 #if UFDB_MALLOC_DEBUG
297 if (ufdbGV.debug)
298 ufdbLogMessage( " ufdbRealloc 0x%08lx %'ld", (long) ptr, (long) elsize );
299 #endif
300
301 #if UFDB_DPDK_SUPPORT
302 p = rte_realloc( ptr, (unsigned int) elsize, 0 );
303 #elif UFDB_DP_DEV
304 ufdbLogFatalError( "ufdbRealloc: realloc is not implemented on OCTEON" );
305 p = NULL; // cvmx_realloc( alist, ptr, elsize );
306 #elif UFDB_BARE_METAL_SUPPORT && __OCTEON__
307 ufdbLogFatalError( "ufdbRealloc: realloc is not implemented on OCTEON" );
308 p = NULL;
309 #else
310 p = (void *) realloc( ptr, elsize );
311 #endif
312 if (p == NULL && elsize > 0)
313 {
314 ufdbGV.memoryAllocationErrors++;
315 ufdbLogFatalError( "cannot reallocate %'ld bytes memory", (long) elsize );
316 }
317
318 #if UFDB_MALLOC_DEBUG
319 if (ufdbGV.debug)
320 ufdbLogMessage( " ufdbRealloc 0x%08lx %'ld -> %08lx", (long) ptr, (long) elsize, (long) p );
321 #endif
322
323 return p;
324 }
325 #endif
326
327
ufdbFree(void * ptr)328 void ufdbFree( void * ptr )
329 {
330 #if UFDB_MALLOC_DEBUG
331 if (ufdbGV.debug)
332 ufdbLogMessage( " ufdbFree 0x%08lx", (long) ptr );
333 #endif
334
335 if (ptr != NULL)
336 {
337 #if UFDB_DPDK_SUPPORT
338 rte_free( ptr );
339 #elif UFDB_DP_DEV
340 cvmx_free( ptr );
341 #elif UFDB_BARE_METAL_SUPPORT && __OCTEON__
342 if (ufdbGV.debug)
343 ufdbLogMessage( "ufdbFree: going to call free_wrapper(%p)", ptr );
344 free_wrapper( ptr );
345 #else
346 free( ptr );
347 #endif
348
349 #if UFDB_MALLOC_DEBUG
350 if (ufdbGV.debug)
351 ufdbLogMessage( " ufdbFree 0x%08lx freed", (long) ptr );
352 #endif
353 }
354 }
355
356
ufdbZlibMalloc(UFDB_GCC_UNUSED void * opaque,unsigned int items,unsigned int size)357 void * ufdbZlibMalloc( UFDB_GCC_UNUSED void * opaque, unsigned int items, unsigned int size )
358 {
359 #if UFDB_BARE_METAL_SUPPORT && __OCTEON__
360 if (ufdbGV.debug)
361 ufdbLogMessage( "ufdbZlibMalloc: calling ufdbMalloc" );
362 #endif
363 return ufdbMalloc( (size_t) items * size );
364 }
365
366
ufdbZlibFree(UFDB_GCC_UNUSED void * opaque,void * address)367 void ufdbZlibFree( UFDB_GCC_UNUSED void * opaque, void * address )
368 {
369 #if UFDB_BARE_METAL_SUPPORT && __OCTEON__
370 if (ufdbGV.debug)
371 ufdbLogMessage( "ufdbZlibFree: calling ufdbFree" );
372 #endif
373 return ufdbFree( address );
374 }
375
376
ufdbStrdup(const char * s)377 char * ufdbStrdup( const char * s )
378 {
379 int size;
380
381 #if defined(UFDB_DEBUG)
382 ufdbLogMessage( " ufdbStrdup %-60.60s", s );
383 #endif
384
385 size = strlen( s ) + 1;
386 return strcpy( (char *) ufdbMalloc(size), s );
387 }
388
389
ufdbStrStrEnd(const char * s,const char * end)390 int ufdbStrStrEnd( const char * s, const char * end )
391 {
392 int n;
393
394 n = strlen( end );
395 while (s != NULL && *s != '\0')
396 {
397 s = strstr( s, end );
398 if (s != NULL)
399 {
400 if (*(s+n) == '\0')
401 return 1;
402 else
403 s++;
404 }
405 }
406 return 0;
407 }
408
409
UFDBfgets(char * requestBuffer,int bufferSize,FILE * fp)410 char * UFDBfgets(
411 char * requestBuffer,
412 int bufferSize,
413 FILE * fp )
414 {
415 char * b;
416 int ch;
417 int size;
418
419 b = requestBuffer;
420 size = 1;
421
422 while ((ch = getc_unlocked(fp)) != EOF)
423 {
424 *b++ = ch;
425 if (ch == '\n')
426 goto end;
427 if (++size == bufferSize)
428 goto end;
429 }
430
431 if (b == requestBuffer && (feof(fp) || ferror(fp)))
432 return NULL;
433
434 end:
435 *b = '\0';
436 return requestBuffer;
437 }
438
439
UFDBfgetsNoNL(char * s,int size,FILE * stream)440 char * UFDBfgetsNoNL( char * s, int size, FILE * stream )
441 {
442 char * buf;
443 int ch;
444
445 buf = s;
446 while ((ch = getc_unlocked(stream)) != EOF && --size > 0)
447 {
448 if (ch == '\r')
449 continue;
450 if (ch == '\n')
451 break;
452 *buf++ = ch;
453 }
454 *buf = '\0';
455 if (ch == EOF && buf == s)
456 return NULL;
457
458 /* remove trailing spaces */
459 while (buf > s)
460 {
461 if (*(buf-1) == ' ')
462 {
463 buf--;
464 *buf = '\0';
465 }
466 else
467 break;
468 }
469
470 return s;
471 }
472
473
474 #if UFDB_REGEX_SUPPORT
UFDBregcomp(void * preg,const char * regex,int cflags)475 static int UFDBregcomp( void * preg, const char * regex, int cflags )
476 {
477 int retval;
478 #if (HAVE_PCRE_COMPILE || HAVE_PCRE_COMPILE2)
479 int pcre_options;
480 int pcre_error;
481 const char * pcre_errstr;
482 int pcre_erroffset;
483 pcre ** ppreg;
484 pcre * pcre_comp_re;
485 #endif
486
487 #if HAVE_PCRE_COMPILE2
488 pcre_options = PCRE_UTF8;
489 if (cflags & REG_ICASE)
490 pcre_options |= PCRE_CASELESS;
491 pcre_comp_re = pcre_compile2( regex, pcre_options, &pcre_error, &pcre_errstr, &pcre_erroffset, NULL );
492 retval = 0;
493 if (pcre_comp_re == NULL)
494 {
495 if (ufdbGV.debug || ufdbGV.debugRegexp)
496 ufdbLogError( "pcre_compile2: error with regular expression \"%s\": %s", regex, pcre_errstr );
497 retval = pcre_error;
498 }
499 else
500 {
501 ppreg = (pcre**) preg;
502 *ppreg = pcre_comp_re;
503 }
504 #elif HAVE_PCRE_COMPILE
505 pcre_options = PCRE_UTF8;
506 if (cflags & REG_ICASE)
507 pcre_options |= PCRE_CASELESS;
508 pcre_comp_re = pcre_compile( regex, pcre_options, &pcre_errstr, &pcre_errofsset, NULL );
509 retval = 0;
510 if (pcre_comp_re == NULL)
511 {
512 if (ufdbGV.debug || ufdbGV.debugRegexp)
513 ufdbLogError( "pcre_compile: error with regular expression \"%s\": %s", regex, pcre_errstr );
514 retval = REG_ECOLLATE;
515 }
516 else
517 {
518 ppreg = (pcre**) preg;
519 *ppreg = pcre_comp_re;
520 }
521 #else
522 retval = regcomp( (regex_t*) preg, regex, cflags );
523 #endif
524
525 return retval;
526 }
527
528
529 UFDB_GCC_INLINE
UFDBregfree(void * preg)530 static void UFDBregfree( void * preg )
531 {
532 #if HAVE_PCRE_COMPILE2 || HAVE_PCRE_COMPILE
533 pcre_free( (pcre*) preg );
534 #else
535 regfree( (regex_t*) preg );
536 #endif
537 }
538
539
540 /* TO-DO: make a macro for UFDBregexec() */
541 UFDB_GCC_HOT
UFDBregexec(const void * preg,const char * string,size_t nmatch,regmatch_t pmatch[],int eflags)542 int UFDBregexec( const void * preg, const char * string, size_t nmatch, regmatch_t pmatch[], int eflags )
543 {
544 int retval;
545 #if HAVE_PCRE_COMPILE2 || HAVE_PCRE_COMPILE
546 int pcre_ovector[2*3];
547 int pcre_ovecsize;
548 #endif
549
550 #if NEED_REGEXEC_MUTEX
551 ufdb_mutex_lock( &ufdb_regexec_mutex );
552 #endif
553
554 #if (HAVE_PCRE_COMPILE2 || HAVE_PCRE_COMPILE)
555 pcre_ovecsize = nmatch * 3;
556 if (pcre_ovecsize > (int) sizeof(pcre_ovector))
557 pcre_ovecsize = sizeof(pcre_ovector);
558 retval = pcre_exec( (pcre*) preg, NULL, string, strlen(string), 0,
559 PCRE_NO_UTF8_CHECK, pcre_ovector, pcre_ovecsize );
560 if (retval == PCRE_ERROR_NOMATCH)
561 retval = REG_NOMATCH;
562 else if (nmatch > 0)
563 {
564 /* convert pcre ovector to regmatch_t */
565 pmatch[0].rm_so = pcre_ovector[0];
566 pmatch[0].rm_eo = pcre_ovector[1];
567 if (nmatch > 1)
568 {
569 pmatch[1].rm_so = pcre_ovector[2];
570 pmatch[1].rm_eo = pcre_ovector[3];
571 }
572 }
573 #else
574 retval = regexec( (regex_t*) preg, string, nmatch, pmatch, eflags );
575 #endif
576
577 #if NEED_REGEXEC_MUTEX
578 ufdb_mutex_unlock( &ufdb_regexec_mutex );
579 #endif
580
581 return retval;
582 }
583
584
ufdbNewPatternBuffer(char * pattern,int flags)585 struct ufdbRegExp * ufdbNewPatternBuffer(
586 char * pattern,
587 int flags )
588 {
589 struct ufdbRegExp * re;
590 #if !(HAVE_PCRE_COMPILE2 || HAVE_PCRE_COMPILE)
591 int i;
592 #endif
593
594 re = (struct ufdbRegExp *) ufdbMallocAligned( 64, sizeof(struct ufdbRegExp) );
595
596 #if !(HAVE_PCRE_COMPILE2 || HAVE_PCRE_COMPILE) && !defined(UFDB_API_NO_THREADS)
597 re->next_nregex_i = 0;
598 ufdb_mutex_init( &(re->lock) );
599 #endif
600
601 #if HAVE_PCRE_COMPILE2 || HAVE_PCRE_COMPILE
602 re->compiled[0] = NULL;
603 re->error = UFDBregcomp( &(re->compiled[0]), pattern, flags );
604 #else
605 re->compiled[0] = ufdbCalloc( 1, sizeof(regex_t) );
606 re->error = UFDBregcomp( re->compiled[0], pattern, flags );
607 if (!re->error)
608 {
609 for (i = 1; i < UFDB_NREGEX; i++)
610 {
611 re->compiled[i] = ufdbCalloc( 1, sizeof(regex_t) );
612 (void) UFDBregcomp( re->compiled[i], pattern, flags );
613 }
614 }
615 #endif
616 re->pattern = ufdbStrdup( pattern );
617 re->substitute = NULL;
618 re->flags = flags;
619 re->global = 0;
620 re->httpcode = NULL;
621 re->next = NULL;
622
623 return re;
624 }
625
626
627 /*
628 * optimise list of RE1 ... REn into one RE with (RE1)| ... |(REn)
629 */
UFDBoptimizeExprList(char * reSource,struct ufdbRegExp * reList)630 struct ufdbRegExp * UFDBoptimizeExprList(
631 char * reSource,
632 struct ufdbRegExp * reList )
633 {
634 struct ufdbRegExp * re;
635 int n;
636 int totalStrlen;
637
638 n = 0;
639 totalStrlen = 0;
640
641 for (re = reList; re != NULL; re = re->next)
642 {
643 if (re->error == 0)
644 {
645 n++;
646 totalStrlen += strlen( re->pattern );
647 }
648 }
649
650 if (n == 0)
651 {
652 if (ufdbGV.debugRegexp)
653 ufdbLogMessage( " UFDBoptimizeExprList: %s has no REs.", reSource );
654 return NULL;
655 }
656
657 if (ufdbGV.debug || ufdbGV.debugRegexp)
658 ufdbLogMessage( " UFDBoptimizeExprList: %s has %d REs", reSource, n );
659 if (ufdbGV.debugRegexp > 1)
660 {
661 ufdbLogMessage( " UFDBoptimizeExprList: %d REs of %s are not optimised due to expression debugging",
662 n, reSource );
663 return reList;
664 }
665
666 if (n > 1)
667 {
668 char * newpattern;
669
670 newpattern = (char *) ufdbMalloc( totalStrlen + 3*n + 1 );
671 newpattern[0] = '\0';
672 for (re = reList; re != NULL; re = re->next)
673 {
674 if (re->error == 0)
675 {
676 #ifdef UFDB_USE_OPTIM_RE_BRACKETS
677 strcat( newpattern, "(" );
678 strcat( newpattern, re->pattern );
679 if (re->next == NULL)
680 strcat( newpattern, ")" );
681 else
682 strcat( newpattern, ")|" );
683 #else
684 strcat( newpattern, re->pattern );
685 if (re->next != NULL)
686 strcat( newpattern, "|" );
687 #endif
688 }
689 }
690 if (ufdbGV.debug > 2 || ufdbGV.debugRegexp)
691 ufdbLogMessage( "going to optimise complex expression of %d subexpressions and %d characters",
692 n, totalStrlen + 1*(n-1) );
693 if (n > 500)
694 ufdbLogMessage( "WARNING: the expressionlist has %d expressions and may use many resources *****\n"
695 "Note that large numbers of expressions may impact performance considerably",
696 n );
697 re = ufdbNewPatternBuffer( newpattern, reList->flags );
698 if (re->error)
699 {
700 ufdbLogError( "UFDBoptimizeExprList: unable to optimise %d expressions of %s (error %d) *****",
701 n, reSource, re->error );
702 if (n >= 20)
703 ufdbLogMessage( "Since the %d expressions could not be optimised into one expression, "
704 "they will be evaluated one by one which impacts performance *****", n );
705 ufdbFree( newpattern );
706 ufdbFreeRegExprList( re );
707 return reList;
708 }
709
710 ufdbLogMessage( "the %d expressions of %s have been optimised", n, reSource );
711 if (ufdbGV.debugRegexp)
712 ufdbLogMessage( "optimised expression: %s", newpattern );
713
714 ufdbFree( newpattern );
715 ufdbFreeRegExprList( reList );
716 return re;
717 }
718 else if (n == 1)
719 {
720 if (ufdbGV.debugRegexp || ufdbGV.debug)
721 ufdbLogMessage( "the expressions of %s has one RE and does not need optimisation", reSource );
722 }
723
724 return reList;
725 }
726
727
728 /*
729 * initialize an expression list (read them from a file and do the regexp compilation)
730 */
UFDBloadExpressions(struct ufdbRegExp ** exprList,char * file)731 int UFDBloadExpressions(
732 struct ufdbRegExp ** exprList,
733 char * file )
734 {
735 FILE * fin;
736 char * eoln;
737 struct ufdbRegExp * re;
738 struct ufdbRegExp * last;
739 int retCode;
740 char line[1024];
741
742 if (exprList == NULL)
743 return UFDB_API_ERR_NULL;
744 *exprList = NULL;
745
746 if (file == NULL)
747 return UFDB_API_ERR_NULL;
748
749 fin = fopen( file, "r" );
750 if (fin == NULL)
751 return UFDB_API_ERR_NOFILE;
752
753 retCode = UFDB_API_OK;
754 last = NULL;
755 re = NULL;
756
757 while (fgets( line, sizeof(line), fin ) != NULL)
758 {
759 if (line[0] == '#') /* skip comments */
760 continue;
761
762 eoln = strchr( line, '\n' );
763 if (eoln == NULL || eoln == &line[0])
764 continue; /* skip empty lines and lines without a newline */
765 else
766 {
767 if (*(eoln-1) == '\r')
768 eoln--;
769 }
770 *eoln = '\0'; /* get rid of the newline */
771
772 /* URLs are folded to lowercase so we do not use REG_ICASE any more */
773 re = ufdbNewPatternBuffer( line, REG_EXTENDED | REG_NOSUB );
774 if (re->error)
775 {
776 ufdbLogError( "could not compile regular expression from %s (error %d) : \"%s\"",
777 file, re->error, line );
778 retCode = UFDB_API_ERR_EXPR;
779 }
780
781 re->next = last;
782 last = re;
783 }
784
785 if (ufdbGV.expressionOptimisation)
786 {
787 *exprList = UFDBoptimizeExprList( file, re );
788 }
789 else
790 *exprList = re;
791
792 fclose( fin );
793
794 return retCode;
795 }
796
797
798 /*
799 * match a URL with a compiled RE.
800 * return 0 if no match, 1 if there is a match.
801 */
802 UFDB_GCC_HOT
ufdbRegExpMatch(struct ufdbRegExp * regexp,const char * str)803 int ufdbRegExpMatch(
804 struct ufdbRegExp * regexp,
805 const char * str )
806 {
807 struct ufdbRegExp * rp;
808 int error;
809 int i;
810
811 if (ufdbGV.debugRegexp)
812 ufdbLogMessage( " ufdbRegExpMatch \"%s\" %s", str, regexp==NULL ? "no REs" : "RE to test" );
813
814 for (rp = regexp; rp != NULL; rp = rp->next)
815 {
816 if (ufdbGV.debugRegexp)
817 ufdbLogMessage( " ufdbRegExpMatch %s %s error=%d", str, rp->pattern, rp->error );
818 if (rp->error)
819 continue;
820
821 #if !(HAVE_PCRE_COMPILE2 || HAVE_PCRE_COMPILE) && !defined(UFDB_API_NO_THREADS)
822 ufdb_mutex_lock( &(rp->lock) );
823 i = rp->next_nregex_i;
824 rp->next_nregex_i = (i + 1) % UFDB_NREGEX;
825 ufdb_mutex_unlock( &(rp->lock) );
826 #else
827 i = 0;
828 #endif
829
830 #if HAVE_PCRE_COMPILE || HAVE_PCRE_COMPILE2
831 error = UFDBregexec( (pcre*) rp->compiled[i], str, 0, NULL, 0 );
832 #else
833 error = UFDBregexec( (regex_t*) rp->compiled[i], str, 0, NULL, 0 );
834 #endif
835 if (error == 0) /* match */
836 {
837 if (ufdbGV.debugRegexp)
838 ufdbLogMessage( " RE match: %s %s", rp->pattern, str );
839 return UFDB_API_MATCH;
840 }
841 if (error != REG_NOMATCH)
842 {
843 if (ufdbGV.debugRegexp)
844 ufdbLogMessage( " RE error %d: %s %s error=%d", error, rp->pattern, str, error );
845 return UFDB_API_ERR_EXPR;
846 }
847 }
848
849 return 0;
850 }
851
852
ufdbFreeRegExprList(struct ufdbRegExp * re)853 void ufdbFreeRegExprList( struct ufdbRegExp * re )
854 {
855 struct ufdbRegExp * tmp;
856 int i;
857
858 while (re != NULL)
859 {
860 tmp = re->next;
861 if (!re->error)
862 {
863 for (i = 0; i < UFDB_NREGEX; i++)
864 {
865 UFDBregfree( re->compiled[i] );
866 #if !HAVE_PCRE_COMPILE && !HAVE_PCRE_COMPILE2
867 ufdbFree( re->compiled[i] );
868 #endif
869 }
870 }
871 ufdbFree( re->pattern );
872 ufdbFree( re->substitute );
873 ufdbFree( re );
874 re = tmp;
875 }
876 }
877 #endif /* UFDB_REGEX_SUPPORT */
878
879
ufdbResetCPUs(void)880 void ufdbResetCPUs( void )
881 {
882 cpu_mask = 0UL;
883 }
884
885
ufdbAPIstatusString(int api_code)886 const char * ufdbAPIstatusString( int api_code )
887 {
888 switch (api_code)
889 {
890 case UFDB_API_OK: return "OK";
891 case UFDB_API_ERR_NULL: return "ERR_NULL";
892 case UFDB_API_ERR_NOFILE: return "ERR_NOFILE";
893 case UFDB_API_ERR_READ: return "ERR_READ";
894 case UFDB_API_ERR_EXPR: return "ERR_EXPR";
895 case UFDB_API_ERR_RANGE: return "ERR_RANGE";
896 case UFDB_API_ERR_ERRNO: return "ERR_ERRNO";
897 case UFDB_API_ERR_SOCKET: return "ERR_SOCKET";
898 case UFDB_API_ERR_NOMEM: return "ERR_NOMEM";
899 case UFDB_API_REQ_QUEUED: return "REQ_QUEUED";
900 case UFDB_API_ERR_TUNNEL: return "ERR_TUNNEL";
901 case UFDB_API_ERR_INVALID_CERT: return "ERR_INVALID_CERT";
902 case UFDB_API_ERR_IP_ADDRESS: return "ERR_IP_ADDRESS";
903 case UFDB_API_ERR_OLD_TABLE: return "ERR_OLD_TABLE";
904 case UFDB_API_ERR_INVALID_TABLE: return "ERR_INVALID_TABLE";
905 case UFDB_API_ERR_INVALID_KEY: return "ERR_INVALID_KEY";
906 case UFDB_API_ERR_IS_SKYPE: return "ERR_IS_SKYPE";
907 case UFDB_API_ERR_FULL: return "ERR_FULL";
908 case UFDB_API_ERR_UNKNOWN_PROTOCOL: return "ERR_UNKNOWN_PROTOCOL";
909 case UFDB_API_ERR_IS_GTALK: return "ERR_IS_GTALK";
910 case UFDB_API_ERR_IS_YAHOOMSG: return "ERR_IS_YAHOOMSG";
911 case UFDB_API_ERR_IS_AIM: return "ERR_IS_AIM";
912 case UFDB_API_ERR_IS_FBCHAT: return "ERR_IS_FBCHAT";
913 case UFDB_API_ERR_IS_CITRIXONLINE: return "ERR_IS_CITRIXONLINE";
914 case UFDB_API_ERR_IS_ANYDESK: return "ERR_IS_ANYDESK";
915 case UFDB_API_ERR_IS_TEAMVIEWER: return "ERR_IS_TEAMVIEWER";
916 case UFDB_API_ERR_CKSUM_NOT_VALID: return "ERR_CKSUM_NOT_VALID";
917 case UFDB_API_ERR_OUTDATED: return "ERR_OUTDATED";
918 case UFDB_API_ERR_FATAL: return "ERR_FATAL";
919 case UFDB_API_ERR_TLS: return "ERR_TLS";
920 case UFDB_API_BEING_VERIFIED: return "BEING_VERIFIED";
921 case UFDB_API_MODIFIED_FOR_SAFESEARCH: return "MODIFIED_FOR_SAFESEARCH";
922 case -1: return "INTERNAL_ERROR_MINUS_ONE";
923 }
924
925 return "INTERNAL_ERROR_UNKNOWN_CODE";
926 }
927
928
ufdbDBstat2string(int status)929 const char * ufdbDBstat2string( int status )
930 {
931 switch (status)
932 {
933 case UFDB_API_STATUS_DATABASE_OK: return "up to date";
934 case UFDB_API_STATUS_DATABASE_OLD: return "one or more tables are more than 4 days old. Check cron job for ufdbUpdate.";
935 case UFDB_API_STATUS_DATABASE_EXPIRED: return "one or more tables are EXPIRED. Check licenses and cron job for ufdbUpdate.";
936 }
937 return "internal-error";
938 }
939
940
ufdbStatus2string(int status)941 const char * ufdbStatus2string( int status )
942 {
943 switch (status)
944 {
945 case UFDB_API_STATUS_VIRGIN: return "virgin";
946 case UFDB_API_STATUS_STARTED_OK: return "started";
947 case UFDB_API_STATUS_TERMINATED: return "terminated";
948 case UFDB_API_STATUS_RELOADING: return "reloading";
949 case UFDB_API_STATUS_RELOAD_OK: return "reloaded";
950 case UFDB_API_STATUS_FATAL_ERROR: return "error";
951 case UFDB_API_STATUS_ROLLING_LOGFILE: return "rolling-logfile";
952 case UFDB_API_STATUS_UPDATE: return "status-update";
953 case UFDB_API_STATUS_CRASH_REPORT_UPLOADED: return "crash-report-uploaded";
954 case UFDB_API_STATUS_CRASH_REPORT_NOT_UPLOADED: return "upload-crash-reports-off-prohibits-upload";
955 }
956 return "internal-error-unknown-status";
957 }
958
959
960 #ifndef ufdbStrncpy
961
ufdbStrncpy(char * dest,const char * src,size_t n)962 UFDB_GCC_HOT void ufdbStrncpy( char * dest, const char * src, size_t n )
963 {
964 if (memccpy( dest, src, '\0', n ) == NULL)
965 dest[n-1] = '\0';
966 }
967
968 #endif
969
970
971 #ifdef __cplusplus
972 }
973 #endif
974