Skip to content

Commit b6254da

Browse files
committed
Issue 84. IGate was truncating packets that contained nul character
in the information/comment part.
1 parent 785c8de commit b6254da

File tree

5 files changed

+299
-95
lines changed

5 files changed

+299
-95
lines changed

CHANGES.md

+17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22
# Revision History #
33

44

5+
## Version 1.4 -- Development snapshot H -- March 2017 ##
6+
7+
**This is beta test quality. If no significant issues are reported this will be the version 1.4 release.**
8+
9+
### New Features: ###
10+
11+
- Take advantage of new 'gpio' group and new /sys/class/gpio ownership in Raspbian Jessie.
12+
13+
- Handle more complicated gpio naming for CubieBoard, etc.
14+
15+
16+
### Bugs Fixed: ###
17+
18+
- IGate did not retain nul characters in the information part of a packet. This should never happen with a valid APRS packet but there are a couple cases where it has. If we encounter these malformed packets, pass them along as-is, rather than truncating.
19+
20+
- Don't digipeat packets when the source is my call.
21+
522
----------
623

724
## Version 1.4 -- Development snapshot G -- January 2017 ##

ax25_pad.c

+69-67
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,18 @@ void ax25_delete (packet_t this_p)
335335
* Purpose: Parse a frame in human-readable monitoring format and change
336336
* to internal representation.
337337
*
338-
* Input: monitor - "TNC-2" format of a monitored packet. i.e.
338+
* Input: monitor - "TNC-2" monitor format for packet. i.e.
339339
* source>dest[,repeater1,repeater2,...]:information
340340
*
341+
* The information part can have non-printable characters
342+
* in the form of <0xff>. This will be converted to single
343+
* bytes. e.g. <0x0d> is carriage return.
344+
* In version 1.4H we will allow nul characters which means
345+
* we have to maintain a length rather than using strlen().
346+
* I maintain that it violates the spec but want to handle it
347+
* because it does happen and we want to preserve it when
348+
* acting as an IGate rather than corrupting it.
349+
*
341350
* strict - True to enforce rules for packets sent over the air.
342351
* False to be more lenient for packets from IGate server.
343352
*
@@ -369,17 +378,11 @@ packet_t ax25_from_text (char *monitor, int strict)
369378
char *pa;
370379
char *saveptr; /* Used with strtok_r because strtok is not thread safe. */
371380

372-
static int first_time = 1;
373-
static regex_t unhex_re;
374-
int e;
375-
char emsg[100];
376-
#define MAXMATCH 1
377-
regmatch_t match[MAXMATCH];
378-
int keep_going;
379-
char temp[512];
380381
int ssid_temp, heard_temp;
381382
char atemp[AX25_MAX_ADDR_LEN];
382383

384+
char info_part[AX25_MAX_INFO_LEN+1];
385+
int info_len;
383386

384387
packet_t this_p = ax25_new ();
385388

@@ -392,58 +395,15 @@ packet_t ax25_from_text (char *monitor, int strict)
392395

393396
/* Is it possible to have a nul character (zero byte) in the */
394397
/* information field of an AX.25 frame? */
395-
/* Yes, but it would be difficult in the from-text case. */
398+
/* At this point, we have a normal C string. */
399+
/* It is possible that will convert <0x00> to a nul character later. */
400+
/* There we need to maintain a separate length and not use normal C string functions. */
396401

397402
strlcpy (stuff, monitor, sizeof(stuff));
398403

399-
/*
400-
* Translate hexadecimal values like <0xff> to non-printing characters.
401-
* MIC-E message type uses 5 different non-printing characters.
402-
*/
403-
404-
if (first_time)
405-
{
406-
e = regcomp (&unhex_re, "<0x[0-9a-fA-F][0-9a-fA-F]>", 0);
407-
if (e) {
408-
regerror (e, &unhex_re, emsg, sizeof(emsg));
409-
text_color_set(DW_COLOR_ERROR);
410-
dw_printf ("%s:%d: %s\n", __FILE__, __LINE__, emsg);
411-
}
412-
413-
first_time = 0;
414-
}
415-
416-
#if 0
417-
text_color_set(DW_COLOR_DEBUG);
418-
dw_printf ("BEFORE: %s\n", stuff);
419-
ax25_safe_print (stuff, -1, 0);
420-
dw_printf ("\n");
421-
#endif
422-
keep_going = 1;
423-
while (keep_going) {
424-
if (regexec (&unhex_re, stuff, MAXMATCH, match, 0) == 0) {
425-
int n;
426-
char *p;
427-
428-
stuff[match[0].rm_so + 5] = '\0';
429-
n = strtol (stuff + match[0].rm_so + 3, &p, 16);
430-
stuff[match[0].rm_so] = n;
431-
strlcpy (temp, stuff + match[0].rm_eo, sizeof(temp));
432-
strlcpy (stuff + match[0].rm_so + 1, temp, sizeof(stuff)-match[0].rm_so-1);
433-
}
434-
else {
435-
keep_going = 0;
436-
}
437-
}
438-
#if 0
439-
text_color_set(DW_COLOR_DEBUG);
440-
dw_printf ("AFTER: %s\n", stuff);
441-
ax25_safe_print (stuff, -1, 0);
442-
dw_printf ("\n");
443-
#endif
444404

