1 /*
2 *
3 * XASTIR, Amateur Station Tracking and Information Reporting
4 * Copyright (C) 1999,2000 Frank Giannandrea
5 * Copyright (C) 2000-2019 The Xastir Group
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * Look at the README for more information on the program.
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif // HAVE_CONFIG_H
27
28 #include "snprintf.h"
29
30 #include <termios.h>
31 #include <stdio.h>
32 #include <fcntl.h>
33 #include <ctype.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <Xm/XmAll.h>
39 #include <X11/Xatom.h>
40 #include <X11/Shell.h>
41
42 #include "xastir.h"
43 #include "igate.h"
44 #include "main.h"
45 #include "interface.h"
46 #include "xa_config.h"
47 #include "util.h"
48
49 // Must be last include file
50 #include "leak_detection.h"
51
52
53
54 time_t last_nws_stations_file_time = 0;
55 int NWS_stations = 0;
56 int max_NWS_stations = 0;
57 NWS_Data *NWS_station_data;
58
59
60 void load_NWS_stations(char *file);
61 int check_NWS_stations(char *call);
62
63
64
65 // Struct for holding packet data. We use dynamically-allocated
66 // singly-linked lists. The last record should have its "next"
67 // pointer set to NULL.
68 //
69 typedef struct _DupeRecord
70 {
71 char data[MAX_LINE_SIZE+15]; // Packet data
72 time_t time; // The time the record was inserted
73 struct _DupeRecord *next; // pointer to next record in list
74 } DupeRecord;
75
76
77
78 // Sent and Heard queue pointers. These are used for the dupe-checking
79 // we do in the below routines. We have one Sent and one Heard queue
80 // for each interface device. These pointers will point to the head of
81 // each queue. We really only need these queues for each TNC interface,
82 // but the user might destroy a NET interface and create a TNC interface
83 // during a single runtime, so we need to populate all of the pointers
84 // just in case. If people switch types, the old queue will empty out
85 // (effectively anyway) within XX seconds, so we don't have to worry
86 // about cleaning out the queues in this case.
87 //
88 DupeRecord *heard_queue[MAX_IFACE_DEVICES];
89 DupeRecord *sent_queue[MAX_IFACE_DEVICES];
90
91
92
93 // Types of queues for each interface
94 #define HEARD 0
95 #define SENT 1
96
97
98
99 // Insert mode for the queues
100 #define NO_FORCED_INSERT 0
101 #define FORCED_INSERT 1
102
103
104
105
106
107 // Initialization routine for this module which sets up the queue
108 // pointers when Xastir first starts. Called from main.c:main()
109 //
igate_init(void)110 void igate_init(void)
111 {
112 int i;
113
114 for (i = 0; i < MAX_IFACE_DEVICES; i++)
115 {
116 heard_queue[i] = NULL;
117 sent_queue[i] = NULL;
118 }
119 }
120
121
122
123
124
125 //
126 // not_a_dupe: Function which checks for duplicate packets.
127 //
128 // Returns: 1 if it's _not_ a duplicate record or we have an error
129 // 0 if it _is_ a duplicate record
130 //
131 // Since we need to run through every record checking for dupes anyway,
132 // we check the timestamp on each one as we go through. If too old, we
133 // delete it from the head of the chain. We add new records to the end.
134 // This makes it easy to keep it as a singly-linked list, and only have
135 // to deal with one record at a time.
136 //
137 // The way this is set up we keep a thirty second queue for each
138 // interface. Any records older than this are at the head of the chain
139 // and are deleted one by one whenever this routine is called again due
140 // to a new packet coming through. It's ok if these records sit around
141 // on the queue for a long time due to no igate activity. It doesn't
142 // take long to delete them!
143 //
not_a_dupe(int queue_type,int port,char * line,int insert_mode)144 int not_a_dupe(int queue_type, int port, char *line, int insert_mode)
145 {
146 DupeRecord *ptr;
147 DupeRecord *ptr_last;
148 int insert_new;
149 time_t time_cutoff;
150 int found_dupe = 0;
151 char match_line[MAX_LINE_SIZE*2];
152 char line2[MAX_LINE_SIZE+1];
153 char *c0, *c1, *c2;
154
155
156 if ( (line == NULL) || (line[0] == '\0') )
157 {
158 return(1);
159 }
160
161
162 // Figure out what's "old"
163 time_cutoff = sec_now() - (time_t)29; // 29 seconds ago
164
165
166 // Fill the destination string with zeroes. This is a nice
167 // segfault-prevention technique. Whatever strings we throw in here
168 // will be automatically terminated.
169 memset(match_line, 0, MAX_LINE_SIZE*2);
170
171
172 switch (queue_type)
173 {
174
175 case HEARD:
176 ptr_last = ptr = heard_queue[port]; // May be NULL!
177
178 // The insert_into_heard_queue() function below (called by
179 // db.c decode routines in turn) will call this function
180 // with FORCED_INSERT. Other routines in igate.c will call
181 // it with NO_FORCED_INSERT. For the Heard queue we only
182 // want the db.c decode routines inserting records.
183 if (insert_mode == FORCED_INSERT)
184 {
185 insert_new = 1; // Insert new records.
186 }
187 else
188 {
189 insert_new = 0; // Don't insert new records.
190 }
191
192 // RF packets will have third-party headers and regular
193 // headers that must be stripped off. We only want to store
194 // 3rd party RF strings in the Heard queue as the others
195 // aren't going to be igated anyway. For matching and
196 // storage purposes the 3rd party packets should look
197 // identical to how they were originally passed on the 'net,
198 // so that we can try to find duplicates before transmitting
199 // them again.
200
201 // NOTE: Below is the parsing code for an internet packet for the Sent
202 // queue. Modify it to parse 3rd party packets for the Heard queue.
203
204 // VE7VFM-12>APD214,VE7VAN-3*,WIDE3*:}WA7JAK>APK002,TCPIP*,VE7VFM-12*::N7WGR-7 :does{2
205
206 // Changes needed before parsing code: Get rid of first
207 // part of packet up to the '}' symbol. After this the
208 // generic parsing code will work.
209 // Note that the REPLY-ACK algorithm also uses the '}' symbol.
210
211 c0 = strstr(line, ":}"); // Find start of 3rd party packet
212 if (c0 == NULL) // Not 3rd party packet
213 {
214 if (debug_level & 1024)
215 {
216 fprintf(stderr," Not 3rd party HeardQ: %s\n",line);
217 }
218 return(1);
219 }
220
221 // Copy original packet into line2 for later parsing. We
222 // want to keep the '}' character because our own
223 // transmissions out RF have that character as well.
224 // Note that the REPLY-ACK algorithm also uses the '}' symbol.
225 if (debug_level & 1024)
226 {
227 fprintf(stderr,"3rd party HeardQ: %s\n",line);
228 }
229
230 xastir_snprintf(line2,
231 sizeof(line2),
232 "%s",
233 c0+1);
234
235 break;
236
237 case SENT:
238 // For this queue we always want to insert records. Only
239 // igate.c functions call this.
240 ptr_last = ptr = sent_queue[port]; // May be NULL!
241 insert_new = 1; // Insert new records
242
243 // No extra changes needed before parsing code, Example:
244 // }VE7VFM-11>APW251,TCPIP,WE7U-14*::VE7VFM-9 :OK GOT EMAIL OK{058
245 xastir_snprintf(line2,
246 sizeof(line2),
247 "%s",
248 line);
249
250 if (debug_level & 1024)
251 {
252 fprintf(stderr," COMPLETE SENT PACKET: %s\n",line2);
253 }
254
255 break;
256
257 default:
258 // We shouldn't be here.
259 return(1);
260
261 break;
262 }
263
264
265 // Create the string we're going to compare against and that we
266 // might store in the queue. Knock off the path info and just check
267 // source/destination/info portions of the packet for a match.
268
269 c1 = strstr(line2, ","); // Find comma after destination
270 c2 = strstr(line2, ":"); // Find end of path
271
272 if ( (c1 != NULL) && (c2 != NULL) ) // Found both separators
273 {
274
275 // Copy source/destination portion
276 xastir_snprintf(match_line,
277 sizeof(match_line),
278 "%s",
279 line2);
280 match_line[(int)(c1-line2)] = '\0'; // Terminate the substring
281
282 strncat(match_line, // Copy info portion
283 c2+1,
284 sizeof(match_line) - 1 - strlen(match_line));
285 }
286 else // At least one separator was not found, copy entire string
287 {
288 xastir_snprintf(match_line,
289 sizeof(match_line),
290 "%s",
291 line2);
292 }
293
294
295 // Run through the selected queue from beginning to end. If the
296 // pointer is NULL, the queue is empty and we're already done.
297 while (ptr != NULL && !found_dupe)
298 {
299
300 // Check the timestamp to determine whether to delete this
301 // record
302 if (ptr->time < time_cutoff) // Old record, delete it
303 {
304 DupeRecord *temp;
305
306 if (debug_level & 1024)
307 {
308 switch (queue_type)
309 {
310 case HEARD:
311 fprintf(stderr,"HEARD Deleting record: %s\n",ptr->data);
312 break;
313 case SENT:
314 fprintf(stderr," SENT Deleting record: %s\n",ptr->data);
315 break;
316 default:
317 break;
318 }
319 }
320
321 // Delete record and free up the space
322 temp = ptr;
323 ptr = ptr->next; // May be NULL!
324 free(temp);
325
326 // Point master queue pointer to new head of queue.
327 // Make sure to carry along ptr_last as well, as this is
328 // our possible insertion point later.
329 switch (queue_type)
330 {
331 case HEARD:
332 heard_queue[port] = ptr_last = ptr; // May be NULL!
333 break;
334 case SENT:
335 sent_queue[port] = ptr_last = ptr; // May be NULL!
336 default:
337 break;
338 }
339 }
340
341 else // Record is current. Check for a match.
342 {
343
344 //fprintf(stderr,"\n\t\t%s\n\t\t%s\n",ptr->data,match_line);
345
346 if (strcmp(ptr->data,match_line) == 0)
347 {
348 // We found a dupe! We're done with the loop.
349 found_dupe++;
350
351 if (debug_level & 1024)
352 {
353 switch (queue_type)
354 {
355 case HEARD:
356 fprintf(stderr,"HEARD* Found dupe: %s\n",match_line);
357 break;
358 case SENT:
359 fprintf(stderr,"SENT* Found dupe: %s\n",match_line);
360 default:
361 break;
362 }
363 }
364 }
365 else // Not a dupe, skip to the next record in the
366 {
367 // queue. Keep a pointer to the last record
368 // compared so that we have a possible insertion
369 // point later. Once we hit the end (NULL), we
370 // can't back up one.
371 ptr_last = ptr; // Save pointer to last record
372 ptr = ptr->next; // Advance one. May be NULL!
373 }
374 }
375 } // End of while loop
376
377
378 if (found_dupe)
379 {
380
381 if (debug_level & 1024)
382 {
383 switch (port_data[port].device_type)
384 {
385 case DEVICE_SERIAL_TNC_AUX_GPS:
386 case DEVICE_SERIAL_TNC_HSP_GPS:
387 case DEVICE_SERIAL_TNC:
388 case DEVICE_AX25_TNC:
389 case DEVICE_SERIAL_KISS_TNC:
390 case DEVICE_SERIAL_MKISS_TNC:
391 case DEVICE_NET_AGWPE:
392 fprintf(stderr," Found RF dupe: %s\n",match_line);
393 break;
394
395 default:
396 fprintf(stderr," Found NET dupe: %s\n",match_line);
397 break;
398 }
399 }
400
401 return(0); // Found a dupe, return
402 }
403
404 else
405 {
406
407 // If insert_new == 1, insert each non-dupe record into the
408 // queue and give it a timestamp. ptr_next is currently
409 // either NULL or points to the last record in the chain.
410 if (insert_new)
411 {
412 DupeRecord *temp;
413
414 if (debug_level & 1024)
415 {
416 switch (queue_type)
417 {
418 case HEARD:
419 fprintf(stderr,"HEARD Adding record: %s\n",match_line);
420 break;
421 case SENT:
422 fprintf(stderr," SENT Adding record: %s\n",match_line);
423 break;
424 default:
425 break;
426 }
427 }
428
429 // Allocate a new storage space for the record and fill
430 // it in.
431 temp = (DupeRecord *)malloc(sizeof(DupeRecord));
432
433 if (!temp)
434 {
435 fprintf(stderr,"Couldn't allocate memory in not_a_dupe()\n");
436 return(1); // Send back "not a dupe"
437 }
438
439 temp->time = (time_t)sec_now();
440
441 memcpy(temp->data, match_line, sizeof(temp->data));
442 temp->data[sizeof(temp->data)-1] = '\0'; // Terminate string
443
444 temp->next = NULL; // Will be the end of the linked list
445
446 if (ptr_last == NULL) // Queue is currently empty
447 {
448
449 // Add record to empty list. Point master queue pointer
450 // to new head of queue.
451 switch (queue_type)
452 {
453 case HEARD:
454 heard_queue[port] = temp;
455 break;
456 case SENT:
457 sent_queue[port] = temp;
458 default:
459 break;
460 }
461 }
462 else // Queue is not empty, add the record to the end of
463 {
464 // the list.
465 ptr_last->next = temp;
466 }
467 }
468 }
469 return(1); // Nope, not a dupe
470 }
471
472
473
474
475
476 // Function which the receive routines call to insert a received
477 // packet into the HEARD queue for an interface. The packet will
478 // get added to the end of the linked list if it's not a duplicate
479 // record.
480 //
481 // Check to make sure it's an RF interface, else return
482 //
insert_into_heard_queue(int port,char * line)483 void insert_into_heard_queue(int port, char *line)
484 {
485
486 switch (port_data[port].device_type)
487 {
488
489 case DEVICE_SERIAL_TNC_AUX_GPS:
490 case DEVICE_SERIAL_TNC_HSP_GPS:
491 case DEVICE_SERIAL_TNC:
492 case DEVICE_AX25_TNC:
493 case DEVICE_SERIAL_KISS_TNC:
494 case DEVICE_SERIAL_MKISS_TNC:
495 case DEVICE_NET_AGWPE:
496
497 // We're not using the dupe check function, but merely the
498 // expiration and insert functions of not_a_dupe()
499
500 // Don't insert the "Tickle" lines that keep the internet
501 // sockets alive
502 if ( (strncasecmp(line,"# Tickle",8) != 0)
503 && (strncasecmp(line,"#Tickle",7) != 0) )
504 {
505 (void)not_a_dupe(HEARD, port, line, FORCED_INSERT);
506 }
507
508 break;
509
510 default: // Get out if not an RF interface
511 return;
512
513 break;
514 }
515 }
516
517
518
519
520
521 /****************************************************************/
522 /* output data to inet interfaces */
523 /* line: data to send out */
524 /* port: port data came from */
525 /****************************************************************/
output_igate_net(char * line,int port,int third_party)526 void output_igate_net(char *line, int port, int third_party)
527 {
528 char data_txt[MAX_LINE_SIZE+5];
529 char temp[MAX_LINE_SIZE+5];
530 char *call_sign;
531 char *path;
532 char *message;
533 int len,i,x,first;
534 int igate_options;
535 char log_file_path[MAX_VALUE];
536
537 call_sign = NULL;
538 path = NULL;
539 message = NULL;
540 first = 1;
541
542 if (line == NULL)
543 {
544 return;
545 }
546
547 if (line[0] == '\0')
548 {
549 return;
550 }
551
552 // Don't igate packets read in from a log file (port -1).
553 // Packets from x_spider (port -2) are ok to igate.
554 if (port == -1)
555 {
556 return;
557 }
558
559 //fprintf(stderr,"Igating: %s\n", line);
560
561 // Should we Igate from RF->NET?
562 if (operate_as_an_igate <= 0)
563 {
564 return;
565 }
566
567 xastir_snprintf(temp,
568 sizeof(temp),
569 "%s",
570 line);
571
572 // Check for null call_sign field
573 call_sign = strtok(temp,">");
574 if (call_sign == NULL)
575 {
576 return;
577 }
578
579 // Check for null path field
580 path = strtok(NULL,":");
581 if (path == NULL)
582 {
583 return;
584 }
585
586 get_user_base_dir(LOGFILE_IGATE,log_file_path, sizeof(log_file_path));
587 // Check for "TCPIP" or "TCPXX" in the path. If found, don't
588 // gate this into the internet again, it's already been gated to
589 // RF, which means it's already been on the 'net. No looping
590 // allowed here...
591 //
592 // We also now support NOGATE and RFONLY options. If these are
593 // seen in the path, do _not_ gate those packets into the
594 // internet.
595 //
596 // Don't gate OpenTrac expanded packets to the 'net.
597 //
598 if ( (strstr(path,"TCPXX") != NULL)
599 || (strstr(path,"TCPIP") != NULL && port >= 0) // x_spider ok
600 || (strstr(path,"NOGATE") != NULL)
601 || (strstr(path,"RFONLY") != NULL)
602 || (strstr(path,"OPNTRK") != NULL) // OpenTrac Packet
603 || (strstr(path,"OPNTRC") != NULL) ) // OpenTrac Packet
604 {
605
606 if (log_igate && (debug_level & 1024) )
607 {
608
609 xastir_snprintf(temp,
610 sizeof(temp),
611 "IGATE RF->NET(%c):%s\n",
612 third_party ? 'T':'N',
613 line);
614 log_data( log_file_path, temp );
615
616 xastir_snprintf(temp,
617 sizeof(temp),
618 "REJECT: Packet was gated before or shouldn't be gated!\n");
619 log_data( log_file_path, temp );
620
621 fprintf(stderr, "%s", temp);
622 }
623 return;
624 }
625
626 // Check for null message field
627 message = strtok(NULL,"");
628 if (message == NULL)
629 {
630 return;
631 }
632
633 // Check for third party messages. We don't want to gate these
634 // back onto the internet feeds
635 // Note that the REPLY-ACK algorithm also uses the '}' symbol.
636 if (message[0] == '}')
637 {
638
639 if (log_igate && (debug_level & 1024) )
640 {
641
642 xastir_snprintf(temp,
643 sizeof(temp),
644 "IGATE RF->NET(%c):%s\n",
645 third_party ? 'T':'N',
646 line);
647 log_data( log_file_path, temp );
648
649 xastir_snprintf(temp,
650 sizeof(temp),
651 "REJECT: Third party traffic!\n");
652 log_data( log_file_path, temp );
653
654 fprintf(stderr, "%s", temp);
655 }
656 return;
657 }
658
659 // Check for "general" queries. We don't wish to gate these in
660 // either direction. There are exactly three general query
661 // types defined in the spec.
662 //
663 if ( ( strstr(message,"?APRS?" ) != NULL)
664 || (strstr(message,"?IGATE?") != NULL)
665 || (strstr(message,"?WX?" ) != NULL) )
666 {
667
668 // We found a general query, don't gate it.
669
670 if (log_igate && (debug_level & 1024) )
671 {
672
673 xastir_snprintf(temp,
674 sizeof(temp),
675 "IGATE RF->NET(%c):%s\n",
676 third_party ? 'T':'N',
677 line);
678 log_data( log_file_path, temp );
679
680 xastir_snprintf(temp,
681 sizeof(temp),
682 "REJECT: General Query!\n");
683 log_data( log_file_path, temp );
684
685 fprintf(stderr, "%s", temp);
686 }
687 return;
688 }
689
690 len = (int)strlen(call_sign);
691 for (i=0; i<len; i++)
692 {
693
694 // just in case we see an asterisk get rid of it
695 if (call_sign[i] == '*')
696 {
697 call_sign[i] = '\0';
698 i = len+1;
699 }
700 }
701
702 // Check for my callsign
703 if (strcmp(call_sign,my_callsign) == 0)
704 {
705
706 if (log_igate && (debug_level & 1024) )
707 {
708
709 xastir_snprintf(temp,
710 sizeof(temp),
711 "IGATE RF->NET(%c):%s\n",
712 third_party ? 'T':'N',
713 line);
714 log_data( log_file_path, temp );
715
716 xastir_snprintf(temp,
717 sizeof(temp),
718 "REJECT: From my call!\n");
719 log_data( log_file_path, temp );
720
721 fprintf(stderr, "%s", temp);
722 }
723 return;
724 }
725
726 // Should I filter out more here.. get rid of all data
727 // or Look in the path for things line "AP" "GPS" "ID" etc..?
728
729 begin_critical_section(&devices_lock, "igate.c:output_igate_net" );
730
731 // If received from x_spider port or it's our own tactical call.
732 // Here are the special port numbers we might see:
733 // -1: We're reading in from a log file
734 // -2: Packet came from x_spider server port (therefore it's
735 // already authenticated)
736 // -3: We're reading in tactical calls from file
737 //
738 if (port == -1) // Packet came from a log file.
739 {
740 igate_options = 0; // Don't igate it.
741 }
742
743 else if (port == -2) // Packet came from x_spider server port
744 {
745 igate_options = 1; // Ok to igate.
746 }
747
748 else if (port == -3) // We're reading tactical call from file.
749 {
750 igate_options = 0; // Don't igate it.
751 }
752
753 else if (port < -2) // Errant port number.
754 {
755 igate_options = 0; // Don't igate it.
756 }
757
758 else // Port number is 0 or positive number. A real port.
759 // Decide whether to igate it based on the port's
760 // configuration.
761 {
762 igate_options = devices[port].igate_options;
763 }
764
765
766 end_critical_section(&devices_lock, "igate.c:output_igate_net" );
767
768 if (igate_options <= 0 )
769 {
770
771 if (log_igate && (debug_level & 1024) )
772 {
773
774 xastir_snprintf(temp,
775 sizeof(temp),
776 "IGATE RF->NET(%c):%s\n",
777 third_party ? 'T':'N',
778 line);
779 log_data( log_file_path, temp );
780
781 xastir_snprintf(temp,
782 sizeof(temp),
783 "REJECT: No RF->NET from input port [%d]!\n",
784 port);
785 log_data( log_file_path, temp );
786
787 fprintf(stderr, "%s", temp);
788 }
789 return;
790 }
791
792 xastir_snprintf(data_txt,
793 sizeof(data_txt),
794 "%s%c%c",
795 line,
796 '\r',
797 '\n');
798
799 // write data out to net interfaces
800 for (x = 0; x < MAX_IFACE_DEVICES; x++)
801 {
802
803 // Find all internet interfaces that are "up"
804 if (port_data[x].device_type == DEVICE_NET_STREAM
805 && x!=port && port_data[x].status == DEVICE_UP)
806 {
807 int pcode;
808
809 // Check whether we have a valid callsign/password
810 // combination for this interface. If not, don't gate
811 // packets to it.
812 pcode = atoi(port_data[x].device_host_pswd);
813 if (checkHash(my_callsign, pcode))
814 {
815 // The pcode checks out. Allow sending the
816 // packet out to the internet.
817
818 // log traffic for the first "up" interface only
819 if (log_igate && first)
820 {
821 xastir_snprintf(temp,
822 sizeof(temp),
823 "IGATE RF->NET(%c):%s\n",
824 third_party ? 'T':'N',
825 line);
826 log_data( log_file_path, temp );
827
828 first = 0;
829 }
830
831 // Now log the interface that each bit of traffic
832 // goes out on.
833 xastir_snprintf(temp,
834 sizeof(temp),
835 "TRANSMIT: IGate RF->NET packet on device:%d\n",
836 x);
837
838 // log output
839 if (log_igate)
840 {
841 log_data( log_file_path, temp );
842 }
843
844 if (debug_level & 1024)
845 {
846 fprintf(stderr,"%s\n",temp);
847 }
848
849 // Write this data out to the Inet port The "1"
850 // means raw format, the last digit says to _not_
851 // use the unproto_igate path
852 output_my_data(data_txt,x,1,0,0,NULL);
853 //fprintf(stderr,"Sending: %s\n", data_txt);
854 }
855 }
856 }
857 }
858
859
860
861
862
863 /****************************************************************/
864 /* output data to tnc interfaces */
865 /* from: type of port heard from (No! It's the source call!) */
866 /* call: call sign heard from (No! It's the destination call!) */
867 /* line: data to gate to rf */
868 /* port: port data came from */
869 /****************************************************************/
output_igate_rf(char * from,char * call,char * path,char * line,int port,int third_party,char * object_name)870 void output_igate_rf(char *from, char *call, char *path, char *line,
871 int port, int third_party, char *object_name)
872 {
873
874 char temp[MAX_LINE_SIZE+20];
875 int x;
876 int first = 1;
877 int found_in_nws_file = 0;
878 char log_file_path[MAX_VALUE];
879 char nws_file_path[MAX_VALUE];
880
881
882 if ( (from == NULL) || (call == NULL) || (path == NULL) || (line == NULL) )
883 {
884 return;
885 }
886
887 if ( (from[0] == '\0') || (call[0] == '\0') || (path[0] == '\0') || (line[0] == '\0') )
888 {
889 return;
890 }
891
892 // Should we Igate from NET->RF?
893 if (operate_as_an_igate <= 1)
894 {
895 return;
896 }
897
898
899 get_user_base_dir(LOGFILE_IGATE,log_file_path, sizeof(log_file_path));
900
901 // Don't gate anything with NOGATE in it, in either direction.
902 // Same for OpenTrac packets.
903 if ( (strstr(path,"NOGATE") != NULL)
904 || (strstr(path,"OPNTRK") != NULL) // OpenTrac Packet
905 || (strstr(path,"OPNTRC") != NULL) ) // OpenTrac Packet
906 {
907 // "NOGATE" was found in the header. Don't gate it.
908 if (log_igate && (debug_level & 1024) )
909 {
910 xastir_snprintf(temp,
911 sizeof(temp),
912 "IGATE NET->RF(%c):%s\n",
913 third_party ? 'T':'N',
914 line);
915 log_data( log_file_path, temp );
916
917 xastir_snprintf(temp,
918 sizeof(temp),
919 "REJECT: NOGATE found in path or shouldn't be gated!\n");
920 log_data( log_file_path, temp );
921 fprintf(stderr, "%s", temp);
922 }
923 return;
924 }
925
926 // Don't gate "general" queries in any direction. There are
927 // exactly three general query types defined in the spec.
928 //
929 if ( (strstr(line,"?APRS?" ) != NULL)
930 || (strstr(line,"?IGATE?") != NULL)
931 || (strstr(line,"?WX?" ) != NULL) )
932 {
933
934 // We found a general query, don't gate it.
935
936 if (log_igate && (debug_level & 1024) )
937 {
938 xastir_snprintf(temp,
939 sizeof(temp),
940 "IGATE NET->RF(%c):%s\n",
941 third_party ? 'T':'N',
942 line);
943 log_data( log_file_path, temp );
944
945 xastir_snprintf(temp,
946 sizeof(temp),
947 "REJECT: General Query!\n");
948 log_data( log_file_path, temp );
949 fprintf(stderr, "%s", temp);
950 }
951 return;
952 }
953
954
955 // check to see if the nws-stations file is newer than last read
956 get_user_base_dir("data/nws-stations.txt",nws_file_path,
957 sizeof(nws_file_path));
958 if (last_nws_stations_file_time < file_time(nws_file_path))
959 {
960 last_nws_stations_file_time = file_time(nws_file_path);
961 load_NWS_stations(nws_file_path);
962 //fprintf(stderr,"NWS Station file time is old\n");
963 }
964
965
966 // Check whether gating of packets from this station/object/item
967 // has been specifically authorized via the nws-stations.txt
968 // mechanism.
969 //
970 if (object_name) // It's an object or item name
971 {
972
973 if ( check_NWS_stations( object_name ) || group_active(object_name))
974 {
975
976 found_in_nws_file++; // Object/Item is in nws-stations.txt
977 }
978 }
979 else // It's a station callsign
980 {
981
982 if ( check_NWS_stations( from ) || group_active(from))
983 {
984
985 found_in_nws_file++; // Source callsign is in nws-stations.txt
986 }
987 }
988 // The above is really the same as the following code, but less
989 // confusing:
990 // if (check_NWS_stations( (object_name) ? object_name : from ) ) {
991 // found_in_nws_file++;
992 // }
993
994
995 // Check for TCPXX in string only if station wasn't found in the
996 // nws-stations.txt file. If TCPXX found, we have an
997 // unregistered net user and the packet shouldn't normally head
998 // to RF.
999 //
1000 // I removed the trailing asterisk -we7u
1001 //
1002 // Note that we CAN now gate stations to RF that have TCPXX in
1003 // the string if they are authorized via the nws-stations.txt
1004 // mechanism.
1005 //
1006 if (!found_in_nws_file) // Skip this check if they're always authorized via the file
1007 {
1008
1009 if (strstr(path,"TCPXX") != NULL)
1010 {
1011
1012 // "TCPXX" was found in the header. We have an
1013 // unregistered user.
1014
1015 if (log_igate && (debug_level & 1024) )
1016 {
1017 xastir_snprintf(temp,
1018 sizeof(temp),
1019 "IGATE NET->RF(%c):%s\n",
1020 third_party ? 'T':'N',
1021 line);
1022 log_data( log_file_path, temp );
1023
1024 xastir_snprintf(temp,
1025 sizeof(temp),
1026 "REJECT: Unregistered net user!\n");
1027 log_data( log_file_path, temp );
1028 fprintf(stderr, "%s", temp);
1029 }
1030 return;
1031 }
1032 }
1033
1034
1035
1036 // If we made it to this point, the packet is from an authorized net
1037 // user (no TCPXX found in the path), or the callsign has been
1038 // authorized via the nws-stations.txt file (whether or not TCPXX
1039 // was found in the path).
1040 //
1041 // Found in file: Gate always
1042 //
1043 // Not found: Gate if TCPXX not in path -AND- if destination
1044 // station was heard in last hour on RF -AND- if
1045 // source station was NOT heard in last hour on RF.
1046
1047
1048
1049 // Check whether the source and destination calls have been
1050 // heard on local RF.
1051 if ( !found_in_nws_file // Skip this check if they're always authorized via the file
1052 && ( !heard_via_tnc_in_past_hour(call) // Haven't heard destination call in previous hour
1053 || heard_via_tnc_in_past_hour(from)) ) // Have heard source call in previous hour
1054 {
1055
1056 if (log_igate && (debug_level & 1024) )
1057 {
1058 xastir_snprintf(temp,
1059 sizeof(temp),
1060 "IGATE NET->RF(%c):%s\n",
1061 third_party ? 'T':'N',
1062 line);
1063 log_data( log_file_path, temp );
1064
1065 // heard(call), heard(from) : RF-to-RF talk
1066 // !heard(call), heard(from) : Destination not heard on TNC
1067 // !heard(call), !heard(from) : Destination/source not heard on TNC
1068
1069 if (!heard_via_tnc_in_past_hour(call))
1070 xastir_snprintf(temp,
1071 sizeof(temp),
1072 "REJECT: Destination not heard on TNC within an hour %s!\n",
1073 call );
1074 else
1075 xastir_snprintf(temp,
1076 sizeof(temp),
1077 "REJECT: RF->RF talk!\n");
1078 log_data( log_file_path, temp );
1079 fprintf(stderr, "%s", temp);
1080 }
1081 return;
1082 }
1083
1084
1085
1086 // Station we are going to is heard via tnc but station sending
1087 // shouldn't be heard via TNC. Write data out to interfaces.
1088 for (x=0; x<MAX_IFACE_DEVICES; x++)
1089 {
1090
1091 //fprintf(stderr,"%d\n",x);
1092
1093 //WE7U
1094 // Check here against "heard" queue for each interface.
1095 // Drop the packet on the floor if it was already received
1096 // on this interface within the last XX seconds. This means
1097 // that some other igate beat us to the punch. The receive
1098 // routines have to fill this queue. Prune outdated
1099 // records.
1100 //
1101 // Also check here against "sent" queue for each interface.
1102 // Drop the packet on the floor if already sent within the
1103 // last XX seconds. Add this packet to the queue if it
1104 // isn't already in it. Prune outdated records.
1105 if (x != port
1106 && not_a_dupe(HEARD, x, line, NO_FORCED_INSERT)
1107 && not_a_dupe( SENT, x, line, NO_FORCED_INSERT) )
1108 {
1109
1110 //fprintf(stderr,"output_igate_rf: Not a dupe port %d, transmitting\n",x);
1111
1112 switch (port_data[x].device_type)
1113 {
1114
1115 case DEVICE_SERIAL_TNC_AUX_GPS:
1116 case DEVICE_SERIAL_TNC_HSP_GPS:
1117 case DEVICE_SERIAL_TNC:
1118 case DEVICE_AX25_TNC:
1119 case DEVICE_SERIAL_KISS_TNC:
1120 case DEVICE_SERIAL_MKISS_TNC:
1121 case DEVICE_NET_AGWPE:
1122
1123 begin_critical_section(&devices_lock, "igate.c:output_igate_rf" );
1124
1125 if (devices[x].igate_options>1 && port_data[x].status==DEVICE_UP)
1126 {
1127
1128 // log traffic for first "up" interface only
1129 if (log_igate && first)
1130 {
1131 xastir_snprintf(temp,
1132 sizeof(temp),
1133 "IGATE NET->RF(%c):%s\n",
1134 third_party ? 'T':'N',
1135 line);
1136 log_data( log_file_path, temp );
1137 first = 0;
1138 }
1139
1140 xastir_snprintf(temp,
1141 sizeof(temp),
1142 "TRANSMIT: IGate NET->RF packet on device:%d\n",
1143 x);
1144
1145 // log output
1146 if (log_igate)
1147 {
1148 log_data( log_file_path, temp );
1149 }
1150
1151 if (debug_level & 1024)
1152 {
1153 fprintf(stderr, "%s", temp);
1154 }
1155
1156 // ok write this data out to the RF port
1157
1158 end_critical_section(&devices_lock, "igate.c:output_igate_rf" );
1159
1160 // First "0" means "cooked"
1161 // format, last digit: use
1162 // unproto_igate path
1163 output_my_data(line,x,0,0,1,NULL);
1164
1165 //fprintf(stderr, "Igating->RF: %s\n", line);
1166
1167 begin_critical_section(&devices_lock, "igate.c:output_igate_rf" );
1168
1169 }
1170 else
1171 {
1172 if (log_igate && (debug_level & 1024) )
1173 {
1174 xastir_snprintf(temp,
1175 sizeof(temp),
1176 "IGATE NET->RF(%c):%s\n",
1177 third_party ? 'T':'N',
1178 line);
1179 log_data( log_file_path, temp );
1180
1181 xastir_snprintf(temp,
1182 sizeof(temp),
1183 "REJECT: NET->RF on port [%d]!\n",
1184 x);
1185 log_data( log_file_path, temp );
1186 fprintf(stderr, "%s", temp);
1187 }
1188 }
1189
1190 end_critical_section(&devices_lock, "igate.c:output_igate_rf" );
1191
1192 break;
1193
1194 default:
1195 break;
1196 } // End of switch
1197 } // End of if
1198 } // End of for
1199 }
1200
1201
1202
1203
1204
add_NWS_stations(void)1205 void add_NWS_stations(void)
1206 {
1207 void *tmp_ptr;
1208
1209 if (NWS_stations>=max_NWS_stations)
1210 {
1211 if ((tmp_ptr = realloc(NWS_station_data, sizeof(NWS_Data)*(max_NWS_stations+11))))
1212 {
1213 NWS_station_data = tmp_ptr;
1214 max_NWS_stations += 10;
1215 }
1216 else
1217 {
1218 fprintf(stderr,"Unable to allocate more space for NWS_station_data\n");
1219 }
1220 }
1221 }
1222
1223
1224
1225
1226
1227 /****************************************************************/
1228 /* Load NWS stations file */
1229 /* file: file to read */
1230 /****************************************************************/
load_NWS_stations(char * file)1231 void load_NWS_stations(char *file)
1232 {
1233 FILE *f;
1234 char line[40];
1235
1236 if (file == NULL)
1237 {
1238 return;
1239 }
1240
1241 if (file[0] == '\0')
1242 {
1243 return;
1244 }
1245
1246 if (NWS_station_data)
1247 {
1248 free(NWS_station_data);
1249 NWS_station_data = NULL;
1250 }
1251
1252 NWS_stations = 0;
1253 max_NWS_stations = 0;
1254
1255 f = fopen(file,"r");
1256 if (f!=NULL)
1257 {
1258 while (!feof(f))
1259 {
1260 if (strlen(get_line(f,line,40))>0)
1261 {
1262 // look for comment
1263 if (line[0] != '#' )
1264 {
1265 NWS_stations++;
1266 add_NWS_stations();
1267 if (NWS_station_data != NULL)
1268 {
1269 // add data
1270 // Note: Size of string variable is 12
1271 // bytes, defined in igate.h
1272 if (1 != sscanf(line,"%11s",NWS_station_data[NWS_stations-1].call))
1273 {
1274 fprintf(stderr,"load_NWS_stations: sscanf parsing error\n");
1275 }
1276 if (debug_level & 1024)
1277 {
1278 fprintf(stderr,"LINE:%s\n",line);
1279 }
1280 }
1281 else
1282 {
1283 fprintf(stderr,"Can't allocate data space for NWS station\n");
1284 }
1285 }
1286 }
1287 }
1288 (void)fclose(f);
1289 }
1290 else
1291 {
1292 fprintf(stderr,"Couldn't open NWS stations file: %s\n", file);
1293 }
1294 }
1295
1296
1297
1298
1299
1300 // check NWS stations file
1301 //
1302 // call: call to check
1303 // returns 1 for found
1304 //
1305 // Both the incoming call and the stored call we're matching against
1306 // have to be >= 3 characters long. This routine will match only up
1307 // to the length of the stored string, so we now allow partial
1308 // matches.
1309 //
check_NWS_stations(char * call)1310 int check_NWS_stations(char *call)
1311 {
1312 int ok, i, length, length_incoming;
1313
1314
1315 if (call == NULL)
1316 {
1317 return(0);
1318 }
1319
1320 if (call[0] == '\0')
1321 {
1322 return(0);
1323 }
1324
1325 if (NWS_station_data == NULL)
1326 {
1327 return(0);
1328 }
1329
1330 if (debug_level & 1024)
1331 {
1332 fprintf(stderr,"igate.c::check_NWS_stations %s\n", call);
1333 }
1334
1335 // Make sure that the incoming call is longer than three
1336 // characters. If not, skip it.
1337 length_incoming = strlen(call);
1338 if (length_incoming < 3)
1339 {
1340 return(0);
1341 }
1342
1343 ok=0;
1344 for (i=0; i<NWS_stations && !ok; i++)
1345 {
1346
1347 // Compute length of stored string. If it's shorter than
1348 // three characters, skip it and go on to the next one.
1349 length = strlen(NWS_station_data[i].call);
1350
1351 if (length >= 3)
1352 {
1353 // Compare the incoming call only up to the length of the
1354 // stored call. This allows partial matches. The
1355 // stored call could be significantly shorter than the
1356 // incoming call, but at least three characters.
1357 if (strncasecmp(call, NWS_station_data[i].call, length)==0)
1358 {
1359
1360 ok=1; // match found
1361 if (debug_level & 1024)
1362 {
1363 fprintf(stderr,"NWS-MATCH:(%s) (%s)\n",NWS_station_data[i].call,call);
1364 }
1365 }
1366 }
1367 else
1368 {
1369 // Do nothing. Stored call is too short.
1370 }
1371 }
1372 return(ok);
1373 }
1374
1375
1376
1377
1378
1379 /****************************************************************/
1380 /* output NWS data to tnc interfaces */
1381 /* from: type of port heard from */
1382 /* call: call sign heard from */
1383 /* line: data to gate to rf */
1384 /* port: port data came from */
1385 /****************************************************************/
output_nws_igate_rf(char * from,char * path,char * line,int port,int third_party)1386 void output_nws_igate_rf(char *from, char *path, char *line, int port, int third_party)
1387 {
1388 char temp[MAX_LINE_SIZE+20];
1389 int x;
1390 int first = 1;
1391 char log_file_path[MAX_VALUE];
1392 char nws_file_path[MAX_VALUE];
1393
1394
1395 if ( (from == NULL) || (path == NULL) || (line == NULL) )
1396 {
1397 return;
1398 }
1399
1400 if ( (from[0] == '\0') || (path[0] == '\0') || (line[0] == '\0') )
1401 {
1402 return;
1403 }
1404
1405 // Should we Igate from NET->RF?
1406 if (operate_as_an_igate <= 1)
1407 {
1408 return;
1409 }
1410
1411 get_user_base_dir(LOGFILE_IGATE,log_file_path, sizeof(log_file_path));
1412 get_user_base_dir("data/nws-stations.txt",nws_file_path,
1413 sizeof(nws_file_path));
1414
1415 // Check for TCPXX in string! If found, we have an
1416 // unregistered net user.
1417 // I removed the trailing asterisk --we7u
1418 if (strstr(path,"TCPXX") != NULL)
1419 {
1420 // "TCPXX" was found in the header. We have an
1421 // unregistered user.
1422 if (log_igate && (debug_level & 1024) )
1423 {
1424 xastir_snprintf(temp,
1425 sizeof(temp),
1426 "NWS IGATE NET->RF(%c):%s\n",
1427 third_party ? 'T':'N',
1428 line);
1429 log_data( log_file_path, temp );
1430
1431 xastir_snprintf(temp,
1432 sizeof(temp),
1433 "REJECT: Unregistered net user!\n");
1434 log_data( log_file_path, temp );
1435 fprintf(stderr, "%s", temp);
1436 }
1437 return;
1438 }
1439
1440 // no unregistered net user found in string. Look for NOGATE
1441 // next.
1442
1443 if ( strstr(path,"NOGATE") != NULL )
1444 {
1445 // "NOGATE" was found in the header. Don't gate it.
1446 if (log_igate && (debug_level & 1024) )
1447 {
1448 xastir_snprintf(temp,
1449 sizeof(temp),
1450 "NWS IGATE NET->RF(%c):%s\n",
1451 third_party ? 'T':'N',
1452 line);
1453 log_data( log_file_path, temp );
1454
1455 xastir_snprintf(temp,
1456 sizeof(temp),
1457 "REJECT: NOGATE found in path!\n");
1458 log_data( log_file_path, temp );
1459 fprintf(stderr, "%s", temp);
1460 }
1461 return;
1462 }
1463
1464 // see if we can gate NWS messages
1465 if (!filethere(nws_file_path))
1466 {
1467 if (log_igate && (debug_level & 1024) )
1468 {
1469 xastir_snprintf(temp,
1470 sizeof(temp),
1471 "NWS IGATE NET->RF(%c):%s\n",
1472 third_party ? 'T':'N',
1473 line);
1474 log_data( log_file_path, temp );
1475
1476 xastir_snprintf(temp,
1477 sizeof(temp),
1478 "REJECT: No nws-stations.txt file!\n");
1479 log_data( log_file_path, temp );
1480 fprintf(stderr, "%s", temp);
1481 }
1482 return;
1483 }
1484
1485 // check to see if the nws-stations file is newer than last read
1486 if (last_nws_stations_file_time < file_time(nws_file_path))
1487 {
1488 last_nws_stations_file_time = file_time(nws_file_path);
1489 load_NWS_stations(nws_file_path);
1490 //fprintf(stderr,"NWS Station file time is old\n");
1491 }
1492
1493 // Look for NWS station in file data
1494 if (!check_NWS_stations(from) || !group_active(from)) // Couldn't find the station
1495 {
1496
1497 if (log_igate && (debug_level & 1024) )
1498 {
1499 xastir_snprintf(temp,
1500 sizeof(temp),
1501 "NWS IGATE NET->RF(%c):%s\n",
1502 third_party ? 'T':'N',
1503 line);
1504 log_data( log_file_path, temp );
1505
1506 xastir_snprintf(temp,
1507 sizeof(temp),
1508 "REJECT: No matching station in nws-stations.txt file!\n");
1509 log_data( log_file_path, temp );
1510 fprintf(stderr, "%s", temp);
1511 }
1512 return; // Match for station not found in file
1513 }
1514
1515 //fprintf(stderr,"SENDING NWS VIA TNC!!!!\n");
1516 // write data out to interfaces
1517 for (x=0; x<MAX_IFACE_DEVICES; x++)
1518 {
1519
1520 //WE7U
1521 // Check here against "heard" queue for each interface.
1522 // Drop the packet on the floor if it was already received
1523 // on this interface within the last XX seconds. This means
1524 // that some other igate beat us to the punch. The receive
1525 // routines have to fill this queue. Prune outdated
1526 // records.
1527 //
1528 // Also check here against "sent" queue for each interface.
1529 // Drop the packet on the floor if already sent within the
1530 // last XX seconds. Add this packet to the queue if it
1531 // isn't already in it. Prune outdated records.
1532 if (x != port
1533 && not_a_dupe(HEARD, x, line, NO_FORCED_INSERT)
1534 && not_a_dupe( SENT, x, line, NO_FORCED_INSERT) )
1535 {
1536
1537 switch (port_data[x].device_type)
1538 {
1539
1540 case DEVICE_SERIAL_TNC_AUX_GPS:
1541 case DEVICE_SERIAL_TNC_HSP_GPS:
1542 case DEVICE_SERIAL_TNC:
1543 case DEVICE_AX25_TNC:
1544 case DEVICE_SERIAL_KISS_TNC:
1545 case DEVICE_SERIAL_MKISS_TNC:
1546 case DEVICE_NET_AGWPE:
1547
1548 begin_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" );
1549
1550 if (devices[x].igate_options>1
1551 && port_data[x].status==DEVICE_UP)
1552 {
1553
1554 // log traffic for first "up" interface only
1555 if (log_igate && first)
1556 {
1557 xastir_snprintf(temp,
1558 sizeof(temp),
1559 "NWS IGATE NET->RF(%c):%s\n",
1560 third_party ? 'T':'N',
1561 line);
1562 log_data( log_file_path, temp );
1563 first = 0;
1564 }
1565
1566 xastir_snprintf(temp,
1567 sizeof(temp),
1568 "TRANSMIT: IGate NET->RF packet on device:%d\n",
1569 x);
1570
1571 // log output
1572 if (log_igate)
1573 {
1574 log_data( log_file_path, temp );
1575 }
1576
1577 if (debug_level & 1024)
1578 {
1579 fprintf(stderr, "%s", temp);
1580 }
1581
1582 // ok write this data out to the RF port
1583
1584 end_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" );
1585
1586 // First "0" means "cooked"
1587 // format, last digit: use
1588 // unproto_igate path
1589 output_my_data(line,x,0,0,1,NULL);
1590
1591 begin_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" );
1592
1593 }
1594 else
1595 {
1596 if (log_igate && (debug_level & 1024) )
1597 {
1598 xastir_snprintf(temp,
1599 sizeof(temp),
1600 "NWS IGATE NET->RF(%c):%s\n",
1601 third_party ? 'T':'N',
1602 line);
1603 log_data( log_file_path, temp );
1604
1605 xastir_snprintf(temp,
1606 sizeof(temp),
1607 "REJECT: NET->RF on port [%d]!\n",
1608 x);
1609 log_data( log_file_path, temp );
1610 fprintf(stderr, "%s", temp);
1611 }
1612 }
1613
1614 end_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" );
1615
1616 break;
1617
1618 default:
1619 break;
1620 }
1621 }
1622 }
1623 }
1624
1625
1626