1 /*
2  *	aprsc
3  *
4  *	(c) Heikki Hannikainen, OH7LZB <hessu@hes.iki.fi>
5  *
6  *     This program is licensed under the BSD license, which can be found
7  *     in the file LICENSE.
8  *
9  */
10 
11 /*
12  *	incoming.c: processes incoming data within the worker thread
13  */
14 
15 #include "ac-hdrs.h"
16 
17 #define _GNU_SOURCE
18 #include <string.h>
19 #include <strings.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <fnmatch.h>
25 
26 #ifdef HAVE_ALLOCA_H
27 #include <alloca.h>
28 #endif
29 
30 #include <stdlib.h>
31 
32 #include "config.h"
33 #include "incoming.h"
34 #include "hlog.h"
35 #include "parse_aprs.h"
36 #include "parse_qc.h"
37 #include "filter.h"
38 #include "clientlist.h"
39 #include "client_heard.h"
40 #include "version.h"
41 #include "cellmalloc.h"
42 #include "messaging.h"
43 #include "dupecheck.h"
44 
45 /* When adding labels here, remember to add the description strings in
46  * web/aprsc.js rx_err_strings, and worker.h constants
47  */
48 const char *inerr_labels[] = {
49 	"unknown",
50 	"no_colon",
51 	"no_dst",
52 	"no_path",
53 	"inv_srccall",
54 	"no_body",
55 	"inv_dstcall",
56 	"disallow_unverified",
57 	"disallow_unverified_path",
58 	"path_nogate",
59 	"party_3rd_ip", /* was 3rd_party, but labels starting with numbers collide with munin */
60 	"party_3rd_inv",
61 	"general_query",
62 	"aprsc_oom_pbuf",
63 	"aprsc_class_fail",
64 	"aprsc_q_bug",
65 	"q_drop",
66 	"short_packet",
67 	"long_packet",
68 	"inv_path_call",
69 	"q_qax",
70 	"q_qaz",
71 	"q_path_mycall",
72 	"q_path_call_twice",
73 	"q_path_login_not_last",
74 	"q_path_call_is_local",
75 	"q_path_call_inv",
76 	"q_qau_path_call_srccall",
77 	"q_newq_buffer_small",
78 	"q_nonval_multi_q_calls",
79 	"q_i_no_viacall",
80 	"q_disallow_protocol",
81 	"inerr_empty",
82 	"disallow_srccall",
83 	"disallow_dx",
84 	"disallow_msg_dst"
85 };
86 
87 #define incoming_strerror(i) ((i <= 0 && i >= INERR_MIN) ? inerr_labels[i * -1] : inerr_labels[0])
88 
89 
90 /* a static list of source callsigns which are dropped */
91 static char *disallow_srccalls[] = {
92 	"N0CALL", /* default in some apps */
93 	"NOCALL", /* default in some apps */
94 	"SERVER", /* originated by APRS-IS server */
95 	NULL
96 };
97 
98 #ifdef _FOR_VALGRIND_
99 typedef struct cellarena_t {
100   int dummy;
101 } cellarena_t;
102 #endif
103 /* global packet buffer freelists */
104 
105 cellarena_t *pbuf_cells_small;
106 cellarena_t *pbuf_cells_medium;
107 cellarena_t *pbuf_cells_large;
108 
109 int pbuf_cells_kb = 2048; /* 2M bunches is faster for system than 16M ! */
110 
111 /*
112  *	Get a buffer for a packet
113  *
114  *	pbuf_t buffers are accumulated into each worker local buffer in small sets,
115  *	and then used from there.  The buffers are returned into global pools.
116  */
117 
pbuf_init(void)118 void pbuf_init(void)
119 {
120 #ifndef _FOR_VALGRIND_
121 	pbuf_cells_small  = cellinit( "pbuf small",
122 				      sizeof(struct pbuf_t) + PACKETLEN_MAX_SMALL,
123 				      __alignof__(struct pbuf_t), CELLMALLOC_POLICY_FIFO,
124 				      pbuf_cells_kb /* n kB at the time */, 0 /* minfree */ );
125 	pbuf_cells_medium = cellinit( "pbuf medium",
126 				      sizeof(struct pbuf_t) + PACKETLEN_MAX_MEDIUM,
127 				      __alignof__(struct pbuf_t), CELLMALLOC_POLICY_FIFO,
128 				      pbuf_cells_kb /* n kB at the time */, 0 /* minfree */ );
129 	pbuf_cells_large  = cellinit( "pbuf large",
130 				      sizeof(struct pbuf_t) + PACKETLEN_MAX_LARGE,
131 				      __alignof__(struct pbuf_t), CELLMALLOC_POLICY_FIFO,
132 				      pbuf_cells_kb /* n kB at the time */, 0 /* minfree */ );
133 #endif
134 }
135 
136 /*
137  *	pbuf_free  sends buffer back to worker local pool, or when invoked
138  *	without 'self' pointer, like in final history buffer cleanup,
139  *	to the global pool.
140  */
141 
pbuf_free(struct worker_t * self,struct pbuf_t * p)142 void pbuf_free(struct worker_t *self, struct pbuf_t *p)
143 {
144 	if (self) { /* Return to worker local pool */
145 
146 		// hlog(LOG_DEBUG, "pbuf_free(%p) for worker %p - packet length: %d", p, self, p->buf_len);
147 
148 		switch (p->buf_len) {
149 		case PACKETLEN_MAX_SMALL:
150 			p->next = self->pbuf_free_small;
151 			self->pbuf_free_small = p;
152 			break;
153 		case PACKETLEN_MAX_MEDIUM:
154 			p->next = self->pbuf_free_medium;
155 			self->pbuf_free_medium = p;
156 			break;
157 		case PACKETLEN_MAX_LARGE:
158 			p->next = self->pbuf_free_large;
159 			self->pbuf_free_large = p;
160 			break;
161 		default:
162 			hlog(LOG_ERR, "pbuf_free(%p) for worker %p - packet length not known: %d", p, self, p->buf_len);
163 			break;
164 		}
165 		return;
166 	}
167 
168 #ifndef _FOR_VALGRIND_
169 
170 	/* Not worker local processing then, return to global pools. */
171 
172 	// hlog(LOG_DEBUG, "pbuf_free(%p) for global pool - packet length: %d", p, p->buf_len);
173 
174 	switch (p->buf_len) {
175 	case PACKETLEN_MAX_SMALL:
176 		cellfree(pbuf_cells_small, p);
177 		break;
178 	case PACKETLEN_MAX_MEDIUM:
179 		cellfree(pbuf_cells_medium, p);
180 		break;
181 	case PACKETLEN_MAX_LARGE:
182 		cellfree(pbuf_cells_large, p);
183 		break;
184 	default:
185 		hlog(LOG_ERR, "pbuf_free(%p) - packet length not known: %d", p, p->buf_len);
186 		break;
187 	}
188 	return;
189 #else
190 	hfree(p);
191 	return;
192 #endif
193 }
194 
195 /*
196  *	pbuf_free_many  sends buffers back to the global pool in groups
197  *                      after size sorting them...
198  *			Multiple cells are returned with single mutex.
199  */
200 
pbuf_free_many(struct pbuf_t ** array,int numbufs)201 void pbuf_free_many(struct pbuf_t **array, int numbufs)
202 {
203 	int i;
204 	void **arraysmall   = alloca(sizeof(void*)*numbufs);
205 	void **arraymedium  = alloca(sizeof(void*)*numbufs);
206 	void **arraylarge   = alloca(sizeof(void*)*numbufs);
207 	int smallcnt = 0, mediumcnt = 0, largecnt = 0;
208 
209 	for (i = 0; i < numbufs; ++i) {
210 		array[i]->is_free = 1;
211 		//__sync_synchronize();
212 		switch (array[i]->buf_len) {
213 		case PACKETLEN_MAX_SMALL:
214 			arraysmall [smallcnt++]  = array[i];
215 			break;
216 		case PACKETLEN_MAX_MEDIUM:
217 			arraymedium[mediumcnt++] = array[i];
218 			break;
219 		case PACKETLEN_MAX_LARGE:
220 			arraylarge [largecnt++]  = array[i];
221 			break;
222 		default:
223 		  hlog( LOG_ERR, "pbuf_free_many(%p) - packet length not known: %d :%d",
224 			array[i], array[i]->buf_len, array[i]->packet_len );
225 			break;
226 		}
227 	}
228 
229 	// hlog( LOG_DEBUG, "pbuf_free_many(); counts: small %d large %d huge %d", smallcnt, mediumcnt, largecnt );
230 
231 #ifndef _FOR_VALGRIND_
232 	if (smallcnt > 0)
233 		cellfreemany(pbuf_cells_small,  arraysmall,  smallcnt);
234 	if (mediumcnt > 0)
235 		cellfreemany(pbuf_cells_medium, arraymedium, mediumcnt);
236 	if (largecnt > 0)
237 		cellfreemany(pbuf_cells_large,  arraylarge,  largecnt);
238 
239 #else
240 	for (i = 0; i < numbufs; ++i) {
241 		hfree(array[i]);
242 	}
243 #endif
244 }
245 
246 /*
247  *	pbuf_dump_*: tools to dump packet buffers to a file
248  */
249 
pbuf_dump_entry(FILE * fp,struct pbuf_t * pb)250 static void pbuf_dump_entry(FILE *fp, struct pbuf_t *pb)
251 {
252 	fprintf(fp, "%ld\t",	(long)pb->t); /* arrival time */
253 	fprintf(fp, "%x\t",	pb->packettype);
254 	fprintf(fp, "%x\t",	pb->flags);
255       	fprintf(fp, "%.*s\t",	pb->srcname_len, pb->srcname);
256 	fprintf(fp, "%f\t%f\t",	pb->lat, pb->lng);
257 	fprintf(fp, "%d\t",     pb->packet_len);
258 	fwrite(pb->data, pb->packet_len-2, 1, fp); /* without terminating CRLF */
259 	fprintf(fp, "\n");
260 }
261 
pbuf_dump(FILE * fp)262 void pbuf_dump(FILE *fp)
263 {
264 	/* Dump the pbuf queue out on text format */
265 	struct pbuf_t *pb = pbuf_global;
266 
267 	for ( ; pb ; pb = pb->next ) {
268 		pbuf_dump_entry(fp, pb);
269 	}
270 }
271 
pbuf_dupe_dump(FILE * fp)272 void pbuf_dupe_dump(FILE *fp)
273 {
274 	/* Dump the pbuf queue out on text format */
275 	struct pbuf_t *pb = pbuf_global_dupe;
276 
277 	for ( ; pb ; pb = pb->next ) {
278 		pbuf_dump_entry(fp, pb);
279 	}
280 }
281 
282 /*
283  *	get a buffer for an incoming packet, from either a thread-local
284  *	freelist of preallocated buffers, or from the global cellmalloc
285  *	area.
286  */
287 
pbuf_get(struct worker_t * self,int len)288 static struct pbuf_t *pbuf_get(struct worker_t *self, int len)
289 {
290 	struct pbuf_t *pb;
291 	int i;
292 	struct pbuf_t **allocarray;
293 	struct pbuf_t **pool;
294 	cellarena_t *global_pool;
295 	int bunchlen;
296 
297 	/* select which thread-local freelist to use */
298 	if (len <= PACKETLEN_MAX_SMALL) {
299 		//hlog(LOG_DEBUG, "pbuf_get: Allocating small buffer for a packet of %d bytes", len);
300 		pool        = &self->pbuf_free_small;
301 		global_pool = pbuf_cells_small;
302 		len         = PACKETLEN_MAX_SMALL;
303 		bunchlen    = PBUF_ALLOCATE_BUNCH_SMALL;
304 	} else if (len <= PACKETLEN_MAX_MEDIUM) {
305 		//hlog(LOG_DEBUG, "pbuf_get: Allocating large buffer for a packet of %d bytes", len);
306 		pool        = &self->pbuf_free_medium;
307 		global_pool = pbuf_cells_medium;
308 		len         = PACKETLEN_MAX_MEDIUM;
309 		bunchlen    = PBUF_ALLOCATE_BUNCH_MEDIUM;
310 	} else if (len <= PACKETLEN_MAX_LARGE) {
311 		//hlog(LOG_DEBUG, "pbuf_get: Allocating huge buffer for a packet of %d bytes", len);
312 		pool        = &self->pbuf_free_large;
313 		global_pool = pbuf_cells_large;
314 		len         = PACKETLEN_MAX_LARGE;
315 		bunchlen    = PBUF_ALLOCATE_BUNCH_LARGE;
316 	} else { /* too large! */
317 		hlog(LOG_ERR, "pbuf_get: Not allocating a buffer for a packet of %d bytes!", len);
318 		return NULL;
319 	}
320 
321 	allocarray = alloca(bunchlen * sizeof(void*));
322 
323 	if (*pool) {
324 		/* fine, just get the first buffer from the freelist pool...
325 		 * the pool is not doubly linked (not necessary)
326 		 */
327 		pb = *pool;
328 		*pool = pb->next;
329 
330 		/* zero all header fields */
331 		memset(pb, 0, sizeof(*pb));
332 
333 		/* we know the length in this sub-pool, set it */
334 		pb->buf_len = len;
335 
336 		// hlog(LOG_DEBUG, "pbuf_get(%d): got one buf from local pool: %p", len, pb);
337 
338 		return pb;
339 	}
340 
341 #ifndef _FOR_VALGRIND_
342 	/* The local list is empty... get buffers from the global list. */
343 
344 	bunchlen = cellmallocmany( global_pool, (void**)allocarray, bunchlen );
345 	if (bunchlen < 1) {
346 		hlog(LOG_CRIT, "aprsc: Out of memory: Could not allocate packet buffers!");
347 		return NULL;
348 	}
349 
350 	for ( i = 1;  i < bunchlen; ++i ) {
351 		pb = allocarray[i];
352 		pb->is_free = 0;
353 		pb->next    = *pool;
354 		pb->buf_len = len; // this is necessary for worker local pool discard at worker shutdown
355 		*pool = pb;
356 	}
357 
358 	pb = allocarray[0];
359 
360 	// hlog(LOG_DEBUG, "pbuf_get(%d): got %d bufs from global pool %p", len, bunchlen, pool);
361 
362 	/* ok, return the first buffer from the pool */
363 
364 	/* zero all header fields */
365 	memset(pb, 0, sizeof(*pb));
366 
367 	/* we know the length in this sub-pool, set it */
368 	pb->buf_len = len;
369 
370 	return pb;
371 
372 #else /* Valgrind -version of things */
373 
374 
375 	/* The local list is empty... get buffers from the global list. */
376 
377 	int sz = sizeof(struct pbuf_t) + len;
378 
379 	for ( i = 1;  i < bunchlen; ++i ) {
380 		pb = hmalloc(sz);
381 		pb->next = *pool;
382 		pb->buf_len = len; // for valgrind this is not necessary.. but exists for symmetry's sake
383 		*pool = pb;
384 	}
385 
386 	pb = hmalloc(sz);
387 
388 	memset(pb, 0, sz);
389 	pb->buf_len = len;
390 
391 	// hlog(LOG_DEBUG, "pbuf_get_real(%d): got %d bufs to local pool, returning %p", len, bunchlen, pb);
392 
393 	return pb;
394 #endif
395 }
396 
397 
398 
399 /*
400  *	Move incoming packets from the thread-local incoming buffer
401  *	(self->pbuf_incoming_local) to self->incoming local for the
402  *	dupecheck thread to catch them
403  */
404 
incoming_flush(struct worker_t * self)405 void incoming_flush(struct worker_t *self)
406 {
407 	int me;
408 
409 	/* try grab the lock.. if it fails, we'll try again, either
410 	 * in 200 milliseconds or after next input
411 	 */
412 	if (pthread_mutex_trylock(&self->pbuf_incoming_mutex) != 0)
413 		return;
414 
415 	*self->pbuf_incoming_last = self->pbuf_incoming_local;
416 	self->pbuf_incoming_last  = self->pbuf_incoming_local_last;
417 	self->pbuf_incoming_count += self->pbuf_incoming_local_count;
418         if ((me = pthread_mutex_unlock(&self->pbuf_incoming_mutex))) {
419                 hlog(LOG_ERR, "incoming: could not unlock pbuf_incoming_mutex: %s", strerror(me));
420         }
421 
422 	//hlog( LOG_DEBUG, "incoming_flush() sent out %d packets", self->pbuf_incoming_local_count );
423 
424 #ifdef USE_EVENTFD
425 	/* wake up dupecheck from sleep */
426 	uint64_t u = 1; // could set to pbuf_incoming_local_count, but it wouldn't be used for anything.
427 	int i = write(dupecheck_eventfd, &u, sizeof(uint64_t));
428 	if (i != sizeof(uint64_t)) {
429 		hlog(LOG_ERR, "incoming_flush() failed to write to dupecheck_eventfd: %s", strerror(errno));
430 	}
431 #endif
432 
433 	/* clean the local lockfree queue */
434 	self->pbuf_incoming_local = NULL;
435 	self->pbuf_incoming_local_last = &self->pbuf_incoming_local;
436 	self->pbuf_incoming_local_count = 0;
437 }
438 
439 /*
440  *	Find a string in a binary buffer, case insensitive
441  */
442 
memcasestr(char * needle,char * haystack,char * haystack_end)443 static char *memcasestr(char *needle, char *haystack, char *haystack_end)
444 {
445 	char *hp = haystack;
446 	char *np = needle;
447 	char *match_start = NULL;
448 
449 	while (hp < haystack_end) {
450 		if (toupper(*hp) == toupper(*np)) {
451 			/* matching... is this the start of a new match? */
452 			if (match_start == NULL)
453 				match_start = hp;
454 			/* increase needle pointer, so we'll check the next char */
455 			np++;
456 		} else {
457 			/* not matching... clear state */
458 			match_start = NULL;
459 			np = needle;
460 		}
461 
462 		/* if we've reached the end of the needle, and we have found a match,
463 		 * return a pointer to it
464 		 */
465 		if (*np == 0 && (match_start))
466 			return match_start;
467 		hp++;
468 	}
469 
470 	/* out of luck */
471 	return NULL;
472 }
473 
474 /*
475  *	Check if the digipeater path includes elements indicating that the
476  *	packet should be dropped.
477  */
478 
digi_path_drop(char * via_start,int via_len)479 static int digi_path_drop(char *via_start, int via_len)
480 {
481 	if (memmem(via_start, via_len, ",NOGATE", 7))
482 		return 1;
483 
484 	if (memmem(via_start, via_len, ",RFONLY", 7))
485 		return 1;
486 
487 	return 0;
488 }
489 
490 /*
491  *	Check if a callsign is good for srccall/dstcall
492  *	(valid APRS-IS callsign, * not allowed)
493  */
494 
check_invalid_src_dst(const char * call,int len)495 int check_invalid_src_dst(const char *call, int len)
496 {
497 	//hlog(LOG_DEBUG, "check_invalid_src_dst: '%.*s'", len, call);
498 
499 	if (len < 1 || len > CALLSIGNLEN_MAX)
500 		return -1;
501 
502 	int i = 0;
503 
504 	/* go through callsign body */
505 	while (i < len && call[i] != '-') {
506 		/* alphanumeric */
507 		if (!isalnum(call[i]))
508 			return -1;
509 
510 		i++;
511 	}
512 
513 	/* we're at end? */
514 	if (i == len)
515 		return 0;
516 
517 	/* We have an SSID. */
518 	i++;
519 
520 	/* Check SSID length to be between 1 and 2 */
521 	/* javap4 drops these, javap3 allows, consider to drop later
522 	if (len - i > 2 || len == i)
523 		return -1;
524 	*/
525 	/* Check SSID length to be at least 1 */
526 	if (len == i)
527 		return -1;
528 
529 	/* SSID of 0? */
530 	/* Is allowed in javaprssrvr
531 	if (call[i] == '0')
532 		return -1;
533 	*/
534 
535 	while (i < len) {
536 		if (!isalnum(call[i]))
537 			return -1;
538 		i++;
539 	}
540 
541 	return 0;
542 }
543 
544 /*
545  *	Check callsign against a list to see if it matches
546  */
547 
check_call_match(const char ** set,const char * call,int len)548 int check_call_match(const char **set, const char *call, int len)
549 {
550 	int i;
551 
552 	for (i = 0; (set[i]); i++) {
553 		if (strncmp(call, set[i], len) == 0 && strlen(set[i]) == len)
554 			return -1;
555 	}
556 
557 	return 0;
558 }
559 
check_call_prefix_match(char ** set,const char * call,int len)560 static int check_call_prefix_match(char **set, const char *call, int len)
561 {
562 	int i, l;
563 
564 	for (i = 0; (set[i]); i++) {
565 		l = strlen(set[i]);
566 		if (len >= l && strncmp(call, set[i], l) == 0)
567 			return -1;
568 	}
569 
570 	return 0;
571 }
572 
573 #define MAX_TEST_CALL_LEN 32
check_call_glob_match(char ** set,const char * call,int len)574 int check_call_glob_match(char **set, const char *call, int len)
575 {
576 	int i;
577 	char ts[MAX_TEST_CALL_LEN+1];
578 
579 	if (len > MAX_TEST_CALL_LEN)
580 		return 0; /* no match */
581 
582 	/* glob match requires having a null-terminated string */
583 	memcpy(ts, call, len);
584 	ts[len] = 0;
585 
586 	for (i = 0; (set[i]); i++) {
587 		if (fnmatch(set[i], ts, FNM_CASEFOLD) == 0)
588 			return -1;
589 	}
590 
591 	return 0;
592 }
593 
594 /*
595  *	Check if a callsign is good for a digi path entry
596  *	(valid APRS-IS callsign, * allowed in end)
597  */
598 
check_invalid_path_callsign(const char * call,int len,int after_q)599 static int check_invalid_path_callsign(const char *call, int len, int after_q)
600 {
601 	//hlog(LOG_DEBUG, "check_invalid_src_dst: '%.*s'", len, call);
602 
603 	/* allow a '*' in the end, and don't check for it */
604 	if (len > 1 && call[len-1] == '*')
605 		len--;
606 
607 	if (len < 1)
608 		return -1;
609 
610 	if (len > CALLSIGNLEN_MAX && !(len == 32 && after_q))
611 		return -1;
612 
613 	int i = 0;
614 
615 	/* go through callsign body */
616 	while (i < len && call[i] != '-') {
617 		/* alphanumeric */
618 		if (!isalnum(call[i]))
619 			return -1;
620 
621 		i++;
622 	}
623 
624 	/* we're at end? */
625 	if (i == len)
626 		return 0;
627 
628 	/* We have an SSID. */
629 	i++;
630 
631 	/* Check SSID length to be between 1 and 2 */
632 	if (len - i > 2 || len == i)
633 		return -1;
634 
635 	/* SSID of 0? */
636 	if (call[i] == '0')
637 		return -1;
638 
639 	while (i < len) {
640 		if (!isalnum(call[i]))
641 			return -1;
642 		i++;
643 	}
644 
645 	return 0;
646 }
647 
648 /*
649  *	Check for invalid callsigns in path
650  */
651 
check_path_calls(const char * via_start,const char * path_end)652 int check_path_calls(const char *via_start, const char *path_end)
653 {
654 	const char *p = via_start + 1;
655 	const char *e;
656 	int calls = 0;
657 	int after_q = 0;
658 
659 	while (p < path_end) {
660 		calls++;
661 		e = p;
662 		/* find end of path callsign */
663 		while (*e != ',' && e < path_end)
664 			e++;
665 
666 		/* is this a q construct? */
667 		if (*p == 'q' && e-p == 3) {
668 			//hlog(LOG_DEBUG, "check_path_calls found Q construct: '%.*s'", e-p, p);
669 			after_q = 1;
670 			p = e + 1;
671 			continue;
672 		}
673 
674 		//hlog(LOG_DEBUG, "check_path_calls: '%.*s'%s", e-p, p, (after_q) ? " after q" : "");
675 		if (check_invalid_path_callsign(p, e-p, after_q) != 0)
676 			return -1;
677 
678 		p = e + 1;
679 	}
680 
681 	//hlog(LOG_DEBUG, "check_path_calls returning %d", calls);
682 
683 	return calls;
684 }
685 
686 /*
687  *	Handle incoming messages to SERVER
688  */
689 
incoming_server_message(struct worker_t * self,struct client_t * c,struct pbuf_t * pb)690 static int incoming_server_message(struct worker_t *self, struct client_t *c, struct pbuf_t *pb)
691 {
692 	struct aprs_message_t am;
693 
694 	int e;
695 	if ((e = parse_aprs_message(pb, &am))) {
696 		hlog(LOG_DEBUG, "message to SERVER from %.*s failed message parsing: %d", pb->srcname_len, pb->srcname, e);
697 		return 0;
698 	}
699 
700 	if (am.is_ack) {
701 		hlog(LOG_DEBUG, "message ack to SERVER from %.*s for msgid '%.*s'", pb->srcname_len, pb->srcname, am.msgid_len, am.msgid);
702 		return 0;
703 	}
704 
705 	hlog(LOG_DEBUG, "message to SERVER from %.*s: '%.*s'", pb->srcname_len, pb->srcname, am.body_len, am.body);
706 
707 	/* send ack */
708 	if (am.msgid) {
709 		if ((e = messaging_ack(self, c, pb, &am)) < 0) {
710 			hlog(LOG_DEBUG, "failed to ack message to SERVER from %.*s: '%.*s': %d",
711 				pb->srcname_len, pb->srcname, am.body_len, am.body, e);
712 			return e;
713 		}
714 	}
715 
716 	if (strncasecmp(am.body, "filter?", 7) == 0)
717 		return messaging_message_client(self, c, "filter %s active", c->filter_s);
718 
719 	if (strncasecmp(am.body, "filter", 6) == 0)
720 		return filter_commands(self, c, 1, am.body, am.body_len);
721 
722 	/* unknown command */
723 	return messaging_message_client(self, c, "Unknown command");
724 }
725 
726 /*
727  *	Store the coordinates given in the current packet to the client
728  *	structure, so that they can be used later when processing the
729  *	m/ filter.
730  */
731 
client_loc_update(struct client_t * c,struct pbuf_t * pb)732 static void client_loc_update(struct client_t *c, struct pbuf_t *pb)
733 {
734 	c->lat = pb->lat;
735 	c->lng = pb->lng;
736 	c->cos_lat = pb->cos_lat;
737 	c->loc_known = 1;
738 }
739 
740 /*
741  *	Parse an incoming packet.
742  *
743  *	Returns -1 if the packet is pathologically invalid on APRS-IS
744  *	and can be discarded, 0 if it is correct for APRS-IS and will be
745  *	forwarded, 1 if it was successfully parsed by the APRS parser.
746  *
747  *	This function also allocates the pbuf structure for the new packet
748  *	and forwards it to the dupecheck thread.
749  */
750 
751 // Must be large enough to accommodate the largest packet we accept on input
752 // + the length of the IPv6 qAI appended address and our callsign
753 #define PATH_APPEND_LEN 600
754 
incoming_parse(struct worker_t * self,struct client_t * c,char * s,int len)755 int incoming_parse(struct worker_t *self, struct client_t *c, char *s, int len)
756 {
757 	struct pbuf_t *pb;
758 	char *src_end; /* pointer to the > after srccall */
759 	char *path_start; /* pointer to the start of the path */
760 	char *path_end; /* pointer to the : after the path */
761 	const char *packet_end; /* pointer to the end of the packet */
762 	const char *info_start; /* pointer to the beginning of the info */
763 	const char *info_end; /* end of the info */
764 	char *dstcall_end_or_ssid; /* end of dstcall, before SSID ([-:,]) */
765 	char *dstcall_end; /* end of dstcall including SSID ([:,]) */
766 	char *via_start; /* start of the digipeater path (after dstcall,) */
767 	char *q_start = NULL; /* start of the Q construct (points to the 'q') */
768 	char *q_replace = NULL; /* whether the existing Q construct is replaced */
769 	char *data;	  /* points to original incoming path/payload separating ':' character */
770 	int src_len;		/* source callsign length */
771 	int datalen;		  /* length of the data block excluding tail \r\n */
772 	int pathlen;		  /* length of the path  ==  data-s  */
773 	int rc;
774 	char path_append[PATH_APPEND_LEN]; /* data to be appended to the path (generated Q construct, etc), could be long */
775 	int path_append_len;
776 	int originated_by_client = 0;
777 	char *p;
778 	char quirked[PACKETLEN_MAX+2]; /* rewritten packet */
779 
780 	/* for quirky clients, do some special treatment: build a new copy of
781 	 * the packet with extra spaces removed from packets
782 	 */
783 	if (c->quirks_mode) {
784 		/* rewritten packet */
785 		char *np = quirked;
786 
787 		// Easy pointer for comparing against far end..
788 		packet_end = s + len;
789 
790 		/* trim spaces and NULs from beginning */
791 		p = s;
792 
793 		while (p < packet_end && (*p == ' ' || *p == 0))
794 			p++;
795 
796 		if (p == packet_end)
797 			return INERR_EMPTY;
798 
799 		/* copy srccall, look for the '>' */
800 		while (p < packet_end && *p != '>' && *p != ' ')
801 			*np++ = *p++;
802 
803 		/* skip spaces in end of srccall */
804 		while (*p == ' ' && p < packet_end)
805 			p++;
806 
807 		if (*p != '>')
808 			return INERR_NO_DST;
809 
810 		/* copy path, removing trailing spaces from callsigns */
811 		while (p < packet_end && *p != ':') {
812 			/* copy path element */
813 			while (p < packet_end && *p != ',' && *p != ':' && *p != ' ')
814 				*np++ = *p++;
815 
816 			/* if we found spaces, scan over them */
817 			while (p < packet_end && *p == ' ')
818 				p++;
819 
820 			/* if the element ends with a comma, fine */
821 			if (p < packet_end && *p == ',') {
822 				*np++ = *p++;
823 				continue;
824 			}
825 
826 			/* end of path? fine */
827 			if (*p == ':')
828 				continue;
829 
830 			/* not fine. */
831 			return INERR_INV_PATH_CALL;
832 		}
833 
834 		/* copy rest of packet */
835 		while (p < packet_end)
836 			*(np++) = *(p++);
837 
838 		*np = 0;
839 		if (np - quirked != len) {
840 			hlog_packet(LOG_DEBUG, s, len, "borrked packet: ");
841 			hlog_packet(LOG_DEBUG, quirked, np - quirked, "quirked packet: ");
842 		}
843 
844 		s = quirked;
845 		len = np - quirked;
846 	}
847 
848 	/* check for minimum length of packet */
849 	if (len < PACKETLEN_MIN-2)
850 		return INERR_SHORT_PACKET;
851 
852 	// Easy pointer for comparing against far end..
853 	packet_end = s + len;
854 
855 	/* a packet looks like:
856 	 * SRCCALL>DSTCALL,PATH,PATH:INFO\r\n
857 	 * (we have normalized the \r\n by now)
858 	 */
859 
860 	path_end = memchr(s, ':', len);
861 	if (!path_end)
862 		return INERR_NO_COLON; // No ":" in the packet
863 	pathlen = path_end - s;
864 
865 	data = path_end;            // Begins with ":"
866 	datalen = len - pathlen;    // Not including line end \r\n
867 
868 	/* look for the '>' */
869 	src_end = memchr(s, '>', pathlen < CALLSIGNLEN_MAX+1 ? pathlen : CALLSIGNLEN_MAX+1);
870 	if (!src_end)
871 		return INERR_NO_DST;	// No ">" in packet start..
872 	src_len = src_end - s;
873 
874 	path_start = src_end+1;
875 	if (path_start >= packet_end)	// We're already at the path end
876 		return INERR_NO_PATH;
877 
878 	if (check_invalid_src_dst(s, src_len) != 0)
879 		return INERR_INV_SRCCALL; /* invalid or too long for source callsign */
880 
881 	if (check_call_prefix_match(disallow_srccalls, s, src_len))
882 		return INERR_DIS_SRCCALL; /* disallowed srccall */
883 
884 	if (disallow_srccall_glob && check_call_glob_match(disallow_srccall_glob, s, src_len))
885 		return INERR_DIS_SRCCALL; /* disallowed srccall */
886 
887 	info_start = path_end+1;	// @":"+1 - first char of the payload
888 	if (info_start >= packet_end)
889 		return INERR_NO_BODY;
890 
891 	/* see that there is at least some data in the packet */
892 	info_end = packet_end;
893 	if (info_end <= info_start)
894 		return INERR_NO_BODY;
895 
896 	/* look up end of dstcall (excluding SSID - this is the way dupecheck and
897 	 * mic-e parser wants it)
898 	 */
899 
900 	dstcall_end = path_start;
901 	while (dstcall_end < path_end && *dstcall_end != '-' && *dstcall_end != ',' && *dstcall_end != ':')
902 		dstcall_end++;
903 	dstcall_end_or_ssid = dstcall_end; // OK, SSID is here (or the dstcall end), go for the real end
904 	while (dstcall_end < path_end && *dstcall_end != ',' && *dstcall_end != ':')
905 		dstcall_end++;
906 
907 	if (check_invalid_src_dst(path_start, dstcall_end - path_start))
908 		return INERR_INV_DSTCALL; /* invalid or too long for destination callsign */
909 
910 	/* where does the digipeater path start? */
911 	via_start = dstcall_end;
912 
913 	/* check if the srccall equals the client's login */
914 	if (strlen(c->username) == src_len && memcmp(c->username, s, src_len) == 0)
915 		originated_by_client = 1;
916 
917 	/* check if the path contains NOGATE or other signs which tell the
918 	 * packet should be dropped
919 	 */
920 	int via_len = path_end - via_start;
921 	if (digi_path_drop(via_start, via_len))
922 		return INERR_NOGATE;
923 
924 	/* check if there are invalid callsigns in the digipeater path before Q */
925 	if (check_path_calls(via_start, path_end) == -1)
926 		return INERR_INV_PATH_CALL;
927 
928 	/* check for 3rd party packets */
929 	if (*(data + 1) == '}') {
930 		/* if the 3rd-party packet's header has TCPIP or TCPXX, drop it */
931 		/* TODO: only scan against the path, not src/dst */
932 		char *party_hdr_end = memchr(data+2, ':', packet_end-data-2);
933 		if (party_hdr_end) {
934 			/* TCPIP is more likely, test for it first */
935 			char *party_path = data + 2;
936 			int party_path_len = party_hdr_end - party_path;
937 			if ((memmem(party_path, party_path_len, ",TCPIP", 6)) || (memmem(party_path, party_path_len, ",TCPXX", 6)) )
938 				return INERR_3RD_PARTY_IP;
939 		}
940 	}
941 
942 	/* process Q construct, path_append_len of path_append will be copied
943 	 * to the end of the path later
944 	 */
945 	path_append_len = q_process( c, s, path_append, sizeof(path_append),
946 					via_start, &path_end, pathlen, &q_start,
947 					&q_replace, originated_by_client );
948 
949 	if (path_append_len < 0) {
950 		/* the q construct algorithm decided to drop the packet */
951 		hlog(LOG_DEBUG, "%s/%s: q construct drop: %d", c->addr_rem, c->username, path_append_len);
952 		return path_append_len;
953 	}
954 
955 	/* get a packet buffer */
956 	int new_len;
957 	if (q_replace)
958 		new_len = len+path_append_len-(path_end-q_replace)+3; /* we remove the old path first */
959 	else
960 		new_len = len+path_append_len+3; /* we add path_append_len + CRLFNUL */
961 
962 	/* check if the resulting packet is too long */
963 	if (new_len > PACKETLEN_MAX_LARGE) {
964 		hlog(LOG_DEBUG, "packet too long after inserting new Q construct (%d bytes, max %d)", new_len, PACKETLEN_MAX_LARGE);
965 		return INERR_LONG_PACKET;
966 	}
967 
968 	pb = pbuf_get(self, new_len);
969 	if (!pb) {
970 		// This should never happen... LOG_CRIT error logged in pbuf_get()
971 		//hlog(LOG_DEBUG, "pbuf_get failed to get packet buffer");
972 		return INERR_OUT_OF_PBUFS; // No room :-(
973 	}
974 	pb->next = NULL; // OPTIMIZE: pbuf arrives pre-zeroed, this could be removed maybe?
975 	pb->flags = 0;
976 
977 	/* store the source reference */
978 	pb->origin = c;
979 
980 	/* when it was received ? */
981 	pb->t = tick;
982 
983 	/* classify the packet as coming from an uplink or client */
984 	if (c->state == CSTATE_COREPEER || (c->flags & CLFLAGS_UPLINKPORT)) {
985 		pb->flags |= F_FROM_UPSTR;
986 	} else if (c->flags & CLFLAGS_DUPEFEED) {
987 		/* we ignore packets from duplicate feeds */
988 		rc = 0;
989 		goto free_pb_ret;
990 	} else if (c->flags & CLFLAGS_INPORT) {
991 		pb->flags |= F_FROM_DOWNSTR;
992 	} else {
993 		hlog(LOG_ERR, "%s/%s (fd %d): incoming_parse failed to classify packet", c->addr_rem, c->username, c->fd);
994 		rc = INERR_CLASS_FAIL;
995 		goto free_pb_ret;
996 	}
997 
998 	/* if the packet is sourced by a local login, but the packet is not
999 	 * originated by that station, drop it.
1000 	 */
1001 	if (!originated_by_client && clientlist_check_if_validated_client(s, src_len) != -1) {
1002 		/* We mark the packet as a dupe, since dropping it completely
1003 		 * would result in an error-type counter getting incremented.
1004 		 * This is slightly incorrect (perhaps the packet is not a
1005 		 * duplicate after all), probably there should be a separate
1006 		 * statistics counter for this. TODO: add a "looped" counter.
1007 		 */
1008 		//hlog(LOG_DEBUG, "%s/%s: dropping due to source call '%.*s' being logged in on another socket", c->addr_rem, c->username, src_len, s);
1009 		pb->flags |= F_DUPE;
1010 	}
1011 
1012 	/* Copy the unmodified part of the packet header */
1013 	if (q_replace) {
1014 		/* if we're replacing the Q construct, we don't copy the old one */
1015 		memcpy(pb->data, s, q_replace - s);
1016 		p = pb->data + (q_replace - s);
1017 	} else {
1018 		memcpy(pb->data, s, path_end - s);
1019 		p = pb->data + (path_end - s);
1020 	}
1021 
1022 	/* If q_process left q_start unmodified (as NULL), it wants to say
1023 	 * that it produced a new Q construct, which is returned in
1024 	 * path_append. If it points somewhere in the header, then fine,
1025 	 * it points to an existing Q construct.
1026 	 */
1027 	if (q_start == NULL && path_append_len > 0) {
1028 		pb->qconst_start = p + 1;
1029 	} else if (q_start > s && q_start < path_end) {
1030 		pb->qconst_start = pb->data + (q_start - s);
1031 	} else {
1032 		/* If this ever happened, it'd be bad: we didn't find an
1033 		 * existing Q construct and we didn't pick one to insert.
1034 		 */
1035 		hlog(LOG_INFO, "%s/%s: q construct bug: did not find a good construct or produce a new one for:\n%s\n", c->addr_rem, c->username, s);
1036 		rc = INERR_Q_BUG;
1037 		goto free_pb_ret;
1038 	}
1039 
1040 	/* Copy the modified or appended part of the packet header -- qcons */
1041 	memcpy(p, path_append, path_append_len);
1042 	p += path_append_len;
1043 
1044 	//hlog(LOG_DEBUG, "q construct: %.*s", 3, pb->qconst_start);
1045 
1046 	/* Copy the unmodified end of the packet (including the :) */
1047 	memcpy(p, info_start - 1, datalen);
1048 	info_start = p + 1;
1049 	p += datalen;
1050 	memcpy(p, "\r\n", 3); /* append missing CRLFNUL,
1051 				 the NUL is implied in C-style ASCIIZ strings  */
1052 	p += 2; /* We ignore the convenience NUL. */
1053 
1054 	/* How much there really is data? */
1055 	pb->packet_len = p - pb->data;
1056 
1057 	/* fill necessary info for parsing and dupe checking in the packet buffer */
1058 	pb->srcname = pb->data;
1059 	pb->srcname_len = src_len;
1060 	pb->srccall_end = pb->data + src_len;
1061 	pb->dstcall_end_or_ssid = pb->data + (dstcall_end_or_ssid - s);
1062 	pb->dstcall_end = pb->data + (dstcall_end - s);
1063 	pb->dstcall_len = via_start - src_end - 1;
1064 	pb->info_start  = info_start;
1065 
1066 	//hlog_packet(LOG_DEBUG, pb->data, pb->packet_len-2, "After parsing and Qc algorithm: ");
1067 
1068 	/* just try APRS parsing */
1069 	rc = parse_aprs(pb);
1070 
1071 	if (rc < 0)
1072 		goto free_pb_ret;
1073 
1074 	if (rc == 0 && (pb->packettype & T_MESSAGE) && pb->dstname_len == 6
1075 		&& strncasecmp(pb->dstname, "SERVER", 6) == 0) {
1076 		/* This is a message from a client destined to the local server.
1077 		 * Process it!
1078 		 */
1079 		if (!originated_by_client) {
1080 			hlog(LOG_DEBUG, "message to SERVER from non-local client %.*s, dropping", pb->srcname_len, pb->srcname);
1081 			goto free_pb_ret;
1082 		}
1083 
1084 		rc = incoming_server_message(self, c, pb);
1085 		goto free_pb_ret;
1086 	}
1087 
1088 	/* check for general queries - those cause reply floods and need
1089 	 * to be dropped
1090 	 */
1091 	if (pb->packettype & T_QUERY) {
1092 		rc = INERR_GENERAL_QUERY;
1093 		goto free_pb_ret;
1094 	}
1095 
1096 	/* If the client sent this packet itself, update its coordinates
1097 	 * in the client struct based on the packet for use in m/ filter
1098 	 * processing. This needs to be after parse_aprs and before dropping
1099 	 * unvalidated packets, so that t/m works for unvalidated
1100 	 * read-only clients.
1101 	 */
1102 	if (originated_by_client && (pb->packettype & T_POSITION))
1103 		client_loc_update(c, pb);
1104 
1105 	/* If disallow_unverified is enabled, don't allow unverified clients
1106 	 * to send any packets. Do this after any potential client_loc_update
1107 	 * so that unverified clients can have their packets parsed
1108 	 * and m/ filters working.
1109 	 */
1110 	if (disallow_unverified) {
1111 		if (!c->validated) {
1112 			rc = INERR_DISALLOW_UNVERIFIED;
1113 			goto free_pb_ret;
1114 		}
1115 		if (memmem(via_start, via_len, ",TCPXX", 6)) {
1116 			rc = INERR_DISALLOW_UNVERIFIED_PATH;
1117 			goto free_pb_ret;
1118 		}
1119 	}
1120 
1121 	/* Filter preprocessing before sending this to dupefilter.. */
1122 	filter_preprocess_dupefilter(pb);
1123 
1124 	/* If the packet came in on a filtered port, mark the station as
1125 	 * heard on this port, so that messages can be routed to it.
1126 	 */
1127 	if (c->flags & CLFLAGS_IGATE)
1128 		client_heard_update(c, pb);
1129 
1130 	/* put the buffer in the thread's incoming queue */
1131 	*self->pbuf_incoming_local_last = pb;
1132 	self->pbuf_incoming_local_last = &pb->next;
1133 	self->pbuf_incoming_local_count++;
1134 
1135 	return rc;
1136 
1137 	/* in case the packet does not go to the incoming queue, free it up */
1138 free_pb_ret:
1139 	pbuf_free(self, pb);
1140 	return rc;
1141 }
1142 
1143 /*
1144  *	Handler called once for each input APRS-IS line by the socket reading function
1145  *	for normal APRS-IS traffic.
1146  */
1147 
incoming_handler(struct worker_t * self,struct client_t * c,int l4proto,char * s,int len)1148 int incoming_handler(struct worker_t *self, struct client_t *c, int l4proto, char *s, int len)
1149 {
1150 	int e;
1151 
1152 	/* note: len does not include CRLF, it's reconstructed here... we accept
1153 	 * CR, LF or CRLF on input but make sure to use CRLF on output.
1154 	 */
1155 
1156 	/* Make sure it looks somewhat like an APRS-IS packet... len is without CRLF.
1157 	 * Do not do PACKETLEN_MIN test here, since it would drop the 'filter'
1158 	 * commands.
1159 	 */
1160 	if (len > PACKETLEN_MAX-2) {
1161 		e = INERR_LONG_PACKET;
1162 		goto in_drop;
1163 	}
1164 
1165 	/* starts with '#' => a comment packet, timestamp or something */
1166 	if (*s == '#') {
1167 		hlog_packet(LOG_DEBUG, s, len, "%s/%s: #-in: ", c->addr_rem, c->username);
1168 		if (l4proto != IPPROTO_UDP && (c->flags & CLFLAGS_USERFILTEROK)) {
1169 			/* filter adjunct commands ? */
1170 			char *filtercmd = memcasestr("filter", s, s + len);
1171 			if (filtercmd)
1172 				return filter_commands(self, c, 0, filtercmd, len - (filtercmd - s));
1173 
1174 		}
1175 
1176 		return 0;
1177 	}
1178 
1179 	/* parse and process the packet */
1180 	e = incoming_parse(self, c, s, len);
1181 
1182 in_drop:
1183 	if (e < 0) {
1184 		/* failed parsing */
1185 		hlog_packet(LOG_DEBUG, s, len, "%s/%s: Dropped packet (%d: %s) len %d: ",
1186 			c->addr_rem, c->username, e, incoming_strerror(e), len);
1187 	}
1188 
1189 	/* Account the one incoming packet.
1190 	 * Incoming bytes were already accounted earlier.
1191 	 */
1192 	clientaccount_add(c, l4proto, 0, 1, 0, 0, (e < 0) ? e : 0, 0);
1193 
1194 	return 0;
1195 }
1196 
1197 #ifndef _FOR_VALGRIND_
incoming_cell_stats(struct cellstatus_t * cellst_pbuf_small,struct cellstatus_t * cellst_pbuf_medium,struct cellstatus_t * cellst_pbuf_large)1198 void incoming_cell_stats(struct cellstatus_t *cellst_pbuf_small,
1199 	struct cellstatus_t *cellst_pbuf_medium,
1200 	struct cellstatus_t *cellst_pbuf_large)
1201 {
1202 	cellstatus(pbuf_cells_small, cellst_pbuf_small);
1203 	cellstatus(pbuf_cells_medium, cellst_pbuf_medium);
1204 	cellstatus(pbuf_cells_large, cellst_pbuf_large);
1205 }
1206 #endif
1207