|
@@ -101,21 +101,21 @@ int debug_level = 0;
|
101
|
101
|
static void show_ts_pack(uint16_t pid, char *wtf, char *extra, uint8_t *ts_packet) {
|
102
|
102
|
char cw1_dump[8 * 6];
|
103
|
103
|
char cw2_dump[8 * 6];
|
104
|
|
- if (debug_level < 4)
|
105
|
|
- return;
|
106
|
|
- if (ts_pack_shown)
|
107
|
|
- return;
|
108
|
|
- int stype = ts_packet_get_scrambled(ts_packet);
|
109
|
|
- ts_hex_dump_buf(cw1_dump, 8 * 6, cur_cw , 8, 0);
|
110
|
|
- ts_hex_dump_buf(cw2_dump, 8 * 6, cur_cw + 8, 8, 0);
|
111
|
|
- fprintf(stderr, "@ %s %s %03x %5ld %7ld | %s %s | %s\n",
|
112
|
|
- stype == 0 ? "------" :
|
113
|
|
- stype == 2 ? "even 0" :
|
114
|
|
- stype == 3 ? "odd 1" : "??????",
|
115
|
|
- wtf,
|
116
|
|
- pid,
|
117
|
|
- ts_pack, ts_pack * 188,
|
118
|
|
- cw1_dump, cw2_dump, extra ? extra : wtf);
|
|
104
|
+ if (debug_level >= 4) {
|
|
105
|
+ if (ts_pack_shown)
|
|
106
|
+ return;
|
|
107
|
+ int stype = ts_packet_get_scrambled(ts_packet);
|
|
108
|
+ ts_hex_dump_buf(cw1_dump, 8 * 6, cur_cw , 8, 0);
|
|
109
|
+ ts_hex_dump_buf(cw2_dump, 8 * 6, cur_cw + 8, 8, 0);
|
|
110
|
+ fprintf(stderr, "@ %s %s %03x %5ld %7ld | %s %s | %s\n",
|
|
111
|
+ stype == 0 ? "------" :
|
|
112
|
+ stype == 2 ? "even 0" :
|
|
113
|
+ stype == 3 ? "odd 1" : "??????",
|
|
114
|
+ wtf,
|
|
115
|
+ pid,
|
|
116
|
+ ts_pack, ts_pack * 188,
|
|
117
|
+ cw1_dump, cw2_dump, extra ? extra : wtf);
|
|
118
|
+ }
|
119
|
119
|
}
|
120
|
120
|
|
121
|
121
|
static void dump_ts_pack(uint16_t pid, uint8_t *ts_packet) {
|
|
@@ -134,15 +134,139 @@ static void dump_ts_pack(uint16_t pid, uint8_t *ts_packet) {
|
134
|
134
|
|
135
|
135
|
enum CA_system req_CA_sys = CA_CONNAX;
|
136
|
136
|
int server_fd = -1;
|
137
|
|
-char *camd35_server = "10.0.1.78";
|
138
|
|
-struct in_addr camd35_server_ip;
|
139
|
|
-uint16_t camd35_port = 2233;
|
|
137
|
+struct in_addr camd35_server_addr;
|
|
138
|
+unsigned int camd35_server_port = 2233;
|
140
|
139
|
char *camd35_user = "user";
|
141
|
140
|
char *camd35_pass = "pass";
|
142
|
141
|
uint32_t camd35_auth = 0;
|
143
|
142
|
AES_KEY camd35_aes_encrypt_key;
|
144
|
143
|
AES_KEY camd35_aes_decrypt_key;
|
145
|
144
|
|
|
145
|
+int emm_filter = 0;
|
|
146
|
+
|
|
147
|
+struct in_addr output_addr;
|
|
148
|
+unsigned int output_port;
|
|
149
|
+int output_ttl = 1;
|
|
150
|
+struct in_addr output_intf;
|
|
151
|
+
|
|
152
|
+void show_help() {
|
|
153
|
+ printf("TSDECRYPT v1.0\n");
|
|
154
|
+ printf("Copyright (c) 2011 Unix Solutions Ltd.\n");
|
|
155
|
+ printf("\n");
|
|
156
|
+ printf(" Usage: tsdecrypt [opts] < mpeg_ts\n");
|
|
157
|
+ printf("\n");
|
|
158
|
+ printf(" Options:\n");
|
|
159
|
+ printf(" -c ca_system | default: %s valid: IRDETO, CONNAX, CRYPTOWORKS\n", ts_get_CA_sys_txt(req_CA_sys));
|
|
160
|
+ printf(" -e | Disable EMM processing.\n");
|
|
161
|
+ printf("\n");
|
|
162
|
+ printf(" CAMD35 server options:\n");
|
|
163
|
+ printf(" -s server_addr | default: disabled (format 1.2.3.4:2233)\n");
|
|
164
|
+ printf(" -U server_user | default: %s\n", camd35_user);
|
|
165
|
+ printf(" -P server_pass | default: %s\n", camd35_pass);
|
|
166
|
+ printf("\n");
|
|
167
|
+ printf(" Output options (if output is disabled stdout is used for output):\n");
|
|
168
|
+ printf(" -o output_addr | default: disabled (format: 239.78.78.78:5000)\n");
|
|
169
|
+ printf(" -i output_intf | default: %s\n", inet_ntoa(output_intf));
|
|
170
|
+ printf(" -t output_ttl | default: %d\n", output_ttl);
|
|
171
|
+ printf("\n");
|
|
172
|
+ printf(" Misc options:\n");
|
|
173
|
+ printf(" -D debug_level | level 0 - default messages\n");
|
|
174
|
+ printf(" level 1 - show PSI tables\n");
|
|
175
|
+ printf(" level 2 - show EMMs\n");
|
|
176
|
+ printf(" level 3 - show duplicate ECMs\n");
|
|
177
|
+ printf(" level 4 - packet debug\n");
|
|
178
|
+ printf("\n");
|
|
179
|
+}
|
|
180
|
+
|
|
181
|
+void parse_options(int argc, char **argv) {
|
|
182
|
+ int j, ca_err = 0, server_err = 1, output_addr_err = 0, output_intf_err = 0;
|
|
183
|
+ while ((j = getopt(argc, argv, "ces:o:i:t:U:P:D:h")) != -1) {
|
|
184
|
+ char *p = NULL;
|
|
185
|
+ switch (j) {
|
|
186
|
+ case 'c':
|
|
187
|
+ if (strcasecmp("IRDETO", optarg) == 0)
|
|
188
|
+ req_CA_sys = CA_IRDETO;
|
|
189
|
+ else if (strcasecmp("CONNAX", optarg) == 0)
|
|
190
|
+ req_CA_sys = CA_CONNAX;
|
|
191
|
+ else if (strcasecmp("CRYPTOWORKS", optarg) == 0)
|
|
192
|
+ req_CA_sys = CA_CRYPTOWORKS;
|
|
193
|
+ else
|
|
194
|
+ ca_err = 1;
|
|
195
|
+ break;
|
|
196
|
+ case 'e':
|
|
197
|
+ emm_filter = 1;
|
|
198
|
+ break;
|
|
199
|
+
|
|
200
|
+ case 's':
|
|
201
|
+ p = strrchr(optarg, ':');
|
|
202
|
+ if (p) {
|
|
203
|
+ *p = 0x00;
|
|
204
|
+ camd35_server_port = atoi(p + 1);
|
|
205
|
+ }
|
|
206
|
+ if (inet_aton(optarg, &camd35_server_addr) == 0)
|
|
207
|
+ server_err = 1;
|
|
208
|
+ else
|
|
209
|
+ server_err = 0;
|
|
210
|
+ break;
|
|
211
|
+
|
|
212
|
+ case 'o':
|
|
213
|
+ p = strrchr(optarg, ':');
|
|
214
|
+ if (p) {
|
|
215
|
+ *p = 0x00;
|
|
216
|
+ output_port = atoi(p + 1);
|
|
217
|
+ }
|
|
218
|
+ if (inet_aton(optarg, &output_addr) == 0)
|
|
219
|
+ output_addr_err = 1;
|
|
220
|
+ break;
|
|
221
|
+ case 'i':
|
|
222
|
+ if (inet_aton(optarg, &output_intf) == 0)
|
|
223
|
+ output_intf_err = 1;
|
|
224
|
+ break;
|
|
225
|
+ case 't':
|
|
226
|
+ output_ttl = atoi(optarg);
|
|
227
|
+ break;
|
|
228
|
+
|
|
229
|
+ case 'U':
|
|
230
|
+ camd35_user = optarg;
|
|
231
|
+ break;
|
|
232
|
+ case 'P':
|
|
233
|
+ camd35_pass = optarg;
|
|
234
|
+ break;
|
|
235
|
+
|
|
236
|
+ case 'D':
|
|
237
|
+ debug_level = atoi(optarg);
|
|
238
|
+ break;
|
|
239
|
+
|
|
240
|
+ case 'h':
|
|
241
|
+ show_help();
|
|
242
|
+ exit(0);
|
|
243
|
+ }
|
|
244
|
+ }
|
|
245
|
+ if (ca_err || server_err) {
|
|
246
|
+ show_help();
|
|
247
|
+ if (ca_err)
|
|
248
|
+ fprintf(stderr, "ERROR: Requested CA system is unsupported.\n");
|
|
249
|
+ if (server_err)
|
|
250
|
+ fprintf(stderr, "ERROR: Server IP address is not set or it is invalid.\n");
|
|
251
|
+ if (output_addr_err)
|
|
252
|
+ fprintf(stderr, "ERROR: Output IP address is invalid.\n");
|
|
253
|
+ if (output_intf_err)
|
|
254
|
+ fprintf(stderr, "ERROR: Output interface address is invalid.\n");
|
|
255
|
+ exit(1);
|
|
256
|
+ }
|
|
257
|
+ ts_LOGf("CA System : %s\n", ts_get_CA_sys_txt(req_CA_sys));
|
|
258
|
+ ts_LOGf("EMM : %s\n", emm_filter ? "filter" : "process");
|
|
259
|
+ ts_LOGf("Server addr: %s:%u\n", inet_ntoa(camd35_server_addr), camd35_server_port);
|
|
260
|
+ ts_LOGf("Server user: %s\n", camd35_user);
|
|
261
|
+ ts_LOGf("Server pass: %s\n", camd35_pass);
|
|
262
|
+ if (output_port) {
|
|
263
|
+ ts_LOGf("Output addr: %s:%u\n", inet_ntoa(output_addr), output_port);
|
|
264
|
+ ts_LOGf("Output intf: %s\n", inet_ntoa(output_intf));
|
|
265
|
+ ts_LOGf("Output ttl : %d\n", output_ttl);
|
|
266
|
+ }
|
|
267
|
+
|
|
268
|
+}
|
|
269
|
+
|
146
|
270
|
static int connect_to(struct in_addr ip, int port) {
|
147
|
271
|
ts_LOGf("Connecting to %s:%d\n", inet_ntoa(ip), port);
|
148
|
272
|
|
|
@@ -181,7 +305,7 @@ static void camd35_init_auth(char *user, char *pass) {
|
181
|
305
|
|
182
|
306
|
static void camd35_connect() {
|
183
|
307
|
if (server_fd < 0)
|
184
|
|
- server_fd = connect_to(camd35_server_ip, camd35_port);
|
|
308
|
+ server_fd = connect_to(camd35_server_addr, camd35_server_port);
|
185
|
309
|
}
|
186
|
310
|
|
187
|
311
|
static int camd35_recv(uint8_t *data, int *data_len) {
|
|
@@ -215,14 +339,14 @@ NEXT:
|
215
|
339
|
if (camd35_recv(data, &data_len) < 0)
|
216
|
340
|
ERR("No data!");
|
217
|
341
|
|
218
|
|
- if (data_len < 48)
|
219
|
|
- ERR("len mismatch != 48");
|
220
|
|
-
|
221
|
342
|
if (data[0] < 0x01) {
|
222
|
343
|
ts_LOGf("Not valid CW response, skipping it. data[0] = 0x%02x\n", data[0]);
|
223
|
344
|
goto NEXT;
|
224
|
345
|
}
|
225
|
346
|
|
|
347
|
+ if (data_len < 48)
|
|
348
|
+ ERR("len mismatch != 48");
|
|
349
|
+
|
226
|
350
|
if (data[1] < 0x10)
|
227
|
351
|
ERR("CW len mismatch != 0x10");
|
228
|
352
|
|
|
@@ -319,7 +443,8 @@ static int camd35_send_emm(uint16_t ca_id, uint8_t *data, uint8_t data_len) {
|
319
|
443
|
ts_##TABLE##_free(&ts->TABLE); \
|
320
|
444
|
ts->TABLE = ts_##TABLE##_copy(ts->cur##TABLE); \
|
321
|
445
|
ts_##TABLE##_clear(ts->cur##TABLE); \
|
322
|
|
- ts_##TABLE##_dump(ts->TABLE); \
|
|
446
|
+ if (debug_level >= 1) \
|
|
447
|
+ ts_##TABLE##_dump(ts->TABLE); \
|
323
|
448
|
} while(0)
|
324
|
449
|
|
325
|
450
|
void process_pat(struct ts *ts, uint16_t pid, uint8_t *ts_packet) {
|
|
@@ -381,14 +506,17 @@ void process_emm(struct ts *ts, uint16_t pid, uint8_t *ts_packet) {
|
381
|
506
|
|
382
|
507
|
struct ts_header *th = &ts->emm->ts_header;
|
383
|
508
|
struct ts_section_header *sec = ts->emm->section_header;
|
384
|
|
- ts_hex_dump_buf(dump, dump_buf_sz, sec->section_data, min(dump_sz, sec->section_data_len), 0);
|
385
|
|
- ts_LOGf("EMM | CAID: 0x%04x PID 0x%04x Table: 0x%02x Length: %3d ----------- Data: %s..\n",
|
386
|
|
- ts->emm_caid,
|
387
|
|
- th->pid,
|
388
|
|
- sec->table_id,
|
389
|
|
- sec->section_data_len,
|
390
|
|
- dump);
|
391
|
|
- camd35_send_emm(ts->emm_caid, sec->section_data, sec->section_data_len);
|
|
509
|
+ if (debug_level >= 2) {
|
|
510
|
+ ts_hex_dump_buf(dump, dump_buf_sz, sec->section_data, min(dump_sz, sec->section_data_len), 0);
|
|
511
|
+ ts_LOGf("EMM | CAID: 0x%04x PID 0x%04x Table: 0x%02x Length: %3d ----------- Data: %s..\n",
|
|
512
|
+ ts->emm_caid,
|
|
513
|
+ th->pid,
|
|
514
|
+ sec->table_id,
|
|
515
|
+ sec->section_data_len,
|
|
516
|
+ dump);
|
|
517
|
+ }
|
|
518
|
+ if (!emm_filter)
|
|
519
|
+ camd35_send_emm(ts->emm_caid, sec->section_data, sec->section_data_len);
|
392
|
520
|
ts_privsec_copy(ts->emm, ts->last_emm);
|
393
|
521
|
ts_privsec_clear(ts->emm);
|
394
|
522
|
}
|
|
@@ -415,7 +543,7 @@ void process_ecm(struct ts *ts, uint16_t pid, uint8_t *ts_packet) {
|
415
|
543
|
ts->ecm_counter,
|
416
|
544
|
dump);
|
417
|
545
|
camd35_send_ecm(ts->service_id, ts->ecm_caid, ts->ecm_counter++, sec->section_data, sec->section_data_len);
|
418
|
|
- } else if (debug_level > 2) {
|
|
546
|
+ } else if (debug_level >= 3) {
|
419
|
547
|
ts_LOGf("ECM | CAID: 0x%04x PID 0x%04x Table: 0x%02x Length: %3d IDX: 0x%04x Data: -dup-\n",
|
420
|
548
|
ts->ecm_caid,
|
421
|
549
|
th->pid,
|
|
@@ -474,78 +602,6 @@ void ts_write_packets(struct ts *ts, uint8_t *data, ssize_t data_len) {
|
474
|
602
|
*/
|
475
|
603
|
}
|
476
|
604
|
|
477
|
|
-void show_help() {
|
478
|
|
- printf("TSDECRYPT v1.0\n");
|
479
|
|
- printf("Copyright (c) 2011 Unix Solutions Ltd.\n");
|
480
|
|
- printf("\n");
|
481
|
|
- printf(" Usage: tsdecrypt [opts] < mpeg_ts > mpeg_ts.decrypted\n");
|
482
|
|
- printf("\n");
|
483
|
|
- printf(" Options:\n");
|
484
|
|
- printf(" -C ca_system | default: %s valid: IRDETO, CONNAX, CRYPTOWORKS\n", ts_get_CA_sys_txt(req_CA_sys));
|
485
|
|
- printf("\n");
|
486
|
|
- printf(" Server options:\n");
|
487
|
|
- printf(" -S server_ip | default: %s\n", camd35_server);
|
488
|
|
- printf(" -P server_port | default: %u\n", (unsigned int)camd35_port);
|
489
|
|
- printf(" -u server_user | default: %s\n", camd35_user);
|
490
|
|
- printf(" -p server_pass | default: %s\n", camd35_pass);
|
491
|
|
- printf("\n");
|
492
|
|
- exit(0);
|
493
|
|
-}
|
494
|
|
-
|
495
|
|
-void parse_options(int argc, char **argv) {
|
496
|
|
- int j, ca_err = 0, server_err = 0;
|
497
|
|
- inet_aton(camd35_server, &camd35_server_ip);
|
498
|
|
- while ((j = getopt(argc, argv, "C:S:P:u:p:hd:")) != -1) {
|
499
|
|
- switch (j) {
|
500
|
|
- case 'C':
|
501
|
|
- if (strcasecmp("IRDETO", optarg) == 0)
|
502
|
|
- req_CA_sys = CA_IRDETO;
|
503
|
|
- else if (strcasecmp("CONNAX", optarg) == 0)
|
504
|
|
- req_CA_sys = CA_CONNAX;
|
505
|
|
- else if (strcasecmp("CRYPTOWORKS", optarg) == 0)
|
506
|
|
- req_CA_sys = CA_CRYPTOWORKS;
|
507
|
|
- else
|
508
|
|
- ca_err = 1;
|
509
|
|
- break;
|
510
|
|
- case 'S':
|
511
|
|
- camd35_server = optarg;
|
512
|
|
- if (inet_aton(camd35_server, &camd35_server_ip) == 0)
|
513
|
|
- server_err = 1;
|
514
|
|
- break;
|
515
|
|
- case 'P':
|
516
|
|
- camd35_port = atoi(optarg);
|
517
|
|
- break;
|
518
|
|
- case 'u':
|
519
|
|
- camd35_user = optarg;
|
520
|
|
- break;
|
521
|
|
- case 'p':
|
522
|
|
- camd35_pass = optarg;
|
523
|
|
- break;
|
524
|
|
- case 'd':
|
525
|
|
- debug_level = atoi(optarg);
|
526
|
|
- break;
|
527
|
|
- case 'h':
|
528
|
|
- show_help();
|
529
|
|
- exit(0);
|
530
|
|
- }
|
531
|
|
- }
|
532
|
|
- if (ca_err || server_err) {
|
533
|
|
- if (ca_err)
|
534
|
|
- fprintf(stderr, "ERROR: Unknown CA\n");
|
535
|
|
- if (server_err)
|
536
|
|
- fprintf(stderr, "ERROR: Invalid server IP address\n");
|
537
|
|
- fprintf(stderr, "\n");
|
538
|
|
- show_help();
|
539
|
|
- exit(1);
|
540
|
|
- }
|
541
|
|
- ts_LOGf("CA System : %s\n", ts_get_CA_sys_txt(req_CA_sys));
|
542
|
|
- ts_LOGf("Server\n");
|
543
|
|
- ts_LOGf(" Addr : %s:%d\n", inet_ntoa(camd35_server_ip), camd35_port);
|
544
|
|
- ts_LOGf(" Auth : %s / %s\n", camd35_user, camd35_pass);
|
545
|
|
-
|
546
|
|
- camd35_connect();
|
547
|
|
-}
|
548
|
|
-
|
549
|
605
|
#define FRAME_SIZE (188 * 7)
|
550
|
606
|
|
551
|
607
|
int main(int argc, char **argv) {
|
|
@@ -560,6 +616,8 @@ int main(int argc, char **argv) {
|
560
|
616
|
|
561
|
617
|
parse_options(argc, argv);
|
562
|
618
|
|
|
619
|
+ camd35_connect();
|
|
620
|
+
|
563
|
621
|
struct ts *ts = ts_alloc();
|
564
|
622
|
do {
|
565
|
623
|
readen = read(0, ts_packet, FRAME_SIZE);
|