Attempt to count descramblers used properly
[oscam.git] / module-anticasc.c
blob09cb43b108c3f8771c3f512e10a6931150a811ec
1 #define MODULE_LOG_PREFIX "anticasc"
3 //FIXME Not checked on threadsafety yet; after checking please remove this line
4 #include "globals.h"
6 #ifdef CS_ANTICASC
8 #include "module-anticasc.h"
9 #include "oscam-conf.h"
10 #include "oscam-client.h"
11 #include "oscam-garbage.h"
12 #include "oscam-string.h"
13 #include "oscam-time.h"
15 #define cs_ac "oscam.ac"
17 static FILE *ac_log;
18 static uint8_t ac_ecmd5[CS_ECMSTORESIZE];
20 bool anticasc_logging(char *txt)
22 if (!ac_log)
23 return false;
24 if (strstr(txt, "acasc: "))
26 fprintf(ac_log, "%s\n", txt);
27 fflush(ac_log);
28 return true;
30 return false;
33 static int32_t ac_init_log(void)
35 if(ac_log)
36 { return 1; }
37 if(!cfg.ac_logfile)
39 cs_log("ERROR: anti cascading is enabled but ac_logfile is not set.");
40 return 0;
42 ac_log = fopen(cfg.ac_logfile, "a+");
43 if(!ac_log)
45 cs_log("ERROR: Can't open anti cascading logfile: %s (errno=%d %s)",
46 cfg.ac_logfile, errno, strerror(errno));
47 return 0;
49 cs_log("anti cascading log initialized");
50 return 1;
54 void ac_clear(void)
56 struct s_client *client;
57 struct s_auth *account;
59 for(client = first_client; client; client = client->next)
61 if(client->typ != 'c') { continue; }
62 memset(&client->acasc, 0, sizeof(client->acasc));
65 for(account = cfg.account; account; account = account->next)
66 { memset(&account->ac_stat, 0, sizeof(account->ac_stat)); }
69 void ac_init_stat(void)
71 if(!cfg.ac_enabled)
72 { return; }
73 ac_clear();
74 ac_init_log();
77 void ac_do_stat(void)
79 int32_t j, idx, exceeds, maxval, prev_deny = 0;
81 struct s_client *client;
82 for(client = first_client; client; client = client->next)
84 if(client->typ != 'c') { continue; }
86 struct s_acasc *ac_stat = &client->account->ac_stat;
87 struct s_acasc_shm *acasc = &client->acasc;
89 idx = ac_stat->idx;
90 ac_stat->stat[idx] = acasc->ac_count;
91 acasc->ac_count = 0;
93 if(ac_stat->stat[idx])
95 if(client->ac_penalty == 2) // banned
97 cs_log_dbg(D_CLIENT, "acasc: user '%s' banned", client->account->usr);
98 acasc->ac_deny = 1;
100 else
102 for(j = exceeds = maxval = 0; j < cfg.ac_samples; j++)
104 if(ac_stat->stat[j] > maxval)
105 { maxval = ac_stat->stat[j]; }
106 exceeds += (ac_stat->stat[j] > client->ac_limit);
108 prev_deny = acasc->ac_deny;
109 acasc->ac_deny = (exceeds >= cfg.ac_denysamples);
111 cs_log_dbg(D_CLIENT, "acasc: %s limit=%d, max=%d, samples=%d, dsamples=%d, [idx=%d]:",
112 client->account->usr, client->ac_limit, maxval,
113 cfg.ac_samples, cfg.ac_denysamples, idx);
114 cs_log_dbg(D_CLIENT, "acasc: %d %d %d %d %d %d %d %d %d %d ", ac_stat->stat[0],
115 ac_stat->stat[1], ac_stat->stat[2], ac_stat->stat[3],
116 ac_stat->stat[4], ac_stat->stat[5], ac_stat->stat[6],
117 ac_stat->stat[7], ac_stat->stat[8], ac_stat->stat[9]);
118 if(acasc->ac_deny)
120 cs_log("acasc: user '%s' exceeds limit", client->account->usr);
121 ac_stat->stat[idx] = 0;
123 else if(prev_deny)
124 { cs_log("acasc: user '%s' restored access", client->account->usr); }
127 else if(acasc->ac_deny)
129 prev_deny = 1;
130 acasc->ac_deny = 0;
131 cs_log("acasc: restored access for inactive user '%s'", client->account->usr);
134 if(!acasc->ac_deny && !prev_deny)
135 { ac_stat->idx = (ac_stat->idx + 1) % cfg.ac_samples; }
139 void ac_init_client(struct s_client *client, struct s_auth *account)
141 client->ac_limit = 0;
142 client->ac_penalty = account->ac_penalty == -1 ? cfg.ac_penalty : account->ac_penalty;
143 client->ac_fakedelay = account->ac_fakedelay == -1 ? cfg.ac_fakedelay : account->ac_fakedelay;
144 if(cfg.ac_enabled)
146 int32_t numusers = account->ac_users;
147 if(numusers == -1)
148 { numusers = cfg.ac_users; }
150 if(numusers)
152 client->ac_limit = (numusers * 100 + 80) * cfg.ac_stime;
153 cs_log_dbg(D_CLIENT, "acasc: user '%s', users=%d, stime=%d min, dwlimit=%d per min, penalty=%d",
154 account->usr, numusers, cfg.ac_stime,
155 numusers * 100 + 80, client->ac_penalty);
157 else
159 cs_log_dbg(D_CLIENT, "acasc: anti-cascading not used for user '%s'", account->usr);
164 static int32_t ac_dw_weight(ECM_REQUEST *er)
166 struct s_cpmap *cpmap;
168 for(cpmap = cfg.cpmap; (cpmap) ; cpmap = cpmap->next)
169 if((cpmap->caid == 0 || cpmap->caid == er->caid) &&
170 (cpmap->provid == 0 || cpmap->provid == er->prid) &&
171 (cpmap->sid == 0 || cpmap->sid == er->srvid) &&
172 (cpmap->chid == 0 || cpmap->chid == er->chid))
173 { return (cpmap->dwtime * 100 / 60); }
175 cs_log_dbg(D_CLIENT, "acasc: WARNING: CAID %04X, PROVID %06X, SID %04X, CHID %04X not found in oscam.ac",
176 er->caid, er->prid, er->srvid, er->chid);
177 cs_log_dbg(D_CLIENT, "acasc: set DW lifetime 10 sec");
178 return 16; // 10*100/60
181 void ac_chk(struct s_client *cl, ECM_REQUEST *er, int32_t level)
183 if(!cl->ac_limit || !cfg.ac_enabled) { return; }
185 struct s_acasc_shm *acasc = &cl->acasc;
187 if(level == 1)
189 if(er->rc == E_FAKE)
190 { acasc->ac_count++; }
192 if(er->rc >= E_NOTFOUND)
193 { return; } // not found
195 if(memcmp(ac_ecmd5, er->ecmd5, CS_ECMSTORESIZE) != 0)
197 acasc->ac_count += ac_dw_weight(er);
198 memcpy(ac_ecmd5, er->ecmd5, CS_ECMSTORESIZE);
200 return;
203 if(acasc->ac_deny)
205 if(cl->ac_penalty)
207 if(cl->ac_penalty == 3)
209 if(cl->ac_fakedelay > 0)
210 { cs_log_dbg(D_CLIENT, "acasc: fake delay %d ms", cl->ac_fakedelay); }
212 else
214 cs_log_dbg(D_CLIENT, "acasc: send fake dw");
215 er->rc = E_FAKE; // fake
216 er->rcEx = 0;
218 if(cl->ac_fakedelay > 0)
219 { cs_sleepms(cl->ac_fakedelay); }
224 static void ac_load_config(void)
226 FILE *fp = open_config_file(cs_ac);
227 if(!fp)
228 { return; }
230 int32_t nr;
231 char *saveptr1 = NULL, *token;
232 if(!cs_malloc(&token, MAXLINESIZE))
233 { return; }
234 struct s_cpmap *cur_cpmap, *first_cpmap = NULL, *last_cpmap = NULL;
236 for(nr = 0; fgets(token, MAXLINESIZE, fp);)
238 int32_t i, skip;
239 uint16_t caid, sid, chid, dwtime;
240 uint32_t provid;
241 char *ptr, *ptr1;
243 if(strlen(token) < 4) { continue; }
245 caid = sid = chid = dwtime = 0;
246 provid = 0;
247 skip = 0;
248 ptr1 = 0;
249 for(i = 0, ptr = strtok_r(token, "=", &saveptr1); (i < 2) && (ptr); ptr = strtok_r(NULL, "=", &saveptr1), i++)
251 trim(ptr);
252 if(*ptr == ';' || *ptr == '#' || *ptr == '-')
254 skip = 1;
255 break;
257 switch(i)
259 case 0:
260 ptr1 = ptr;
261 break;
262 case 1:
263 dwtime = atoi(ptr);
264 break;
268 if(!skip)
270 for(i = 0, ptr = strtok_r(ptr1, ":", &saveptr1); (i < 4) && (ptr); ptr = strtok_r(NULL, ":", &saveptr1), i++)
272 trim(ptr);
273 switch(i)
275 case 0:
276 if(*ptr == '*') { caid = 0; }
277 else { caid = a2i(ptr, 4); }
278 break;
279 case 1:
280 if(*ptr == '*') { provid = 0; }
281 else { provid = a2i(ptr, 6); }
282 break;
283 case 2:
284 if(*ptr == '*') { sid = 0; }
285 else { sid = a2i(ptr, 4); }
286 break;
287 case 3:
288 if(*ptr == '*') { chid = 0; }
289 else { chid = a2i(ptr, 4); }
290 break;
293 if(!cs_malloc(&cur_cpmap, sizeof(struct s_cpmap)))
295 for(cur_cpmap = first_cpmap; cur_cpmap;)
297 last_cpmap = cur_cpmap;
298 cur_cpmap = cur_cpmap->next;
299 NULLFREE(last_cpmap);
301 NULLFREE(token);
302 return;
304 if(last_cpmap)
305 { last_cpmap->next = cur_cpmap; }
306 else
307 { first_cpmap = cur_cpmap; }
308 last_cpmap = cur_cpmap;
310 cur_cpmap->caid = caid;
311 cur_cpmap->provid = provid;
312 cur_cpmap->sid = sid;
313 cur_cpmap->chid = chid;
314 cur_cpmap->dwtime = dwtime;
315 cur_cpmap->next = 0;
317 cs_log_dbg(D_CLIENT, "nr=%d, caid=%04X, provid=%06X, sid=%04X, chid=%04X, dwtime=%d",
318 nr, caid, provid, sid, chid, dwtime);
319 nr++;
322 NULLFREE(token);
323 fclose(fp);
325 last_cpmap = cfg.cpmap;
326 cfg.cpmap = first_cpmap;
327 for(cur_cpmap = last_cpmap; cur_cpmap; cur_cpmap = cur_cpmap->next)
328 { add_garbage(cur_cpmap); }
329 //cs_log("%d lengths for caid guessing loaded", nr);
330 return;
333 void ac_copy_vars(struct s_auth *src, struct s_auth *dst)
335 dst->ac_stat = src->ac_stat;
338 void ac_init(void)
340 if(!cfg.ac_enabled)
342 cs_log("anti cascading disabled");
343 return;
346 ac_load_config();
347 ac_init_stat();
350 int8_t get_caid_weight(ECM_REQUEST *er)
352 switch(er->caid)
354 case 0x0100:
355 switch (er->prid)
357 case 0x00003D:
358 return 20;
359 case 0x000065:
360 return 7;
361 default:
362 return 10;
364 case 0x0500:
365 switch(er->prid)
367 case 0x020910:
368 return 30;
369 case 0x024400:
370 case 0x032830:
371 return 10;
372 case 0x043800:
373 return 25;
374 default:
375 return 15;
377 case 0x0604:
378 return 11;
379 case 0x1702:
380 case 0x1722:
381 case 0x1833:
382 case 0x09C4:
383 switch(er->srvid)
385 case 0x0022: // Disney Channel
386 case 0x0016: // Heimatkanal
387 case 0x0203: // MGM
388 case 0x0008: // Sky Comedy
389 case 0x002B: // Sky Cinema +24
390 case 0x000B: // Sky Cinema +1
391 case 0x0009: // Sky Action
392 case 0x000A: // Sky Cinema
393 case 0x0014: // Sky Emotion
394 case 0x0029: // Sky Hits
395 case 0x0204: // Sky Nostalgie
396 case 0x0011: // Sky Sport News
397 case 0x0024: // Syfy
398 return 10;
399 default:
400 return 7;
402 case 0x1830:
403 return 15;
404 case 0x1843:
405 case 0x1834:
406 case 0x09C7:
407 return 7;
408 case 0x4A70:
409 return 14;
410 case 0x183D:
411 return 13;
412 case 0x1810:
413 case 0x0D05:
414 case 0x0D95:
415 case 0x093B:
416 case 0x098C:
417 case 0x098D:
418 case 0x0B00:
419 default:
420 return 10;
425 void insert_zaplist(ECM_REQUEST *er, struct s_client *client)
427 bool new_zaplist_entry = false;
428 int8_t zap_caid_weight;
429 zap_caid_weight = get_caid_weight(er);
430 int8_t k = 0;
431 bool found = false;
432 time_t zaptime = time(NULL);
434 for(k=0; k<15 ; k++)
436 if(er->caid == client->client_zap_list[k].caid && er->prid == client->client_zap_list[k].provid && er->chid == client->client_zap_list[k].chid && er->srvid == client->client_zap_list[k].sid) //found
438 if(zaptime-zap_caid_weight*2 < client->client_zap_list[k].lasttime)
440 cs_log_dbg(D_TRACE, "[zaplist] update Entry [%i] for Client: %s %04X@%06X/%04X/%04X TIME: %ld Diff: %ld zcw: %i(%i)", k, username(client), er->caid, er->prid, er->chid, er->srvid, zaptime, zaptime-client->client_zap_list[k].lasttime, zap_caid_weight, zap_caid_weight*2);
441 client->client_zap_list[k].lasttime = zaptime;
442 if(client->client_zap_list[k].request_stage < 10)
444 client->client_zap_list[k].request_stage ++;
446 found = true;
447 break;
452 if(!found)
454 for(k=0; k<15 ; k++)
456 if(zaptime-30 > client->client_zap_list[k].lasttime) //make a new Entry and use a memoryplace of a old entry
458 client->client_zap_list[k].caid = er->caid;
459 client->client_zap_list[k].provid = er->prid;
460 client->client_zap_list[k].chid = er->chid;
461 client->client_zap_list[k].sid = er->srvid;
462 client->client_zap_list[k].request_stage = 1; //need for ACoSC
463 client->client_zap_list[k].lasttime = zaptime;
464 cs_log_dbg(D_TRACE, "[zaplist] new Entry [%i] for Client: %s %04X@%06X/%04X/%04X TIME: %ld", k, username(client), er->caid, er->prid, er->chid, er->srvid, zaptime);
465 new_zaplist_entry = true;
466 break;
469 if(!new_zaplist_entry)
470 { cs_log_dbg(D_TRACE, "[zaplist] no free slot for client: %s", username(client)); }
472 if(client->account->acosc_user_zap_count_start_time+60 > zaptime)
473 { client->account->acosc_user_zap_count ++; }
474 else
476 client->account->acosc_user_zap_count_start_time = zaptime;
477 client->account->acosc_user_zap_count = 0;
478 cs_log_dbg(D_TRACE, "[zaplist] Client: %s reset acosc_user_zap_count_start_time", username(client));
479 for(k=0; k<15 ; k++)
481 if(client->client_zap_list[k].lasttime > zaptime-60)
483 client->account->acosc_user_zap_count ++;
486 cs_log_dbg(D_TRACE, "[zaplist] Client: %s zap_count: %i", username(client), client->account->acosc_user_zap_count);
491 #endif