Browse Source

Add support for sending ECM/EMM packets from file.

Georgi Chorbadzhiyski 11 years ago
parent
commit
27379785be
6 changed files with 199 additions and 34 deletions
  1. 2
    0
      ChangeLog
  2. 7
    0
      README
  3. 29
    0
      tsdecrypt.1
  4. 115
    34
      tsdecrypt.c
  5. 45
    0
      util.c
  6. 1
    0
      util.h

+ 2
- 0
ChangeLog View File

@@ -5,6 +5,8 @@
5 5
   --no-output-filter.
6 6
  * Allow camd server address (--camd-server, -s) to be resolved, not only
7 7
    set by IP address.
8
+ * Allow tsdecrypt to read ECM/EMM packet from text file. The added
9
+   parameters are -n, -ecm-file <file> and -m --emm-file <file>.
8 10
 
9 11
 2012-04-19 : Version 8.1
10 12
  * Add support for Bulcrypt CAS.

+ 7
- 0
README View File

@@ -180,6 +180,10 @@ Logging options:
180 180
                             .    4 = packet debug
181 181
                             .    5 = packet debug + packet dump
182 182
 
183
+Debugging options:
184
+ -n --ecm-file <file.txt>   | Read ECM from text file.
185
+ -m --emm-file <file.txt>   | Read EMM from text file.
186
+
183 187
 Misc options:
184 188
  -j --pid-report            | Report how much packets were received.
185 189
  -b --bench                 | Benchmark decrypton.
@@ -236,6 +240,9 @@ Examples:
236 240
    tsdecrypt --const-cw 0x00000000000000001111111111111111 \
237 241
        --input encrypted-file.ts --output decrypted-file.ts
238 242
 
243
+   # Send ECM from file
244
+   tsdecrypt --ecm-file ecm.txt --caid 0x5581 --input-service 12345 \
245
+       --camd-server example.com
239 246
 
240 247
 OSCAM cs378x configuration
241 248
 ==========================

+ 29
- 0
tsdecrypt.1 View File

@@ -241,6 +241,35 @@ reports are not affected by this option.
241 241
 \fB\-J\fR, \fB\-\-cw\-warn\-time\fR <seconds>
242 242
 After how much seconds to warn if valid code word was not received.
243 243
 The default is \fB60\fR seconds. Set to \fB0\fR to disable the warning.
244
+.TP
245
+.SH DEBUG OPTIONS
246
+.PP
247
+.TP
248
+\fB\-n\fR, \fB\-\-ecm\-file\fR <file.txt>
249
+Read ECM from text file and send it to CAMD server for processing. This
250
+option must be used along with \fB\-\-caid\fR and \fB\-\-input-service\fR
251
+options.
252
+
253
+The file should be normal text file, the format of the file is described
254
+bellow.
255
+.TP
256
+\fB\-m\fR, \fB\-\-emm\-file\fR <file.txt>
257
+Read EMM from text file and send it to CAMD server for processing. This
258
+option must be used along with \fB\-\-caid\fR and \fB\-\-input-service\fR
259
+options.
260
+
261
+Bellow is an example text file, lines starting with # are ignored and
262
+also 0x prefixes are ignored. Any other symbol in the file is processed
263
+as hex number. An example file might look like this:
264
+
265
+.nf
266
+    # comment
267
+    aa bb cc dd ee
268
+    ff 01 02 03 04
269
+    # Other comment
270
+    0x05 0x06 0x07
271
+.fi
272
+
244 273
 .SH EVENTS
245 274
 Notification events are sent when \fB\-\-notify\-program\fR and \fB\-\-ident\fR
246 275
 options are used. The event parameters are set as environmental variables

+ 115
- 34
tsdecrypt.c View File

@@ -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);

+ 45
- 0
util.c View File

@@ -13,6 +13,10 @@
13 13
  *
14 14
  */
15 15
 
16
+#include <stdio.h>
17
+#include <stdlib.h>
18
+#include <unistd.h>
19
+#include <ctype.h>
16 20
 #include <time.h>
17 21
 #include <string.h>
18 22
 #include <errno.h>
@@ -176,3 +180,44 @@ int64_t get_time(void) {
176 180
 #endif
177 181
 	return ts.tv_sec * 1000000ll + ts.tv_nsec / 1000;
178 182
 }
183
+
184
+unsigned int file_hex2buf(char *filename, uint8_t *buffer, unsigned int buf_size) {
185
+	FILE *f = fopen(filename, "r");
186
+	if (!f) {
187
+		fprintf(stderr, "ERROR: Can't open %s: %s\n", filename, strerror(errno));
188
+		exit(1);
189
+	}
190
+	memset(buffer, 0, buf_size);
191
+	size_t len;
192
+	ssize_t readb;
193
+	char *line = NULL;
194
+	unsigned int buf_pos = 0, consumed = 0;
195
+	while ((readb = getline(&line, &len, f)) != -1) {
196
+		ssize_t i;
197
+		if (!readb || line[0] == '#')
198
+			continue;
199
+		for (i = 0; i < readb; i++) {
200
+			char ch = toupper(line[i]);
201
+			// Skip 0x prefixes
202
+			if (i + 1 < readb && ch == '0' && toupper(line[i+1]) == 'X')
203
+				continue;
204
+			if (!isxdigit(ch))
205
+				continue;
206
+			ch -= ch > 64 ? 55 : 48; // hex2dec
207
+			if (consumed % 2 == 0) {
208
+				buffer[buf_pos] += ch << 4;
209
+			} else {
210
+				buffer[buf_pos] += ch;
211
+				buf_pos++;
212
+				if (buf_pos == buf_size)
213
+					goto OUT;
214
+			}
215
+			consumed++;
216
+		}
217
+	}
218
+OUT:
219
+	free(line);
220
+	fclose(f);
221
+
222
+	return buf_pos;
223
+}

+ 1
- 0
util.h View File

@@ -25,5 +25,6 @@ uint8_t *init_2b(uint32_t val, uint8_t *b);
25 25
 void set_thread_name(char *thread_name);
26 26
 int decode_hex_string(char *hex, uint8_t *bin, int asc_len);
27 27
 int64_t get_time(void);
28
+unsigned int file_hex2buf(char *filename, uint8_t *buffer, unsigned int buf_size);
28 29
 
29 30
 #endif

Loading…
Cancel
Save