1 | #include "globals.h"
|
---|
2 | #ifdef CW_CYCLE_CHECK
|
---|
3 |
|
---|
4 | #include "module-cw-cycle-check.h"
|
---|
5 | #include "oscam-chk.h"
|
---|
6 | #include "oscam-client.h"
|
---|
7 | #include "oscam-ecm.h"
|
---|
8 | #include "oscam-lock.h"
|
---|
9 | #include "oscam-string.h"
|
---|
10 |
|
---|
11 | extern CS_MUTEX_LOCK cwcycle_lock;
|
---|
12 |
|
---|
13 | static struct s_cw_cycle_check *cw_cc_list;
|
---|
14 | static int32_t cw_cc_list_size;
|
---|
15 | static time_t last_cwcyclecleaning;
|
---|
16 |
|
---|
17 | /*
|
---|
18 | * Check for CW CYCLE
|
---|
19 | */
|
---|
20 | static inline uint8_t checkECMD5CW(uchar *ecmd5_cw)
|
---|
21 | {
|
---|
22 | int8_t i;
|
---|
23 | for (i=0;i<CS_ECMSTORESIZE;i++)
|
---|
24 | if (ecmd5_cw[i]) return 1;
|
---|
25 | return 0;
|
---|
26 | }
|
---|
27 |
|
---|
28 | static uint8_t checkCWpart(ECM_REQUEST *er, int8_t nextcyclecw) {
|
---|
29 | uint8_t eo = nextcyclecw?8:0;
|
---|
30 | int8_t i;
|
---|
31 | for (i=0;i<8;i++)
|
---|
32 | if (er->cw[i+eo]) return 1;
|
---|
33 | return 0;
|
---|
34 | }
|
---|
35 |
|
---|
36 | static uint8_t checkvalidCW (ECM_REQUEST *er) {
|
---|
37 | checkCW(er); //check zero
|
---|
38 | if (er->rc == E_NOTFOUND) {
|
---|
39 | //wrong
|
---|
40 | return 0;
|
---|
41 | }
|
---|
42 | if (er->caid == 0x09C4 || er->caid == 0x098C || er->caid == 0x09CD || er->caid == 0x0963) { //make dyn
|
---|
43 | if (((checkCWpart(er,0)^checkCWpart(er,1)) == 0)) {
|
---|
44 | //wrong
|
---|
45 | return 0;
|
---|
46 | }
|
---|
47 | } else {
|
---|
48 | if (((checkCWpart(er,0)|checkCWpart(er,1)) == 0)) {
|
---|
49 | //wrong
|
---|
50 | return 0;
|
---|
51 | }
|
---|
52 | }
|
---|
53 | return 1;
|
---|
54 | };
|
---|
55 |
|
---|
56 | void cleanupcwcycle(void)
|
---|
57 | {
|
---|
58 | time_t now = time(NULL);
|
---|
59 | if (last_cwcyclecleaning + 120 > now) //only clean once every 2min
|
---|
60 | return;
|
---|
61 |
|
---|
62 | last_cwcyclecleaning = now;
|
---|
63 | int32_t count = 0, kct = cfg.keepcycletime * 60 + 30; // if keepcycletime is set, wait more before deleting
|
---|
64 | struct s_cw_cycle_check *prv = NULL, *currentnode = NULL, *temp = NULL;
|
---|
65 |
|
---|
66 | bool bcleanup = false;
|
---|
67 |
|
---|
68 | //write lock
|
---|
69 | cs_writelock(&cwcycle_lock);
|
---|
70 | for(currentnode = cw_cc_list, prv = NULL; currentnode; prv = currentnode, currentnode = currentnode->next, count++) { // First Remove old Entrys
|
---|
71 | if ((now - currentnode->time) <= kct) { // delete Entry which old to hold list small
|
---|
72 | continue;
|
---|
73 | }
|
---|
74 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [Cleanup] diff: %ld kct: %i", now - currentnode->time, kct);
|
---|
75 | if (prv != NULL) {
|
---|
76 | prv->next = NULL;
|
---|
77 | } else {
|
---|
78 | cw_cc_list = NULL;
|
---|
79 | }
|
---|
80 | bcleanup = true;
|
---|
81 | break; //we need only once, all follow to old
|
---|
82 | }
|
---|
83 | cs_writeunlock(&cwcycle_lock);
|
---|
84 | while (currentnode != NULL) {
|
---|
85 | temp = currentnode->next;
|
---|
86 | if (!currentnode->old)
|
---|
87 | cw_cc_list_size--;
|
---|
88 | free(currentnode);
|
---|
89 | currentnode = temp;
|
---|
90 | }
|
---|
91 | if (bcleanup)
|
---|
92 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [Cleanup] list new size: %d (realsize: %d)", cw_cc_list_size, count);
|
---|
93 | }
|
---|
94 |
|
---|
95 | static int32_t checkcwcycle_int(ECM_REQUEST *er, char *er_ecmf , char *user, uchar *cw , char *reader)
|
---|
96 | {
|
---|
97 |
|
---|
98 | int8_t i,ret = 6; // ret = 6 no checked
|
---|
99 | int8_t cycleok = -1;
|
---|
100 | time_t now = er->tps.time;//time(NULL);
|
---|
101 | uint8_t need_new_entry = 1, upd_entry = 1;
|
---|
102 | char cwstr[17*3]; //cw to check
|
---|
103 |
|
---|
104 | char cwc_ecmf[ECM_FMT_LEN];
|
---|
105 | char cwc_md5[17*3];
|
---|
106 | char cwc_cw[17*3];
|
---|
107 | char cwc_csp[5*3];
|
---|
108 | bool cw_stageswitch = false;
|
---|
109 | int8_t n = 1, m = 1, k;
|
---|
110 | int32_t mcl = cfg.maxcyclelist;
|
---|
111 | struct s_cw_cycle_check *currentnode = NULL, *cwc = NULL;
|
---|
112 |
|
---|
113 |
|
---|
114 | /*for(list = cw_cc_list; list; list = list->next) { // List all Entrys in Log for DEBUG
|
---|
115 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck: [LIST] %04X:%06X:%04X OLD: %i Time: %ld DifftoNow: %ld Stage: %i cw: %s", list->caid, list->provid, list->sid, list->old, list->time, now - list->time, list->stage, cs_hexdump(0, list->cw, 16, cwstr, sizeof(cwstr)));
|
---|
116 |
|
---|
117 | }*/
|
---|
118 |
|
---|
119 | //read lock
|
---|
120 | cs_readlock(&cwcycle_lock);
|
---|
121 | for(currentnode = cw_cc_list; currentnode; currentnode = currentnode->next) {
|
---|
122 | if (currentnode->caid != er->caid || currentnode->provid != er->prid || currentnode->sid != er->srvid || currentnode->chid != er->chid) {
|
---|
123 | continue;
|
---|
124 | }
|
---|
125 | if (er->ecmlen != 0 && currentnode->ecmlen != 0) {
|
---|
126 | if (currentnode->ecmlen != er->ecmlen) {
|
---|
127 | cs_debug_mask(D_CSPCWC, "cyclecheck [other ECM LEN] -> don't check");
|
---|
128 | continue;
|
---|
129 | }
|
---|
130 |
|
---|
131 | }
|
---|
132 | need_new_entry = 0; // we got a entry for caid/prov/sid so we dont need new one
|
---|
133 |
|
---|
134 | cs_hexdump(0, cw, 16, cwstr, sizeof(cwstr)); //checked cw for log
|
---|
135 |
|
---|
136 | if (cs_malloc(&cwc, sizeof(struct s_cw_cycle_check))) {
|
---|
137 |
|
---|
138 | memcpy(cwc, currentnode, sizeof(struct s_cw_cycle_check)); //copy current to new
|
---|
139 |
|
---|
140 |
|
---|
141 |
|
---|
142 | if (!currentnode->old) {
|
---|
143 | currentnode->old = 1; //need later to counting
|
---|
144 | cw_cc_list_size--;
|
---|
145 | }
|
---|
146 | //now we have all data and can leave read lock
|
---|
147 | cs_readunlock(&cwcycle_lock);
|
---|
148 |
|
---|
149 | cs_hexdump(0, cwc->ecm_md5[cwc->cwc_hist_entry].md5, 16, cwc_md5, sizeof(cwc_md5));
|
---|
150 | cs_hexdump(0, (void*)&cwc->ecm_md5[cwc->cwc_hist_entry].csp_hash, 4, cwc_csp, sizeof(cwc_csp));
|
---|
151 | cs_hexdump(0, cwc->cw, 16, cwc_cw, sizeof(cwc_cw));
|
---|
152 | ecmfmt(cwc->caid, cwc->provid, cwc->chid, 0, cwc->sid, cwc->ecmlen, cwc_md5, cwc_csp, cwc_cw, cwc_ecmf, ECM_FMT_LEN);
|
---|
153 |
|
---|
154 |
|
---|
155 | if ( cwc->stage == 3 && cwc->nextcyclecw < 2 && now - cwc->time < cwc->cycletime *2 - cwc->dyncycletime - 1) { // Check for Cycle no need to check Entrys others like stage 3
|
---|
156 | /*for (k=0; k<15; k++) { // debug md5
|
---|
157 | cs_debug_mask(D_CSPCWC, "cyclecheck [checksumlist[%i]]: ecm_md5: %s csp-hash: %d Entry: %i", k, cs_hexdump(0, cwc->ecm_md5[k].md5, 16, ecm_md5, sizeof(ecm_md5)), cwc->ecm_md5[k].csp_hash, cwc->cwc_hist_entry);
|
---|
158 | } */
|
---|
159 | if (checkvalidCW(er)){
|
---|
160 | // first we check if the store cw the same like the current
|
---|
161 | if (memcmp(cwc->cw, cw, 16) == 0) {
|
---|
162 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [Dump Stored CW] Client: %s EA: %s CW: %s Time: %ld", user, cwc_ecmf, cwc_cw, cwc->time);
|
---|
163 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [Dump CheckedCW] Client: %s EA: %s CW: %s Time: %ld Timediff: %ld", user, er_ecmf, cwstr, now, now - cwc->time);
|
---|
164 | ret = 4; // Return 4 same CW
|
---|
165 | upd_entry = 0;
|
---|
166 | break;
|
---|
167 | }
|
---|
168 |
|
---|
169 | if (cwc->nextcyclecw == 0) { //CW0 must Cycle
|
---|
170 | for (i = 0; i < 8; i++) {
|
---|
171 | if (cwc->cw[i] == cw[i]) {
|
---|
172 | cycleok = 0; //means CW0 Cycle OK
|
---|
173 | } else {
|
---|
174 | cycleok = -1;
|
---|
175 | break;
|
---|
176 | }
|
---|
177 | }
|
---|
178 | } else
|
---|
179 | if (cwc->nextcyclecw == 1) { //CW1 must Cycle
|
---|
180 | for (i = 0; i < 8; i++) {
|
---|
181 | if (cwc->cw[i+8] == cw[i+8]) {
|
---|
182 | cycleok = 1; //means CW1 Cycle OK
|
---|
183 | } else {
|
---|
184 | cycleok = -1;
|
---|
185 | break;
|
---|
186 | }
|
---|
187 | }
|
---|
188 | }
|
---|
189 | } else
|
---|
190 | cs_debug_mask(D_CSPCWC,"no");
|
---|
191 | if (cycleok >= 0) {
|
---|
192 | ret = 0; // return Code 0 Cycle OK
|
---|
193 | if (cycleok == 0) {
|
---|
194 | cwc->nextcyclecw = 1;
|
---|
195 | cs_debug_mask(D_CSPCWC, "cyclecheck [Valid CW 0 Cycle] Client: %s EA: %s Timediff: %ld Stage: %i Cycletime: %i dyncycletime: %i nextCycleCW = CW%i from Reader: %s", user, er_ecmf, now-cwc->time, cwc->stage, cwc->cycletime, cwc->dyncycletime, cwc->nextcyclecw, reader);
|
---|
196 | } else
|
---|
197 | if (cycleok == 1) {
|
---|
198 | cwc->nextcyclecw = 0;
|
---|
199 | cs_debug_mask(D_CSPCWC, "cyclecheck [Valid CW 1 Cycle] Client: %s EA: %s Timediff: %ld Stage: %i Cycletime: %i dyncycletime: %i nextCycleCW = CW%i from Reader: %s", user, er_ecmf, now-cwc->time, cwc->stage, cwc->cycletime, cwc->dyncycletime, cwc->nextcyclecw, reader);
|
---|
200 | }
|
---|
201 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [Dump Stored CW] Client: %s EA: %s CW: %s Time: %ld", user, cwc_ecmf, cwc_cw, cwc->time);
|
---|
202 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [Dump CheckedCW] Client: %s EA: %s CW: %s Time: %ld Timediff: %ld", user, er_ecmf, cwstr, now, now - cwc->time);
|
---|
203 | } else {
|
---|
204 |
|
---|
205 | for (k=0; k<15; k++) { // check for old ECMs
|
---|
206 | #ifdef CS_CACHEEX
|
---|
207 | if ( ( checkECMD5CW(er->ecmd5) && checkECMD5CW(cwc->ecm_md5[k].md5) && !(memcmp(er->ecmd5, cwc->ecm_md5[k].md5, sizeof(er->ecmd5)))) || (er->csp_hash && cwc->ecm_md5[k].csp_hash && er->csp_hash == cwc->ecm_md5[k].csp_hash))
|
---|
208 | #else
|
---|
209 | if ((memcmp(er->ecmd5, cwc->ecm_md5[k].md5, sizeof(er->ecmd5))) == 0)
|
---|
210 | #endif
|
---|
211 | {
|
---|
212 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [OLD] [CheckedECM] Client: %s EA: %s", user, er_ecmf);
|
---|
213 | cs_hexdump(0, cwc->ecm_md5[k].md5, 16, cwc_md5, sizeof(cwc_md5));
|
---|
214 | cs_hexdump(0, (void*)&cwc->ecm_md5[k].csp_hash, 4, cwc_csp, sizeof(cwc_csp));
|
---|
215 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [OLD] [Stored ECM] Client: %s EA: %s.%s", user, cwc_md5, cwc_csp);
|
---|
216 | if (!cfg.cwcycle_dropold && !memcmp(cwc->ecm_md5[k].cw, cw, 16))
|
---|
217 | ret = 4;
|
---|
218 | else
|
---|
219 | ret = 2; // old ER
|
---|
220 | upd_entry = 0;
|
---|
221 | break;
|
---|
222 | }
|
---|
223 | }
|
---|
224 | if (!upd_entry) break;
|
---|
225 | cs_debug_mask(D_CSPCWC, "cyclecheck [ATTENTION!! NON Valid CW Cycle] NO CW Cycle detected! Client: %s EA: %s Timediff: %ld Stage: %i Cycletime: %i dyncycletime: %i nextCycleCW = CW%i from Reader: %s", user, er_ecmf, now-cwc->time, cwc->stage, cwc->cycletime, cwc->dyncycletime, cwc->nextcyclecw, reader);
|
---|
226 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [Dump Stored CW] Client: %s EA: %s CW: %s Time: %ld", user, cwc_ecmf, cwc_cw, cwc->time);
|
---|
227 | cs_debug_mask(D_CSPCWCFUL, "cyclecheck [Dump CheckedCW] Client: %s EA: %s CW: %s Time: %ld Timediff: %ld", user, er_ecmf, cwstr, now, now - cwc->time);
|
---|
228 | ret = 1; // bad cycle
|
---|
229 | upd_entry = 0;
|
---|
230 | break;
|
---|
231 | }
|
---|
232 | } else {
|
---|
233 | if (cwc->stage == 3) {
|
---|
234 | if (cfg.keepcycletime > 0 && now - cwc->time < cfg.keepcycletime *60 ) { // we are in keepcycletime window
|
---|
235 | cwc->stage++; // go to stage 4
|
---|
236 | cs_debug_mask(D_CSPCWC, "cyclecheck [Set Stage 4] for Entry: %s Cycletime: %i -> Entry too old but in keepcycletime window - no cycletime learning - only check which CW must cycle", cwc_ecmf, cwc->cycletime);
|
---|
237 | } else {
|
---|
238 | cwc->stage--; // go one stage back, we are not in keepcycletime window
|
---|
239 | cs_debug_mask(D_CSPCWC, "cyclecheck [Back to Stage 2] for Entry: %s Cycletime: %i -> new cycletime learning", cwc_ecmf, cwc->cycletime);
|
---|
240 | }
|
---|
241 | memset(cwc->cw, 0, sizeof(cwc->cw)); //fake cw for stage 2/4
|
---|
242 | ret = 3;
|
---|
243 | cwc->nextcyclecw = 2;
|
---|
244 | cw_stageswitch = true;
|
---|
245 | }
|
---|
246 | }
|
---|
247 | if (upd_entry){ // learning stages
|
---|
248 | if (now > cwc->locktime) {
|
---|
249 | if (cwc->stage <= 0) { // stage 0 is passed; we update the cw's and time and store cycletime
|
---|
250 | if (cwc->cycletime == now - cwc->time) { // if we got a stable cycletime we go to stage 1
|
---|
251 | cs_debug_mask(D_CSPCWC, "cyclecheck [Set Stage 1] %s Cycletime: %i Lockdiff: %ld", cwc_ecmf, cwc->cycletime, now - cwc->locktime);
|
---|
252 | cwc->stage++; // increase stage
|
---|
253 | } else {
|
---|
254 | cs_debug_mask(D_CSPCWC, "cyclecheck [Stay on Stage 0] %s Cycletime: %i -> no constant CW-Change-Time", cwc_ecmf, cwc->cycletime);
|
---|
255 | }
|
---|
256 |
|
---|
257 | } else
|
---|
258 | if (cwc->stage == 1) { // stage 1 is passed; we update the cw's and time and store cycletime
|
---|
259 | if (cwc->cycletime == now - cwc->time) { // if we got a stable cycletime we go to stage 2
|
---|
260 | cs_debug_mask(D_CSPCWC, "cyclecheck [Set Stage 2] %s Cycletime: %i Lockdiff: %ld", cwc_ecmf, cwc->cycletime, now - cwc->locktime);
|
---|
261 | cwc->stage++; // increase stage
|
---|
262 | } else {
|
---|
263 | cs_debug_mask(D_CSPCWC, "cyclecheck [Back to Stage 0] for Entry %s Cycletime: %i -> no constant CW-Change-Time", cwc_ecmf, cwc->cycletime);
|
---|
264 | cwc->stage--;
|
---|
265 | }
|
---|
266 | } else
|
---|
267 | if ((cwc->stage == 2 || cwc->stage == 4) && !cw_stageswitch) { // stage 2 is passed; we update the cw's and compare cycletime
|
---|
268 | if ((cwc->cycletime == now - cwc->time && cwc->cycletime > 0) || cwc->cw_stageswitch) { // if we got a stable cycletime we go to stage 3
|
---|
269 | n = memcmp( cwc->cw, cw, 8);
|
---|
270 | m = memcmp( cwc->cw+8, cw+8, 8);
|
---|
271 | if (n == 0) {
|
---|
272 | cwc->nextcyclecw = 1;
|
---|
273 | }
|
---|
274 | if (m == 0) {
|
---|
275 | cwc->nextcyclecw = 0;
|
---|
276 | }
|
---|
277 | if (n == m || !checkECMD5CW(cw)) cwc->nextcyclecw = 2; //be sure only one cw part cycle and is valid
|
---|
278 | if (cwc->nextcyclecw < 2) {
|
---|
279 | cs_debug_mask(D_CSPCWC, "cyclecheck [Set Stage 3] %s Cycletime: %i Lockdiff: %ld nextCycleCW = CW%i", cwc_ecmf, cwc->cycletime, now - cwc->locktime, cwc->nextcyclecw);
|
---|
280 | cs_debug_mask(D_CSPCWC, "cyclecheck [Set Cycletime %i] for Entry: %s -> now we can check CW's", cwc->cycletime, cwc_ecmf);
|
---|
281 | cwc->stage = 3; // increase stage
|
---|
282 | } else
|
---|
283 | if (cwc->badrepeat < 2) {
|
---|
284 | cwc->badrepeat++;
|
---|
285 | cs_debug_mask(D_CSPCWC, "cyclecheck [Stay on Stage %d] for Entry %s Cycletime: %i no cycle detect!", cwc->stage, cwc_ecmf, cwc->cycletime);
|
---|
286 | } else {
|
---|
287 | cs_debug_mask(D_CSPCWC, "cyclecheck [Back to Stage 1] for Entry %s Cycletime: %i -> no CW-Cycle in Learning Stage", cwc_ecmf, cwc->cycletime); // if a server asked only every twice ECM we got a stable cycletime*2 ->but thats wrong
|
---|
288 | cwc->stage = 1;
|
---|
289 | }
|
---|
290 |
|
---|
291 | } else {
|
---|
292 |
|
---|
293 | cs_debug_mask(D_CSPCWC, "cyclecheck [Back to Stage 1] for Entry %s Cycletime: %i -> no constant CW-Change-Time", cwc_ecmf, cwc->cycletime);
|
---|
294 | cwc->stage = 1;
|
---|
295 | }
|
---|
296 | }
|
---|
297 | if (cwc->stage == 3) {
|
---|
298 | cwc->locktime = 0;
|
---|
299 | cwc->badrepeat = 0;
|
---|
300 | } else {
|
---|
301 | if (cwc->stage < 3 && !cw_stageswitch) cwc->cycletime = now - cwc->time;
|
---|
302 | cwc->locktime = now + (cfg.ftimeout / 1000);
|
---|
303 | }
|
---|
304 | } else if (cwc->stage != 3) {
|
---|
305 | cs_debug_mask(D_CSPCWC, "cyclecheck [Ignore this EA] for LearningStages because of locktime EA: %s Lockdiff: %ld", cwc_ecmf, now - cwc->locktime);
|
---|
306 | upd_entry = 0;
|
---|
307 | }
|
---|
308 |
|
---|
309 | if (cwc->stage == 3 ) { // we stay in Stage 3 so we update only time and cw
|
---|
310 | if (now - cwc->time > cwc->cycletime) {
|
---|
311 | cwc->dyncycletime = now - cwc->time - cwc->cycletime;
|
---|
312 | } else {
|
---|
313 | cwc->dyncycletime = 0;
|
---|
314 | }
|
---|
315 | }
|
---|
316 | }
|
---|
317 | } else {
|
---|
318 | upd_entry = 0;
|
---|
319 | cwc = NULL;
|
---|
320 | }
|
---|
321 | break;
|
---|
322 | }
|
---|
323 |
|
---|
324 | if (need_new_entry) {
|
---|
325 | cs_readunlock(&cwcycle_lock);
|
---|
326 | if (cw_cc_list_size <= mcl) { //only add when we have space
|
---|
327 | struct s_cw_cycle_check *new = NULL;
|
---|
328 | if (cs_malloc(&new, sizeof(struct s_cw_cycle_check))) { // store cw on top in cyclelist
|
---|
329 | memcpy(new->cw, cw, sizeof(new->cw));
|
---|
330 | // csp cache got no ecm and no md5 hash
|
---|
331 | memcpy(new->ecm_md5[0].md5, er->ecmd5, sizeof(er->ecmd5));
|
---|
332 | #ifdef CS_CACHEEX
|
---|
333 | new->ecm_md5[0].csp_hash = er->csp_hash; // we got no ecm_md5 so CSP-Hash could be necessary
|
---|
334 | #else
|
---|
335 | new->ecm_md5[0].csp_hash = 0; //fake CSP-Hash we got a ecm_md5 so CSP-Hash is not necessary
|
---|
336 | #endif
|
---|
337 | memcpy(new->ecm_md5[0].cw, cw, sizeof(new->cw));
|
---|
338 | new->ecmlen = er->ecmlen;
|
---|
339 | new->cwc_hist_entry = 0;
|
---|
340 | new->caid = er->caid;
|
---|
341 | new->provid = er->prid;
|
---|
342 | new->sid = er->srvid;
|
---|
343 | new->chid = er->chid;
|
---|
344 | new->time = now;
|
---|
345 | new->locktime = now + (cfg.ftimeout / 1000);
|
---|
346 | new->stage = 0;
|
---|
347 | new->cycletime = 99;
|
---|
348 | new->dyncycletime = 0; // to react of share timings
|
---|
349 | new->nextcyclecw = 2; //2=we dont know which next cw Cycle; 0= next cw Cycle CW0; 1= next cw Cycle CW1;
|
---|
350 | new->badrepeat = 0; // on stage 4 counting to prevent too much check again
|
---|
351 | new->cw_stageswitch = false;
|
---|
352 | new->prev = new->next = NULL;
|
---|
353 | new->old = 0;
|
---|
354 | //write lock
|
---|
355 | cs_writelock(&cwcycle_lock);
|
---|
356 | if (cw_cc_list) { // the new entry on top
|
---|
357 | cw_cc_list->prev = new;
|
---|
358 | new->next = cw_cc_list;
|
---|
359 | }
|
---|
360 | cw_cc_list = new;
|
---|
361 | cw_cc_list_size++;
|
---|
362 | //write unlock /
|
---|
363 | cs_writeunlock(&cwcycle_lock);
|
---|
364 |
|
---|
365 | cs_debug_mask(D_CSPCWC, "cyclecheck [Store New Entry] %s Time: %ld Stage: %i Cycletime: %i Locktime: %ld", er_ecmf, new->time, new->stage, new->cycletime, new->locktime);
|
---|
366 | //new = NULL; // maybe this helps against double free or corruption (!prev)
|
---|
367 | }
|
---|
368 | } else {
|
---|
369 | cs_debug_mask(D_CSPCWC, "cyclecheck [Store New Entry] Max List arrived -> dont store new Entry list_size: %i, mcl: %i", cw_cc_list_size, mcl);
|
---|
370 | }
|
---|
371 | } else
|
---|
372 | if (upd_entry && cwc) {
|
---|
373 | cwc->prev = cwc->next = NULL;
|
---|
374 | cwc->old = 0;
|
---|
375 |
|
---|
376 | memcpy(cwc->cw, cw, sizeof(cwc->cw));
|
---|
377 | cwc->time = now;
|
---|
378 | cwc->cwc_hist_entry++;
|
---|
379 | if (cwc->cwc_hist_entry > 14) { //ringbuffer for md5
|
---|
380 | cwc->cwc_hist_entry = 0;
|
---|
381 | }
|
---|
382 | // csp cache got no ecm and no md5 hash
|
---|
383 | memcpy(cwc->ecm_md5[cwc->cwc_hist_entry].md5, er->ecmd5, sizeof(cwc->ecm_md5[0].md5));
|
---|
384 | #ifdef CS_CACHEEX
|
---|
385 | cwc->ecm_md5[cwc->cwc_hist_entry].csp_hash = er->csp_hash;
|
---|
386 | #else
|
---|
387 | cwc->ecm_md5[cwc->cwc_hist_entry].csp_hash = 0; //fake CSP-Hash for logging
|
---|
388 | #endif
|
---|
389 | memcpy(cwc->ecm_md5[cwc->cwc_hist_entry].cw, cw, sizeof(cwc->cw));
|
---|
390 | cwc->ecmlen = er->ecmlen;
|
---|
391 | cwc->cw_stageswitch = cw_stageswitch; //need for zapping
|
---|
392 | //write lock /
|
---|
393 | cs_writelock(&cwcycle_lock);
|
---|
394 | if (cw_cc_list) { // the clone entry on top
|
---|
395 | cw_cc_list->prev = cwc;
|
---|
396 | cwc->next = cw_cc_list;
|
---|
397 | }
|
---|
398 | cw_cc_list = cwc;
|
---|
399 | cw_cc_list_size++;
|
---|
400 | //write unlock /
|
---|
401 | cs_writeunlock(&cwcycle_lock);
|
---|
402 | cs_debug_mask(D_CSPCWC, "cyclecheck [Update Entry and add on top] %s Time: %ld Stage: %i Cycletime: %i", er_ecmf, cwc->time, cwc->stage, cwc->cycletime);
|
---|
403 | } else if (cwc) {
|
---|
404 | free(cwc);
|
---|
405 | }
|
---|
406 | return ret;
|
---|
407 | }
|
---|
408 |
|
---|
409 | uint8_t checkcwcycle(ECM_REQUEST *er, struct s_reader *reader, uchar *cw, int8_t rc){
|
---|
410 |
|
---|
411 | if (!cfg.cwcycle_check_enable)
|
---|
412 | return 3;
|
---|
413 | if (!(rc == E_FOUND) && !(rc == E_CACHEEX))
|
---|
414 | return 2;
|
---|
415 | if (!cw || !er)
|
---|
416 | return 2;
|
---|
417 | if (!(chk_ctab_ex(er->caid,&cfg.cwcycle_check_caidtab))) // dont check caid not in list
|
---|
418 | return 1; // no match leave the check
|
---|
419 |
|
---|
420 | memcpy(er->cw,cw,16);
|
---|
421 | char er_ecmf[ECM_FMT_LEN];
|
---|
422 | format_ecm(er,er_ecmf,ECM_FMT_LEN);
|
---|
423 |
|
---|
424 | char c_reader[64];
|
---|
425 | struct s_client *client = er->client;
|
---|
426 | char *user = username(client);
|
---|
427 |
|
---|
428 | if (reader)
|
---|
429 | snprintf(c_reader, sizeof(c_reader), "%s", reader->label);
|
---|
430 | else
|
---|
431 | snprintf(c_reader, sizeof(c_reader), "cache");
|
---|
432 |
|
---|
433 |
|
---|
434 | cs_debug_mask(D_CSPCWC | D_TRACE,"cyclecheck EA: %s rc: %i reader: %s", er_ecmf, rc, c_reader);
|
---|
435 |
|
---|
436 | switch(checkcwcycle_int(er, er_ecmf, user, cw, c_reader)) {
|
---|
437 |
|
---|
438 | case 0: // CWCYCLE OK
|
---|
439 | if (client){
|
---|
440 | client->cwcycledchecked++;
|
---|
441 | client->cwcycledok++;
|
---|
442 | }
|
---|
443 | first_client->cwcycledchecked++;
|
---|
444 | first_client->cwcycledok++;
|
---|
445 | if (client && client->account) {
|
---|
446 | client->account->cwcycledchecked++;
|
---|
447 | client->account->cwcycledok++;
|
---|
448 | }
|
---|
449 | break;
|
---|
450 |
|
---|
451 | case 1: // CWCYCLE NOK
|
---|
452 | if (client){
|
---|
453 | client->cwcycledchecked++;
|
---|
454 | client->cwcyclednok++;
|
---|
455 | }
|
---|
456 | first_client->cwcycledchecked++;
|
---|
457 | first_client->cwcyclednok++;
|
---|
458 | if (client && client->account) {
|
---|
459 | client->account->cwcycledchecked++;
|
---|
460 | client->account->cwcyclednok++;
|
---|
461 | }
|
---|
462 | if (cfg.onbadcycle > 0) { // ignore ECM Request
|
---|
463 | cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> drop cw (ECM Answer)", user, er_ecmf, c_reader); //D_CSPCWC| D_TRACE
|
---|
464 | return 0;
|
---|
465 | } else { // only logging
|
---|
466 | cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> do nothing", user, er_ecmf, c_reader);//D_CSPCWC| D_TRACE
|
---|
467 | break;
|
---|
468 | }
|
---|
469 |
|
---|
470 | case 2: // ER to OLD
|
---|
471 | if (client){
|
---|
472 | client->cwcycledchecked++;
|
---|
473 | client->cwcyclednok++;
|
---|
474 | }
|
---|
475 | first_client->cwcycledchecked++;
|
---|
476 | first_client->cwcyclednok++;
|
---|
477 | if (client && client->account) {
|
---|
478 | client->account->cwcycledchecked++;
|
---|
479 | client->account->cwcyclednok++;
|
---|
480 | }
|
---|
481 | cs_log("cyclecheck [Bad CW Cycle] for: %s %s from: %s -> ECM Answer is too OLD -> drop cw (ECM Answer)", user, er_ecmf, c_reader);//D_CSPCWC| D_TRACE
|
---|
482 | return 0;
|
---|
483 |
|
---|
484 | case 3: // CycleCheck ignored (stage 4 or Entry to Old)
|
---|
485 | if (client){
|
---|
486 | client->cwcycledchecked++;
|
---|
487 | client->cwcycledign++;
|
---|
488 | }
|
---|
489 | first_client->cwcycledchecked++;
|
---|
490 | first_client->cwcycledign++;
|
---|
491 | if (client && client->account) {
|
---|
492 | client->account->cwcycledchecked++;
|
---|
493 | client->account->cwcycledign++;
|
---|
494 | }
|
---|
495 | break;
|
---|
496 |
|
---|
497 | case 4: // same CW
|
---|
498 | cs_debug_mask(D_CSPCWC, "cyclecheck [Same CW] for: %s %s -> same CW detected from: %s -> do nothing ", user, er_ecmf, c_reader);
|
---|
499 | break;
|
---|
500 |
|
---|
501 | case 6: // not checked ( learning Stages or Caid not in cyclelist )
|
---|
502 | break;
|
---|
503 |
|
---|
504 | }
|
---|
505 | return 1;
|
---|
506 | }
|
---|
507 |
|
---|
508 | uint8_t cwcycle_check_act(uint16_t caid){
|
---|
509 | return chk_ctab_ex(caid,&cfg.cwcycle_check_caidtab);
|
---|
510 | }
|
---|
511 | /*
|
---|
512 | *
|
---|
513 | */
|
---|
514 |
|
---|
515 | #endif
|
---|