Browse Source

Detect if the input is encrypted and switch the input

Georgi Chorbadzhiyski 6 years ago
parent
commit
2ec6a7f1e5
3 changed files with 177 additions and 2 deletions
  1. 102
    0
      bitstream.h
  2. 1
    0
      config.h
  3. 74
    2
      tomcast.c

+ 102
- 0
bitstream.h View File

@@ -0,0 +1,102 @@
1
+/*
2
+ * TS bitstream functions
3
+ * The following functions are copied from bitstream/mpeg.ts and bitstream/mpeg/pes.h
4
+
5
+ * Copyright (c) 2010-2011 VideoLAN
6
+
7
+ * Permission is hereby granted, free of charge, to any person obtaining
8
+ * a copy of this software and associated documentation files (the
9
+ * "Software"), to deal in the Software without restriction, including
10
+ * without limitation the rights to use, copy, modify, merge, publish,
11
+ * distribute, sublicense, and/or sell copies of the Software, and to
12
+ * permit persons to whom the Software is furnished to do so, subject
13
+ * to the following conditions:
14
+
15
+ * The above copyright notice and this permission notice shall be
16
+ * included in all copies or substantial portions of the Software.
17
+
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ */
26
+#ifndef BITSTREAM_H
27
+#define BITSTREAM_H
28
+
29
+#include <stdbool.h>
30
+#include <inttypes.h>
31
+
32
+#define TS_SIZE                     188
33
+#define TS_HEADER_SIZE              4
34
+#define PES_HEADER_SIZE_PTS         14
35
+#define PES_HEADER_SIZE_PTSDTS      19
36
+#define PES_STREAM_ID_MIN           0xbc
37
+#define PES_STREAM_ID_PRIVATE_2     0xbf
38
+
39
+static inline bool ts_validate(const uint8_t *p_ts)
40
+{
41
+    return p_ts[0] == 0x47;
42
+}
43
+
44
+static inline bool ts_get_unitstart(const uint8_t *p_ts)
45
+{
46
+    return !!(p_ts[1] & 0x40);
47
+}
48
+
49
+static inline bool ts_has_payload(const uint8_t *p_ts)
50
+{
51
+    return !!(p_ts[3] & 0x10);
52
+}
53
+
54
+static inline bool ts_has_adaptation(const uint8_t *p_ts)
55
+{
56
+    return !!(p_ts[3] & 0x20);
57
+}
58
+
59
+static inline uint8_t ts_get_adaptation(const uint8_t *p_ts)
60
+{
61
+    return p_ts[4];
62
+}
63
+
64
+static inline uint8_t pes_get_streamid(const uint8_t *p_pes)
65
+{
66
+    return p_pes[3];
67
+}
68
+
69
+static inline bool pes_validate(const uint8_t *p_pes)
70
+{
71
+    return (p_pes[0] == 0x0 && p_pes[1] == 0x0 && p_pes[2] == 0x1
72
+             && p_pes[3] >= PES_STREAM_ID_MIN);
73
+}
74
+
75
+static inline bool pes_validate_header(const uint8_t *p_pes)
76
+{
77
+    return ((p_pes[6] & 0xc0) == 0x80);
78
+}
79
+
80
+static inline bool pes_has_pts(const uint8_t *p_pes)
81
+{
82
+    return !!(p_pes[7] & 0x80);
83
+}
84
+
85
+static inline bool pes_has_dts(const uint8_t *p_pes)
86
+{
87
+    return (p_pes[7] & 0xc0) == 0xc0;
88
+}
89
+
90
+static inline bool pes_validate_pts(const uint8_t *p_pes)
91
+{
92
+    return ((p_pes[9] & 0xe1) == 0x21)
93
+            && (p_pes[11] & 0x1) && (p_pes[13] & 0x1);
94
+}
95
+
96
+static inline bool pes_validate_dts(const uint8_t *p_pes)
97
+{
98
+    return (p_pes[9] & 0x10) && ((p_pes[14] & 0xf1) == 0x11)
99
+            && (p_pes[16] & 0x1) && (p_pes[18] & 0x1);
100
+}
101
+
102
+#endif

+ 1
- 0
config.h View File

@@ -62,6 +62,7 @@ typedef struct {
62 62
 	pthread_rwlock_t lock;
63 63
 	time_t conn_ts;
64 64
 	uint64_t read_bytes;
65
+	int64_t last_decrypted_input_ts;
65 66
 	char status[64];
66 67
 } RESTREAMER;
67 68
 

+ 74
- 2
tomcast.c View File

@@ -13,6 +13,7 @@
13 13
  *
14 14
  */
15 15
 #include <stdio.h>
16
+#include <stdbool.h>
16 17
 #include <stdlib.h>
17 18
 #include <unistd.h>
18 19
 #include <string.h>
@@ -31,6 +32,7 @@
31 32
 #include <netdb.h> // for uint32_t
32 33
 
33 34
 #include "libfuncs/libfuncs.h"
35
+#include "bitstream.h"
34 36
 #include "config.h"
35 37
 
36 38
 #include "web_server.h"
@@ -68,11 +70,34 @@
68 70
 #endif
69 71
 
70 72
 char *server_sig = "tomcast";