445405
/*
446-
* Initialize the packet with two addresses and control/pid
406+
* Initialize the packet structure with two addresses and control/pid
447407
* for APRS.
448408
*/
449409
memset (this_p->frame_data + AX25_DESTINATION*7, ' ' << 1, 6);
@@ -473,12 +433,6 @@ packet_t ax25_from_text (char *monitor, int strict)
473433
*pinfo = '\0';
474434
pinfo++;
475435

476-
if (strlen(pinfo) > AX25_MAX_INFO_LEN) {
477-
text_color_set(DW_COLOR_ERROR);
478-
dw_printf ("Warning: Information part truncated to %d characters.\n", AX25_MAX_INFO_LEN);
479-
pinfo[AX25_MAX_INFO_LEN] = '\0';
480-
}
481-
482436
/*
483437
* Separate the addresses.
484438
* Note that source and destination order is swappped.
@@ -535,7 +489,6 @@ packet_t ax25_from_text (char *monitor, int strict)
535489
*/
536490
while (( pa = strtok_r (NULL, ",", &saveptr)) != NULL && this_p->num_addr < AX25_MAX_ADDRS ) {
537491

538-
//char *last;
539492
int k;
540493

541494
k = this_p->num_addr;
@@ -561,11 +514,61 @@ packet_t ax25_from_text (char *monitor, int strict)
561514
}
562515
}
563516

517+
518+
/*
519+
* Finally, process the information part.
520+
*
521+
* Translate hexadecimal values like <0xff> to single bytes.
522+
* MIC-E format uses 5 different non-printing characters.
523+
* We might want to manually generate UTF-8 characters such as degree.
524+
*/
525+
526+
//#define DEBUG14H 1
527+
528+
#if DEBUG14H
529+
text_color_set(DW_COLOR_DEBUG);
530+
dw_printf ("BEFORE: %s\nSAFE: ", pinfo);
531+
ax25_safe_print (pinfo, -1, 0);
532+
dw_printf ("\n");
533+
#endif
534+
535+
info_len = 0;
536+
while (*pinfo != '\0' && info_len < AX25_MAX_INFO_LEN) {
537+
538+
if (strlen(pinfo) >= 6 &&
539+
pinfo[0] == '<' &&
540+
pinfo[1] == '0' &&
541+
pinfo[2] == 'x' &&
542+
isxdigit(pinfo[3]) &&
543+
isxdigit(pinfo[4]) &&
544+
pinfo[5] == '>') {
545+
546+
char *p;
547+
548+
info_part[info_len] = strtol (pinfo + 3, &p, 16);
549+
info_len++;
550+
pinfo += 6;
551+
}
552+
else {
553+
info_part[info_len] = *pinfo;
554+
info_len++;
555+
pinfo++;
556+
}
557+
}
558+
info_part[info_len] = '\0';
559+
560+
#if DEBUG14H
561+
text_color_set(DW_COLOR_DEBUG);
562+
dw_printf ("AFTER: %s\nSAFE: ", info_part);
563+
ax25_safe_print (info_part, info_len, 0);
564+
dw_printf ("\n");
565+
#endif
566+
564567
/*
565568
* Append the info part.
566569
*/
567-
strlcpy ((char*)(this_p->frame_data+this_p->frame_len), pinfo, sizeof(this_p->frame_data)-this_p->frame_len);
568-
this_p->frame_len += strlen(pinfo);
570+
memcpy ((char*)(this_p->frame_data+this_p->frame_len), info_part, info_len);
571+
this_p->frame_len += info_len;
569572

570573
return (this_p);
571574
}
@@ -2536,7 +2539,7 @@ unsigned short ax25_m_m_crc (packet_t pp)
25362539
*
25372540
* Inputs: pstr - Pointer to string.
25382541
*
2539-
* len - Maximum length if not -1.
2542+
* len - Number of bytes. If < 0 we use strlen().
25402543
*
25412544
* ascii_only - Restrict output to only ASCII.
25422545
* Normally we allow UTF-8.
@@ -2587,7 +2590,6 @@ void ax25_safe_print (char *pstr, int len, int ascii_only)
25872590
if (len > MAXSAFE)
25882591
len = MAXSAFE;
25892592

2590-
//while (len > 0 && *pstr != '\0')
25912593
while (len > 0)
25922594
{
25932595
ch = *((unsigned char *)pstr);

decode_aprs.c

+71-1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,33 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet)
199199
ax25_get_addr_with_ssid (pp, AX25_SOURCE, A->g_src);
200200
ax25_get_addr_with_ssid (pp, AX25_DESTINATION, dest);
201201

