tsdecrypt reads and decrypts CSA encrypted incoming mpeg transport stream over UDP/RTP using code words obtained from OSCAM or similar CAM server. tsdecrypt communicates with CAM server using cs378x (camd35 over tcp) protocol or newcamd protocol. https://georgi.unixsol.org/programs/tsdecrypt/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tsdecrypt.c 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #include <stdlib.h>
  2. #include <unistd.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <errno.h>
  8. #include "data.h"
  9. #include "util.h"
  10. #include "camd.h"
  11. #include "process.h"
  12. #include "udp.h"
  13. static void LOG_func(const char *msg) {
  14. char date[64];
  15. struct tm tm;
  16. time_t now;
  17. now = time(NULL);
  18. localtime_r(&now, &tm);
  19. strftime(date, sizeof(date), "%F %H:%M:%S", localtime(&now));
  20. fprintf(stderr, "%s | %s", date, msg);
  21. }
  22. static void show_help(struct ts *ts) {
  23. printf("tsdecrypt v1.0\n");
  24. printf("Copyright (c) 2011 Unix Solutions Ltd.\n");
  25. printf("\n");
  26. printf(" Usage: tsdecrypt [opts]\n");
  27. printf("\n");
  28. printf(" Input options:\n");
  29. printf(" -I input | Where to read from. Supports files and multicast\n");
  30. printf(" | -I 224.0.0.1:5000 (multicast receive)\n");
  31. printf(" | -I file.ts (read from file)\n");
  32. printf(" | -I - (read from STDIN, the default)\n");
  33. printf("\n");
  34. printf(" -c ca_system | default: %s valid: IRDETO, CONNAX, CRYPTOWORKS\n", ts_get_CA_sys_txt(ts->req_CA_sys));
  35. printf("\n");
  36. printf(" Output options:\n");
  37. printf(" -O output | Where to send output. Supports files and multicast\n");
  38. printf(" | -O 239.0.0.1:5000 (multicast send)\n");
  39. printf(" | -O file.ts (write to file)\n");
  40. printf(" | -O - (write to STDOUT, the default)\n");
  41. printf("\n");
  42. printf(" -i output_intf | default: %s\n", inet_ntoa(ts->output.intf));
  43. printf(" -t output_ttl | default: %d\n", ts->output.ttl);
  44. printf("\n");
  45. printf(" CAMD35 server options:\n");
  46. printf(" -s server_addr | default: disabled (format 1.2.3.4:2233)\n");
  47. printf(" -U server_user | default: %s\n", ts->camd35.user);
  48. printf(" -P server_pass | default: %s\n", ts->camd35.pass);
  49. printf("\n");
  50. printf(" Filtering options:\n");
  51. printf(" -e | EMM send (default: %s).\n", ts->emm_send ? "enabled" : "disabled");
  52. printf(" | - Send EMMs to CAMD server for processing.\n");
  53. printf("\n");
  54. printf(" -p | Output PID filter (default: %s).\n", ts->pid_filter ? "enabled" : "disabled");
  55. printf(" | - When PID filter is enabled only PAT/PMT/SDT/data\n");
  56. printf(" | - packets are left in the output.\n");
  57. printf("\n");
  58. printf(" -D debug_level | Message debug level.\n");
  59. printf(" | 0 - default messages\n");
  60. printf(" | 1 - show PSI tables\n");
  61. printf(" | 2 - show EMMs\n");
  62. printf(" | 3 - show duplicate ECMs\n");
  63. printf(" | 4 - packet debug\n");
  64. printf("\n");
  65. }
  66. static int parse_io_param(struct io *io, char *opt, int open_flags, mode_t open_mode) {
  67. io->type = WTF_IO;
  68. char *p = strrchr(opt, ':');
  69. if (!p) {
  70. io->type = FILE_IO;
  71. if (strcmp(opt, "-") != 0) {
  72. io->fd = open(opt, open_flags, open_mode);
  73. if (io->fd < 0) {
  74. fprintf(stderr, "ERROR: Can not open file (%s): %s\n", opt, strerror(errno));
  75. exit(1);
  76. }
  77. }
  78. io->fname = strdup(opt);
  79. return 0;
  80. }
  81. *p = 0x00;
  82. io->type = NET_IO;
  83. io->port = atoi(p + 1);
  84. if (inet_aton(opt, &io->addr) == 0)
  85. return 1;
  86. return 0;
  87. }
  88. static void parse_options(struct ts *ts, int argc, char **argv) {
  89. int j, ca_err = 0, server_err = 1, input_addr_err = 0, output_addr_err = 0, output_intf_err = 0;
  90. while ((j = getopt(argc, argv, "cFs:I:O:i:t:U:P:epD:h")) != -1) {
  91. char *p = NULL;
  92. switch (j) {
  93. case 'c':
  94. if (strcasecmp("IRDETO", optarg) == 0)
  95. ts->req_CA_sys = CA_IRDETO;
  96. else if (strcasecmp("CONNAX", optarg) == 0)
  97. ts->req_CA_sys = CA_CONNAX;
  98. else if (strcasecmp("CRYPTOWORKS", optarg) == 0)
  99. ts->req_CA_sys = CA_CRYPTOWORKS;
  100. else
  101. ca_err = 1;
  102. break;
  103. case 's':
  104. p = strrchr(optarg, ':');
  105. if (p) {
  106. *p = 0x00;
  107. ts->camd35.server_port = atoi(p + 1);
  108. }
  109. if (inet_aton(optarg, &ts->camd35.server_addr) == 0)
  110. server_err = 1;
  111. else
  112. server_err = 0;
  113. break;
  114. case 'I':
  115. input_addr_err = parse_io_param(&ts->input, optarg, O_RDONLY, 0);
  116. break;
  117. case 'O':
  118. output_addr_err = parse_io_param(&ts->output, optarg,
  119. O_CREAT | O_WRONLY | O_TRUNC,
  120. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  121. break;
  122. case 'i':
  123. if (inet_aton(optarg, &ts->output.intf) == 0)
  124. output_intf_err = 1;
  125. break;
  126. case 't':
  127. ts->output.ttl = atoi(optarg);
  128. break;
  129. case 'U':
  130. strncpy(ts->camd35.user, optarg, sizeof(ts->camd35.user) - 1);
  131. ts->camd35.user[sizeof(ts->camd35.user) - 1] = 0;
  132. break;
  133. case 'P':
  134. strncpy(ts->camd35.pass, optarg, sizeof(ts->camd35.pass) - 1);
  135. ts->camd35.pass[sizeof(ts->camd35.pass) - 1] = 0;
  136. break;
  137. case 'e':
  138. ts->emm_send = !ts->emm_send;
  139. break;
  140. case 'p':
  141. ts->pid_filter = !ts->pid_filter;
  142. break;
  143. case 'D':
  144. ts->debug_level = atoi(optarg);
  145. break;
  146. case 'h':
  147. show_help(ts);
  148. exit(0);
  149. }
  150. }
  151. if (ca_err || server_err || input_addr_err || output_addr_err || ts->input.type == WTF_IO || ts->output.type == WTF_IO) {
  152. show_help(ts);
  153. if (ca_err)
  154. fprintf(stderr, "ERROR: Requested CA system is unsupported.\n");
  155. if (server_err)
  156. fprintf(stderr, "ERROR: Server IP address is not set or it is invalid.\n");
  157. if (input_addr_err)
  158. fprintf(stderr, "ERROR: Input IP address is invalid.\n");
  159. if (output_addr_err)
  160. fprintf(stderr, "ERROR: Output IP address is invalid.\n");
  161. if (output_intf_err)
  162. fprintf(stderr, "ERROR: Output interface address is invalid.\n");
  163. exit(1);
  164. }
  165. ts_LOGf("CA System : %s\n", ts_get_CA_sys_txt(ts->req_CA_sys));
  166. if (ts->input.type == NET_IO) {
  167. ts_LOGf("Input addr : udp://%s:%u/\n", inet_ntoa(ts->input.addr), ts->input.port);
  168. } else if (ts->input.type == FILE_IO) {
  169. ts_LOGf("Input file : %s\n", ts->input.fd == 0 ? "STDIN" : ts->input.fname);
  170. }
  171. if (ts->output.type == NET_IO) {
  172. ts_LOGf("Output addr: udp://%s:%u/\n", inet_ntoa(ts->output.addr), ts->output.port);
  173. ts_LOGf("Output intf: %s\n", inet_ntoa(ts->output.intf));
  174. ts_LOGf("Output ttl : %d\n", ts->output.ttl);
  175. } else if (ts->output.type == FILE_IO) {
  176. ts_LOGf("Output file: %s\n", ts->output.fd == 1 ? "STDOUT" : ts->output.fname);
  177. }
  178. ts_LOGf("Server addr: tcp://%s:%u/\n", inet_ntoa(ts->camd35.server_addr), ts->camd35.server_port);
  179. ts_LOGf("Server user: %s\n", ts->camd35.user);
  180. ts_LOGf("Server pass: %s\n", ts->camd35.pass);
  181. ts_LOGf("EMM send : %s\n", ts->emm_send ? "enabled" : "disabled");
  182. ts_LOGf("PID filter : %s\n", ts->pid_filter ? "enabled" : "disabled");
  183. ts->threaded = !(ts->input.type == FILE_IO && ts->input.fd != 0);
  184. ts_LOGf("Decoding : %s\n", ts->threaded ? "threaded" : "single thread");
  185. }
  186. int main(int argc, char **argv) {
  187. ssize_t readen;
  188. uint8_t ts_packet[FRAME_SIZE];
  189. struct ts ts;
  190. ts_set_log_func(LOG_func);
  191. data_init(&ts);
  192. parse_options(&ts, argc, argv);
  193. if (ts.input.type == NET_IO && udp_connect_input(&ts.input) < 1)
  194. goto EXIT;
  195. if (ts.output.type == NET_IO && udp_connect_output(&ts.output) < 1)
  196. goto EXIT;
  197. if (&ts.threaded) {
  198. pthread_create(&ts.decode_thread, NULL, &decode_thread, &ts);
  199. pthread_create(&ts.write_thread, NULL , &write_thread , &ts);
  200. }
  201. camd_start(&ts);
  202. do {
  203. readen = read(ts.input.fd, ts_packet, FRAME_SIZE);
  204. if (readen > 0)
  205. process_packets(&ts, ts_packet, readen);
  206. } while (readen > 0);
  207. EXIT:
  208. camd_stop(&ts);
  209. if (ts.threaded) {
  210. ts.decode_stop = 1;
  211. ts.write_stop = 1;
  212. pthread_join(ts.decode_thread, NULL);
  213. pthread_join(ts.write_thread, NULL);
  214. }
  215. data_free(&ts);
  216. exit(0);
  217. }