71
-char *server_ver = "1.30";
72
-char *copyright  = "Copyright (C) 2010-2016 Unix Solutions Ltd.";
73
+char *server_ver = "1.34";
74
+char *copyright  = "Copyright (C) 2010-2018 Unix Solutions Ltd.";
73 75
 
74 76
 static struct config config;
75 77
 
78
+#ifdef __MACH__
79
+#include <mach/clock.h>
80
+#include <mach/mach.h>
81
+#endif
82
+
83
+int64_t get_time(void) {
84
+	struct timespec ts;
85
+#ifdef __MACH__
86
+// OS X does not have clock_gettime, use clock_get_time
87
+	clock_serv_t cclock;
88
+	mach_timespec_t mts;
89
+	host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
90
+	clock_get_time(cclock, &mts);
91
+	mach_port_deallocate(mach_task_self(), cclock);
92
+	ts.tv_sec = mts.tv_sec;
93
+	ts.tv_nsec = mts.tv_nsec;
94
+#else
95
+	if (clock_gettime(CLOCK_MONOTONIC, &ts) == EINVAL) // Shouldn't happen on modern Linux
96
+		clock_gettime(CLOCK_REALTIME, &ts);
97
+#endif
98
+	return ts.tv_sec * 1000000ll + ts.tv_nsec / 1000;
99
+}
100
+
76 101
 channel_source get_sproto(char *url) {
77 102
 	return strncmp(url, "http", 4)==0 ? tcp_sock : udp_sock;
78 103
 }
@@ -250,6 +275,7 @@ RESTREAMER * new_restreamer(const char *name, CHANNEL *channel) {
250 275
 	r->dst_sockname = sockname;
251 276
 	pthread_rwlock_init(&r->lock, NULL);
252 277
 	connect_destination(r);
278
+	r->last_decrypted_input_ts = get_time();
253 279
 	return r;
254 280
 }
255 281
 
@@ -808,6 +834,39 @@ char reset[FRAME_PACKET_SIZE] = {
808 834
   0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
809 835
 };
810 836
 
837
+
838
+/*
839
+	Return value:
840
+		ret        == 0    - No valid payload was found
841
+		ret & 0x01 == 0x01 - PES was found
842
+		ret & 0x02 == 0x02 - PTS was found
843
+		ret & 0x04 == 0x04 - DTS was found
844
+*/
845
+static unsigned int ts_have_valid_pes(uint8_t *buf, unsigned int buffer_size) {
846
+	unsigned int ret = 0;
847
+	uint8_t *buf_end = buf + buffer_size;
848
+	while (buf < buf_end && ts_validate(buf)) {
849
+		uint16_t header_size = TS_HEADER_SIZE + (ts_has_adaptation(buf) ? 1 : 0) + ts_get_adaptation(buf);
850
+		if (ts_get_unitstart(buf) && ts_has_payload(buf) && header_size + PES_HEADER_SIZE_PTS <= TS_SIZE) {
851
+			//printf("Got payload\n");
852
+			if (pes_validate(buf + header_size) && pes_get_streamid(buf + header_size) != PES_STREAM_ID_PRIVATE_2 && pes_validate_header(buf + header_size)) {
853
+				//printf("Got PES\n");
854
+				ret |= 0x01;
855
+				if (pes_has_pts(buf + header_size) && pes_validate_pts(buf + header_size)) {
856
+					ret |= 0x02;
857
+					//printf("Got PTS\n");
858
+					if (header_size + PES_HEADER_SIZE_PTSDTS <= TS_SIZE && pes_has_dts(buf + header_size) && pes_validate_dts(buf + header_size)) {
859
+						//printf("Got DTS\n");
860
+						ret |= 0x04;
861
+					}
862
+				}
863
+			}
864
+		}
865
+		buf += TS_SIZE;
866
+	}
867
+	return ret;
868
+}
869
+
811 870
 void * proxy_ts_stream(void *self) {
812 871
 	RESTREAMER *r = self;
813 872
 	char buf[FRAME_PACKET_SIZE];
@@ -869,6 +928,19 @@ void * proxy_ts_stream(void *self) {
869 928
 				send_reset = 0;
870 929
 				fdwrite(r->clientsock, reset, FRAME_PACKET_SIZE);
871 930
 			}
931
+
932
+			int64_t now = get_time();
933
+			int ret;
934
+			if ((ret = ts_have_valid_pes((uint8_t *)buf, readen)) == 0) { // Is the output encrypted?
935
+				/* The output is encrypted, check if 1000 ms have passed and if such, notify that we probably have invalid key */
936
+				if (now > r->last_decrypted_input_ts + 500000) {
937
+					proxy_log(r, "ERR  ","Scrambled input");
938
+					proxy_set_status(r, "ERROR: Encrypted stream input");
939
+					goto RECONNECT;
940
+				}
941
+			} else {
942
+				r->last_decrypted_input_ts = now;
943
+			}
872 944
 			written = fdwrite(r->clientsock, buf, FRAME_PACKET_SIZE);
873 945
 			if (written == -1) {
874 946
 				LOGf("PROXY: Error writing to dst_fd: %i on srv_fd: %i | Channel: %s Source: %s\n", r->clientsock, r->sock, r->channel->name, r->channel->source);

Loading…
Cancel
Save