202+
/*
203+
* Report error if the information part contains a nul character.
204+
* There are two known cases where this can happen.
205+
*
206+
* - The Kenwood TM-D710A sometimes sends packets like this:
207+
*
208+
* VA3AJ-9>T2QU6X,VE3WRC,WIDE1,K8UNS,WIDE2*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`nW<0x1f>oS8>/]"6M}driving fast=
209+
* K4JH-9>S5UQ6X,WR4AGC-3*,WIDE1*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`jP}l"&>/]"47}QRV from the EV =
210+
*
211+
* Notice that the data type indicator of "4" is not valid. If we remove
212+
* 4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00> we are left with a good MIC-E format.
213+
* This same thing has been observed from others and is intermittent.
214+
*
215+
* - AGW Tracker can send UTF-16 if an option is selected. This can introduce nul bytes.
216+
* This is wrong, it should be using UTF-8.
217+
*/
218+
219+
if ( ( ! A->g_quiet ) && ( (int)strlen((char*)pinfo) != info_len) ) {
220+
221+
text_color_set(DW_COLOR_ERROR);
222+
dw_printf("'nul' character found in Information part. This should never happen.\n");
223+
dw_printf("It seems that %s is transmitting with defective software.\n", A->g_src);
224+
225+
if (strcmp((char*)pinfo, "4P") == 0) {
226+
dw_printf("The TM-D710 will do this intermittently. A firmware upgrade is needed to fix it.\n");
227+
}
228+
}
202229

203230
switch (*pinfo) { /* "DTI" data type identifier. */
204231

@@ -3907,7 +3934,7 @@ static void substr_se (char *dest, const char *src, int start, int endp1)
39073934
* clen - Length of comment or -1 to take it all.
39083935
*
39093936
* Outputs: A->g_telemetry - Base 91 telemetry |ss1122|
3910-
* A->g_altitude_ft - from /A=123456
3937+
* A->g_altitude_ft - from /A=123456
39113938
* A->g_lat - Might be adjusted from !DAO!
39123939
* A->g_lon - Might be adjusted from !DAO!
39133940
* A->g_aprstt_loc - Private extension to !DAO!
@@ -3938,6 +3965,49 @@ static void substr_se (char *dest, const char *src, int start, int endp1)
39383965
*
39393966
* /A=123456 Altitude
39403967
*
3968+
* What can appear in a comment?
3969+
*
3970+
* Chapter 5 of the APRS spec ( http://www.aprs.org/doc/APRS101.PDF ) says:
3971+
*
3972+
* "The comment may contain any printable ASCII characters (except | and ~,
3973+
* which are reserved for TNC channel switching)."
3974+
*
3975+
* "Printable" would exclude character values less than space (00100000), e.g.
3976+
* tab, carriage return, line feed, nul. Sometimes we see carriage return
3977+
* (00001010) at the end of APRS packets. This would be in violation of the
3978+
* specification.
3979+
*
3980+
* The base 91 telemetry format (http://he.fi/doc/aprs-base91-comment-telemetry.txt ),
3981+
* which is not part of the APRS spec, uses the | character in the comment to delimit encoded
3982+
* telemetry data. This would be in violation of the original spec.
3983+
*
3984+
* The APRS Spec Addendum 1.2 Proposals ( http://www.aprs.org/aprs12/datum.txt)
3985+
* adds use of UTF-8 (https://en.wikipedia.org/wiki/UTF-8 )for the free form text in
3986+
* messages and comments. It can't be used in the fixed width fields.
3987+
*
3988+
* Non-ASCII characters are represented by multi-byte sequences. All bytes in these
3989+
* multi-byte sequences have the most significant bit set to 1. Using UTF-8 would not
3990+
* add any nul (00000000) bytes to the stream.
3991+
*
3992+
* There are two known cases where we can have a nul character value.
3993+
*
3994+
* * The Kenwood TM-D710A sometimes sends packets like this:
3995+
*
3996+
* VA3AJ-9>T2QU6X,VE3WRC,WIDE1,K8UNS,WIDE2*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`nW<0x1f>oS8>/]"6M}driving fast=
3997+
* K4JH-9>S5UQ6X,WR4AGC-3*,WIDE1*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`jP}l"&>/]"47}QRV from the EV =
3998+
*
3999+
* Notice that the data type indicator of "4" is not valid. If we remove
4000+
* 4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00> we are left with a good MIC-E format.
4001+
* This same thing has been observed from others and is intermittent.
4002+
*
4003+
* * AGW Tracker can send UTF-16 if an option is selected. This can introduce nul bytes.
4004+
* This is wrong. It should be using UTF-8 and I'm not going to accomodate it here.
4005+
*
4006+
*
4007+
* The digipeater and IGate functions should pass along anything exactly the
4008+
* we received it, even if it is invalid. If different implementations try to fix it up
4009+
* somehow, like changing unprintable characters to spaces, we will only make things
4010+
* worse and thwart the duplicate detection.
39414011
*
39424012
*------------------------------------------------------------------*/
39434013

direwolf.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ int main (int argc, char *argv[])
260260
text_color_init(t_opt);
261261
text_color_set(DW_COLOR_INFO);
262262
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
263-
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "G", __DATE__);
263+
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "H", __DATE__);
264264
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
265265

266266
#if defined(ENABLE_GPSD) || defined(USE_HAMLIB)

0 commit comments

Comments
 (0)