00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00048 #ifdef USE_DST_BLACKLIST
00049
00050 #include "dst_blacklist.h"
00051 #include "globals.h"
00052 #include "cfg_core.h"
00053 #include "mem/shm_mem.h"
00054 #include "hashes.h"
00055 #include "locking.h"
00056 #include "timer.h"
00057 #include "timer_ticks.h"
00058 #include "ip_addr.h"
00059 #include "error.h"
00060 #include "rpc.h"
00061 #include "compiler_opt.h"
00062 #include "resolve.h"
00063 #ifdef USE_DST_BLACKLIST_STATS
00064 #include "pt.h"
00065 #endif
00066
00067
00068
00069
00070 struct dst_blst_entry{
00071 struct dst_blst_entry* next;
00072 ticks_t expire;
00073 unsigned short port;
00074 unsigned char proto;
00075 unsigned char flags;
00076 unsigned char ip[4];
00077 };
00078
00079 #define DST_BLST_ENTRY_SIZE(b) \
00080 (sizeof(struct dst_blst_entry)+((b).flags&BLST_IS_IPV6)*12)
00081
00082
00083 #define DST_BLST_HASH_SIZE 1024
00084 #define DEFAULT_BLST_TIMER_INTERVAL 60
00085
00086
00087
00088 #ifdef GEN_LOCK_T_UNLIMITED
00089 #define BLST_LOCK_PER_BUCKET
00090 #elif defined GEN_LOCK_SET_T_UNLIMITED
00091 #define BLST_LOCK_SET
00092 #else
00093 #define BLST_ONE_LOCK
00094 #endif
00095
00096
00097 #ifdef BLST_LOCK_PER_BUCKET
00098
00099 #define LOCK_BLST(h) lock_get(&dst_blst_hash[(h)].lock)
00100 #define UNLOCK_BLST(h) lock_release(&dst_blst_hash[(h)].lock)
00101 #elif defined BLST_LOCK_SET
00102 static gen_lock_set_t* blst_lock_set=0;
00103 #define LOCK_BLST(h) lock_set_get(blst_lock_set, (h))
00104 #define UNLOCK_BLST(h) lock_set_release(blst_lock_set, (h))
00105 #else
00106
00107 static gen_lock_t* blst_lock=0;
00108 #define LOCK_BLST(h) lock_get(blst_lock)
00109 #define UNLOCK_BLST(h) lock_release(blst_lock)
00110 #endif
00111
00112
00113
00114
00115 #define BLST_HASH_STATS
00116
00117 #ifdef BLST_HASH_STATS
00118 #define BLST_HASH_STATS_DEC(h) dst_blst_hash[(h)].entries--
00119 #define BLST_HASH_STATS_INC(h) dst_blst_hash[(h)].entries++
00120 #else
00121 #define BLST_HASH_STATS_DEC(h) do{}while(0)
00122 #define BLST_HASH_STATS_INC(h) do{}while(0)
00123 #endif
00124
00125 struct dst_blst_lst_head{
00126 struct dst_blst_entry* first;
00127 #ifdef BLST_LOCK_PER_BUCKET
00128 gen_lock_t lock;
00129 #endif
00130 #ifdef BLST_HASH_STATS
00131 unsigned int entries;
00132 #endif
00133 };
00134
00135 int dst_blacklist_init=1;
00136 static struct timer_ln* blst_timer_h=0;
00137
00138 static volatile unsigned int* blst_mem_used=0;
00139 unsigned int blst_timer_interval=DEFAULT_BLST_TIMER_INTERVAL;
00140 struct dst_blst_lst_head* dst_blst_hash=0;
00141
00142 #ifdef USE_DST_BLACKLIST_STATS
00143 struct t_dst_blacklist_stats* dst_blacklist_stats=0;
00144 #endif
00145
00146
00147 unsigned blst_proto_imask[PROTO_LAST+1];
00148
00149 #ifdef DST_BLACKLIST_HOOKS
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 #define MAX_BLST_HOOKS 1
00168
00169 struct blst_callbacks_lst{
00170 struct blacklist_hook* hooks;
00171 unsigned int max_hooks;
00172 int last_idx;
00173 };
00174
00175 static struct blst_callbacks_lst blst_add_cb;
00176 static struct blst_callbacks_lst blst_search_cb;
00177
00178 static int init_blst_callback_lst(struct blst_callbacks_lst* cb_lst, int max)
00179 {
00180
00181 cb_lst->max_hooks=MAX_BLST_HOOKS;
00182 cb_lst->last_idx=0;
00183 cb_lst->hooks=pkg_malloc(cb_lst->max_hooks*sizeof(struct blacklist_hook));
00184 if (cb_lst->hooks==0)
00185 goto error;
00186 memset(cb_lst->hooks, 0, cb_lst->max_hooks*sizeof(struct blacklist_hook));
00187 return 0;
00188 error:
00189 return -1;
00190 }
00191
00192
00193 static void destroy_blst_callback_lst(struct blst_callbacks_lst* cb_lst)
00194 {
00195 int r;
00196 if (cb_lst && cb_lst->hooks){
00197 for (r=0; r<cb_lst->last_idx; r++){
00198 if (cb_lst->hooks[r].destroy)
00199 cb_lst->hooks[r].destroy();
00200 }
00201 pkg_free(cb_lst->hooks);
00202 cb_lst->hooks=0;
00203 cb_lst->last_idx=0;
00204 cb_lst->max_hooks=0;
00205 }
00206 }
00207
00208
00209 static void destroy_blacklist_hooks()
00210 {
00211 destroy_blst_callback_lst(&blst_add_cb);
00212 destroy_blst_callback_lst(&blst_search_cb);
00213 }
00214
00215
00216 static int init_blacklist_hooks()
00217 {
00218
00219 if (init_blst_callback_lst(&blst_add_cb, MAX_BLST_HOOKS)!=0)
00220 goto error;
00221 if (init_blst_callback_lst(&blst_search_cb, MAX_BLST_HOOKS)!=0)
00222 goto error;
00223 return 0;
00224 error:
00225 LOG(L_ERR, "blacklist_hooks: failure initializing internal lists\n");
00226 destroy_blacklist_hooks();
00227 return -1;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236 int register_blacklist_hook(struct blacklist_hook *h, int type)
00237 {
00238 struct blst_callbacks_lst* cb_lst;
00239 struct blacklist_hook* tmp;
00240 int new_max_hooks;
00241
00242 if (dst_blacklist_init==0) {
00243 LOG(L_ERR, "register_blacklist_hook: blacklist is turned off, "
00244 "the hook cannot be registered\n");
00245 goto error;
00246 }
00247
00248 switch(type){
00249 case DST_BLACKLIST_ADD_CB:
00250 cb_lst=&blst_add_cb;
00251 break;
00252 case DST_BLACKLIST_SEARCH_CB:
00253 cb_lst=&blst_search_cb;
00254 break;
00255 default:
00256 BUG("register_blacklist_hook: invalid type %d\n", type);
00257 goto error;
00258 }
00259 if (cb_lst==0 || cb_lst->hooks==0 || cb_lst->max_hooks==0){
00260 BUG("register_blacklist_hook: intialization error\n");
00261 goto error;
00262 }
00263
00264 if (cb_lst->last_idx >= cb_lst->max_hooks){
00265 new_max_hooks=2*cb_lst->max_hooks;
00266 tmp=pkg_realloc(cb_lst->hooks,
00267 new_max_hooks*sizeof(struct blacklist_hook));
00268 if (tmp==0){
00269 goto error;
00270 }
00271 cb_lst->hooks=tmp;
00272
00273
00274 memset(&cb_lst->hooks[cb_lst->max_hooks+1], 0,
00275 (new_max_hooks-cb_lst->max_hooks-1)*
00276 sizeof(struct blacklist_hook));
00277 cb_lst->max_hooks=new_max_hooks;
00278 }
00279 cb_lst->hooks[cb_lst->last_idx]=*h;
00280 cb_lst->last_idx++;
00281 return 0;
00282 error:
00283 return -1;
00284 }
00285
00286
00287 inline static int blacklist_run_hooks(struct blst_callbacks_lst *cb_lst,
00288 struct dest_info* si, unsigned char* flags,
00289 struct sip_msg* msg)
00290 {
00291 int r;
00292 int ret;
00293
00294 ret=DST_BLACKLIST_CONTINUE;
00295
00296 if (likely(cb_lst->last_idx==0))
00297 return ret;
00298 for (r=0; r<cb_lst->last_idx; r++){
00299 ret=cb_lst->hooks[r].on_blst_action(si, flags, msg);
00300 if (ret!=DST_BLACKLIST_CONTINUE) break;
00301 }
00302 return ret;
00303 }
00304
00305
00306 #endif
00307
00308
00312 int blst_init_ign_masks(void)
00313 {
00314 if ((PROTO_UDP > PROTO_LAST) || (PROTO_TCP > PROTO_LAST) ||
00315 (PROTO_TLS > PROTO_LAST) || (PROTO_SCTP > PROTO_LAST)){
00316 BUG("protocol array too small\n");
00317 return -1;
00318 }
00319 blst_proto_imask[PROTO_UDP]=cfg_get(core, core_cfg, blst_udp_imask);
00320 blst_proto_imask[PROTO_TCP]=cfg_get(core, core_cfg, blst_tcp_imask);
00321 blst_proto_imask[PROTO_TLS]=cfg_get(core, core_cfg, blst_tls_imask);
00322 blst_proto_imask[PROTO_SCTP]=cfg_get(core, core_cfg, blst_sctp_imask);
00323 blst_proto_imask[PROTO_NONE]=blst_proto_imask[PROTO_UDP];
00324 return 0;
00325 }
00326
00327
00328
00329 inline static void blst_destroy_entry(struct dst_blst_entry* e)
00330 {
00331 shm_free(e);
00332 }
00333
00334
00335 static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data);
00336
00337
00338 inline static void dst_blst_entry2ip(struct ip_addr* ip,
00339 struct dst_blst_entry* e)
00340 {
00341 #ifdef USE_IPV6
00342 if (e->flags & BLST_IS_IPV6){
00343 ip->af=AF_INET6;
00344 ip->len=16;
00345 }else
00346 #endif
00347 {
00348 ip->af=AF_INET;
00349 ip->len=4;
00350 }
00351 memcpy(ip->u.addr, e->ip, ip->len);
00352 }
00353
00354
00355
00356 inline static unsigned short dst_blst_hash_no(unsigned char proto,
00357 struct ip_addr* ip,
00358 unsigned short port)
00359 {
00360 str s1;
00361 str s2;
00362
00363 s1.s=(char*)ip->u.addr;
00364 s1.len=ip->len;
00365 s2.s=(char*)&port;
00366 s2.len=sizeof(unsigned short);
00367 return get_hash2_raw(&s1, &s2)%DST_BLST_HASH_SIZE;
00368 }
00369
00370
00371
00372 void destroy_dst_blacklist()
00373 {
00374 int r;
00375 struct dst_blst_entry** crt;
00376 struct dst_blst_entry* e;
00377
00378 if (blst_timer_h){
00379 timer_del(blst_timer_h);
00380 timer_free(blst_timer_h);
00381 blst_timer_h=0;
00382 }
00383 #ifdef BLST_LOCK_PER_BUCKET
00384 if (dst_blst_hash)
00385 for(r=0; r<DST_BLST_HASH_SIZE; r++)
00386 lock_destroy(&dst_blst_hash[r].lock);
00387 #elif defined BLST_LOCK_SET
00388 if (blst_lock_set){
00389 lock_set_destroy(blst_lock_set);
00390 lock_set_dealloc(blst_lock_set);
00391 blst_lock_set=0;
00392 }
00393 #else
00394 if (blst_lock){
00395 lock_destroy(blst_lock);
00396 lock_dealloc(blst_lock);
00397 blst_lock=0;
00398 }
00399 #endif
00400
00401 if (dst_blst_hash){
00402 for(r=0; r<DST_BLST_HASH_SIZE; r++){
00403 crt=&dst_blst_hash[r].first;
00404 while(*crt){
00405 e=*crt;
00406 *crt=(*crt)->next;
00407 blst_destroy_entry(e);
00408 }
00409 }
00410 shm_free(dst_blst_hash);
00411 dst_blst_hash=0;
00412 }
00413 if (blst_mem_used){
00414 shm_free((void*)blst_mem_used);
00415 blst_mem_used=0;
00416 }
00417 #ifdef DST_BLACKLIST_HOOKS
00418 destroy_blacklist_hooks();
00419 #endif
00420
00421 #ifdef USE_DST_BLACKLIST_STATS
00422 if (dst_blacklist_stats)
00423 shm_free(dst_blacklist_stats);
00424 #endif
00425 }
00426
00427
00428
00429 int init_dst_blacklist()
00430 {
00431 int ret;
00432 #ifdef BLST_LOCK_PER_BUCKET
00433 int r;
00434 #endif
00435
00436 if (dst_blacklist_init==0) {
00437
00438 default_core_cfg.use_dst_blacklist=0;
00439 return 0;
00440 }
00441
00442 ret=-1;
00443 #ifdef DST_BLACKLIST_HOOKS
00444 if (init_blacklist_hooks()!=0){
00445 ret=E_OUT_OF_MEM;
00446 goto error;
00447 }
00448 #endif
00449 blst_mem_used=shm_malloc(sizeof(*blst_mem_used));
00450 if (blst_mem_used==0){
00451 ret=E_OUT_OF_MEM;
00452 goto error;
00453 }
00454 *blst_mem_used=0;
00455 dst_blst_hash=shm_malloc(sizeof(struct dst_blst_lst_head) *
00456 DST_BLST_HASH_SIZE);
00457 if (dst_blst_hash==0){
00458 ret=E_OUT_OF_MEM;
00459 goto error;
00460 }
00461 memset(dst_blst_hash, 0, sizeof(struct dst_blst_lst_head) *
00462 DST_BLST_HASH_SIZE);
00463 #ifdef BLST_LOCK_PER_BUCKET
00464 for (r=0; r<DST_BLST_HASH_SIZE; r++){
00465 if (lock_init(&dst_blst_hash[r].lock)==0){
00466 ret=-1;
00467 goto error;
00468 }
00469 }
00470 #elif defined BLST_LOCK_SET
00471 blst_lock_set=lock_set_alloc(DST_BLST_HASH_SIZE);
00472 if (blst_lock_set==0){
00473 ret=E_OUT_OF_MEM;
00474 goto error;
00475 }
00476 if (lock_set_init(blst_lock_set)==0){
00477 lock_set_dealloc(blst_lock_set);
00478 blst_lock_set=0;
00479 ret=-1;
00480 goto error;
00481 }
00482 #else
00483 blst_lock=lock_alloc();
00484 if (blst_lock==0){
00485 ret=E_OUT_OF_MEM;
00486 goto error;
00487 }
00488 if (lock_init(blst_lock)==0){
00489 lock_dealloc(blst_lock);
00490 blst_lock=0;
00491 ret=-1;
00492 goto error;
00493 }
00494 #endif
00495 blst_timer_h=timer_alloc();
00496 if (blst_timer_h==0){
00497 ret=E_OUT_OF_MEM;
00498 goto error;
00499 }
00500
00501 default_core_cfg.blst_max_mem<<=10;
00502 if (blst_timer_interval){
00503 timer_init(blst_timer_h, blst_timer, 0 ,0);
00504 if (timer_add(blst_timer_h, S_TO_TICKS(blst_timer_interval))<0){
00505 LOG(L_CRIT, "BUG: init_dst_blacklist: failed to add the timer\n");
00506 timer_free(blst_timer_h);
00507 blst_timer_h=0;
00508 goto error;
00509 }
00510 }
00511 if (blst_init_ign_masks() < 0){
00512 ret=E_BUG;
00513 goto error;
00514 }
00515 return 0;
00516 error:
00517 destroy_dst_blacklist();
00518 return ret;
00519 }
00520
00521 #ifdef USE_DST_BLACKLIST_STATS
00522 int init_dst_blacklist_stats(int iproc_num)
00523 {
00524
00525 if (dst_blacklist_init==0) return 0;
00526
00527
00528 if (dst_blacklist_stats)
00529 shm_free(dst_blacklist_stats);
00530
00531 dst_blacklist_stats=shm_malloc(sizeof(*dst_blacklist_stats) * iproc_num);
00532 if (dst_blacklist_stats==0){
00533 return E_OUT_OF_MEM;
00534 }
00535 memset(dst_blacklist_stats, 0, sizeof(*dst_blacklist_stats) * iproc_num);
00536
00537 return 0;
00538 }
00539 #endif
00540
00541
00542
00543 #define dst_blacklist_lst_add(head, e)\
00544 do{ \
00545 (e)->next=*(head); \
00546 *(head)=(e); \
00547 }while(0)
00548
00549
00550
00551
00552
00553
00554
00555 inline static struct dst_blst_entry* _dst_blacklist_lst_find(
00556 unsigned short hash,
00557 struct ip_addr* ip,
00558 unsigned char proto,
00559 unsigned short port,
00560 ticks_t now)
00561 {
00562 struct dst_blst_entry** crt;
00563 struct dst_blst_entry** tmp;
00564 struct dst_blst_entry* e;
00565 struct dst_blst_entry** head;
00566 unsigned char type;
00567
00568 head=&dst_blst_hash[hash].first;
00569 #ifdef USE_IPV6
00570 type=(ip->af==AF_INET6)*BLST_IS_IPV6;
00571 #else
00572 if (unlikely(ip->af!=AF_INET)) return 0;
00573 type=0;
00574 #endif
00575 for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
00576 e=*crt;
00577 prefetch_loc_r((*crt)->next, 1);
00578
00579 if ((s_ticks_t)(now-(*crt)->expire)>=0){
00580 *crt=(*crt)->next;
00581 tmp=crt;
00582 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
00583 BLST_HASH_STATS_DEC(hash);
00584 blst_destroy_entry(e);
00585 }else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
00586 ((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
00587 (e->proto==proto)) &&
00588 (memcmp(ip->u.addr, e->ip, ip->len)==0)){
00589 return e;
00590 }
00591 }
00592 return 0;
00593 }
00594
00595
00596
00597
00598
00599
00600
00601 inline static int _dst_blacklist_del(
00602 unsigned short hash,
00603 struct ip_addr* ip,
00604 unsigned char proto,
00605 unsigned short port,
00606 ticks_t now)
00607 {
00608 struct dst_blst_entry** crt;
00609 struct dst_blst_entry** tmp;
00610 struct dst_blst_entry* e;
00611 struct dst_blst_entry** head;
00612 unsigned char type;
00613
00614 head=&dst_blst_hash[hash].first;
00615 #ifdef USE_IPV6
00616 type=(ip->af==AF_INET6)*BLST_IS_IPV6;
00617 #else
00618 if (unlikely(ip->af!=AF_INET)) return 0;
00619 type=0;
00620 #endif
00621 for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){
00622 e=*crt;
00623 prefetch_loc_r((*crt)->next, 1);
00624
00625 if ((s_ticks_t)(now-(*crt)->expire)>=0){
00626 *crt=(*crt)->next;
00627 tmp=crt;
00628 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
00629 BLST_HASH_STATS_DEC(hash);
00630 blst_destroy_entry(e);
00631 }else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) &&
00632 ((e->proto==PROTO_NONE) || (proto==PROTO_NONE) ||
00633 (e->proto==proto)) &&
00634 (memcmp(ip->u.addr, e->ip, ip->len)==0)){
00635 *crt=(*crt)->next;
00636 tmp=crt;
00637 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
00638 BLST_HASH_STATS_DEC(hash);
00639 blst_destroy_entry(e);
00640 return 1;
00641 }
00642 }
00643 return 0;
00644 }
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660 inline static int dst_blacklist_clean_expired(unsigned int target,
00661 ticks_t delta,
00662 ticks_t timeout)
00663 {
00664 static unsigned int start=0;
00665 unsigned int h;
00666 struct dst_blst_entry** crt;
00667 struct dst_blst_entry** tmp;
00668 struct dst_blst_entry* e;
00669 ticks_t start_time;
00670 ticks_t now;
00671 int no=0;
00672 int i;
00673
00674 now=start_time=get_ticks_raw();
00675 for(h=start; h!=(start+DST_BLST_HASH_SIZE); h++){
00676 i=h%DST_BLST_HASH_SIZE;
00677 if (dst_blst_hash[i].first){
00678 LOCK_BLST(i);
00679 for (crt=&dst_blst_hash[i].first, tmp=&(*crt)->next;
00680 *crt; crt=tmp, tmp=&(*crt)->next){
00681 e=*crt;
00682 prefetch_loc_r((*crt)->next, 1);
00683 if ((s_ticks_t)(now+delta-(*crt)->expire)>=0){
00684 *crt=(*crt)->next;
00685 tmp=crt;
00686 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
00687 blst_destroy_entry(e);
00688 BLST_HASH_STATS_DEC(i);
00689 no++;
00690 if (*blst_mem_used<=target){
00691 UNLOCK_BLST(i);
00692 goto skip;
00693 }
00694 }
00695 }
00696 UNLOCK_BLST(i);
00697
00698 now=get_ticks_raw();
00699 if ((now-start_time)>=timeout){
00700 DBG("_dst_blacklist_clean_expired_unsafe: timeout: %d > %d\n",
00701 TICKS_TO_MS(now-start_time), TICKS_TO_MS(timeout));
00702 goto skip;
00703 }
00704 }
00705 }
00706 skip:
00707 start=h;
00708 if (no){
00709 DBG("dst_blacklist_clean_expired, %d entries removed\n", no);
00710 }
00711 return no;
00712 }
00713
00714
00715
00716
00717 static ticks_t blst_timer(ticks_t ticks, struct timer_ln* tl, void* data)
00718 {
00719 dst_blacklist_clean_expired(0, 0, 2);
00720 return (ticks_t)(-1);
00721 }
00722
00723
00724
00725
00726
00727
00728
00729 inline static int dst_blacklist_add_ip(unsigned char err_flags,
00730 unsigned char proto,
00731 struct ip_addr* ip, unsigned short port,
00732 ticks_t timeout)
00733 {
00734 int size;
00735 struct dst_blst_entry* e;
00736 unsigned short hash;
00737 ticks_t now;
00738 int ret;
00739
00740 ret=0;
00741 if (ip->af==AF_INET){
00742 err_flags&=~BLST_IS_IPV6;
00743 size=sizeof(struct dst_blst_entry);
00744 }else{
00745 err_flags|=BLST_IS_IPV6;
00746 size=sizeof(struct dst_blst_entry)+12 ;
00747 }
00748 now=get_ticks_raw();
00749 hash=dst_blst_hash_no(proto, ip, port);
00750
00751 LOCK_BLST(hash);
00752 e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
00753 if (e){
00754 e->flags|=err_flags;
00755 e->expire=now+timeout;
00756 }else{
00757 if (unlikely((*blst_mem_used+size) >=
00758 cfg_get(core, core_cfg, blst_max_mem))){
00759 #ifdef USE_DST_BLACKLIST_STATS
00760 dst_blacklist_stats[process_no].bkl_lru_cnt++;
00761 #endif
00762 UNLOCK_BLST(hash);
00763
00764
00765 dst_blacklist_clean_expired(*blst_mem_used/16*14, 0,
00766 MS_TO_TICKS(250));
00767 if (unlikely(*blst_mem_used+size >=
00768 cfg_get(core, core_cfg, blst_max_mem))){
00769 ret=-1;
00770 goto error;
00771 }
00772 LOCK_BLST(hash);
00773 }
00774 e=shm_malloc(size);
00775 if (e==0){
00776 UNLOCK_BLST(hash);
00777 ret=E_OUT_OF_MEM;
00778 goto error;
00779 }
00780 *blst_mem_used+=size;
00781 e->flags=err_flags;
00782 e->proto=proto;
00783 e->port=port;
00784 memcpy(e->ip, ip->u.addr, ip->len);
00785 e->expire=now+timeout;
00786 e->next=0;
00787 dst_blacklist_lst_add(&dst_blst_hash[hash].first, e);
00788 BLST_HASH_STATS_INC(hash);
00789 }
00790 UNLOCK_BLST(hash);
00791 error:
00792 return ret;
00793 }
00794
00795
00796
00797
00798 inline static int dst_is_blacklisted_ip(unsigned char proto,
00799 struct ip_addr* ip,
00800 unsigned short port)
00801 {
00802 struct dst_blst_entry* e;
00803 unsigned short hash;
00804 ticks_t now;
00805 int ret;
00806
00807 ret=0;
00808 now=get_ticks_raw();
00809 hash=dst_blst_hash_no(proto, ip, port);
00810 if (unlikely(dst_blst_hash[hash].first)){
00811 LOCK_BLST(hash);
00812 e=_dst_blacklist_lst_find(hash, ip, proto, port, now);
00813 if (e){
00814 ret=e->flags;
00815 }
00816 UNLOCK_BLST(hash);
00817 }
00818 return ret;
00819 }
00820
00821
00822
00831 int dst_blacklist_force_add_to(unsigned char err_flags, struct dest_info* si,
00832 struct sip_msg* msg, ticks_t timeout)
00833 {
00834 struct ip_addr ip;
00835
00836 #ifdef DST_BLACKLIST_HOOKS
00837 if (unlikely (blacklist_run_hooks(&blst_add_cb, si, &err_flags, msg) ==
00838 DST_BLACKLIST_DENY))
00839 return 0;
00840 #endif
00841 su2ip_addr(&ip, &si->to);
00842 return dst_blacklist_add_ip(err_flags, si->proto, &ip,
00843 su_getport(&si->to), timeout);
00844 }
00845
00846
00847
00852 int dst_blacklist_force_su_to(unsigned char err_flags, unsigned char proto,
00853 union sockaddr_union* dst,
00854 struct sip_msg* msg, ticks_t timeout)
00855 {
00856 struct ip_addr ip;
00857 #ifdef DST_BLACKLIST_HOOKS
00858 struct dest_info si;
00859
00860 init_dest_info(&si);
00861 si.to=*dst;
00862 si.proto=proto;
00863 if (unlikely (blacklist_run_hooks(&blst_add_cb, &si, &err_flags, msg) ==
00864 DST_BLACKLIST_DENY))
00865 return 0;
00866 #endif
00867 su2ip_addr(&ip, dst);
00868 return dst_blacklist_add_ip(err_flags, proto, &ip,
00869 su_getport(dst), timeout);
00870 }
00871
00872
00873
00874 int dst_is_blacklisted(struct dest_info* si, struct sip_msg* msg)
00875 {
00876 int ires;
00877 struct ip_addr ip;
00878 #ifdef DST_BLACKLIST_HOOKS
00879 unsigned char err_flags;
00880 int action;
00881 #endif
00882 su2ip_addr(&ip, &si->to);
00883
00884 #ifdef DST_BLACKLIST_HOOKS
00885 err_flags=0;
00886 if (unlikely((action=(blacklist_run_hooks(&blst_search_cb, si, &err_flags, msg))
00887 ) != DST_BLACKLIST_CONTINUE)){
00888 if (action==DST_BLACKLIST_DENY)
00889 return 0;
00890 else
00891 return err_flags;
00892 }
00893 #endif
00894 ires=dst_is_blacklisted_ip(si->proto, &ip, su_getport(&si->to));
00895 #ifdef USE_DST_BLACKLIST_STATS
00896 if (ires)
00897 dst_blacklist_stats[process_no].bkl_hit_cnt++;
00898 #endif
00899 return ires;
00900 }
00901
00902
00903
00904
00905 int dst_blacklist_del(struct dest_info* si, struct sip_msg* msg)
00906 {
00907 unsigned short hash;
00908 struct ip_addr ip;
00909 ticks_t now;
00910 int ret;
00911 unsigned short port;
00912
00913 ret=0;
00914 su2ip_addr(&ip, &si->to);
00915 port=su_getport(&si->to);
00916 now=get_ticks_raw();
00917 hash=dst_blst_hash_no(si->proto, &ip, port);
00918 if (unlikely(dst_blst_hash[hash].first)){
00919 LOCK_BLST(hash);
00920 ret=_dst_blacklist_del(hash, &ip, si->proto, port, now);
00921 UNLOCK_BLST(hash);
00922 }
00923 return ret;
00924 }
00925
00926
00927
00928
00929 void dst_blst_mem_info(rpc_t* rpc, void* ctx)
00930 {
00931 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
00932 rpc->fault(ctx, 500, "dst blacklist support disabled");
00933 return;
00934 }
00935 rpc->add(ctx, "dd", *blst_mem_used, cfg_get(core, core_cfg, blst_max_mem));
00936 }
00937
00938
00939
00940
00941 #ifdef USE_DST_BLACKLIST_STATS
00942
00943 static unsigned long stat_sum(int ivar, int breset) {
00944 unsigned long isum=0;
00945 int i1=0;
00946
00947 for (; i1 < get_max_procs(); i1++)
00948 switch (ivar) {
00949 case 0:
00950 isum+=dst_blacklist_stats[i1].bkl_hit_cnt;
00951 if (breset)
00952 dst_blacklist_stats[i1].bkl_hit_cnt=0;
00953 break;
00954 case 1:
00955 isum+=dst_blacklist_stats[i1].bkl_lru_cnt;
00956 if (breset)
00957 dst_blacklist_stats[i1].bkl_lru_cnt=0;
00958 break;
00959 }
00960
00961 return isum;
00962 }
00963
00964
00965 void dst_blst_stats_get(rpc_t* rpc, void* c)
00966 {
00967 char *name=NULL;
00968 void *handle;
00969 int found=0,i=0;
00970 int reset=0;
00971 char* dst_blacklist_stats_names[] = {
00972 "bkl_hit_cnt",
00973 "bkl_lru_cnt",
00974 NULL
00975 };
00976
00977 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
00978 rpc->fault(c, 500, "dst blacklist support disabled");
00979 return;
00980 }
00981 if (rpc->scan(c, "s", &name) < 0)
00982 return;
00983 if (rpc->scan(c, "d", &reset) < 0)
00984 return;
00985 if (!strcasecmp(name, DST_BLACKLIST_ALL_STATS)) {
00986
00987 rpc->add(c, "{", &handle);
00988 for (i=0; dst_blacklist_stats_names[i]; i++)
00989 rpc->struct_add(handle, "d",
00990 dst_blacklist_stats_names[i],
00991 stat_sum(i, reset));
00992
00993 found=1;
00994 } else {
00995 for (i=0; dst_blacklist_stats_names[i]; i++)
00996 if (!strcasecmp(dst_blacklist_stats_names[i], name)) {
00997 rpc->add(c, "{", &handle);
00998 rpc->struct_add(handle, "d",
00999 dst_blacklist_stats_names[i],
01000 stat_sum(i, reset));
01001 found=1;
01002 break;
01003 }
01004 }
01005 if(!found)
01006 rpc->fault(c, 500, "unknown dst blacklist stat parameter");
01007
01008 return;
01009 }
01010 #endif
01011
01012
01013 void dst_blst_debug(rpc_t* rpc, void* ctx)
01014 {
01015 int h;
01016 struct dst_blst_entry* e;
01017 ticks_t now;
01018 struct ip_addr ip;
01019
01020 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
01021 rpc->fault(ctx, 500, "dst blacklist support disabled");
01022 return;
01023 }
01024 now=get_ticks_raw();
01025 for(h=0; h<DST_BLST_HASH_SIZE; h++){
01026 LOCK_BLST(h);
01027 for(e=dst_blst_hash[h].first; e; e=e->next){
01028 dst_blst_entry2ip(&ip, e);
01029 rpc->add(ctx, "ssddd", get_proto_name(e->proto),
01030 ip_addr2a(&ip), e->port,
01031 (s_ticks_t)(now-e->expire)<=0?
01032 TICKS_TO_S(e->expire-now):
01033 -TICKS_TO_S(now-e->expire) ,
01034 e->flags);
01035 }
01036 UNLOCK_BLST(h);
01037 }
01038 }
01039
01040
01041 void dst_blst_hash_stats(rpc_t* rpc, void* ctx)
01042 {
01043 int h;
01044 struct dst_blst_entry* e;
01045 #ifdef BLST_HASH_STATS
01046 int n;
01047
01048 n=0;
01049 #endif
01050 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
01051 rpc->fault(ctx, 500, "dst blacklist support disabled");
01052 return;
01053 }
01054 for(h=0; h<DST_BLST_HASH_SIZE; h++){
01055 #ifdef BLST_HASH_STATS
01056 LOCK_BLST(h);
01057 for(e=dst_blst_hash[h].first; e; e=e->next) n++;
01058 UNLOCK_BLST(h);
01059 rpc->add(ctx, "dd", h, n);
01060 #else
01061 rpc->add(ctx, "dd", h, dst_blst_hash[h].entries);
01062 #endif
01063 }
01064 }
01065
01066
01067 void dst_blst_view(rpc_t* rpc, void* ctx)
01068 {
01069 int h;
01070 int expires;
01071 struct dst_blst_entry* e;
01072 ticks_t now;
01073 struct ip_addr ip;
01074
01075 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
01076 rpc->fault(ctx, 500, "dst blacklist support disabled");
01077 return;
01078 }
01079 now=get_ticks_raw();
01080 for(h=0; h<DST_BLST_HASH_SIZE; h++) {
01081 LOCK_BLST(h);
01082 for(e=dst_blst_hash[h].first; e; e=e->next) {
01083 expires = (s_ticks_t)(now-e->expire)<=0?
01084 TICKS_TO_S(e->expire-now): -TICKS_TO_S(now-e->expire);
01085
01086 if (expires < 0) {
01087 continue;
01088 }
01089 dst_blst_entry2ip(&ip, e);
01090 rpc->printf(ctx, "{\n protocol: %s", get_proto_name(e->proto));
01091 rpc->printf(ctx, " ip: %s", ip_addr2a(&ip));
01092 rpc->printf(ctx, " port: %d", e->port);
01093 rpc->printf(ctx, " expires in (s): %d", expires);
01094 rpc->printf(ctx, " flags: %d\n}", e->flags);
01095 }
01096 UNLOCK_BLST(h);
01097 }
01098 }
01099
01100
01101
01102
01103
01104 void dst_blst_flush(void)
01105 {
01106 int h;
01107 struct dst_blst_entry* e;
01108 struct dst_blst_entry** crt;
01109 struct dst_blst_entry** tmp;
01110
01111 for(h=0; h<DST_BLST_HASH_SIZE; h++){
01112 LOCK_BLST(h);
01113 for (crt=&dst_blst_hash[h].first, tmp=&(*crt)->next;
01114 *crt; crt=tmp, tmp=&(*crt)->next){
01115 e=*crt;
01116 prefetch_loc_r((*crt)->next, 1);
01117 if (!(e->flags & BLST_PERMANENT)){
01118 *crt=(*crt)->next;
01119 tmp=crt;
01120 *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e);
01121 blst_destroy_entry(e);
01122 BLST_HASH_STATS_DEC(h);
01123 }
01124 }
01125 UNLOCK_BLST(h);
01126 }
01127 }
01128
01129
01130 void dst_blst_delete_all(rpc_t* rpc, void* ctx)
01131 {
01132 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
01133 rpc->fault(ctx, 500, "dst blacklist support disabled");
01134 return;
01135 }
01136 dst_blst_flush();
01137 }
01138
01139
01140 void dst_blst_add(rpc_t* rpc, void* ctx)
01141 {
01142 str ip;
01143 int port, proto, flags;
01144 unsigned char err_flags;
01145 struct ip_addr *ip_addr;
01146
01147 if (!cfg_get(core, core_cfg, use_dst_blacklist)){
01148 rpc->fault(ctx, 500, "dst blacklist support disabled");
01149 return;
01150 }
01151 if (rpc->scan(ctx, "Sddd", &ip, &port, &proto, &flags) < 4)
01152 return;
01153
01154 err_flags = (unsigned char)flags;
01155
01156 if ((unsigned char)proto > PROTO_SCTP) {
01157 rpc->fault(ctx, 400, "Unknown protocol");
01158 return;
01159 }
01160
01161 if (err_flags & BLST_IS_IPV6) {
01162 #ifdef USE_IPV6
01163
01164 ip_addr = str2ip6(&ip);
01165 #else
01166 rpc->fault(ctx, 400, "IPv6 support disabled");
01167 return;
01168 #endif
01169 } else {
01170
01171 ip_addr = str2ip(&ip);
01172 if (!ip_addr) {
01173 #ifdef USE_IPV6
01174 ip_addr = str2ip6(&ip);
01175 err_flags |= BLST_IS_IPV6;
01176 #else
01177 rpc->fault(ctx, 400, "Malformed or IPv6 ip address");
01178 return;
01179 #endif
01180 }
01181 }
01182 if (!ip_addr) {
01183 rpc->fault(ctx, 400, "Malformed ip address");
01184 return;
01185 }
01186
01187 if (dst_blacklist_add_ip(err_flags, proto, ip_addr, port,
01188 S_TO_TICKS(cfg_get(core, core_cfg, blst_timeout))))
01189 rpc->fault(ctx, 400, "Failed to add the entry to the blacklist");
01190 }
01191
01192
01193
01194
01195 int use_dst_blacklist_fixup(void *handle, str *gname, str *name, void **val)
01196 {
01197 if ((int)(long)(*val) && !dst_blacklist_init) {
01198 LOG(L_ERR, "ERROR: use_dst_blacklist_fixup(): "
01199 "dst blacklist is turned off by dst_blacklist_init=0, "
01200 "it cannot be enabled runtime.\n");
01201 return -1;
01202 }
01203 return 0;
01204 }
01205
01206
01207 int blst_max_mem_fixup(void *handle, str *gname, str *name, void **val)
01208 {
01209 unsigned int u;
01210
01211 u = ((unsigned int)(long)(*val))<<10;
01212 (*val) = (void *)(long)u;
01213 return 0;
01214 }
01215
01216
01217
01219 void blst_reinit_ign_masks(str* gname, str* name)
01220 {
01221 blst_init_ign_masks();
01222 }
01223
01224
01225 #endif
01226