|
@@ -47,9 +47,19 @@ static char *log_filename = NULL;
|
47
|
47
|
static int local_syslog = 0;
|
48
|
48
|
static int remote_syslog = 0;
|
49
|
49
|
|
|
50
|
+static int packet_from_file = 0;
|
|
51
|
+static int packet_buflen;
|
|
52
|
+static uint8_t packet_buf[256];
|
|
53
|
+static enum msg_type packet_type = ECM_MSG;
|
|
54
|
+
|
50
|
55
|
static void do_log(FILE *f, time_t now, const char *msg) {
|
51
|
56
|
char date[64];
|
52
|
57
|
struct tm tm;
|
|
58
|
+ // There is no need to show timestamps when debug options are used
|
|
59
|
+ if (packet_from_file) {
|
|
60
|
+ fprintf(f, "%s", msg);
|
|
61
|
+ return;
|
|
62
|
+ }
|
53
|
63
|
localtime_r(&now, &tm);
|
54
|
64
|
strftime(date, sizeof(date), "%F %H:%M:%S", localtime_r(&now, &tm));
|
55
|
65
|
fprintf(f, "%s | %s", date, msg);
|
|
@@ -66,9 +76,9 @@ static void LOG_func(const char *msg) {
|
66
|
76
|
LOG(msg);
|
67
|
77
|
}
|
68
|
78
|
|
69
|
|
-static const char short_options[] = "i:d:N:Sl:L:F:I:RzM:T:W:O:o:t:rk:g:upwxyc:C:Y:Q:A:s:U:P:B:eZ:Ef:X:H:G:KJ:D:jbhV";
|
|
79
|
+static const char short_options[] = "i:d:N:Sl:L:F:I:RzM:T:W:O:o:t:rk:g:upwxyc:C:Y:Q:A:s:U:P:B:eZ:Ef:X:H:G:KJ:D:jbhVn:m:";
|
70
|
80
|
|
71
|
|
-// Unused short options: amnqv0123456789
|
|
81
|
+// Unused short options: aqv0123456789
|
72
|
82
|
static const struct option long_options[] = {
|
73
|
83
|
{ "ident", required_argument, NULL, 'i' },
|
74
|
84
|
{ "daemon", required_argument, NULL, 'd' },
|
|
@@ -125,6 +135,9 @@ static const struct option long_options[] = {
|
125
|
135
|
{ "help", no_argument, NULL, 'h' },
|
126
|
136
|
{ "version", no_argument, NULL, 'V' },
|
127
|
137
|
|
|
138
|
+ { "ecm-file", required_argument, NULL, 'n' },
|
|
139
|
+ { "emm-file", required_argument, NULL, 'm' },
|
|
140
|
+
|
128
|
141
|
{ 0, 0, 0, 0 }
|
129
|
142
|
};
|
130
|
143
|
|
|
@@ -218,6 +231,10 @@ static void show_help(struct ts *ts) {
|
218
|
231
|
printf(" . 4 = packet debug\n");
|
219
|
232
|
printf(" . 5 = packet debug + packet dump\n");
|
220
|
233
|
printf("\n");
|
|
234
|
+ printf("Debugging options:\n");
|
|
235
|
+ printf(" -n --ecm-file <file.txt> | Read ECM from text file.\n");
|
|
236
|
+ printf(" -m --emm-file <file.txt> | Read EMM from text file.\n");
|
|
237
|
+ printf("\n");
|
221
|
238
|
printf("Misc options:\n");
|
222
|
239
|
printf(" -j --pid-report | Report how much packets were received.\n");
|
223
|
240
|
printf(" -b --bench | Benchmark decrypton.\n");
|
|
@@ -517,6 +534,17 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
|
517
|
534
|
csa_benchmark();
|
518
|
535
|
exit(EXIT_SUCCESS);
|
519
|
536
|
|
|
537
|
+ case 'n': // --ecm-file
|
|
538
|
+ case 'm': // --emm-file
|
|
539
|
+ packet_from_file = 1;
|
|
540
|
+ packet_buflen = file_hex2buf(optarg, packet_buf, sizeof(packet_buf));
|
|
541
|
+ if (!packet_buflen) {
|
|
542
|
+ fprintf(stderr, "ERROR: Can't init packet from file.\n");
|
|
543
|
+ exit(1);
|
|
544
|
+ }
|
|
545
|
+ packet_type = j == 'n' ? ECM_MSG : EMM_MSG;
|
|
546
|
+ break;
|
|
547
|
+
|
520
|
548
|
case 'h': // --help
|
521
|
549
|
show_help(ts);
|
522
|
550
|
exit(EXIT_SUCCESS);
|
|
@@ -531,6 +559,35 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
|
531
|
559
|
ident_err = 1;
|
532
|
560
|
}
|
533
|
561
|
|
|
562
|
+ if (packet_from_file) {
|
|
563
|
+ int err = 0;
|
|
564
|
+ if (!ts->forced_caid) {
|
|
565
|
+ fprintf(stderr, "ERROR: CAID was not set. Use --caid option.\n");
|
|
566
|
+ err++;
|
|
567
|
+ }
|
|
568
|
+ if (!ts->forced_service_id) {
|
|
569
|
+ fprintf(stderr, "ERROR: Service id was not set. Use --input-service option.\n");
|
|
570
|
+ err++;
|
|
571
|
+ }
|
|
572
|
+ if (err)
|
|
573
|
+ exit(EXIT_FAILURE);
|
|
574
|
+
|
|
575
|
+ ts->threaded = 0;
|
|
576
|
+ input_addr_err = 0;
|
|
577
|
+ output_addr_err = 0;
|
|
578
|
+ ts->input.type = FILE_IO;
|
|
579
|
+ ts->input.fd = 0;
|
|
580
|
+ ts->output.type = FILE_IO;
|
|
581
|
+ ts->output.fd = 1;
|
|
582
|
+ ts->pid_filter = 0;
|
|
583
|
+ ts->emm_send = 1;
|
|
584
|
+ ts->emm_report_interval = 0;
|
|
585
|
+ ts->ecm_report_interval = 0;
|
|
586
|
+ ts->cw_warn_sec = 0;
|
|
587
|
+ ts->camd.no_reconnect = 1;
|
|
588
|
+ ts->camd.check_emm_errors = 1;
|
|
589
|
+ }
|
|
590
|
+
|
534
|
591
|
// Constant codeword is special. Disable conflicting options
|
535
|
592
|
if (ts->camd.constant_codeword) {
|
536
|
593
|
server_err = 0; // No server settings are required
|
|
@@ -587,8 +644,10 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
|
587
|
644
|
ts_LOGf("Syslog : %s:%d\n", ts->syslog_host, ts->syslog_port);
|
588
|
645
|
else
|
589
|
646
|
ts_LOGf("Syslog : enabled\n");
|
590
|
|
- } else
|
591
|
|
- ts_LOGf("Syslog : disabled\n");
|
|
647
|
+ } else {
|
|
648
|
+ if (!packet_from_file)
|
|
649
|
+ ts_LOGf("Syslog : disabled\n");
|
|
650
|
+ }
|
592
|
651
|
|
593
|
652
|
if (!ts->camd.constant_codeword) {
|
594
|
653
|
if (ts->forced_caid)
|
|
@@ -615,7 +674,8 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
|
615
|
674
|
ts_LOGf("Input buff : %u ms\n", ts->input_buffer_time);
|
616
|
675
|
}
|
617
|
676
|
} else if (ts->input.type == FILE_IO) {
|
618
|
|
- ts_LOGf("Input file : %s\n", ts->input.fd == 0 ? "STDIN" : ts->input.fname);
|
|
677
|
+ if (!packet_from_file)
|
|
678
|
+ ts_LOGf("Input file : %s\n", ts->input.fd == 0 ? "STDIN" : ts->input.fname);
|
619
|
679
|
}
|
620
|
680
|
if (ts->input_dump_filename) {
|
621
|
681
|
ts->input_dump_file = fopen(ts->input_dump_filename, "w");
|
|
@@ -647,13 +707,16 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
|
647
|
707
|
RAND_bytes((unsigned char *)&(ts->rtp_seqnum), 2);
|
648
|
708
|
}
|
649
|
709
|
} else if (ts->output.type == FILE_IO) {
|
650
|
|
- ts_LOGf("Output file: %s\n", ts->output.fd == 1 ? "STDOUT" : ts->output.fname);
|
|
710
|
+ if (!packet_from_file)
|
|
711
|
+ ts_LOGf("Output file: %s\n", ts->output.fd == 1 ? "STDOUT" : ts->output.fname);
|
|
712
|
+ }
|
|
713
|
+ if (!packet_from_file) {
|
|
714
|
+ ts_LOGf("Out filter : %s (%s)%s\n",
|
|
715
|
+ ts->pid_filter ? "enabled" : "disabled",
|
|
716
|
+ ts->pid_filter ? "output only service related PIDs" : "output everything",
|
|
717
|
+ ts->no_output_on_error ? " (No output on CW error)" : ""
|
|
718
|
+ );
|
651
|
719
|
}
|
652
|
|
- ts_LOGf("Out filter : %s (%s)%s\n",
|
653
|
|
- ts->pid_filter ? "enabled" : "disabled",
|
654
|
|
- ts->pid_filter ? "output only service related PIDs" : "output everything",
|
655
|
|
- ts->no_output_on_error ? " (No output on CW error)" : ""
|
656
|
|
- );
|
657
|
720
|
if (ts->pid_filter) {
|
658
|
721
|
if (ts->nit_passthrough)
|
659
|
722
|
ts_LOGf("Out filter : Pass through NIT.\n");
|
|
@@ -672,36 +735,44 @@ static void parse_options(struct ts *ts, int argc, char **argv) {
|
672
|
735
|
ts_LOGf("CAMD deskey: %s\n", ts->camd.newcamd.hex_des_key);
|
673
|
736
|
}
|
674
|
737
|
|
675
|
|
- ts_LOGf("TS discont : %s\n", ts->ts_discont ? "report" : "ignore");
|
676
|
|
- ts->threaded = !(ts->input.type == FILE_IO && ts->input.fd != 0);
|
677
|
|
- if (ts->emm_send && ts->emm_report_interval)
|
678
|
|
- ts_LOGf("EMM report : %d sec\n", ts->emm_report_interval);
|
679
|
|
- if (ts->emm_send && ts->emm_report_interval == 0)
|
680
|
|
- ts_LOGf("EMM report : disabled\n");
|
681
|
|
- if (ts->forced_emm_pid)
|
682
|
|
- ts_LOGf("EMM pid : 0x%04x (%d)\n", ts->forced_emm_pid, ts->forced_emm_pid);
|
|
738
|
+ if (!packet_from_file) {
|
|
739
|
+ ts_LOGf("TS discont : %s\n", ts->ts_discont ? "report" : "ignore");
|
|
740
|
+ ts->threaded = !(ts->input.type == FILE_IO && ts->input.fd != 0);
|
|
741
|
+ }
|
|
742
|
+ if (!packet_from_file) {
|
|
743
|
+ if (ts->emm_send && ts->emm_report_interval)
|
|
744
|
+ ts_LOGf("EMM report : %d sec\n", ts->emm_report_interval);
|
|
745
|
+ if (ts->emm_send && ts->emm_report_interval == 0)
|
|
746
|
+ ts_LOGf("EMM report : disabled\n");
|
|
747
|
+ if (ts->forced_emm_pid)
|
|
748
|
+ ts_LOGf("EMM pid : 0x%04x (%d)\n", ts->forced_emm_pid, ts->forced_emm_pid);
|
|
749
|
+ }
|
683
|
750
|
if (ts->emm_only) {
|
684
|
751
|
ts_LOGf("EMM only : %s\n", ts->emm_only ? "yes" : "no");
|
685
|
752
|
} else {
|
686
|
|
- if (!ts->camd.constant_codeword)
|
687
|
|
- ts_LOGf("EMM send : %s\n", ts->emm_send ? "enabled" : "disabled");
|
688
|
|
- ts_LOGf("Decoding : %s\n", ts->threaded ? "threaded" : "single thread");
|
|
753
|
+ if (!packet_from_file) {
|
|
754
|
+ if (!ts->camd.constant_codeword)
|
|
755
|
+ ts_LOGf("EMM send : %s\n", ts->emm_send ? "enabled" : "disabled");
|
|
756
|
+ ts_LOGf("Decoding : %s\n", ts->threaded ? "threaded" : "single thread");
|
|
757
|
+ }
|
689
|
758
|
}
|
690
|
759
|
|
691
|
|
- if (!ts->emm_only && ts->ecm_report_interval)
|
692
|
|
- ts_LOGf("ECM report : %d sec\n", ts->emm_report_interval);
|
693
|
|
- if (!ts->emm_only && ts->ecm_report_interval == 0 && !ts->camd.constant_codeword)
|
694
|
|
- ts_LOGf("ECM report : disabled\n");
|
695
|
|
- if (ts->forced_ecm_pid)
|
696
|
|
- ts_LOGf("ECM pid : 0x%04x (%d)\n", ts->forced_ecm_pid, ts->forced_ecm_pid);
|
|
760
|
+ if (!packet_from_file) {
|
|
761
|
+ if (!ts->emm_only && ts->ecm_report_interval)
|
|
762
|
+ ts_LOGf("ECM report : %d sec\n", ts->emm_report_interval);
|
|
763
|
+ if (!ts->emm_only && ts->ecm_report_interval == 0 && !ts->camd.constant_codeword)
|
|
764
|
+ ts_LOGf("ECM report : disabled\n");
|
|
765
|
+ if (ts->forced_ecm_pid)
|
|
766
|
+ ts_LOGf("ECM pid : 0x%04x (%d)\n", ts->forced_ecm_pid, ts->forced_ecm_pid);
|
697
|
767
|
|
698
|
|
- if (!ts->emm_only && ts->cw_warn_sec)
|
699
|
|
- ts_LOGf("CW warning : %d sec\n", ts->cw_warn_sec);
|
700
|
|
- if (!ts->emm_only && ts->cw_warn_sec && !ts->camd.constant_codeword)
|
701
|
|
- ts_LOGf("CW warning : disabled\n");
|
|
768
|
+ if (!ts->emm_only && ts->cw_warn_sec)
|
|
769
|
+ ts_LOGf("CW warning : %d sec\n", ts->cw_warn_sec);
|
|
770
|
+ if (!ts->emm_only && ts->cw_warn_sec && !ts->camd.constant_codeword)
|
|
771
|
+ ts_LOGf("CW warning : disabled\n");
|
702
|
772
|
|
703
|
|
- if (!ts->ecm_cw_log && !ts->camd.constant_codeword)
|
704
|
|
- ts_LOGf("ECM/CW log : disabled\n");
|
|
773
|
+ if (!ts->ecm_cw_log && !ts->camd.constant_codeword)
|
|
774
|
+ ts_LOGf("ECM/CW log : disabled\n");
|
|
775
|
+ }
|
705
|
776
|
|
706
|
777
|
if (ts->ident) {
|
707
|
778
|
int len = strlen(ts->ident);
|
|
@@ -854,6 +925,16 @@ int main(int argc, char **argv) {
|
854
|
925
|
ts.emm_last_report = time(NULL) + FIRST_REPORT_SEC;
|
855
|
926
|
ts.ecm_last_report = time(NULL) + FIRST_REPORT_SEC;
|
856
|
927
|
camd_start(&ts);
|
|
928
|
+
|
|
929
|
+ if (packet_from_file) {
|
|
930
|
+ uint8_t tmp[2048];
|
|
931
|
+ ts_hex_dump_buf((char *)tmp, sizeof(tmp), packet_buf, packet_buflen, 16);
|
|
932
|
+ ts_LOGf("%s | Processing packet with CAID 0x%04x\n", packet_type == ECM_MSG ? "ECM" : "EMM", ts.forced_caid);
|
|
933
|
+ ts_LOGf("%s | Packet dump:\n%s\n", packet_type == ECM_MSG ? "ECM" : "EMM", tmp);
|
|
934
|
+ camd_process_packet(&ts, camd_msg_alloc(packet_type, ts.forced_caid, ts.forced_service_id, packet_buf, packet_buflen));
|
|
935
|
+ goto EXIT;
|
|
936
|
+ }
|
|
937
|
+
|
857
|
938
|
do {
|
858
|
939
|
if (!ts.camd.constant_codeword)
|
859
|
940
|
do_reports(&ts);
|