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.

filter.c 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. * Filtering functions
  3. * Copyright (C) 2012 Unix Solutions Ltd.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2
  7. * as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License (COPYING file) for more details.
  13. *
  14. */
  15. #include <ctype.h>
  16. #include <string.h>
  17. #include "data.h"
  18. #include "filter.h"
  19. struct filter_actions_map {
  20. const char *token;
  21. bool last;
  22. enum filter_action type;
  23. };
  24. static struct filter_actions_map action_tokens[] = {
  25. { "accept_all", true, FILTER_ACCEPT_ALL },
  26. { "acceptall", true, FILTER_ACCEPT_ALL },
  27. { "reject_all", true, FILTER_REJECT_ALL },
  28. { "rejectall", true, FILTER_REJECT_ALL },
  29. { "accept", false, FILTER_ACCEPT },
  30. { "reject", false, FILTER_REJECT },
  31. { NULL, true, FILTER_NO_MATCH },
  32. };
  33. enum filter_token { T_UNKNOWN, T_NAME, T_OFFSET, T_DATA, T_MATCH, T_MASK, T_LENGTH };
  34. struct filter_data_map {
  35. const char *token;
  36. enum filter_token type;
  37. };
  38. static struct filter_data_map data_tokens[] = {
  39. { "name", T_NAME },
  40. { "ofs", T_OFFSET },
  41. { "offset", T_OFFSET },
  42. { "data", T_DATA },
  43. { "match", T_MATCH },
  44. { "mask", T_MASK },
  45. { "length", T_LENGTH },
  46. { NULL, T_UNKNOWN },
  47. };
  48. int parse_hex(char *data, uint8_t *output, uint8_t *output_len, uint8_t output_size) {
  49. int i, len = strlen(data), consumed = 0;
  50. uint8_t local_output_len = 0;
  51. if (!output_len)
  52. output_len = &local_output_len;
  53. for (i = 0; i < len; i++) { // Parse data (01 02 03 04 ...)
  54. char ch = toupper(data[i]);
  55. // Skip 0x prefixes
  56. if (i + 1 < len && ch == '0' && toupper(data[i + 1]) == 'X')
  57. continue;
  58. if (!isxdigit(ch))
  59. continue;
  60. ch -= ch > 64 ? 55 : 48; // hex2dec
  61. if (consumed % 2 == 0) {
  62. output[*output_len] = 0; // Reset
  63. output[*output_len] += ch << 4;
  64. } else {
  65. output[*output_len] += ch;
  66. (*output_len)++;
  67. if (*output_len + 1 >= output_size) {
  68. fprintf(stderr, "WARN : Too much filter data (max %d bytes), ignoring last bytes: %s\n",
  69. output_size, data + i + 2);
  70. break;
  71. }
  72. }
  73. consumed++;
  74. }
  75. return *output_len;
  76. }
  77. int filter_parse(char *filter_def, struct filter *filter) {
  78. int j, k, ret = 0;
  79. char *str1, *saveptr1 = NULL;
  80. char *f = strdup(filter_def);
  81. memset(filter, 0, sizeof(struct filter));
  82. memset(filter->mask, 0xff, sizeof(filter->mask));
  83. snprintf(filter->name, sizeof(filter->name), "NONAME");
  84. for (j = 1, str1 = f; ; j++, str1 = NULL) {
  85. char *token = strtok_r(str1, "/", &saveptr1);
  86. if (token == NULL)
  87. break;
  88. if (j == 1) { // First token, the command
  89. struct filter_actions_map *m;
  90. for (m = action_tokens; m->token; m++) {
  91. if (strstr(token, m->token) == token) {
  92. filter->action = m->type;
  93. ret = 1;
  94. if (m->last)
  95. goto OUT; // Other tokens are not needed
  96. break;
  97. }
  98. }
  99. if (filter->action == FILTER_NO_MATCH) {
  100. fprintf(stderr, "ERROR: Unknown filter command: %s\n", token);
  101. ret = 0;
  102. goto OUT; // Other tokens are not needed
  103. }
  104. }
  105. if (j == 2) { // Second token, the settings
  106. char *str2, *saveptr2 = NULL;
  107. for (k = 1, str2 = token; ; k++, str2 = NULL) {
  108. char *token2 = strtok_r(str2, ",", &saveptr2);
  109. if (token2 == NULL)
  110. break;
  111. char *tokdata = strrchr(token2, '=');
  112. if (tokdata) {
  113. tokdata++; // Skip =
  114. struct filter_data_map *m;
  115. enum filter_token data_type = T_UNKNOWN;
  116. for (m = data_tokens; m->token; m++) {
  117. if (strstr(token2, m->token) == token2) {
  118. data_type = m->type;
  119. break;
  120. }
  121. }
  122. switch (data_type) {
  123. case T_NAME:
  124. snprintf(filter->name, sizeof(filter->name), "%s", tokdata);
  125. break;
  126. case T_OFFSET:
  127. filter->offset = strtoul(tokdata, NULL, 0);
  128. break;
  129. case T_DATA:
  130. ret = parse_hex(tokdata, filter->data, &filter->filter_len, MAX_FILTER_LEN);
  131. break;
  132. case T_MATCH:
  133. filter->type = FILTER_TYPE_MASK;
  134. ret = parse_hex(tokdata, filter->data, &filter->filter_len, MAX_FILTER_LEN);
  135. break;
  136. case T_MASK:
  137. filter->type = FILTER_TYPE_MASK;
  138. ret = parse_hex(tokdata, filter->mask, NULL, MAX_FILTER_LEN);
  139. break;
  140. case T_LENGTH: {
  141. filter->type = FILTER_TYPE_LENGTH;
  142. int i;
  143. char *ptr, *saveptr3 = NULL;
  144. for (i = 0, ptr = strtok_r(tokdata, " ", &saveptr3);
  145. i < MAX_FILTER_LEN && ptr;
  146. i++ , ptr = strtok_r(NULL, " ", &saveptr3))
  147. {
  148. filter->data[i] = strtoul(ptr, NULL, 0);
  149. }
  150. filter->filter_len = i;
  151. break;
  152. }
  153. case T_UNKNOWN:
  154. fprintf(stderr, "WARN : Unknown filter setting: %s\n", token2);
  155. } // switch (data_type)
  156. }
  157. }
  158. }
  159. }
  160. OUT:
  161. FREE(f);
  162. return ret;
  163. }
  164. void filter_dump(struct filter *filter, char *buffer, unsigned int buf_len) {
  165. unsigned int i, pos = 0;
  166. memset(buffer, 0, buf_len);
  167. pos += snprintf(buffer + pos, buf_len - pos, "Action: %s",
  168. filter->action == FILTER_ACCEPT_ALL ? "ACCEPT_ALL (default)" :
  169. filter->action == FILTER_REJECT_ALL ? "REJECT_ALL (default)" :
  170. filter->action == FILTER_ACCEPT ? "ACCEPT" :
  171. filter->action == FILTER_REJECT ? "REJECT" : "???");
  172. if (filter->action == FILTER_ACCEPT || filter->action == FILTER_REJECT)
  173. pos += snprintf(buffer + pos, buf_len - pos, " Name: %-20s", filter->name);
  174. if (filter->action == FILTER_ACCEPT || filter->action == FILTER_REJECT) {
  175. char tmp_data[MAX_FILTER_LEN * 6], tmp_mask[MAX_FILTER_LEN * 6];
  176. ts_hex_dump_buf(tmp_data, sizeof(tmp_data), filter->data, filter->filter_len, 0);
  177. switch (filter->type) {
  178. case FILTER_TYPE_DATA:
  179. snprintf(buffer + pos, buf_len - pos, " Offset: %2d Data: %s", filter->offset, tmp_data);
  180. break;
  181. case FILTER_TYPE_MASK:
  182. ts_hex_dump_buf(tmp_mask, sizeof(tmp_mask), filter->mask, filter->filter_len, 0);
  183. snprintf(buffer + pos, buf_len - pos, " Match: %s Mask: %s", tmp_data, tmp_mask);
  184. break;
  185. case FILTER_TYPE_LENGTH:
  186. pos += snprintf(buffer + pos, buf_len - pos, " Length:");
  187. for (i = 0; i < filter->filter_len; i++)
  188. pos += snprintf(buffer + pos, buf_len - pos, " 0x%02x", filter->data[i]);
  189. break;
  190. } // switch (filter->type)
  191. }
  192. }
  193. static enum filter_action filter_match(uint8_t *data, unsigned int data_len, struct filter *filter) {
  194. int i;
  195. if (filter->action == FILTER_ACCEPT_ALL || filter->action == FILTER_REJECT_ALL)
  196. return filter->action;
  197. if (filter->action == FILTER_ACCEPT || filter->action == FILTER_REJECT) {
  198. switch (filter->type) {
  199. case FILTER_TYPE_DATA: {
  200. if (filter->filter_len + filter->offset > data_len)
  201. return FILTER_NO_MATCH;
  202. if (memcmp(data + filter->offset, filter->data, filter->filter_len) == 0)
  203. return filter->action;
  204. break;
  205. }
  206. case FILTER_TYPE_MASK: {
  207. if ((unsigned int)filter->filter_len + 3 > data_len)
  208. return FILTER_NO_MATCH;
  209. int matched = 0;
  210. // Check data[0] against filter->data[0]
  211. if ((data[0] & filter->mask[0]) == (filter->data[0] & filter->mask[0])) {
  212. matched++;
  213. for (i = 1; i < filter->filter_len; i++) {
  214. // Check data[3...] against filter->data[1...]
  215. if ((data[i + 2] & filter->mask[i]) == (filter->data[i] & filter->mask[i]))
  216. matched++;
  217. }
  218. }
  219. if (matched == filter->filter_len)
  220. return filter->action;
  221. break;
  222. }
  223. case FILTER_TYPE_LENGTH: {
  224. if (data_len < 3)
  225. return FILTER_NO_MATCH;
  226. for (i = 0; i < filter->filter_len; i++) {
  227. // data[2] holds the section length (not quite, but close to what
  228. // we need, because length= can contain sizes > 255)
  229. if (data[2] == filter->data[i])
  230. return filter->action;
  231. }
  232. }
  233. } // switch (filter->type)
  234. }
  235. return FILTER_NO_MATCH;
  236. }
  237. int filter_match_emm(struct ts *ts, uint8_t *data, unsigned int data_len) {
  238. int i, ret = 1;
  239. for (i = 0; i < ts->emm_filters_num; i++) {
  240. enum filter_action result = filter_match(data, data_len, &ts->emm_filters[i]);
  241. switch (result) {
  242. case FILTER_NO_MATCH : continue;
  243. case FILTER_ACCEPT_ALL: ret = 1; continue;
  244. case FILTER_ACCEPT : ret = 1; break;
  245. case FILTER_REJECT_ALL: ret = 0; continue;
  246. case FILTER_REJECT : ret = 0; break;
  247. }
  248. }
  249. return ret;
  250. }