|
@@ -13,47 +13,40 @@
|
13
|
13
|
#include "camd.h"
|
14
|
14
|
#include "tables.h"
|
15
|
15
|
|
16
|
|
-struct key key;
|
17
|
|
-struct camd35 camd35;
|
18
|
|
-
|
19
|
|
-int debug_level = 0;
|
20
|
|
-unsigned long ts_pack = 0;
|
21
|
|
-int ts_pack_shown = 0;
|
22
|
|
-
|
23
|
|
-enum CA_system req_CA_sys = CA_CONNAX;
|
24
|
|
-
|
25
|
|
-int emm_send = 1;
|
26
|
|
-int pid_filter = 0;
|
27
|
|
-
|
28
|
|
-struct in_addr output_addr;
|
29
|
|
-unsigned int output_port;
|
30
|
|
-int output_ttl = 1;
|
31
|
|
-struct in_addr output_intf;
|
32
|
|
-
|
33
|
|
-void show_help() {
|
34
|
|
- printf("TSDECRYPT v1.0\n");
|
|
16
|
+void LOG_func(const char *msg) {
|
|
17
|
+ char date[64];
|
|
18
|
+ struct tm tm;
|
|
19
|
+ time_t now;
|
|
20
|
+ now = time(NULL);
|
|
21
|
+ localtime_r(&now, &tm);
|
|
22
|
+ strftime(date, sizeof(date), "%F %H:%M:%S", localtime(&now));
|
|
23
|
+ fprintf(stderr, "%s | %s", date, msg);
|
|
24
|
+}
|
|
25
|
+
|
|
26
|
+void show_help(struct ts *ts) {
|
|
27
|
+ printf("ts v1.0\n");
|
35
|
28
|
printf("Copyright (c) 2011 Unix Solutions Ltd.\n");
|
36
|
29
|
printf("\n");
|
37
|
|
- printf(" Usage: tsdecrypt [opts] < mpeg_ts\n");
|
|
30
|
+ printf(" Usage: ts [opts] < mpeg_ts\n");
|
38
|
31
|
printf("\n");
|
39
|
32
|
printf(" Options:\n");
|
40
|
|
- printf(" -c ca_system | default: %s valid: IRDETO, CONNAX, CRYPTOWORKS\n", ts_get_CA_sys_txt(req_CA_sys));
|
|
33
|
+ printf(" -c ca_system | default: %s valid: IRDETO, CONNAX, CRYPTOWORKS\n", ts_get_CA_sys_txt(ts->req_CA_sys));
|
41
|
34
|
printf("\n");
|
42
|
35
|
printf(" CAMD35 server options:\n");
|
43
|
36
|
printf(" -s server_addr | default: disabled (format 1.2.3.4:2233)\n");
|
44
|
|
- printf(" -U server_user | default: %s\n", camd35.user);
|
45
|
|
- printf(" -P server_pass | default: %s\n", camd35.pass);
|
|
37
|
+ printf(" -U server_user | default: %s\n", ts->camd35.user);
|
|
38
|
+ printf(" -P server_pass | default: %s\n", ts->camd35.pass);
|
46
|
39
|
printf("\n");
|
47
|
40
|
printf(" Output options (if output is disabled stdout is used for output):\n");
|
48
|
41
|
printf(" -o output_addr | default: disabled (format: 239.78.78.78:5000)\n");
|
49
|
|
- printf(" -i output_intf | default: %s\n", inet_ntoa(output_intf));
|
50
|
|
- printf(" -t output_ttl | default: %d\n", output_ttl);
|
|
42
|
+ printf(" -i output_intf | default: %s\n", inet_ntoa(ts->output_intf));
|
|
43
|
+ printf(" -t output_ttl | default: %d\n", ts->output_ttl);
|
51
|
44
|
printf("\n");
|
52
|
45
|
printf(" Filtering options:\n");
|
53
|
|
- printf(" -e | EMM send (default: %s).\n", emm_send ? "enabled" : "disabled");
|
|
46
|
+ printf(" -e | EMM send (default: %s).\n", ts->emm_send ? "enabled" : "disabled");
|
54
|
47
|
printf(" | - Send EMMs to CAMD server for processing.\n");
|
55
|
48
|
printf("\n");
|
56
|
|
- printf(" -p | Output PID filter (default: %s).\n", pid_filter ? "enabled" : "disabled");
|
|
49
|
+ printf(" -p | Output PID filter (default: %s).\n", ts->pid_filter ? "enabled" : "disabled");
|
57
|
50
|
printf(" | - When PID filter is enabled only PAT/PMT/SDT/data\n");
|
58
|
51
|
printf(" | - packets are left in the output.\n");
|
59
|
52
|
printf("\n");
|
|
@@ -66,18 +59,18 @@ void show_help() {
|
66
|
59
|
printf("\n");
|
67
|
60
|
}
|
68
|
61
|
|
69
|
|
-void parse_options(int argc, char **argv) {
|
|
62
|
+void parse_options(struct ts *ts, int argc, char **argv) {
|
70
|
63
|
int j, ca_err = 0, server_err = 1, output_addr_err = 0, output_intf_err = 0;
|
71
|
64
|
while ((j = getopt(argc, argv, "cFs:o:i:t:U:P:epD:h")) != -1) {
|
72
|
65
|
char *p = NULL;
|
73
|
66
|
switch (j) {
|
74
|
67
|
case 'c':
|
75
|
68
|
if (strcasecmp("IRDETO", optarg) == 0)
|
76
|
|
- req_CA_sys = CA_IRDETO;
|
|
69
|
+ ts->req_CA_sys = CA_IRDETO;
|
77
|
70
|
else if (strcasecmp("CONNAX", optarg) == 0)
|
78
|
|
- req_CA_sys = CA_CONNAX;
|
|
71
|
+ ts->req_CA_sys = CA_CONNAX;
|
79
|
72
|
else if (strcasecmp("CRYPTOWORKS", optarg) == 0)
|
80
|
|
- req_CA_sys = CA_CRYPTOWORKS;
|
|
73
|
+ ts->req_CA_sys = CA_CRYPTOWORKS;
|
81
|
74
|
else
|
82
|
75
|
ca_err = 1;
|
83
|
76
|
break;
|
|
@@ -86,9 +79,9 @@ void parse_options(int argc, char **argv) {
|
86
|
79
|
p = strrchr(optarg, ':');
|
87
|
80
|
if (p) {
|
88
|
81
|
*p = 0x00;
|
89
|
|
- camd35.server_port = atoi(p + 1);
|
|
82
|
+ ts->camd35.server_port = atoi(p + 1);
|
90
|
83
|
}
|
91
|
|
- if (inet_aton(optarg, &camd35.server_addr) == 0)
|
|
84
|
+ if (inet_aton(optarg, &ts->camd35.server_addr) == 0)
|
92
|
85
|
server_err = 1;
|
93
|
86
|
else
|
94
|
87
|
server_err = 0;
|
|
@@ -98,46 +91,46 @@ void parse_options(int argc, char **argv) {
|
98
|
91
|
p = strrchr(optarg, ':');
|
99
|
92
|
if (p) {
|
100
|
93
|
*p = 0x00;
|
101
|
|
- output_port = atoi(p + 1);
|
|
94
|
+ ts->output_port = atoi(p + 1);
|
102
|
95
|
}
|
103
|
|
- if (inet_aton(optarg, &output_addr) == 0)
|
|
96
|
+ if (inet_aton(optarg, &ts->output_addr) == 0)
|
104
|
97
|
output_addr_err = 1;
|
105
|
98
|
break;
|
106
|
99
|
case 'i':
|
107
|
|
- if (inet_aton(optarg, &output_intf) == 0)
|
|
100
|
+ if (inet_aton(optarg, &ts->output_intf) == 0)
|
108
|
101
|
output_intf_err = 1;
|
109
|
102
|
break;
|
110
|
103
|
case 't':
|
111
|
|
- output_ttl = atoi(optarg);
|
|
104
|
+ ts->output_ttl = atoi(optarg);
|
112
|
105
|
break;
|
113
|
106
|
|
114
|
107
|
case 'U':
|
115
|
|
- strncpy(camd35.user, optarg, sizeof(camd35.user) - 1);
|
116
|
|
- camd35.user[sizeof(camd35.user) - 1] = 0;
|
|
108
|
+ strncpy(ts->camd35.user, optarg, sizeof(ts->camd35.user) - 1);
|
|
109
|
+ ts->camd35.user[sizeof(ts->camd35.user) - 1] = 0;
|
117
|
110
|
break;
|
118
|
111
|
case 'P':
|
119
|
|
- strncpy(camd35.pass, optarg, sizeof(camd35.pass) - 1);
|
120
|
|
- camd35.pass[sizeof(camd35.pass) - 1] = 0;
|
|
112
|
+ strncpy(ts->camd35.pass, optarg, sizeof(ts->camd35.pass) - 1);
|
|
113
|
+ ts->camd35.pass[sizeof(ts->camd35.pass) - 1] = 0;
|
121
|
114
|
break;
|
122
|
115
|
|
123
|
116
|
case 'e':
|
124
|
|
- emm_send = !emm_send;
|
|
117
|
+ ts->emm_send = !ts->emm_send;
|
125
|
118
|
break;
|
126
|
119
|
case 'p':
|
127
|
|
- pid_filter = !pid_filter;
|
|
120
|
+ ts->pid_filter = !ts->pid_filter;
|
128
|
121
|
break;
|
129
|
122
|
|
130
|
123
|
case 'D':
|
131
|
|
- debug_level = atoi(optarg);
|
|
124
|
+ ts->debug_level = atoi(optarg);
|
132
|
125
|
break;
|
133
|
126
|
|
134
|
127
|
case 'h':
|
135
|
|
- show_help();
|
|
128
|
+ show_help(ts);
|
136
|
129
|
exit(0);
|
137
|
130
|
}
|
138
|
131
|
}
|
139
|
132
|
if (ca_err || server_err) {
|
140
|
|
- show_help();
|
|
133
|
+ show_help(ts);
|
141
|
134
|
if (ca_err)
|
142
|
135
|
fprintf(stderr, "ERROR: Requested CA system is unsupported.\n");
|
143
|
136
|
if (server_err)
|
|
@@ -148,17 +141,48 @@ void parse_options(int argc, char **argv) {
|
148
|
141
|
fprintf(stderr, "ERROR: Output interface address is invalid.\n");
|
149
|
142
|
exit(1);
|
150
|
143
|
}
|
151
|
|
- ts_LOGf("CA System : %s\n", ts_get_CA_sys_txt(req_CA_sys));
|
152
|
|
- ts_LOGf("Server addr: %s:%u\n", inet_ntoa(camd35.server_addr), camd35.server_port);
|
153
|
|
- ts_LOGf("Server user: %s\n", camd35.user);
|
154
|
|
- ts_LOGf("Server pass: %s\n", camd35.pass);
|
155
|
|
- if (output_port) {
|
156
|
|
- ts_LOGf("Output addr: %s:%u\n", inet_ntoa(output_addr), output_port);
|
157
|
|
- ts_LOGf("Output intf: %s\n", inet_ntoa(output_intf));
|
158
|
|
- ts_LOGf("Output ttl : %d\n", output_ttl);
|
|
144
|
+ ts_LOGf("CA System : %s\n", ts_get_CA_sys_txt(ts->req_CA_sys));
|
|
145
|
+ ts_LOGf("Server addr: %s:%u\n", inet_ntoa(ts->camd35.server_addr), ts->camd35.server_port);
|
|
146
|
+ ts_LOGf("Server user: %s\n", ts->camd35.user);
|
|
147
|
+ ts_LOGf("Server pass: %s\n", ts->camd35.pass);
|
|
148
|
+ if (ts->output_port) {
|
|
149
|
+ ts_LOGf("Output addr: %s:%u\n", inet_ntoa(ts->output_addr), ts->output_port);
|
|
150
|
+ ts_LOGf("Output intf: %s\n", inet_ntoa(ts->output_intf));
|
|
151
|
+ ts_LOGf("Output ttl : %d\n", ts->output_ttl);
|
159
|
152
|
}
|
160
|
|
- ts_LOGf("EMM send : %s\n", emm_send ? "enabled" : "disabled");
|
161
|
|
- ts_LOGf("PID filter : %s\n", pid_filter ? "enabled" : "disabled");
|
|
153
|
+ ts_LOGf("EMM send : %s\n", ts->emm_send ? "enabled" : "disabled");
|
|
154
|
+ ts_LOGf("PID filter : %s\n", ts->pid_filter ? "enabled" : "disabled");
|
|
155
|
+}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+static unsigned long ts_pack;
|
|
159
|
+static int ts_pack_shown;
|
|
160
|
+
|
|
161
|
+void show_ts_pack(struct ts *ts, uint16_t pid, char *wtf, char *extra, uint8_t *ts_packet) {
|
|
162
|
+ char cw1_dump[8 * 6];
|
|
163
|
+ char cw2_dump[8 * 6];
|
|
164
|
+ if (ts->debug_level >= 4) {
|
|
165
|
+ if (ts_pack_shown)
|
|
166
|
+ return;
|
|
167
|
+ int stype = ts_packet_get_scrambled(ts_packet);
|
|
168
|
+ ts_hex_dump_buf(cw1_dump, 8 * 6, ts->key.cw , 8, 0);
|
|
169
|
+ ts_hex_dump_buf(cw2_dump, 8 * 6, ts->key.cw + 8, 8, 0);
|
|
170
|
+ fprintf(stderr, "@ %s %s %03x %5ld %7ld | %s %s | %s\n",
|
|
171
|
+ stype == 0 ? "------" :
|
|
172
|
+ stype == 2 ? "even 0" :
|
|
173
|
+ stype == 3 ? "odd 1" : "??????",
|
|
174
|
+ wtf,
|
|
175
|
+ pid,
|
|
176
|
+ ts_pack, ts_pack * 188,
|
|
177
|
+ cw1_dump, cw2_dump, extra ? extra : wtf);
|
|
178
|
+ }
|
|
179
|
+}
|
|
180
|
+
|
|
181
|
+void dump_ts_pack(struct ts *ts, uint16_t pid, uint8_t *ts_packet) {
|
|
182
|
+ if (pid == 0x010) show_ts_pack(ts, pid, "nit", NULL, ts_packet);
|
|
183
|
+ else if (pid == 0x11) show_ts_pack(ts, pid, "sdt", NULL, ts_packet);
|
|
184
|
+ else if (pid == 0x12) show_ts_pack(ts, pid, "epg", NULL, ts_packet);
|
|
185
|
+ else show_ts_pack(ts, pid, "---", NULL, ts_packet);
|
162
|
186
|
}
|
163
|
187
|
|
164
|
188
|
void ts_process_packets(struct ts *ts, uint8_t *data, ssize_t data_len) {
|
|
@@ -176,18 +200,18 @@ void ts_process_packets(struct ts *ts, uint8_t *data, ssize_t data_len) {
|
176
|
200
|
process_ecm(ts, pid, ts_packet);
|
177
|
201
|
|
178
|
202
|
if (!ts_pack_shown)
|
179
|
|
- dump_ts_pack(pid, ts_packet);
|
|
203
|
+ dump_ts_pack(ts, pid, ts_packet);
|
180
|
204
|
|
181
|
205
|
int scramble_idx = ts_packet_get_scrambled(ts_packet);
|
182
|
206
|
if (scramble_idx > 1) {
|
183
|
|
- if (key.is_valid_cw) {
|
|
207
|
+ if (ts->key.is_valid_cw) {
|
184
|
208
|
// scramble_idx 2 == even key
|
185
|
209
|
// scramble_idx 3 == odd key
|
186
|
210
|
ts_packet_set_not_scrambled(ts_packet);
|
187
|
|
- dvbcsa_decrypt(key.csakey[scramble_idx - 2], ts_packet + 4, 184);
|
|
211
|
+ dvbcsa_decrypt(ts->key.csakey[scramble_idx - 2], ts_packet + 4, 184);
|
188
|
212
|
} else {
|
189
|
213
|
// Can't decrypt the packet just make it NULL packet
|
190
|
|
- if (pid_filter)
|
|
214
|
+ if (ts->pid_filter)
|
191
|
215
|
ts_packet_set_pid(ts_packet, 0x1fff);
|
192
|
216
|
}
|
193
|
217
|
}
|
|
@@ -201,7 +225,7 @@ void ts_write_packets(struct ts *ts, uint8_t *data, ssize_t data_len) {
|
201
|
225
|
for (i=0; i<data_len; i += 188) {
|
202
|
226
|
uint8_t *ts_packet = data + i;
|
203
|
227
|
uint16_t pid = ts_packet_get_pid(ts_packet);
|
204
|
|
- if (pid_filter) {
|
|
228
|
+ if (ts->pid_filter) {
|
205
|
229
|
if (pidmap_get(&ts->pidmap, pid)) // PAT or allowed PIDs
|
206
|
230
|
write(1, ts_packet, 188);
|
207
|
231
|
} else {
|
|
@@ -215,37 +239,25 @@ void ts_write_packets(struct ts *ts, uint8_t *data, ssize_t data_len) {
|
215
|
239
|
int main(int argc, char **argv) {
|
216
|
240
|
ssize_t readen;
|
217
|
241
|
uint8_t ts_packet[FRAME_SIZE];
|
218
|
|
-
|
219
|
|
- memset(&key, 0, sizeof(key));
|
220
|
|
- key.csakey[0] = dvbcsa_key_alloc();
|
221
|
|
- key.csakey[1] = dvbcsa_key_alloc();
|
222
|
|
-
|
223
|
|
- memset(&camd35, 0, sizeof(camd35));
|
224
|
|
- camd35.server_fd = -1;
|
225
|
|
- camd35.server_port = 2233;
|
226
|
|
- strcpy(camd35.user, "user");
|
227
|
|
- strcpy(camd35.pass, "pass");
|
228
|
|
- camd35.key = &key;
|
|
242
|
+ struct ts ts;
|
229
|
243
|
|
230
|
244
|
ts_set_log_func(LOG_func);
|
231
|
245
|
|
232
|
|
- parse_options(argc, argv);
|
|
246
|
+ data_init(&ts);
|
233
|
247
|
|
234
|
|
- camd35_connect(&camd35);
|
|
248
|
+ parse_options(&ts, argc, argv);
|
235
|
249
|
|
236
|
|
- struct ts *ts = ts_alloc();
|
|
250
|
+ camd35_connect(&ts.camd35);
|
237
|
251
|
do {
|
238
|
252
|
readen = read(0, ts_packet, FRAME_SIZE);
|
239
|
253
|
if (readen > 0) {
|
240
|
|
- ts_process_packets(ts, ts_packet, readen);
|
241
|
|
- ts_write_packets(ts, ts_packet, readen);
|
|
254
|
+ ts_process_packets(&ts, ts_packet, readen);
|
|
255
|
+ ts_write_packets(&ts, ts_packet, readen);
|
242
|
256
|
}
|
243
|
257
|
} while (readen > 0);
|
244
|
|
- ts_free(&ts);
|
|
258
|
+ camd35_disconnect(&ts.camd35);
|
245
|
259
|
|
246
|
|
- dvbcsa_key_free(key.csakey[0]);
|
247
|
|
- dvbcsa_key_free(key.csakey[1]);
|
|
260
|
+ data_free(&ts);
|
248
|
261
|
|
249
|
|
- camd35_disconnect(&camd35);
|
250
|
262
|
exit(0);
|
251
|
263
|
}
|