1 /*
2 * aprsc
3 *
4 * (c) Matti Aarnio, OH2MQK, <oh2mqk@sral.fi>
5 *
6 * This program is licensed under the BSD license, which can be found
7 * in the file LICENSE.
8 *
9 */
10
11 #include "ac-hdrs.h"
12
13 #include <string.h>
14 #include <strings.h>
15 #include <ctype.h>
16 #include <stdint.h>
17 #include <math.h>
18 #ifdef HAVE_ALLOCA_H
19 #include <alloca.h>
20 #endif
21
22 #include "hmalloc.h"
23 #include "hlog.h"
24 #include "worker.h"
25 #include "filter.h"
26 #include "cellmalloc.h"
27 #include "historydb.h"
28 #include "cfgfile.h"
29 #include "config.h"
30 #include "keyhash.h"
31 #include "client_heard.h"
32 #include "version.h"
33 #include "messaging.h"
34
35 //#define FILTER_CLIENT_DEBUGGING
36
37 #ifdef FILTER_CLIENT_DEBUGGING
38 #define FILTER_CLIENT_DEBUG(worker, c, fmt, ...) \
39 do { client_printf(worker, c, fmt, __VA_ARGS__); } while (0)
40 #else
41 #define FILTER_CLIENT_DEBUG(fmt, ...)
42 #endif
43
44
45 // static double rad2deg(double a) { return a * (180.0 * M_1_PI); }
46
47 /*
48 See: http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm
49
50 a/latN/lonW/latS/lonE Area filter
51 b/call1/call2... Budlist filter (*)
52 d/digi1/digi2... USED Digipeater filter (*)
53 e/call1/call1/... Entry station filter (*)
54 f/call/dist Friend Range filter
55 m/dist My Range filter
56 o/obj1/obj2... Object filter (*)
57 p/aa/bb/cc... Prefix filter
58 q/con/ana q Contruct filter
59 r/lat/lon/dist Range filter
60 s/pri/alt/over Symbol filter
61 t/poimntqsu*c Type filter
62 t/poimntqsu*c/call/km Type filter
63 u/unproto1/unproto2/.. Unproto filter (*)
64 g/call/call2/... Message destination filter (*)
65
66 Sample usage frequencies (out of entire APRS-IS):
67
68 23.7 a/ <-- Optimize!
69 9.2 b/ <-- Optimize?
70 1.4 d/
71 0.2 e/
72 2.2 f/
73 20.9 m/ <-- Optimize!
74 0.2 o/
75 14.4 p/ <-- Optimize!
76 0.0 pk
77 0.0 pm
78 0.4 q/
79 19.0 r/ <-- Optimize!
80 0.1 s_
81 1.6 s/
82 6.6 t/
83 0.1 u/
84
85
86 (*) = wild-card supported
87
88 Undocumented at above web-page, but apparent behaviour is:
89
90 - Everything not explicitely stated to be case sensitive is
91 case INSENSITIVE
92
93 - Minus-prefixes on filters behave as is there are two sets of
94 filters:
95
96 - filters without minus-prefixes add on approved set, and all
97 those without are evaluated at first
98 - filters with minus-prefixes are evaluated afterwards to drop
99 selections after the additive filter has been evaluated
100
101
102 - Our current behaviour is: "evaluate everything in entry order,
103 stop at first match", which enables filters like:
104 p/OH2R -p/OH2 p/OH
105 while javAPRSSrvr filter adjunct behaves like the request is:
106 -p/OH2 p/OH
107 that is, OH2R** stations are not passed thru.
108
109 */
110
111
112 /* FIXME: What exactly is the meaning of negation on the pattern ?
113 ** Match as a failure to match, and stop searching ?
114 ** Something filter dependent ?
115 **
116 ** javAPRSSrvr Filter Adjunct manual tells:
117
118 #14 Exclusion filter
119
120 All the above filters also support exclusion. Be prefixing the above filters
121 with a dash the result will be the opposite. Any packet that match the exclusion
122 filter will NOT pass. The exclusion filters will be processed first so if there
123 is a match for an exclusion then the packet is not passed no matter any other
124 filter definitions.
125
126 */
127
128 #define WildCard 0x80 /* it is wild-carded prefix string */
129 #define NegationFlag 0x40 /* */
130 #define LengthMask 0x0F /* only low 4 bits encode length */
131
132 /* values above are chosen for 4 byte alignment.. */
133
134 struct filter_refcallsign_t {
135 char callsign[CALLSIGNLEN_MAX+1]; /* size: 10.. */
136 int8_t reflen; /* length and flags */
137 };
138 struct filter_head_t {
139 struct filter_t *next;
140 const char *text; /* filter text as is */
141 float f_latN, f_lonE;
142 union {
143 float f_latS; /* for A filter */
144 float f_coslat; /* for R filter */
145 }; /* ANONYMOUS UNION */
146 union {
147 float f_lonW; /* for A filter */
148 float f_dist; /* for R filter */
149 }; /* ANONYMOUS UNION */
150 time_t hist_age;
151
152 char type; /* 1 char */
153 int16_t negation; /* boolean flag */
154 union {
155 int16_t numnames; /* used as named, and as cache validity flag */
156 int16_t len1s; /* or len1 of s-filter */
157 }; /* ANONYMOUS UNION */
158 union {
159 int16_t bitflags; /* used as bit-set on T_*** enumerations */
160 int16_t len1; /* or as len2 of s-filter */
161 }; /* ANONYMOUS UNION */
162 union {
163 struct lens_t { int16_t len2s, len2, len3s, len3; } lens; /* of s-filter */
164 /* for cases where there is only one.. */
165 struct filter_refcallsign_t refcallsign;
166 /* hmalloc()ed array, alignment important! */
167 struct filter_refcallsign_t *refcallsigns;
168 }; /* ANONYMOUS UNION */
169 };
170
171 struct filter_t {
172 struct filter_head_t h;
173 #define FILT_TEXTBUFSIZE (512-sizeof(struct filter_head_t))
174 char textbuf[FILT_TEXTBUFSIZE];
175 };
176
177 #define QC_C 0x001 /* Q-filter flag bits */
178 #define QC_X 0x002
179 #define QC_U 0x004
180 #define QC_o 0x008
181 #define QC_O 0x010
182 #define QC_S 0x020
183 #define QC_r 0x040
184 #define QC_R 0x080
185 #define QC_Z 0x100
186 #define QC_I 0x200
187
188 #define QC_AnalyticsI 0x800
189
190 /* For q-filter analytics: entrycall igate filter database */
191 struct filter_entrycall_t {
192 struct filter_entrycall_t *next;
193 time_t expirytime;
194 uint32_t hash;
195 int len;
196 char callsign[CALLSIGNLEN_MAX+1];
197 };
198
199 struct filter_wx_t {
200 struct filter_wx_t *next;
201 time_t expirytime;
202 uint32_t hash;
203 int len;
204 char callsign[CALLSIGNLEN_MAX+1];
205 };
206
207 typedef enum {
208 MatchExact,
209 MatchPrefix,
210 MatchWild
211 } MatchEnum;
212
213 #define FILTER_ENTRYCALL_HASHSIZE 2048 /* Around 500-600 in db, this looks
214 for collision free result.. */
215 rwlock_t filter_entrycall_rwlock;
216 int filter_entrycall_maxage = 60*60; /* 1 hour, default. Validity on
217 lookups: 5 minutes less.. */
218 int filter_entrycall_cellgauge;
219
220 struct filter_entrycall_t *filter_entrycall_hash[FILTER_ENTRYCALL_HASHSIZE];
221
222
223 #define FILTER_WX_HASHSIZE 1024 /* Around 300-400 in db, this looks
224 for collision free result.. */
225 rwlock_t filter_wx_rwlock;
226 int filter_wx_maxage = 60*60; /* 1 hour, default. Validity on
227 lookups: 5 minutes less.. */
228 int filter_wx_cellgauge;
229
230 struct filter_wx_t *filter_wx_hash[FILTER_WX_HASHSIZE];
231
232 rwlock_t filter_cellgauge_rwlock;
233 int filter_cellgauge;
234
235
236 #ifndef _FOR_VALGRIND_
237 cellarena_t *filter_cells;
238 cellarena_t *filter_entrycall_cells;
239 cellarena_t *filter_wx_cells;
240 #endif
241
242 int have_filtered_listeners; /* do we have any filtered listeners, do we need to support them */
243
244 #define HIST_LOOKUP_INTERVAL 10 /* Cache historydb position lookups this much seconds on
245 each filter entry referring to some
246 fixed callsign (f,m,t) */
247
248
filter_lat2rad(float lat)249 float filter_lat2rad(float lat)
250 {
251 return (lat * (M_PI / 180.0));
252 }
253
filter_lon2rad(float lon)254 float filter_lon2rad(float lon)
255 {
256 return (lon * (M_PI / 180.0));
257 }
258
259
filter_init(void)260 void filter_init(void)
261 {
262 rwl_init(&filter_cellgauge_rwlock);
263 #ifndef _FOR_VALGRIND_
264 /* A few hundred... */
265
266 filter_cells = cellinit( "filter",
267 sizeof(struct filter_t),
268 __alignof__(struct filter_t),
269 CELLMALLOC_POLICY_LIFO,
270 512 /* 512 kB at the time,
271 should be enough forever.. */,
272 0 /* minfree */ );
273
274 /* printf("filter: sizeof=%d alignof=%d\n",
275 sizeof(struct filter_t),__alignof__(struct filter_t)); */
276
277 /* Couple thousand */
278
279 filter_entrycall_cells = cellinit( "entrycall",
280 sizeof(struct filter_entrycall_t),
281 __alignof__(struct filter_entrycall_t),
282 CELLMALLOC_POLICY_FIFO,
283 32 /* 32 kB at the time */,
284 0 /* minfree */ );
285
286 /* Under 1 thousand.. */
287
288 filter_wx_cells = cellinit( "wxcalls",
289 sizeof(struct filter_wx_t),
290 __alignof__(struct filter_wx_t),
291 CELLMALLOC_POLICY_FIFO,
292 32 /* 32 kB at the time */,
293 0 /* minfree */ );
294 #endif
295 }
296
filter_entrycall_free(struct filter_entrycall_t * f)297 static void filter_entrycall_free(struct filter_entrycall_t *f)
298 {
299 #ifndef _FOR_VALGRIND_
300 cellfree( filter_entrycall_cells, f );
301 #else
302 hfree(f);
303 #endif
304 -- filter_entrycall_cellgauge;
305 }
306
307 /*
308 * filter_entrycall_insert() is for support of q//i filters.
309 * That is, "pass on any message that has traversed thru entry
310 * igate which has identified itself with qAr or qAR. Not all
311 * messages traversed thru such gate will have those same q-cons
312 * values, thus this database keeps info about entry igate that
313 * have shown such capability in recent past.
314 *
315 * This must be called by the incoming_parse() in every case
316 * (or at least when qcons is either 'r' or 'R'.)
317 *
318 * The key has no guaranteed alignment, no way to play tricks
319 * with gcc builtin optimizers.
320 */
321
filter_entrycall_insert(struct pbuf_t * pb)322 static int filter_entrycall_insert(struct pbuf_t *pb)
323 {
324 struct filter_entrycall_t *f, **fp, *f2;
325 /* OK, pre-parsing produced accepted result */
326 uint32_t hash;
327 int idx, keylen;
328 const char qcons = pb->qconst_start[2];
329 const char *key = pb->qconst_start+4;
330 char uckey[CALLSIGNLEN_MAX+1];
331
332 for (keylen = 0; keylen < CALLSIGNLEN_MAX; ++keylen) {
333 int c = key[keylen];
334 if (c == ',' || c == ':')
335 break;
336 if ('a' <= c && c <= 'z')
337 c -= ('a' - 'A');
338 uckey[keylen] = c;
339 uckey[keylen+1] = 0;
340 }
341 if ((key[keylen] != ',' && key[keylen] != ':') ||
342 (keylen < CALLSIGNLEN_MIN))
343 return 0; /* Bad entry-station callsign */
344
345 pb->entrycall_len = keylen; // FIXME: should be in incoming parser...
346
347 /* We insert only those that have Q-Constructs of qAR or qAr */
348 if (qcons != 'r' && qcons != 'R') return 0;
349
350 hash = keyhash(uckey, keylen, 0);
351 idx = (hash ^ (hash >> 11) ^ (hash >> 22) ) % FILTER_ENTRYCALL_HASHSIZE; /* Fold the hashbits.. */
352
353 rwl_wrlock(&filter_entrycall_rwlock);
354
355 fp = &filter_entrycall_hash[idx];
356 f2 = NULL;
357 while (( f = *fp )) {
358 if ( f->hash == hash ) {
359 if (f->len == keylen) {
360 int cmp = memcmp(f->callsign, uckey, keylen);
361 if (cmp == 0) { /* Have key match */
362 f->expirytime = tick + filter_entrycall_maxage;
363 f2 = f;
364 break;
365 }
366 }
367 }
368 /* No match at all, advance the pointer.. */
369 fp = &(f -> next);
370 }
371 if (!f2) {
372
373 /* Allocate and insert into hash table */
374
375 fp = &filter_entrycall_hash[idx];
376
377 #ifndef _FOR_VALGRIND_
378 f = cellmalloc(filter_entrycall_cells);
379 #else
380 f = hmalloc(sizeof(*f));
381 #endif
382 if (f) {
383 f->next = *fp;
384 f->expirytime = tick + filter_entrycall_maxage;
385 f->hash = hash;
386 f->len = keylen;
387 memcpy(f->callsign, uckey, keylen);
388 memset(f->callsign+keylen, 0, sizeof(f->callsign)-keylen);
389
390 *fp = f2 = f;
391
392 ++ filter_entrycall_cellgauge;
393 } else {
394 hlog(LOG_ERR, "filter_entrycall_insert: cellmalloc failed");
395 }
396 }
397
398 rwl_wrunlock(&filter_entrycall_rwlock);
399
400 return (f2 != NULL);
401 }
402
403 /*
404 * filter_entrycall_lookup() is for support of q//i filters.
405 * That is, "pass on any message that has traversed thru entry
406 * igate which has identified itself with qAr or qAR. Not all
407 * messages traversed thru such gate will have those same q-cons
408 * values, thus this keeps database about entry servers that have
409 * shown such capability in recent past.
410 *
411 * The key has no guaranteed alignment, no way to play tricks
412 * with gcc builtin optimizers.
413 */
414
filter_entrycall_lookup(const struct pbuf_t * pb)415 static int filter_entrycall_lookup(const struct pbuf_t *pb)
416 {
417 struct filter_entrycall_t *f, **fp, *f2;
418 const char *key = pb->qconst_start+4;
419 const int keylen = pb->entrycall_len;
420
421 uint32_t hash = keyhashuc(key, keylen, 0);
422 int idx = ( hash ^ (hash >> 11) ^ (hash >> 22) ) % FILTER_ENTRYCALL_HASHSIZE; /* fold the hashbits.. */
423
424 f2 = NULL;
425
426 rwl_rdlock(&filter_entrycall_rwlock);
427
428 fp = &filter_entrycall_hash[idx];
429 while (( f = *fp )) {
430 if ( f->hash == hash ) {
431 if (f->len == keylen) {
432 int rc = strncasecmp(f->callsign, key, keylen);
433 if (rc == 0) { /* Have key match, see if it is
434 still valid entry ? */
435 if (f->expirytime < tick - 60) {
436 f2 = f;
437 break;
438 }
439 }
440 }
441 }
442 /* No match at all, advance the pointer.. */
443 fp = &(f -> next);
444 }
445
446 rwl_rdunlock(&filter_entrycall_rwlock);
447
448 return (f2 != NULL);
449 }
450
451 /*
452 * The filter_entrycall_cleanup() does purge old entries
453 * out of the database. Run about once a minute.
454 */
filter_entrycall_cleanup(void)455 void filter_entrycall_cleanup(void)
456 {
457 int k, cleancount = 0;
458 struct filter_entrycall_t *f, **fp;
459
460 rwl_wrlock(&filter_entrycall_rwlock);
461
462 for (k = 0; k < FILTER_ENTRYCALL_HASHSIZE; ++k) {
463 fp = & filter_entrycall_hash[k];
464 while (( f = *fp )) {
465 /* Did it expire ? */
466 if (f->expirytime <= tick) {
467 *fp = f->next;
468 f->next = NULL;
469 filter_entrycall_free(f);
470 ++cleancount;
471 continue;
472 }
473 /* No purge, advance the pointer.. */
474 fp = &(f -> next);
475 }
476 }
477
478 rwl_wrunlock(&filter_entrycall_rwlock);
479
480 // hlog( LOG_DEBUG, "filter_entrycall_cleanup() removed %d entries, count now: %ld",
481 // cleancount, filter_entrycall_cellgauge );
482 }
483
484 /*
485 * The filter_entrycall_atend() does purge all entries
486 * out of the database. Run at the exit of the program.
487 * This exists primarily to make valgrind happy...
488 */
filter_entrycall_atend(void)489 void filter_entrycall_atend(void)
490 {
491 int k;
492 struct filter_entrycall_t *f, **fp;
493
494 rwl_wrlock(&filter_entrycall_rwlock);
495
496 for (k = 0; k < FILTER_ENTRYCALL_HASHSIZE; ++k) {
497 fp = & filter_entrycall_hash[k];
498 while (( f = *fp )) {
499 *fp = f->next;
500 f->next = NULL;
501 filter_entrycall_free(f);
502 }
503 }
504
505 rwl_wrunlock(&filter_entrycall_rwlock);
506 }
507
508
filter_entrycall_dump(FILE * fp)509 void filter_entrycall_dump(FILE *fp)
510 {
511 int k;
512 struct filter_entrycall_t *f;
513
514 rwl_rdlock(&filter_entrycall_rwlock);
515
516 for (k = 0; k < FILTER_ENTRYCALL_HASHSIZE; ++k) {
517 f = filter_entrycall_hash[k];
518
519 for ( ; f; f = f->next ) {
520 fprintf( fp, "%ld\t%s\n",
521 (long)f->expirytime, f->callsign );
522 }
523 }
524
525 rwl_rdunlock(&filter_entrycall_rwlock);
526 }
527
528
529 /* ================================================================ */
530
531
532
filter_wx_free(struct filter_wx_t * f)533 static void filter_wx_free(struct filter_wx_t *f)
534 {
535 #ifndef _FOR_VALGRIND_
536 cellfree( filter_wx_cells, f );
537 #else
538 hfree(f);
539 #endif
540 --filter_wx_cellgauge;
541 }
542
543 /*
544 * The filter_wx_insert() does lookup key storage for problem of:
545 *
546 * Positionless T_WX packets want also position packets on output filters.
547 */
548
filter_wx_insert(struct pbuf_t * pb)549 static int filter_wx_insert(struct pbuf_t *pb)
550 {
551 struct filter_wx_t *f, **fp, *f2;
552 /* OK, pre-parsing produced accepted result */
553 const char *key = pb->data;
554 const int keylen = pb->srccall_end - key;
555 uint32_t hash;
556 int idx;
557 char uckey[CALLSIGNLEN_MAX+1];
558
559 /* If it is not a WX packet without position, we are not intrerested */
560 if (!((pb->packettype & T_WX) && !(pb->flags & F_HASPOS)))
561 return 0;
562
563 for (idx = 0; idx < keylen && idx < CALLSIGNLEN_MAX; ++idx) {
564 int c = key[idx];
565 if (c == '>')
566 break;
567 if ('a' <= c && c <= 'z')
568 c -= ('a' - 'A');
569 uckey[idx] = c;
570 uckey[idx+1] = 0;
571 }
572
573 hash = keyhash(uckey, keylen, 0);
574 idx = ( hash ^ (hash >> 10) ^ (hash >> 20) ) % FILTER_WX_HASHSIZE; /* fold the hashbits.. */
575
576 rwl_wrlock(&filter_wx_rwlock);
577
578 fp = &filter_wx_hash[idx];
579 f2 = NULL;
580 while (( f = *fp )) {
581 if ( f->hash == hash ) {
582 if (f->len == keylen) {
583 int cmp = memcmp(f->callsign, uckey, keylen);
584 if (cmp == 0) { /* Have key match */
585 f->expirytime = tick + filter_wx_maxage;
586 f2 = f;
587 break;
588 }
589 }
590 }
591 /* No match at all, advance the pointer.. */
592 fp = &(f -> next);
593 }
594 if (!f2) {
595
596 /* Allocate and insert into hash table */
597
598 fp = &filter_wx_hash[idx];
599
600 #ifndef _FOR_VALGRIND_
601 f = cellmalloc(filter_wx_cells);
602 #else
603 f = hmalloc(sizeof(*f));
604 #endif
605 ++filter_wx_cellgauge;
606 if (f) {
607 f->next = *fp;
608 f->expirytime = tick + filter_wx_maxage;
609 f->hash = hash;
610 f->len = keylen;
611 memcpy(f->callsign, uckey, keylen);
612 memset(f->callsign+keylen, 0, sizeof(f->callsign)-keylen);
613
614 *fp = f2 = f;
615 } else {
616 hlog(LOG_ERR, "filter_wx_insert: cellmalloc failed");
617 }
618 }
619
620 rwl_wrunlock(&filter_wx_rwlock);
621
622 return 0;
623 }
624
filter_wx_lookup(const struct pbuf_t * pb)625 static int filter_wx_lookup(const struct pbuf_t *pb)
626 {
627 struct filter_wx_t *f, **fp, *f2;
628 const char *key = pb->data;
629 const int keylen = pb->srccall_end - key;
630
631 uint32_t hash = keyhashuc(key, keylen, 0);
632 int idx = ( hash ^ (hash >> 10) ^ (hash >> 20) ) % FILTER_WX_HASHSIZE; /* fold the hashbits.. */
633
634 f2 = NULL;
635
636 rwl_rdlock(&filter_wx_rwlock);
637
638 fp = &filter_wx_hash[idx];
639 while (( f = *fp )) {
640 if ( f->hash == hash ) {
641 if (f->len == keylen) {
642 int rc = strncasecmp(f->callsign, key, keylen);
643 if (rc == 0) { /* Have key match, see if it is
644 still valid entry ? */
645 if (f->expirytime < tick - 60) {
646 f2 = f;
647 break;
648 }
649 }
650 }
651 }
652 /* No match at all, advance the pointer.. */
653 fp = &(f -> next);
654 }
655
656 rwl_rdunlock(&filter_wx_rwlock);
657
658 return (f2 != NULL);
659 }
660
661
662 /*
663 * The filter_wx_cleanup() does purge old entries
664 * out of the database. Run about once a minute.
665 */
filter_wx_cleanup(void)666 void filter_wx_cleanup(void)
667 {
668 int k, cleancount = 0;
669 struct filter_wx_t *f, **fp;
670
671 rwl_wrlock(&filter_wx_rwlock);
672
673 for (k = 0; k < FILTER_WX_HASHSIZE; ++k) {
674 fp = & filter_wx_hash[k];
675 while (( f = *fp )) {
676 /* Did it expire ? */
677 if (f->expirytime <= tick) {
678 *fp = f->next;
679 f->next = NULL;
680 filter_wx_free(f);
681 ++cleancount;
682 continue;
683 }
684 /* No purge, advance the pointer.. */
685 fp = &(f -> next);
686 }
687 }
688
689 rwl_wrunlock(&filter_wx_rwlock);
690
691 // hlog( LOG_DEBUG, "filter_wx_cleanup() removed %d entries, count now: %ld",
692 // cleancount, filter_wx_cellgauge );
693 }
694
695 /*
696 * The filter_wx_atend() does purge all entries
697 * out of the database. Run at the exit of the program.
698 * This exists primarily to make valgrind happy...
699 */
filter_wx_atend(void)700 void filter_wx_atend(void)
701 {
702 int k;
703 struct filter_wx_t *f, **fp;
704
705 rwl_wrlock(&filter_wx_rwlock);
706
707 for (k = 0; k < FILTER_WX_HASHSIZE; ++k) {
708 fp = & filter_wx_hash[k];
709 while (( f = *fp )) {
710 *fp = f->next;
711 f->next = NULL;
712 filter_wx_free(f);
713 }
714 }
715
716 rwl_wrunlock(&filter_wx_rwlock);
717 }
718
719
filter_wx_dump(FILE * fp)720 void filter_wx_dump(FILE *fp)
721 {
722 int k;
723 struct filter_wx_t *f;
724
725 rwl_rdlock(&filter_wx_rwlock);
726
727 for (k = 0; k < FILTER_WX_HASHSIZE; ++k) {
728 f = filter_wx_hash[k];
729
730 for ( ; f; f = f->next ) {
731 fprintf( fp, "%ld\t%s\n",
732 (long)f->expirytime, f->callsign );
733 }
734 }
735
736 rwl_rdunlock(&filter_wx_rwlock);
737 }
738
739
740 /* ================================================================ */
741
aprsc_strnstr(const char * s1,const char * s2,size_t len)742 const char *aprsc_strnstr(const char *s1, const char *s2, size_t len)
743 {
744 char c1, c2;
745 size_t n;
746
747 c2 = *(char *) s2++;
748
749 n = strlen(s2);
750
751 do {
752 do {
753 /* if we're going too far */
754 if (len-- == 0)
755 return NULL;
756
757 /* pick first char and advance */
758 c1 = *s1++;
759
760 /* end of string? */
761 if (c1 == 0)
762 return NULL;
763 } while (c1 != c2);
764
765 /* at least the first character matches... if the needle is longer than
766 * what we have left in the haystack, we won't find a match.
767 */
768
769 if (n > len)
770 return NULL;
771
772 } while (strncmp(s1, s2, n) != 0);
773
774 return s1;
775 }
776
777
778 /*
779 * Check if there is a TCPIP* component in the path.
780 * OPTIMIZE: The flag could be set when TCPIP is inserted, or when the path
781 * is analyzed on input.
782 */
783
filter_check_tcpip(struct pbuf_t * pbuf)784 static void filter_check_tcpip(struct pbuf_t *pbuf)
785 {
786 if (aprsc_strnstr(pbuf->dstcall_end, ",TCPIP*,", pbuf->qconst_start - pbuf->dstcall_end))
787 pbuf->flags |= F_HAS_TCPIP;
788 }
789
filter_keyhashes(struct pbuf_t * pb)790 static void filter_keyhashes(struct pbuf_t *pb)
791 {
792 pb->srccall_hash = keyhashuc(pb->data, pb->srccall_end - pb->data, 0);
793
794 if (pb->srcname == pb->data)
795 pb->srcname_hash = pb->srccall_hash;
796 else
797 pb->srcname_hash = keyhashuc(pb->srcname, pb->srcname_len, 0);
798
799 if (pb->dstname)
800 pb->dstname_hash = keyhashuc(pb->dstname, pb->dstname_len, 0);
801 }
802
filter_preprocess_dupefilter(struct pbuf_t * pbuf)803 void filter_preprocess_dupefilter(struct pbuf_t *pbuf)
804 {
805 // TODO: could probably skip filter_check_tcpip, and possibly filter_keyhashes too if no filtered listeners
806 filter_check_tcpip(pbuf);
807 if (have_filtered_listeners) {
808 filter_entrycall_insert(pbuf);
809 filter_wx_insert(pbuf);
810 }
811 filter_keyhashes(pbuf);
812 }
813
filter_postprocess_dupefilter(struct pbuf_t * pbuf)814 void filter_postprocess_dupefilter(struct pbuf_t *pbuf)
815 {
816 /*
817 * If there is no position at this packet from earlier
818 * processing, try now to find one by the callsign of
819 * the packet sender.
820 *
821 */
822 if (!(pbuf->flags & F_HASPOS)) {
823 struct history_cell_t *hist;
824 int rc = historydb_lookup(pbuf->srcname, pbuf->srcname_len, &hist);
825 // hlog( LOG_DEBUG, "postprocess_dupefilter: no pos, looking up '%.*s', rc=%d",
826 // pbuf->srcname_len, pbuf->srcname, rc );
827 if (rc > 0) {
828 pbuf->lat = hist->lat;
829 pbuf->lng = hist->lon;
830 pbuf->cos_lat = hist->coslat;
831
832 pbuf->flags |= F_HASPOS;
833 }
834 }
835 }
836
837
838 /* ================================================================ */
839
840 /*
841 * filter_match_on_callsignset() matches prefixes, or exact keys
842 * on filters of types: b, d, e, o, p, u
843 * ('p' and 'b' need OPTIMIZATION - others get it for free)
844 *
845 */
846
filter_match_on_callsignset(struct filter_refcallsign_t * ref,int keylen,struct filter_t * f,MatchEnum wildok)847 static int filter_match_on_callsignset(struct filter_refcallsign_t *ref, int keylen, struct filter_t *f, MatchEnum wildok)
848 {
849 int i;
850 struct filter_refcallsign_t *r = f->h.refcallsigns;
851 const char *r1 = (const void*)ref->callsign;
852
853 for (i = 0; i < f->h.numnames; ++i) {
854 const int reflen = r[i].reflen;
855 const int len = reflen & LengthMask;
856 const char *r2 = (const void*)r[i].callsign;
857
858 switch (wildok) {
859 case MatchExact:
860 if (len != keylen)
861 continue; /* no match */
862 /* length OK, compare content */
863 if (strncasecmp( r1, r2, len ) != 0) continue;
864 /* So it was an exact match
865 ** Precisely speaking.. we should check that there is
866 ** no WildCard flag, or such. But then this match
867 ** method should not be used if parser finds any such.
868 */
869 return ( reflen & NegationFlag ? 2 : 1 );
870 break;
871 case MatchPrefix:
872 if (len > keylen || !len) {
873 /* reference string length is longer than our key */
874 continue;
875 }
876 if (strncasecmp( r1, r2, len ) != 0) continue;
877
878 return ( reflen & NegationFlag ? 2 : 1 );
879 break;
880 case MatchWild:
881 if (len > keylen || !len) {
882 /* reference string length is longer than our key */
883 continue;
884 }
885
886 if (strncasecmp( r1, r2, len ) != 0) continue;
887
888 if (reflen & WildCard)
889 return ( reflen & NegationFlag ? 2 : 1 );
890
891 if (len == keylen)
892 return ( reflen & NegationFlag ? 2 : 1 );
893 break;
894 default:
895 break;
896 }
897 }
898 return 0; /* no match */
899
900 }
901
902 /*
903 * filter_parse_one_callsignset() collects multiple callsigns
904 * on filters of types: b, d, e, o, p, u
905 *
906 * If previous filter was of same type as this one, that one's
907 * refbuf is extended.
908 */
909
filter_parse_one_callsignset(struct client_t * c,const char * filt0,struct filter_t * f0,struct filter_t * ff,struct filter_t ** ffp,MatchEnum wildok)910 static int filter_parse_one_callsignset(struct client_t *c, const char *filt0, struct filter_t *f0, struct filter_t *ff, struct filter_t **ffp, MatchEnum wildok)
911 {
912 char prefixbuf[CALLSIGNLEN_MAX+1];
913 char *k;
914 const char *p;
915 int i, refcount, wildcard;
916 int refmax = 0, extend = 0;
917 struct filter_refcallsign_t *refbuf;
918
919 p = filt0;
920 if (*p == '-') ++p;
921 while (*p && *p != '/') ++p;
922 if (*p == '/') ++p;
923 /* count the number of prefixes in there.. */
924 while (*p) {
925 if (*p) ++refmax;
926 while (*p && *p != '/') ++p;
927 if (*p == '/') ++p;
928 }
929 if (refmax == 0) return -1; /* No prefixes ?? */
930
931 if (ff && ff->h.type == f0->h.type) { /* SAME TYPE,
932 extend previous record! */
933 extend = 1;
934 refcount = ff->h.numnames + refmax;
935 //hlog(LOG_DEBUG, "extending, refcount %d numnames %d refmax %d", refcount, ff->h.numnames, refmax);
936 refbuf = hrealloc(ff->h.refcallsigns, sizeof(*refbuf) * refcount);
937 ff->h.refcallsigns = refbuf;
938 refcount = ff->h.numnames;
939 } else {
940 refbuf = hmalloc(sizeof(*refbuf)*refmax);
941 refcount = 0;
942 f0->h.refcallsigns = refbuf;
943 f0->h.numnames = 0;
944 }
945
946 p = filt0;
947 if (*p == '-') ++p;
948 while (*p && *p != '/') ++p;
949 if (*p == '/') ++p;
950
951 //hlog(LOG_DEBUG, "p-filter: '%s'", p);
952 while (*p) {
953 k = prefixbuf;
954 memset(prefixbuf, 0, sizeof(prefixbuf));
955 i = 0;
956 wildcard = 0;
957 /* loop through the whole callsign, but only copy max CALLSIGNLEN_MAX
958 * bytes to the buffer
959 */
960 while (*p != 0 && *p != '/') {
961 if (*p == '*') {
962 wildcard = 1;
963 ++p;
964 if (wildok != MatchWild)
965 return -1;
966 continue;
967 }
968 if (i < CALLSIGNLEN_MAX) {
969 *k = *p;
970 ++k;
971 }
972 ++p;
973 ++i;
974 }
975 *k = 0;
976
977 /* OK, we have one prefix part collected,
978 scan source until next '/' */
979 if (*p != 0 && *p != '/') ++p;
980 if (*p == '/') ++p;
981
982 /* If there is more of patterns, the loop continues.. */
983
984 /* Store the refprefix */
985 memset(&refbuf[refcount], 0, sizeof(refbuf[refcount]));
986 memcpy(refbuf[refcount].callsign, prefixbuf, sizeof(refbuf[refcount].callsign));
987 refbuf[refcount].reflen = strlen(prefixbuf);
988 if (wildcard)
989 refbuf[refcount].reflen |= WildCard;
990 if (f0->h.negation)
991 refbuf[refcount].reflen |= NegationFlag;
992 ++refcount;
993 }
994
995 f0->h.numnames = refcount;
996
997 if (extend) {
998 char *s;
999 ff->h.numnames = refcount;
1000 i = strlen(ff->h.text) + strlen(filt0)+2;
1001 if (i <= FILT_TEXTBUFSIZE) {
1002 /* Fits in our built-in buffer block - like previous..
1003 ** Append on existing buffer
1004 */
1005 s = ff->textbuf + strlen(ff->textbuf);
1006 sprintf(s, " %s", filt0);
1007 } else {
1008 /* It does not fit anymore.. */
1009 s = hmalloc(i); /* alloc a new one */
1010 sprintf(s, "%s %s", ff->textbuf, filt0); /* .. and catenate. */
1011 p = ff->h.text;
1012 if (ff->h.text != ff->textbuf) /* possibly free old */
1013 hfree((void*)p);
1014 ff->h.text = s; /* store new */
1015 }
1016 }
1017 /* If not extending existing filter item,
1018 let main parser do the finalizations */
1019
1020 return extend;
1021 }
1022
filter_parse_one_s(struct client_t * c,const char * filt0,struct filter_t * f0,struct filter_t * ff,struct filter_t ** ffp)1023 static int filter_parse_one_s(struct client_t *c, const char *filt0, struct filter_t *f0, struct filter_t *ff, struct filter_t **ffp)
1024 {
1025 /* s/pri/alt/over Symbol filter
1026
1027 pri = symbols in primary table
1028 alt = symbols in alternate table
1029 over = overlay character (case sensitive)
1030
1031 For example:
1032 s/-> This will pass all House and Car symbols (primary table)
1033 s//# This will pass all Digi with or without overlay
1034 s//#/T This will pass all Digi with overlay of capital T
1035
1036 About 10-15 s-filters in entire APRS-IS core at any given time.
1037 Up to 520 invocations per second at peak.
1038 */
1039 const char *s = filt0;
1040 int len1, len2, len3, len4, len5, len6;
1041
1042 if (*s == '-')
1043 ++s;
1044 if (*s == 's' || *s == 'S')
1045 ++s;
1046 if (*s != '/')
1047 return -1;
1048 ++s;
1049
1050 len1 = len2 = len3 = len4 = len5 = len6 = 0;
1051
1052 while (1) {
1053 len1 = s - filt0;
1054 while (*s && *s != '/')
1055 s++;
1056 len2 = s - filt0;
1057
1058 f0->h.len1s = len1;
1059 f0->h.len1 = len2 - len1;
1060 f0->h.lens.len2s = f0->h.lens.len2 = f0->h.lens.len3s = f0->h.lens.len3 = 0;
1061
1062 if (!*s) break;
1063
1064 if (*s == '/') ++s;
1065 len3 = s - filt0;
1066 while (*s && *s != '/')
1067 s++;
1068 len4 = s - filt0;
1069
1070 f0->h.lens.len2s = len3;
1071 f0->h.lens.len2 = len4 - len3;
1072
1073 if (!*s) break;
1074
1075 if (*s == '/') ++s;
1076 len5 = s - filt0;
1077 while (*s) ++s;
1078 len6 = s - filt0;
1079
1080 f0->h.lens.len3s = len5;
1081 f0->h.lens.len3 = len6 - len5;
1082
1083 break;
1084 }
1085
1086 if ((len6-len5 > 0) && (len4-len3 == 0)) {
1087 /* overlay but no secondary table.. */
1088 return -1; /* bad parse */
1089 }
1090 #if 0
1091 {
1092 const char *s1 = filt0+len1, *s2 = filt0+len3, *s3 = filt0+len5;
1093 int l1 = len2-len1, l2 = len4-len3, l3 = len6-len5;
1094
1095 hlog( LOG_DEBUG, "parse s-filter: '%.*s' '%.*s' '%.*s'",
1096 l1, s1, l2, s2, l3, s3 );
1097 }
1098 #endif
1099 return 0;
1100 }
1101
1102
filter_parse(struct client_t * c,const char * filt,int is_user_filter)1103 int filter_parse(struct client_t *c, const char *filt, int is_user_filter)
1104 {
1105 struct filter_t *f, f0;
1106 int i;
1107 const char *filt0 = filt;
1108 const char *s;
1109 char dummyc;
1110 struct filter_t *fp, *fn, *ff, **fff, **ffp, **ffn;
1111
1112 if (is_user_filter && c && (!(c->flags & CLFLAGS_USERFILTEROK))) {
1113 hlog(LOG_DEBUG, "No user-specified filters permitted");
1114 return -1;
1115 }
1116
1117 if (!c) { /* built-in configuration scanning filter parsing */
1118 ffp = &f;
1119 ffn = &f;
1120 f = NULL;
1121 } else if (is_user_filter) {
1122 ffn = &c->neguserfilters;
1123 ffp = &c->posuserfilters;
1124 } else {
1125 ffn = &c->negdefaultfilters;
1126 ffp = &c->posdefaultfilters;
1127 }
1128
1129 fp = *ffp;
1130 fn = *ffn;
1131 for ( ; fp && fp->h.next; fp = fp->h.next)
1132 ;
1133 for ( ; fn && fn->h.next; fn = fn->h.next)
1134 ;
1135 /* f[np] points to last so far accumulated filter,
1136 if none were previously received, it is NULL.. */
1137
1138 memset(&f0, 0, sizeof(f0));
1139 if (*filt == '-') {
1140 ++filt;
1141 ff = fn;
1142 fff = ffn;
1143 } else {
1144 ff = fp;
1145 fff = ffp;
1146 }
1147 f0.h.type = *filt;
1148
1149 if (!strchr("abdefgmopqrstuABDEFGMOPQRSTU", *filt)) {
1150 /* Not valid filter code */
1151 hlog(LOG_DEBUG, "Bad filter code: %s", filt0);
1152 return -1;
1153 }
1154
1155 switch (f0.h.type) {
1156 case 'a':
1157 case 'A':
1158 /* a/latN/lonW/latS/lonE Area filter -- OPTIMIZE! */
1159
1160 i = sscanf(filt+1, "/%f/%f/%f/%f%c",
1161 &f0.h.f_latN, &f0.h.f_lonW,
1162 &f0.h.f_latS, &f0.h.f_lonE, &dummyc);
1163
1164 if (i == 5 && dummyc == '/')
1165 i = 4;
1166
1167 if (i != 4) {
1168 hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1169 return -1;
1170 }
1171
1172 if (!( -90.01 < f0.h.f_latN && f0.h.f_latN < 90.01)) {
1173 hlog(LOG_DEBUG, "Bad filter latN value: %s", filt0);
1174 return -2;
1175 }
1176 if (!(-180.01 < f0.h.f_lonW && f0.h.f_lonW < 180.01)) {
1177 hlog(LOG_DEBUG, "Bad filter lonW value: %s", filt0);
1178 return -2;
1179 }
1180 if (!( -90.01 < f0.h.f_latS && f0.h.f_latS < 90.01)) {
1181 hlog(LOG_DEBUG, "Bad filter latS value: %s", filt0);
1182 return -2;
1183 }
1184 if (!(-180.01 < f0.h.f_lonE && f0.h.f_lonE < 180.01)) {
1185 hlog(LOG_DEBUG, "Bad filter lonE value: %s", filt0);
1186 return -2;
1187 }
1188
1189 if (f0.h.f_latN < f0.h.f_latS) {
1190 hlog(LOG_DEBUG, "Bad filter: latN<latS: %s", filt0);
1191 return -3; /* expect: latN >= latS */
1192 }
1193 if (f0.h.f_lonW > f0.h.f_lonE) {
1194 hlog(LOG_DEBUG, "Bad filter: lonW>lonE: %s", filt0);
1195 return -3; /* expect: lonW <= lonE */
1196 }
1197
1198 // hlog(LOG_DEBUG, "Filter: %s -> A %.3f %.3f %.3f %.3f",
1199 // filt0, f0.h.f_latN, f0.h.f_lonW,
1200 // f0.h.f_latS, f0.h.f_lonE);
1201
1202 f0.h.f_latN = filter_lat2rad(f0.h.f_latN);
1203 f0.h.f_lonW = filter_lon2rad(f0.h.f_lonW);
1204
1205 f0.h.f_latS = filter_lat2rad(f0.h.f_latS);
1206 f0.h.f_lonE = filter_lon2rad(f0.h.f_lonE);
1207
1208
1209
1210 break;
1211
1212 case 'b':
1213 case 'B':
1214 /* b/call1/call2... Budlist filter (*) */
1215
1216 i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1217 if (i < 0)
1218 return i;
1219 if (i > 0) /* extended previous */
1220 return 0;
1221
1222
1223 break;
1224
1225 case 'd':
1226 case 'D':
1227 /* d/digi1/digi2... Used digipeater filter (*) */
1228
1229 i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1230 if (i < 0)
1231 return i;
1232 if (i > 0) /* extended previous */
1233 return 0;
1234
1235 break;
1236
1237 case 'e':
1238 case 'E':
1239 /* e/call1/call1/... Entry station filter (*) */
1240
1241 i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1242 if (i < 0)
1243 return i;
1244 if (i > 0) /* extended previous */
1245 return 0;
1246
1247 break;
1248
1249 case 'f':
1250 case 'F':
1251 /* f/call/dist Friend's range filter */
1252
1253 i = sscanf(filt+1, "/%9[^/]/%f", f0.h.refcallsign.callsign, &f0.h.f_dist);
1254 if (i != 2 || f0.h.f_dist < 0.1) {
1255 hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1256 return -1;
1257 }
1258
1259 f0.h.refcallsign.callsign[CALLSIGNLEN_MAX] = 0;
1260 f0.h.refcallsign.reflen = strlen(f0.h.refcallsign.callsign);
1261 f0.h.numnames = 0; /* reusing this as "position-cache valid" flag */
1262
1263 // hlog(LOG_DEBUG, "Filter: %s -> F xxx %.3f", filt0, f0.h.f_dist);
1264
1265 /* NOTE: Could do static location resolving at connect time,
1266 ** and then use the same way as 'r' range does. The friends
1267 ** are rarely moving...
1268 */
1269
1270 break;
1271
1272 case 'g':
1273 case 'G':
1274 /* g/call1/call1/... Text message destination filter (*) */
1275
1276 i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1277 if (i < 0)
1278 return i;
1279 if (i > 0) /* extended previous */
1280 return 0;
1281
1282 break;
1283
1284 case 'm':
1285 case 'M':
1286 /* m/dist My range filter */
1287
1288 i = sscanf(filt+1, "/%f", &f0.h.f_dist);
1289 if (i != 1 || f0.h.f_dist < 0.1) {
1290 hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1291 return -1;
1292 }
1293 f0.h.numnames = 0; /* reusing this as "position-cache valid" flag */
1294
1295 // hlog(LOG_DEBUG, "Filter: %s -> M %.3f", filt0, f0.h.f_dist);
1296 break;
1297
1298 case 'o':
1299 case 'O':
1300 /* o/obje1/obj2... Object filter (*) */
1301
1302 i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1303 if (i < 0)
1304 return i;
1305 if (i > 0) /* extended previous */
1306 return 0;
1307
1308 break;
1309
1310 case 'p':
1311 case 'P':
1312 /* p/aa/bb/cc... Prefix filter
1313 Pass traffic with fromCall that start with aa or bb or cc...
1314 */
1315 i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchPrefix );
1316 if (i < 0)
1317 return i;
1318 if (i > 0) /* extended previous */
1319 return 0;
1320
1321 break;
1322
1323 case 'q':
1324 case 'Q':
1325 /* q/con/ana q Contruct filter */
1326 s = filt+1;
1327 f0.h.type = 'q';
1328 f0.h.bitflags = 0; /* For QC_* flags */
1329
1330 if (*s++ != '/') {
1331 hlog(LOG_DEBUG, "Bad q-filter parse: %s", filt0);
1332 return -1;
1333 }
1334 for ( ; *s && *s != '/'; ++s ) {
1335 switch (*s) {
1336 case 'C':
1337 f0.h.bitflags |= QC_C;
1338 break;
1339 case 'X':
1340 f0.h.bitflags |= QC_X;
1341 break;
1342 case 'U':
1343 f0.h.bitflags |= QC_U;
1344 break;
1345 case 'o':
1346 f0.h.bitflags |= QC_o;
1347 break;
1348 case 'O':
1349 f0.h.bitflags |= QC_O;
1350 break;
1351 case 'S':
1352 f0.h.bitflags |= QC_S;
1353 break;
1354 case 'r':
1355 f0.h.bitflags |= QC_r;
1356 break;
1357 case 'R':
1358 f0.h.bitflags |= QC_R;
1359 break;
1360 case 'Z':
1361 f0.h.bitflags |= QC_Z;
1362 break;
1363 case 'I':
1364 f0.h.bitflags |= QC_I;
1365 break;
1366 default:
1367 hlog(LOG_DEBUG, "Bad q-filter parse: %s", filt0);
1368 return -1;
1369 }
1370 }
1371 if (*s == '/') { /* second format */
1372 ++s;
1373 if (*s == 'i' || *s == 'I') {
1374 f0.h.bitflags |= QC_AnalyticsI;
1375 ++s;
1376 }
1377 if (*s) {
1378 hlog(LOG_DEBUG, "Bad q-filter parse: %s", filt0);
1379 return -1;
1380 }
1381 }
1382
1383 break;
1384
1385 case 'r':
1386 case 'R':
1387 /* r/lat/lon/dist Range filter */
1388
1389 i = sscanf(filt+1, "/%f/%f/%f",
1390 &f0.h.f_latN, &f0.h.f_lonE, &f0.h.f_dist);
1391 if (i != 3 || f0.h.f_dist < 0.1) {
1392 hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1393 return -1;
1394 }
1395
1396 if (!( -90.01 < f0.h.f_latN && f0.h.f_latN < 90.01)) {
1397 hlog(LOG_DEBUG, "Bad filter lat value: %s", filt0);
1398 return -2;
1399 }
1400 if (!(-180.01 < f0.h.f_lonE && f0.h.f_lonE < 180.01)) {
1401 hlog(LOG_DEBUG, "Bad filter lon value: %s", filt0);
1402 return -2;
1403 }
1404
1405 // hlog(LOG_DEBUG, "Filter: %s -> R %.3f %.3f %.3f", filt0, f0.h.f_latN, f0.h.f_lonW, f0.h.f_dist);
1406
1407 f0.h.f_latN = filter_lat2rad(f0.h.f_latN);
1408 f0.h.f_lonE = filter_lon2rad(f0.h.f_lonE);
1409
1410 f0.h.f_coslat = cosf( f0.h.f_latN ); /* Store pre-calculated COS of LAT */
1411 break;
1412
1413 case 's':
1414 case 'S':
1415 /* s/pri/alt/over Symbol filter */
1416
1417 i = filter_parse_one_s( c, filt0, &f0, ff, fff );
1418 if (i < 0) {
1419 hlog(LOG_DEBUG, "Bad s-filter syntax: %s", filt0);
1420 return i;
1421 }
1422 if (i > 0) /* extended previous */
1423 return 0;
1424 break;
1425
1426 case 't':
1427 case 'T':
1428 /* t/..............
1429 t/............../call/km
1430 */
1431 s = filt+1;
1432 f0.h.type = 't';
1433 f0.h.bitflags = 0;
1434 f0.h.numnames = 0; /* reusing this as "position-cache valid" flag */
1435
1436 if (*s++ != '/') {
1437 hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1438 return -1;
1439 }
1440 for ( ; *s && *s != '/'; ++s ) {
1441 switch (*s) {
1442 case '*':
1443 f0.h.bitflags |= ~T_CWOP; /* "ALL" -- excluding CWOP */
1444 break;
1445 case 'c': case 'C':
1446 f0.h.bitflags |= T_CWOP;
1447 break;
1448 case 'i': case 'I':
1449 f0.h.bitflags |= T_ITEM;
1450 break;
1451 case 'm': case 'M':
1452 f0.h.bitflags |= T_MESSAGE;
1453 break;
1454 case 'n': case 'N':
1455 f0.h.bitflags |= T_NWS;
1456 break;
1457 case 'o': case 'O':
1458 f0.h.bitflags |= T_OBJECT;
1459 break;
1460 case 'p': case 'P':
1461 f0.h.bitflags |= T_POSITION;
1462 break;
1463 case 'q': case 'Q':
1464 f0.h.bitflags |= T_QUERY;
1465 break;
1466 case 's': case 'S':
1467 f0.h.bitflags |= T_STATUS;
1468 break;
1469 case 't': case 'T':
1470 f0.h.bitflags |= T_TELEMETRY;
1471 break;
1472 case 'u': case 'U':
1473 f0.h.bitflags |= T_USERDEF;
1474 break;
1475 case 'w': case 'W':
1476 f0.h.bitflags |= T_WX;
1477 break;
1478 default:
1479 hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1480 return -1;
1481 }
1482 }
1483 if (*s == '/' && s[1] != 0) { /* second format */
1484 i = sscanf(s, "/%9[^/]/%f%c", f0.h.refcallsign.callsign, &f0.h.f_dist, &dummyc);
1485 if ( i != 2 || f0.h.f_dist < 0.1 || /* 0.1 km minimum radius */
1486 strlen(f0.h.refcallsign.callsign) < CALLSIGNLEN_MIN ) {
1487 hlog(LOG_DEBUG, "Bad filter parse: %s", filt0);
1488 return -1;
1489 }
1490 f0.h.refcallsign.callsign[CALLSIGNLEN_MAX] = 0;
1491 f0.h.refcallsign.reflen = strlen(f0.h.refcallsign.callsign);
1492 f0.h.type = 'T'; /* two variants... */
1493 }
1494
1495 break;
1496
1497 case 'u':
1498 case 'U':
1499 /* u/unproto1/unproto2... Unproto filter (*) */
1500
1501 i = filter_parse_one_callsignset(c, filt0, &f0, ff, fff, MatchWild );
1502 if (i < 0)
1503 return i;
1504 if (i > 0) /* extended previous */
1505 return 0;
1506
1507 break;
1508
1509
1510
1511 default:;
1512 /* No pre-parsers for other types */
1513 // hlog(LOG_DEBUG, "Filter: %s", filt0);
1514 break;
1515 }
1516
1517 if (!c) return 0; /* Just a verification scan, not actual fill in parse */
1518
1519 /* OK, pre-parsing produced accepted result */
1520 #ifndef _FOR_VALGRIND_
1521 f = cellmalloc(filter_cells);
1522 if (!f) {
1523 hlog(LOG_ERR, "filter_parse: cellmalloc failed");
1524 return -1;
1525 }
1526 *f = f0; /* store pre-parsed values */
1527 if (strlen(filt0) < FILT_TEXTBUFSIZE) {
1528 strcpy(f->textbuf, filt0);
1529 f->h.text = f->textbuf;
1530 } else
1531 f->h.text = hstrdup(filt0); /* and copy of filter text */
1532 #else
1533 f = hmalloc(sizeof(*f) + strlen(filt0));
1534 *f = f0; /* store pre-parsed values */
1535 f->h.text = f->textbuf;
1536 strcpy(f->textbuf, filt); /* and copy of filter text */
1537 #endif
1538 rwl_wrlock(&filter_cellgauge_rwlock);
1539 ++ filter_cellgauge;
1540 rwl_wrunlock(&filter_cellgauge_rwlock);
1541
1542 hlog(LOG_DEBUG, "parsed filter: t=%c n=%d '%s'", f->h.type, f->h.negation, f->h.text);
1543
1544 /* link to the tail.. */
1545 if (ff)
1546 fff = &ff->h.next;
1547
1548 *fff = f;
1549
1550 return 0;
1551 }
1552
1553 /* Discard the defined filter chain */
filter_free(struct filter_t * f)1554 void filter_free(struct filter_t *f)
1555 {
1556 struct filter_t *fnext;
1557 int freed = 0;
1558
1559 for ( ; f ; f = fnext ) {
1560 fnext = f->h.next;
1561 /* If not pointer to internal string, free it.. */
1562 #ifndef _FOR_VALGRIND_
1563 if (f->h.text != f->textbuf)
1564 hfree((void*)(f->h.text));
1565 cellfree(filter_cells, f);
1566 #else
1567 hfree(f);
1568 #endif
1569 freed++;
1570 }
1571
1572 rwl_wrlock(&filter_cellgauge_rwlock);
1573 filter_cellgauge -= freed;
1574 rwl_wrunlock(&filter_cellgauge_rwlock);
1575 }
1576
1577
1578 /*
1579
1580 #
1581 # Input: This[La] Source Latitude, in radians
1582 # This[Lo] Source Longitude, in radians
1583 # That[La] Destination Latitude, in radians
1584 # That[Lo] Destination Longitude, in radians
1585 # Output: R[s] Distance, in kilometers
1586 #
1587
1588 function maidenhead_km_distance($This, $That) {
1589
1590 #Haversine Formula (from R.W. Sinnott, "Virtues of the Haversine",
1591 #Sky and Telescope, vol. 68, no. 2, 1984, p. 159):
1592
1593 $dlon = $That[Lo] - $This[Lo];
1594 $dlat = $That[La] - $This[La];
1595
1596 $sinDlat2 = sin($dlat/2);
1597 $sinDlon2 = sin($dlon/2);
1598 $a = ($sinDlat2 * $sinDlat2 +
1599 cos($This[La]) * cos($That[La]) * $sinDlon2 * $sinDlon2);
1600
1601 # The Haversine Formula can be expressed in terms of a two-argument
1602 # inverse tangent function, atan2(y,x), instead of an inverse sine
1603 # as follows (no bulletproofing is needed for an inverse tangent):
1604
1605 $c = 2.0 * atan2( sqrt($a), sqrt(1.0-$a) );
1606 # $d = R * $c ; # Radius of ball times angle [radians] ...
1607
1608
1609 $R[s] = rad2deg($c) * 111.2;
1610
1611 return($R);
1612
1613 }
1614
1615 */
1616
maidenhead_km_distance(float lat1,float coslat1,float lon1,float lat2,float coslat2,float lon2)1617 static float maidenhead_km_distance(float lat1, float coslat1, float lon1, float lat2, float coslat2, float lon2)
1618 {
1619 float sindlat2 = sinf((lat1 - lat2) * 0.5);
1620 float sindlon2 = sinf((lon1 - lon2) * 0.5);
1621
1622 float a = (sindlat2 * sindlat2 +
1623 coslat1 * coslat2 * sindlon2 * sindlon2);
1624
1625 float c = 2.0 * atan2f( sqrtf(a), sqrtf(1.0 - a));
1626
1627 return ((111.2 * 180.0 / M_PI) * c);
1628 }
1629
1630
1631 /*
1632 *
1633 * http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm
1634 *
1635 */
1636
filter_process_one_a(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1637 static int filter_process_one_a(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1638 {
1639 /* a/latN/lonW/latS/lonE Area filter
1640
1641 The area filter works the same as range filter but the filter
1642 is defined as a box of coordinates. The coordinates can also
1643 been seen as upper left coordinate and lower right. Lat/lon
1644 are decimal degrees. South and west are negative.
1645
1646 Multiple area filters can be defined at the same time.
1647
1648 Messages addressed to stations within the area are also passed.
1649 (by means of aprs packet parse finding out the location..)
1650
1651 50-70 instances in APRS-IS core at any given time.
1652 Up to 2500 invocations per second.
1653 */
1654 ;
1655 if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
1656 return 0;
1657
1658 if ((pb->lat <= f->h.f_latN) &&
1659 (pb->lat >= f->h.f_latS) &&
1660 (pb->lng <= f->h.f_lonE) && /* East POSITIVE ! */
1661 (pb->lng >= f->h.f_lonW))
1662 /* Inside the box */
1663 return f->h.negation ? 2 : 1;
1664
1665 return 0;
1666 }
1667
filter_process_one_b(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1668 static int filter_process_one_b(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1669 {
1670 /* b/call1/call2... Budlist filter
1671
1672 Pass all traffic FROM exact call: call1, call2, ...
1673 (* wild card allowed)
1674
1675 50/70 instances in APRS-IS core at any given time.
1676 Up to 2500 invocations per second.
1677 */
1678
1679 struct filter_refcallsign_t ref;
1680 int i = pb->srccall_end - pb->data;
1681
1682 if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
1683
1684 /* source address "addr">... */
1685 memcpy( ref.callsign, pb->data, i);
1686 memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
1687
1688 int r = filter_match_on_callsignset(&ref, i, f, MatchWild);
1689
1690 /* match 3rd-party packets based on their innermost srccall,
1691 * only works on non-object/item currently
1692 */
1693 if (r == 0 && pb->srcname != pb->data && (pb->packettype & (T_OBJECT|T_ITEM)) == 0) {
1694 i = pb->srcname_len;
1695 if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
1696
1697 memcpy( ref.callsign, pb->srcname, i);
1698 memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
1699
1700 return filter_match_on_callsignset(&ref, i, f, MatchWild);
1701 }
1702
1703 return r;
1704 }
1705
filter_process_one_d(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1706 static int filter_process_one_d(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1707 {
1708 /* d/digi1/digi2... Digipeater filter
1709
1710 The digipeater filter will pass all packets that have been
1711 digipeated by a particular station(s) (the station's call
1712 is in the path, and a * is present in that callsign or
1713 a following callsign before the Q construct).
1714 This filter allows the * wildcard.
1715
1716 25-35 filters in use at any given time.
1717 Up to 1300 invocations per second.
1718 */
1719 struct filter_refcallsign_t ref;
1720 const char *d = pb->srccall_end + 1 + pb->dstcall_len + 1; /* viacall start */
1721 const char *q = pb->qconst_start-1;
1722 int rc, i, cl, j = 0;
1723 int found_call = 0;
1724
1725 /*hlog( LOG_INFO, "digifilter: '%.*s' -> '%.*s' q-d=%d",
1726 * (int)(pb->packet_len < 50 ? pb->packet_len : 50),
1727 * pb->data, (int)i, d, (int)(q-d) );
1728 */
1729
1730 for (i = 0; d < q; ) {
1731 ++j;
1732 if (j > 10) break; /* way too many callsigns... */
1733
1734 if (*d == ',') ++d; /* second round and onwards.. */
1735 /* find end of callsign */
1736 for (i = 0; i+d <= q && i <= CALLSIGNLEN_MAX; ++i) {
1737 if (d[i] == ',')
1738 break;
1739 }
1740
1741 //hlog(LOG_INFO, "d: -> (%d,%d) '%.*s'", (int)(d-pb->data), i, i, d);
1742
1743 /* When matching callsign, ignore trailing '*' */
1744 cl = i;
1745 if (d[cl-1] == '*')
1746 cl--;
1747
1748 if (cl > CALLSIGNLEN_MAX) cl = CALLSIGNLEN_MAX;
1749
1750 /* digipeater address ",addr," */
1751 memcpy( ref.callsign, d, cl);
1752 memset( ref.callsign+cl, 0, sizeof(ref.callsign)-cl );
1753
1754 rc = filter_match_on_callsignset(&ref, cl, f, MatchWild);
1755 if (rc) {
1756 if (rc == 1) {
1757 found_call = 1;
1758 break;
1759 }
1760 }
1761 d += i;
1762 }
1763
1764 if (!found_call)
1765 return 0;
1766
1767 /* Ok, we found the call. Check if it has a '*' in the end.
1768 * Or if one of the following calls does.
1769 *
1770 * d points to the start of this call, d[i-1] should be it's last character.
1771 */
1772
1773 if (d[cl] == '*')
1774 return 1;
1775
1776 /* continue looking from next callsign */
1777 d += i;
1778 while (d < q) {
1779 ++j;
1780 if (j > 10) break; /* way too many callsigns... */
1781
1782 if (*d == ',')
1783 d++;
1784
1785 /* find end of callsign */
1786 for (i = 0; i+d <= q && i <= CALLSIGNLEN_MAX; ++i) {
1787 if (d[i] == ',')
1788 break;
1789 }
1790
1791 //hlog(LOG_INFO, "d: -> (%d,%d) '%.*s'", (int)(d-pb->data), i, i, d);
1792
1793 /* Is there a trailing '*' in the call? */
1794 if (d[i-1] == '*')
1795 return 1;;
1796
1797 d += i;
1798 }
1799
1800 return 0;
1801 }
1802
filter_process_one_e(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1803 static int filter_process_one_e(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1804 {
1805 /* e/call1/call1/... Entry station filter
1806
1807 This filter passes all packets with the specified
1808 callsign-SSID(s) immediately following the q construct.
1809 This allows filtering based on receiving IGate, etc.
1810 Supports * wildcard.
1811
1812 2-6 instances in APRS-IS core at any given time.
1813 Up to 200 invocations per second.
1814 */
1815
1816 struct filter_refcallsign_t ref;
1817 const char *e = pb->qconst_start+4;
1818 int i = pb->entrycall_len;
1819
1820 if (i < 1) /* should not happen.. */
1821 return 0; /* Bad Entry-station callsign */
1822
1823 /* entry station address "qA*,addr," */
1824 memcpy( ref.callsign, e, i);
1825 memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
1826
1827 return filter_match_on_callsignset(&ref, i, f, MatchWild);
1828 }
1829
filter_process_one_f(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1830 static int filter_process_one_f(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1831 {
1832 /* f/call/dist Friend Range filter
1833 This is the same as the range filter except that the center is
1834 defined as the last known position of call.
1835
1836 Multiple friend filters can be defined at the same time.
1837
1838 Messages addressed to stations within the range are also passed.
1839 (by means of aprs packet parse finding out the location..)
1840
1841 NOTE: Could do static location resolving at connect time,
1842 and then use the same way as 'r' range does. The friends
1843 are rarely moving...
1844
1845 15-25 instances in APRS-IS core at any given time.
1846 Up to 900 invocations per second.
1847
1848 Caching the historydb_lookup() result will lower CPU power
1849 spent on the historydb.
1850 */
1851
1852 struct history_cell_t *history;
1853
1854 float r;
1855 float lat1, lon1, coslat1;
1856 float lat2, lon2, coslat2;
1857
1858 const char *callsign = f->h.refcallsign.callsign;
1859 int i = f->h.refcallsign.reflen;
1860
1861 if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
1862 return 0; /* No position data... */
1863
1864 /* find friend's last location packet */
1865 if (f->h.hist_age < tick || f->h.hist_age > tick + HIST_LOOKUP_INTERVAL) {
1866 i = historydb_lookup( callsign, i, &history );
1867 f->h.numnames = i;
1868 f->h.hist_age = tick + HIST_LOOKUP_INTERVAL;
1869 if (!i) return 0; /* no lookup result.. */
1870 f->h.f_latN = history->lat;
1871 f->h.f_lonE = history->lon;
1872 f->h.f_coslat = history->coslat;
1873 }
1874 if (!f->h.numnames) return 0; /* histdb lookup cache invalid */
1875
1876 lat1 = f->h.f_latN;
1877 lon1 = f->h.f_lonE;
1878 coslat1 = f->h.f_coslat;
1879
1880 lat2 = pb->lat;
1881 lon2 = pb->lng;
1882 coslat2 = pb->cos_lat;
1883
1884 r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
1885
1886 if (r < f->h.f_dist) /* Range is less than given limit */
1887 return (f->h.negation) ? 2 : 1;
1888
1889 return 0;
1890 }
1891
filter_process_one_g(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1892 static int filter_process_one_g(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1893 {
1894 /* g/call1/call1/... Test message recipient callsign filter
1895
1896 This filter passes all packets with the specified
1897 callsign-SSID(s) appearing as the text message
1898 recipient. Wildcards supported.
1899
1900 Appeared in javAPRSSrvr 4.0, not widely used.
1901 */
1902
1903 if ( (pb->packettype & T_MESSAGE) == 0 ) /* not a message */
1904 return 0;
1905
1906 struct filter_refcallsign_t ref;
1907 const char *e = pb->dstname;
1908 int i = pb->dstname_len;
1909
1910 if (i < 1) /* should not happen.. */
1911 return 0; /* Bad Entry-station callsign */
1912
1913 memcpy( ref.callsign, e, i);
1914 memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
1915
1916 return filter_match_on_callsignset(&ref, i, f, MatchWild);
1917 }
1918
filter_process_one_m(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1919 static int filter_process_one_m(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
1920 {
1921 /* m/dist My Range filter
1922 This is the same as the range filter except that the center is
1923 defined as the last known position of the logged in client.
1924 A client location stored in the client struct is used instead of
1925 the history database, since the filter should work for non-validated
1926 clients (such as aprsdroid new users which have not received their
1927 passcode quite yet). The historydb may only be updated by packets
1928 which are actually forwarded.
1929
1930 Messages addressed to stations within the range are also passed.
1931 (by means of aprs packet parse finding out the location..)
1932
1933 NOTE: MY RANGE is rarely moving, once there is a positional
1934 fix, it could stay fixed...
1935
1936 80-120 instances in APRS-IS core at any given time.
1937 Up to 4200 invocations per second.
1938
1939 Caching the historydb_lookup() result will lower CPU power
1940 spent on the historydb.
1941 */
1942
1943 float r;
1944 float lat1, lon1, coslat1;
1945 float lat2, lon2, coslat2;
1946 int i;
1947 struct history_cell_t *history;
1948
1949 if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
1950 return 0;
1951
1952 if (c->loc_known) {
1953 /* If client has sent a location, use it. The client may be an unvalidated
1954 * client which does not exist in the historydb.
1955 */
1956 r = maidenhead_km_distance(c->lat, c->cos_lat, c->lng, pb->lat, pb->cos_lat, pb->lng);
1957 if (r < f->h.f_dist) /* Range is less than given limit */
1958 return f->h.negation ? 2 : 1;
1959
1960 return 0;
1961 }
1962
1963 /* Otherwise, fall back to looking up from the historydb */
1964
1965 if (!*c->username) /* Should not happen... */
1966 return 0;
1967
1968 if (f->h.hist_age < tick || f->h.hist_age > tick + HIST_LOOKUP_INTERVAL) {
1969 i = historydb_lookup( c->username, strlen(c->username), &history );
1970 f->h.numnames = i;
1971 if (!i) {
1972 f->h.hist_age = tick + HIST_LOOKUP_INTERVAL/2;
1973 return 0; /* no result */
1974 }
1975 f->h.hist_age = tick + HIST_LOOKUP_INTERVAL;
1976 f->h.f_latN = history->lat;
1977 f->h.f_lonE = history->lon;
1978 f->h.f_coslat = history->coslat;
1979 }
1980
1981 if (!f->h.numnames)
1982 return 0; /* cached lookup invalid.. */
1983
1984 lat1 = f->h.f_latN;
1985 lon1 = f->h.f_lonE;
1986 coslat1 = f->h.f_coslat;
1987
1988 lat2 = pb->lat;
1989 lon2 = pb->lng;
1990 coslat2 = pb->cos_lat;
1991
1992 r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
1993 if (r < f->h.f_dist) /* Range is less than given limit */
1994 return f->h.negation ? 2 : 1;
1995
1996 return 0;
1997 }
1998
filter_process_one_o(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)1999 static int filter_process_one_o(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2000 {
2001 /* o/obj1/obj2... Object filter
2002 Pass all objects with the exact name of obj1, obj2, ...
2003 (* wild card allowed)
2004 PROBABLY ALSO ITEMs
2005
2006 Usage frequency: 0.2%
2007
2008 .. 2 cases in entire APRS-IS core at any time.
2009 About 50-70 invocations per second at peak.
2010 */
2011 struct filter_refcallsign_t ref;
2012 int i;
2013
2014 if ( (pb->packettype & (T_OBJECT|T_ITEM)) == 0 ) /* not an Object NOR Item */
2015 return 0;
2016
2017 /* parse_aprs() has picked item/object name pointer and length.. */
2018 i = pb->srcname_len;
2019 if (i < 1 || i > CALLSIGNLEN_MAX) return 0; /* Bad object/item name */
2020
2021 /* object name */
2022 memcpy( ref.callsign, pb->srcname, i);
2023 memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
2024
2025 return filter_match_on_callsignset(&ref, i, f, MatchWild);
2026 }
2027
filter_process_one_p(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2028 static int filter_process_one_p(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2029 {
2030
2031 /* p/aa/bb/cc... Prefix filter
2032 Pass traffic with fromCall that start with aa or bb or cc...
2033
2034 Usage frequency: 14.4%
2035
2036 .. 80-100 cases in entire APRS-IS core at any time.
2037 Up to 3500 invocations per second at peak.
2038 */
2039
2040 struct filter_refcallsign_t ref;
2041 int i = pb->srccall_end - pb->data;
2042
2043 if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
2044
2045 /* source address "addr">... */
2046 memcpy( ref.callsign, pb->data, i);
2047 memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
2048
2049 int r = filter_match_on_callsignset(&ref, i, f, MatchPrefix);
2050
2051 /* match 3rd-party packets based on their innermost srccall,
2052 * only works on non-object/item currently
2053 */
2054 if (r == 0 && pb->srcname != pb->data && (pb->packettype & (T_OBJECT|T_ITEM)) == 0) {
2055 i = pb->srcname_len;
2056
2057 if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
2058
2059 memcpy( ref.callsign, pb->srcname, i);
2060 memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
2061
2062 return filter_match_on_callsignset(&ref, i, f, MatchPrefix);
2063 }
2064
2065 return r;
2066 }
2067
filter_process_one_q(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2068 static int filter_process_one_q(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2069 {
2070 /* q/con/ana q Contruct filter
2071
2072 q = q Construct command
2073 con = list of q Construct to pass (case sensitive)
2074 ana = analysis based on q Construct.
2075
2076 I = Pass positions from IGATES identified by qAr or qAR.
2077
2078 For example:
2079 q/C Pass all traffic with qAC
2080 q/rR Pass all traffic with qAr or qAR
2081 q//I Pass all position packets from IGATES identified
2082 in other packets by qAr or qAR
2083
2084 Usage frequency: 0.4%
2085
2086 .. 2-6 cases in entire APRS-IS core at any time.
2087 Up to 200 invocations per second at peak.
2088 */
2089
2090 const char *e = pb->qconst_start+2;
2091 int mask;
2092
2093 switch (*e) {
2094 case 'C':
2095 mask = QC_C;
2096 break;
2097 case 'X':
2098 mask = QC_X;
2099 break;
2100 case 'U':
2101 mask = QC_U;
2102 break;
2103 case 'o':
2104 mask = QC_o;
2105 break;
2106 case 'O':
2107 mask = QC_O;
2108 break;
2109 case 'S':
2110 mask = QC_S;
2111 break;
2112 case 'r':
2113 mask = QC_r;
2114 break;
2115 case 'R':
2116 mask = QC_R;
2117 break;
2118 case 'Z':
2119 mask = QC_Z;
2120 break;
2121 case 'I':
2122 mask = QC_I;
2123 break;
2124 default:
2125 return 0; /* Should not happen... */
2126 break;
2127 }
2128
2129 if (f->h.bitflags & mask) {
2130 /* Something matched! */
2131 return 1;
2132 }
2133 if (f->h.bitflags & QC_AnalyticsI) {
2134 /* Oh ? Analytical!
2135 Has it ever been accepted into entry-igate database ? */
2136 if (filter_entrycall_lookup(pb))
2137 return 1; /* Found on entry-igate database! */
2138 }
2139
2140 return 0; /* No match */
2141 }
2142
2143
filter_process_one_r(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2144 static int filter_process_one_r(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2145 {
2146 /* r/lat/lon/dist Range filter
2147
2148 Pass posits and objects within dist km from lat/lon.
2149 lat and lon are signed degrees, i.e. negative for West/South
2150 and positive for East/North.
2151
2152 Multiple range filters can be defined at the same time.
2153
2154 Messages addressed to stations within the range are also passed.
2155 (by means of aprs packet parse finding out the location..)
2156
2157 About 120-150 r-filters in entire APRS-IS core at any given time.
2158 Up to 5200 invocations per second at peak.
2159 */
2160
2161 float lat1 = f->h.f_latN;
2162 float lon1 = f->h.f_lonE;
2163 float coslat1 = f->h.f_coslat;
2164 float r;
2165
2166 float lat2, lon2, coslat2;
2167
2168 if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
2169 return 0;
2170
2171 lat2 = pb->lat;
2172 lon2 = pb->lng;
2173 coslat2 = pb->cos_lat;
2174
2175 r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
2176
2177 // hlog(LOG_DEBUG, "r: lalo: %.4f %.4f / reflalo: %.4f %.4f / dist: %.2f", rad2deg(lat2),rad2deg(lon2), rad2deg(lat1), rad2deg(lon1), r);
2178
2179 if (r < f->h.f_dist) /* Range is less than given limit */
2180 return (f->h.negation) ? 2 : 1;
2181
2182 return 0;
2183 }
2184
filter_process_one_s(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2185 static int filter_process_one_s(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2186 {
2187 /* s/pri/alt/over Symbol filter
2188
2189 pri = symbols in primary table
2190 alt = symbols in alternate table
2191 over = overlay character (case sensitive)
2192
2193 For example:
2194 s/-> This will pass all House and Car symbols (primary table)
2195 s//# This will pass all Digi with or without overlay
2196 s//#/T This will pass all Digi with overlay of capital T
2197
2198 About 10-15 s-filters in entire APRS-IS core at any given time.
2199 Up to 520 invocations per second at peak.
2200 */
2201 const char symtable = (pb->symbol[0] == '/') ? '/' : '\\';
2202 const char symcode = pb->symbol[1];
2203 const char symolay = (pb->symbol[0] != symtable) ? pb->symbol[0] : 0;
2204
2205 // hlog( LOG_DEBUG, "s-filt %c|%c|%c %s", symtable, symcode, symolay ? symolay : '-', f->h.text );
2206
2207 if (f->h.len1 != 0) {
2208 /* Primary table symbols */
2209 if ( symtable == '/' &&
2210 memchr(f->h.text+f->h.len1s, symcode, f->h.len1) != NULL )
2211 return f->h.negation ? 2 : 1;
2212 // return 0;
2213 }
2214 if (f->h.lens.len3 != 0) {
2215 /* Secondary table with overlay */
2216 if ( memchr(f->h.text+f->h.lens.len3s, symolay, f->h.lens.len3) == NULL )
2217 return 0; // No match on overlay
2218 if ( memchr(f->h.text+f->h.lens.len2s, symcode, f->h.lens.len2) == NULL )
2219 return 0; // No match on overlay
2220 return f->h.negation ? 2 : 1;
2221 }
2222 /* OK, no overlay... */
2223 if (f->h.lens.len2 != 0) {
2224 /* Secondary table symbols */
2225 if ( symtable == '\\' &&
2226 memchr(f->h.text+f->h.lens.len2s, symcode, f->h.lens.len2) != NULL )
2227 return f->h.negation ? 2 : 1;
2228 }
2229 /* No match */
2230 return 0;
2231 }
2232
filter_process_one_t(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2233 static int filter_process_one_t(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2234 {
2235 /* [-]t/poimntqsu
2236 [-]t/poimntqsu/call/km
2237
2238 Type filter Pass all traffic based on packet type.
2239 One or more types can be defined at the same time, t/otq
2240 is a valid definition.
2241
2242 c = CWOP (local extension)
2243 * = ALL (local extension)
2244
2245 i = Items
2246 m = Message
2247 n = NWS Weather & Weather Objects
2248 o = Objects
2249 p = Position packets
2250 q = Query
2251 s = Status
2252 t = Telemetry
2253 u = User-defined
2254 w = Weather
2255
2256 Note: The weather type filter also passes positions packets
2257 for positionless weather packets.
2258
2259 The second format allows putting a radius limit around "call"
2260 (station callsign-SSID or object name) for the requested station
2261 types.
2262
2263 About 40-60 s-filters in entire APRS-IS core at any given time.
2264 Up to 2100 invocations per second at peak.
2265
2266 For the second format perhaps 2-3 in APRS-IS at any time.
2267 (mapping to 60-100 invocations per second)
2268
2269 Usage examples:
2270
2271 -t/c Everything except CWOP
2272 t/.*./OH2RDY/50 Everything within 50 km of OH2RDY's last known position
2273 ("." is dummy addition for C comments..)
2274 */
2275 int rc = 0;
2276 if (pb->packettype & f->h.bitflags) /* bitflags as comparison bitmask */
2277 rc = 1;
2278
2279 if (!rc && (f->h.bitflags & T_WX) && (pb->flags & F_HASPOS)) {
2280 /* "Note: The weather type filter also passes positions packets
2281 // for positionless weather packets."
2282 //
2283 // 1) recognize positionless weather packets
2284 // 2) register their source callsigns, do this in input_parse
2285 // 3) when filtering for weather data, check non-weather
2286 // recognized packets against the database in point 2
2287 // 4) pass on packets matching point 3
2288 */
2289
2290 rc = filter_wx_lookup(pb);
2291 }
2292 /* Either it stops here, or it continues... */
2293
2294 if (rc && f->h.type == 'T') { /* Within a range of callsign ?
2295 * Rather rare.. perhaps 2-3 in APRS-IS.
2296 */
2297 const char *callsign = f->h.refcallsign.callsign;
2298 const int callsignlen = f->h.refcallsign.reflen;
2299 float range, r;
2300 float lat1, lon1, coslat1;
2301 float lat2, lon2, coslat2;
2302 struct history_cell_t *history;
2303 int i;
2304
2305 /* hlog(LOG_DEBUG, "Type filter with callsign range used! '%s'", f->h.text); */
2306
2307 if (!(pb->flags & F_HASPOS)) /* packet with a position.. (msgs with RECEIVER's position) */
2308 return 0; /* No positional data.. */
2309
2310 range = f->h.f_dist;
2311
2312 /* So.. Now we have a callsign, and we have range.
2313 Lets find callsign's location, and range to that item..
2314 .. 60-100 lookups per second. */
2315
2316 if (f->h.hist_age < tick || f->h.hist_age > tick + HIST_LOOKUP_INTERVAL) {
2317 i = historydb_lookup( callsign, callsignlen, &history );
2318 f->h.numnames = i;
2319
2320 /* hlog( LOG_DEBUG, "Type filter with callsign range used! call='%s', range=%.1f position %sfound",
2321 // callsign, range, i ? "" : "not ");
2322 */
2323
2324
2325 if (!i) return 0; /* no lookup result.. */
2326 f->h.hist_age = tick + HIST_LOOKUP_INTERVAL;
2327 f->h.f_latN = history->lat;
2328 f->h.f_lonE = history->lon;
2329 f->h.f_coslat = history->coslat;
2330 }
2331 if (!f->h.numnames) return 0; /* No valid data at range center position cache */
2332
2333 lat1 = f->h.f_latN;
2334 lon1 = f->h.f_lonE;
2335 coslat1 = f->h.f_coslat;
2336
2337 lat2 = pb->lat;
2338 lon2 = pb->lng;
2339 coslat2 = pb->cos_lat;
2340
2341 r = maidenhead_km_distance(lat1, coslat1, lon1, lat2, coslat2, lon2);
2342
2343 if (r < range) /* Range is less than given limit */
2344 return (f->h.negation) ? 2 : 1;
2345
2346 return 0; /* unimplemented! */
2347 }
2348
2349 return (f->h.negation ? (rc+rc) : rc);
2350 }
2351
filter_process_one_u(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2352 static int filter_process_one_u(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2353 {
2354 /* u/unproto1/unproto2/... Unproto filter
2355
2356 This filter passes all packets with the specified destination
2357 callsign-SSID(s) (also known as the To call or unproto call).
2358 Supports * wild card.
2359
2360 Seen hardly ever in APRS-IS core, some rare instances in Tier-2.
2361 */
2362
2363 struct filter_refcallsign_t ref;
2364 const char *d = pb->srccall_end+1;
2365 int i;
2366
2367 i = pb->dstcall_len;
2368
2369 if (i > CALLSIGNLEN_MAX) i = CALLSIGNLEN_MAX;
2370
2371 /* hlog( LOG_INFO, "unproto: '%.*s' -> '%.*s'",
2372 // (int)(pb->packet_len < 30 ? pb->packet_len : 30), pb->data, (int)i, d);
2373 */
2374
2375 /* destination address ">addr," */
2376 memcpy( ref.callsign, d, i);
2377 memset( ref.callsign+i, 0, sizeof(ref.callsign)-i );
2378
2379 return filter_match_on_callsignset(&ref, i, f, MatchWild);
2380 }
2381
filter_process_one(struct client_t * c,struct pbuf_t * pb,struct filter_t * f)2382 static int filter_process_one(struct client_t *c, struct pbuf_t *pb, struct filter_t *f)
2383 {
2384 int rc = 0;
2385
2386 switch (f->h.type) {
2387
2388 case 'a':
2389 case 'A':
2390 rc = filter_process_one_a(c, pb, f);
2391 break;
2392
2393 case 'b':
2394 case 'B':
2395 rc = filter_process_one_b(c, pb, f);
2396 break;
2397
2398 case 'd':
2399 case 'D':
2400 rc = filter_process_one_d(c, pb, f);
2401 break;
2402
2403 case 'e':
2404 case 'E':
2405 rc = filter_process_one_e(c, pb, f);
2406 break;
2407
2408 case 'f':
2409 case 'F':
2410 rc = filter_process_one_f(c, pb, f);
2411 break;
2412
2413 case 'g':
2414 case 'G':
2415 rc = filter_process_one_g(c, pb, f);
2416 break;
2417
2418 case 'm':
2419 case 'M':
2420 rc = filter_process_one_m(c, pb, f);
2421 break;
2422
2423 case 'o':
2424 case 'O':
2425 rc = filter_process_one_o(c, pb, f);
2426 break;
2427
2428 case 'p':
2429 case 'P':
2430 rc = filter_process_one_p(c, pb, f);
2431 break;
2432
2433 case 'q':
2434 case 'Q':
2435 rc = filter_process_one_q(c, pb, f);
2436 break;
2437
2438 case 'r':
2439 case 'R':
2440 rc = filter_process_one_r(c, pb, f);
2441 break;
2442
2443 case 's':
2444 case 'S':
2445 rc = filter_process_one_s(c, pb, f);
2446 break;
2447
2448 case 't':
2449 case 'T':
2450 rc = filter_process_one_t(c, pb, f);
2451 break;
2452
2453 case 'u':
2454 case 'U':
2455 rc = filter_process_one_u(c, pb, f);
2456 break;
2457
2458 default:
2459 rc = -1;
2460 break;
2461 }
2462 //hlog(LOG_DEBUG, "filter '%s' rc=%d", f->h.text, rc);
2463
2464 return rc;
2465 }
2466
filter_process(struct worker_t * self,struct client_t * c,struct pbuf_t * pb)2467 int filter_process(struct worker_t *self, struct client_t *c, struct pbuf_t *pb)
2468 {
2469 struct filter_t *f;
2470
2471 /* messaging support: if (1) this is a text message,
2472 * (2) the client is an igate port,
2473 * and (3) the message's recipient has been heard
2474 * recently on the port, gate the message.
2475 */
2476 if (c->flags & CLFLAGS_IGATE) {
2477 if (pb->packettype & T_MESSAGE) {
2478 if (
2479 (pb->dstname_len == c->username_len && memcmp(pb->dstname, c->username, c->username_len) == 0)
2480 || (client_heard_check(c, pb->dstname, pb->dstname_len, pb->dstname_hash))
2481 ) {
2482 /* insert the source callsign to the courtesy position list */
2483 client_courtesy_update(c, pb);
2484 return 1;
2485 }
2486 }
2487 /* Courtesy position: if a message from this source callsign has been
2488 * passed to this socket within 30 minutes, do pass on the next
2489 * single position packet, too.
2490 */
2491 if (pb->packettype & (T_POSITION|T_OBJECT|T_ITEM)
2492 && client_courtesy_needed(c, pb)) {
2493 FILTER_CLIENT_DEBUG(self, c, "# courtesy position after message\r\n", NULL);
2494 return 1;
2495 }
2496 /* If the source callsign of a packet having TCPIP* in the path has been
2497 * recently heard on this socket, do pass on the packets to this socket too.
2498 * This lets igates know that the station is also available on the Internet,
2499 * and no TX igating to RF should be done.
2500 */
2501 if ((pb->flags & F_HAS_TCPIP) && client_heard_check(c, pb->data, pb->srccall_end - pb->data, pb->srccall_hash)) {
2502 FILTER_CLIENT_DEBUG(self, c, "# igate support TCPIP* packet from a heard station\r\n", NULL);
2503 return 1;
2504 }
2505 }
2506
2507 f = c->negdefaultfilters;
2508 for ( ; f; f = f->h.next ) {
2509 int rc = filter_process_one(c, pb, f);
2510 /* no reports to user about bad filters.. */
2511 if (rc > 0)
2512 return 0; // match on filter - no output on client
2513 }
2514
2515 f = c->posdefaultfilters;
2516 for ( ; f; f = f->h.next ) {
2517 int rc = filter_process_one(c, pb, f);
2518 /* no reports to user about bad filters.. */
2519 if (rc > 0) {
2520 FILTER_CLIENT_DEBUG(self, c, "# matched server default filter %s\r\n", f->h.text);
2521 return rc;
2522 }
2523 }
2524
2525 f = c->neguserfilters;
2526 for ( ; f; f = f->h.next ) {
2527 int rc = filter_process_one(c, pb, f);
2528 if (rc < 0) {
2529 rc = client_bad_filter_notify(self, c, f->h.text);
2530 if (rc < 0) /* possibly the client got destroyed here! */
2531 return rc;
2532 }
2533 if (rc > 0) {
2534 FILTER_CLIENT_DEBUG(self, c, "# matched negative filter %s\r\n", f->h.text);
2535 return 0; // match on filter - no output on client
2536 }
2537 }
2538
2539 f = c->posuserfilters;
2540 for ( ; f; f = f->h.next ) {
2541 int rc = filter_process_one(c, pb, f);
2542 if (rc < 0) {
2543 rc = client_bad_filter_notify(self, c, f->h.text);
2544 if (rc < 0) /* possibly the client got destroyed here! */
2545 return rc;
2546 }
2547 if (rc > 0) {
2548 FILTER_CLIENT_DEBUG(self, c, "# matched filter %s\r\n", f->h.text);
2549 return rc;
2550 }
2551 }
2552
2553 return 0;
2554 }
2555
2556 /*
2557 * Send a reply to a filter command, either using a message or through a comment
2558 * line on the IS stream
2559 */
2560
filter_command_reply(struct worker_t * self,struct client_t * c,int in_message,const char * fmt,...)2561 static int filter_command_reply(struct worker_t *self, struct client_t *c, int in_message, const char *fmt, ...)
2562 {
2563 va_list args;
2564 char s[PACKETLEN_MAX];
2565
2566 va_start(args, fmt);
2567 vsnprintf(s, PACKETLEN_MAX, fmt, args);
2568 va_end(args);
2569
2570 if (!in_message)
2571 return client_printf(self, c, "# %s\r\n", s);
2572
2573 return messaging_message_client(self, c, "%s", s);
2574 }
2575
2576 /*
2577 * filter_commands() implements treatment for incoming client filter requests.
2578 *
2579 * Return value propagates negative returns from things like client_write()
2580 * indicating the struct client_t * object being destroyed.
2581 */
filter_commands(struct worker_t * self,struct client_t * c,int in_message,const char * s,int len)2582 int filter_commands(struct worker_t *self, struct client_t *c, int in_message, const char *s, int len)
2583 {
2584 char *argv[256];
2585 struct filter_t *f;
2586 char *b, *p;
2587 int i, argc;
2588
2589 /* skip over the #filter in the beginning of the command */
2590 len -= 6;
2591 s += 6;
2592
2593 if ( *s == '?' && len == 1 ) {
2594 /* Query current filters */
2595 int lensum = 0;
2596
2597 for (f = c->neguserfilters; f; f = f->h.next) {
2598 lensum += 2 + strlen(f->h.text);
2599 }
2600 for (f = c->posuserfilters; f; f = f->h.next) {
2601 lensum += 2 + strlen(f->h.text);
2602 }
2603
2604 p = b = alloca(lensum+20);
2605 p += sprintf(b, "# filters: ");
2606 for (f = c->neguserfilters; f; f = f->h.next) {
2607 p += sprintf(p, "%s ", f->h.text);
2608 }
2609 for (f = c->posuserfilters; f; f = f->h.next) {
2610 p += sprintf(p, "%s ", f->h.text);
2611 }
2612 p += sprintf(p, "\r\n");
2613 /* client can be destroyed here.. */
2614 return c->write(self, c, b, (int)(p-b));
2615 }
2616 if (*s != ' ') {
2617 return filter_command_reply(self, c, in_message, "Filter: Bad input, no space character after filter command");
2618 }
2619 ++s;
2620 --len;
2621
2622 if ( strncasecmp(s, "default", 7) == 0 && len == 7 ) {
2623 /* discard any user defined filters that possibly were
2624 injected on this connection. */
2625 f = c->neguserfilters;
2626 filter_free(f);
2627 c->neguserfilters = NULL;
2628
2629 f = c->posuserfilters;
2630 filter_free(f);
2631 c->posuserfilters = NULL;
2632 // FIXME: Sleep a bit ? ... no, that would be a way to create a denial of service attack
2633 // FIXME: there is a danger of SEGV-blowing filter processing...
2634 return filter_command_reply(self, c, in_message, "User filters reset to default");
2635 }
2636
2637 /* new filter definitions to supersede previous ones */
2638
2639 /* Discard old ones. */
2640 f = c->neguserfilters;
2641 filter_free(f);
2642 c->neguserfilters = NULL;
2643
2644 f = c->posuserfilters;
2645 c->posuserfilters = NULL;
2646 filter_free(f);
2647 // FIXME: Sleep a bit ? ... no, that would be a way to create a denial of service attack
2648 // FIXME: there is a danger of SEGV-blowing filter processing...
2649
2650 b = hmalloc(len+2);
2651 memcpy(b, s, len);
2652 b[len] = 0;
2653
2654 // archive a copy of the filters, for status display
2655 strncpy(c->filter_s, b, FILTER_S_SIZE);
2656 c->filter_s[FILTER_S_SIZE-1] = 0;
2657 sanitize_ascii_string(c->filter_s);
2658
2659 argc = parse_args( argv, b );
2660 for (i = 0; i < argc; ++i) {
2661 filter_parse(c, argv[i], 1); /* user filters */
2662 }
2663 hfree(b);
2664
2665 return filter_command_reply(self, c, in_message, "filter %s active", c->filter_s);
2666 }
2667
2668 /*
2669 * cellmalloc status
2670 */
2671
2672 #ifndef _FOR_VALGRIND_
filter_cell_stats(struct cellstatus_t * filter_cellst,struct cellstatus_t * filter_entrycall_cellst,struct cellstatus_t * filter_wx_cellst)2673 void filter_cell_stats(struct cellstatus_t *filter_cellst,
2674 struct cellstatus_t *filter_entrycall_cellst,
2675 struct cellstatus_t *filter_wx_cellst)
2676 {
2677 cellstatus(filter_cells, filter_cellst);
2678 cellstatus(filter_entrycall_cells, filter_entrycall_cellst);
2679 cellstatus(filter_wx_cells, filter_wx_cellst);
2680 }
2681 #endif
2682