1 #define MODULE_LOG_PREFIX "anticasc"
3 //FIXME Not checked on threadsafety yet; after checking please remove this line
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"
18 static uint8_t ac_ecmd5
[CS_ECMSTORESIZE
];
20 bool anticasc_logging(char *txt
)
24 if (strstr(txt
, "acasc: "))
26 fprintf(ac_log
, "%s\n", txt
);
33 static int32_t ac_init_log(void)
39 cs_log("ERROR: anti cascading is enabled but ac_logfile is not set.");
42 ac_log
= fopen(cfg
.ac_logfile
, "a+");
45 cs_log("ERROR: Can't open anti cascading logfile: %s (errno=%d %s)",
46 cfg
.ac_logfile
, errno
, strerror(errno
));
49 cs_log("anti cascading log initialized");
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)
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
;
90 ac_stat
->stat
[idx
] = acasc
->ac_count
;
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
);
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]);
120 cs_log("acasc: user '%s' exceeds limit", client
->account
->usr
);
121 ac_stat
->stat
[idx
] = 0;
124 { cs_log("acasc: user '%s' restored access", client
->account
->usr
); }
127 else if(acasc
->ac_deny
)
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
;
146 int32_t numusers
= account
->ac_users
;
148 { numusers
= cfg
.ac_users
; }
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
);
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
;
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
);
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
); }
214 cs_log_dbg(D_CLIENT
, "acasc: send fake dw");
215 er
->rc
= E_FAKE
; // fake
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
);
231 char *saveptr1
= NULL
, *token
;
232 if(!cs_malloc(&token
, MAXLINESIZE
))
234 struct s_cpmap
*cur_cpmap
, *first_cpmap
= NULL
, *last_cpmap
= NULL
;
236 for(nr
= 0; fgets(token
, MAXLINESIZE
, fp
);)
239 uint16_t caid
, sid
, chid
, dwtime
;
243 if(cs_strlen(token
) < 4) { continue; }
245 caid
= sid
= chid
= dwtime
= 0;
249 for(i
= 0, ptr
= strtok_r(token
, "=", &saveptr1
); (i
< 2) && (ptr
); ptr
= strtok_r(NULL
, "=", &saveptr1
), i
++)
252 if(*ptr
== ';' || *ptr
== '#' || *ptr
== '-')
270 for(i
= 0, ptr
= strtok_r(ptr1
, ":", &saveptr1
); (i
< 4) && (ptr
); ptr
= strtok_r(NULL
, ":", &saveptr1
), i
++)
276 if(*ptr
== '*') { caid
= 0; }
277 else { caid
= a2i(ptr
, 4); }
280 if(*ptr
== '*') { provid
= 0; }
281 else { provid
= a2i(ptr
, 6); }
284 if(*ptr
== '*') { sid
= 0; }
285 else { sid
= a2i(ptr
, 4); }
288 if(*ptr
== '*') { chid
= 0; }
289 else { chid
= a2i(ptr
, 4); }
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
);
305 { last_cpmap
->next
= cur_cpmap
; }
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
;
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
);
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);
333 void ac_copy_vars(struct s_auth
*src
, struct s_auth
*dst
)
335 dst
->ac_stat
= src
->ac_stat
;
342 cs_log("anti cascading disabled");
350 int8_t get_caid_weight(ECM_REQUEST
*er
)
385 case 0x0022: // Disney Channel
386 case 0x0016: // Heimatkanal
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
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
);
432 time_t zaptime
= time(NULL
);
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
++;
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;
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
++; }
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
));
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
);