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 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <fnmatch.h>
00033 #include <time.h>
00034 #include <unistd.h>
00035
00036 #include "mem/mem.h"
00037 #include "mem/shm_mem.h"
00038 #include "mi/mi.h"
00039 #include "dprint.h"
00040 #include "blacklists.h"
00041 #include "timer.h"
00042 #include "ut.h"
00043
00044 static struct bl_head *blst_heads = 0;
00045 static unsigned int bl_marker = 0;
00046 static unsigned int bl_default_marker = 0;
00047
00048 static unsigned int max_heads = 8*sizeof(bl_marker);
00049 static unsigned int used_heads = 0;
00050 static unsigned int no_shm = 1;
00051
00052
00053 static void delete_expired_routine(unsigned int ticks, void* param);
00054 static struct mi_root* mi_print_blacklists(struct mi_root *cmd, void *param);
00055
00056
00057 static mi_export_t mi_bl_cmds[] = {
00058 { "list_blacklists", mi_print_blacklists, MI_NO_INPUT_FLAG , 0, 0 },
00059 { 0, 0, 0, 0, 0}
00060 };
00061
00062
00063
00064 int preinit_black_lists(void)
00065 {
00066 blst_heads = (struct bl_head*)pkg_malloc(max_heads*sizeof(struct bl_head));
00067 if (blst_heads==NULL) {
00068 LM_ERR("no more pkg memory!\n");
00069 return -1;
00070 }
00071 memset( blst_heads, 0, max_heads*sizeof(struct bl_head));
00072
00073 used_heads = 0;
00074
00075
00076 return 0;
00077 }
00078
00079
00080
00081 int init_black_lists(void)
00082 {
00083 struct bl_head *old_blst_heads;
00084 struct bl_rule *head;
00085 struct bl_rule *tail;
00086 struct bl_rule *it, *it1;
00087 unsigned int old_used_heads;
00088 unsigned int i;
00089
00090 if (!no_shm) {
00091 LM_CRIT("called twice\n");
00092 return -1;
00093 }
00094 no_shm = 0;
00095
00096 old_blst_heads = blst_heads;
00097 blst_heads = (struct bl_head*)shm_malloc(max_heads*sizeof(struct bl_head));
00098 if (blst_heads==NULL) {
00099 LM_ERR("no more shm memory!\n");
00100 return -1;
00101 }
00102 memset( blst_heads, 0, max_heads * sizeof(struct bl_head));
00103 old_used_heads = used_heads;
00104
00105 used_heads = 0;
00106 bl_default_marker = 0;
00107
00108
00109 for( i=0 ; i<old_used_heads ; i++ ) {
00110
00111
00112 it = old_blst_heads[i].first;
00113 head = tail = 0;
00114
00115 for( it1=it ; it ; it=it1 ) {
00116 if (add_rule_to_list( &head, &tail, &it->ip_net,
00117 &it->body, it->port, it->proto, it->flags)!=0) {
00118 LM_ERR("failed to clone rule!\n");
00119 return -1;
00120 }
00121
00122 it1 = it->next;
00123 pkg_free(it);
00124 }
00125
00126 if (create_bl_head( old_blst_heads[i].owner, old_blst_heads[i].flags,
00127 head, tail, &old_blst_heads[i].name )==NULL ) {
00128 LM_ERR("failed to clone head!\n");
00129 return -1;
00130 }
00131
00132 pkg_free(old_blst_heads[i].name.s);
00133 }
00134
00135 pkg_free(old_blst_heads);
00136
00137
00138 if (register_timer( delete_expired_routine, 0, 1)<0) {
00139 LM_ERR("failed to register timer\n");
00140 return -1;
00141 }
00142
00143
00144 if (register_mi_mod( "blacklists", mi_bl_cmds)<0) {
00145 LM_ERR("unable to register MI cmds\n");
00146 return -1;
00147 }
00148
00149 return 0;
00150 }
00151
00152
00153
00154 struct bl_head *create_bl_head(int owner, int flags, struct bl_rule *head,
00155 struct bl_rule *tail, str *name)
00156 {
00157 unsigned int i;
00158
00159 i = used_heads;
00160 if (i==max_heads) {
00161 LM_ERR("too many lists\n");
00162 return NULL;
00163 }
00164
00165 if (get_bl_head_by_name(name)!=NULL) {
00166 LM_CRIT("duplicated name!\n");
00167 return NULL;
00168 }
00169
00170 if ( flags&BL_READONLY_LIST && flags&BL_DO_EXPIRE){
00171 LM_CRIT("RO lists cannot accept EXPIRES!\n");
00172 return NULL;
00173 }
00174
00175
00176 if (no_shm)
00177 blst_heads[i].name.s = (char*)pkg_malloc(name->len + 1);
00178 else
00179 blst_heads[i].name.s = (char*)shm_malloc(name->len + 1);
00180 if (blst_heads[i].name.s==NULL) {
00181 LM_ERR("no more pkg memory!\n");
00182 return NULL;
00183 }
00184 memcpy( blst_heads[i].name.s, name->s, name->len);
00185 blst_heads[i].name.s[name->len] = '\0';
00186 blst_heads[i].name.len = name->len;
00187
00188
00189 if (!no_shm && !(flags&BL_READONLY_LIST)) {
00190 if ( (blst_heads[i].lock=lock_alloc())==NULL ) {
00191 LM_ERR("failed to create lock!\n");
00192 shm_free(blst_heads[i].name.s);
00193 return NULL;
00194 }
00195 if ( lock_init(blst_heads[i].lock)==NULL ) {
00196 LM_ERR("failed to init lock!\n");
00197 shm_free(blst_heads[i].name.s);
00198 lock_dealloc(blst_heads[i].lock);
00199 return NULL;
00200 }
00201 }
00202
00203 used_heads++;
00204
00205 blst_heads[i].owner = owner;
00206 blst_heads[i].flags = flags;
00207 blst_heads[i].first = head;
00208 blst_heads[i].last = tail;
00209
00210 if (flags&BL_BY_DEFAULT)
00211 bl_default_marker |= (1<<i);
00212
00213 return blst_heads + i;
00214 }
00215
00216
00217
00218 void destroy_black_lists(void)
00219 {
00220 unsigned int i;
00221 struct bl_rule *p, *q;
00222
00223 if (no_shm)
00224 return;
00225
00226 for(i = 0 ; i < used_heads ; i++){
00227
00228 if (blst_heads[i].lock) {
00229 lock_destroy(blst_heads[i].lock);
00230 lock_dealloc(blst_heads[i].lock);
00231 }
00232
00233 for( p=blst_heads[i].first ; p ; ) {
00234 q = p;
00235 p = p->next;
00236 shm_free(q);
00237 }
00238
00239 if (blst_heads[i].name.s)
00240 shm_free(blst_heads[i].name.s);
00241
00242 blst_heads[i].first = blst_heads[i].last = NULL;
00243 }
00244
00245 shm_free(blst_heads);
00246 }
00247
00248
00249
00250 static inline void delete_expired(struct bl_head *elem, unsigned int ticks)
00251 {
00252 struct bl_rule *p, *q;
00253
00254 p = q = 0;
00255
00256
00257 lock_get(elem->lock);
00258 while(elem->count_write){
00259 lock_release(elem->lock);
00260 sleep_us(5);
00261 lock_get(elem->lock);
00262 }
00263 elem->count_write = 1;
00264 while(elem->count_read){
00265 lock_release(elem->lock);
00266 sleep_us(5);
00267 lock_get(elem->lock);
00268 }
00269 lock_release(elem->lock);
00270
00271 if(elem->first==NULL)
00272 goto done;
00273
00274 for( q=0,p = elem->first ; p ; q=p,p=p->next) {
00275 if(p->expire_end > ticks)
00276 break;
00277 }
00278
00279 if (q==NULL)
00280
00281 goto done;
00282
00283 if (p==NULL) {
00284
00285 q = elem->first;
00286 elem->first = elem->last = NULL;
00287 } else {
00288
00289 q->next = 0;
00290 q = elem->first;
00291 elem->first = p;
00292 }
00293
00294 done:
00295 elem->count_write = 0;
00296
00297 for( ; q ; ){
00298 p = q;
00299 q = q->next;
00300 shm_free(p);
00301 }
00302
00303 return;
00304 }
00305
00306
00307
00308 static void delete_expired_routine(unsigned int ticks, void* param)
00309 {
00310 unsigned int i;
00311
00312 for(i = 0 ; i < used_heads ; i++){
00313 if( blst_heads[i].flags&BL_DO_EXPIRE && blst_heads[i].first)
00314 delete_expired(blst_heads + i, ticks);
00315 }
00316 }
00317
00318
00319
00320 static inline int ip_class_compare(struct net *net1, struct net *net2)
00321 {
00322 unsigned int r;
00323
00324 if (net1->ip.af == net2->ip.af){
00325 for(r=0; r<net1->ip.len/4; r++){
00326
00327 if ((net1->ip.u.addr32[r]&net1->mask.u.addr32[r])!=
00328 (net2->ip.u.addr32[r]&net2->mask.u.addr32[r]) ){
00329 return 0;
00330 }
00331 }
00332 return 1;
00333 };
00334 return -1;
00335 }
00336
00337
00338
00339 int add_rule_to_list(struct bl_rule **first, struct bl_rule **last,
00340 struct net *ip_net, str *body, unsigned short port,
00341 unsigned short proto, int flags)
00342 {
00343 struct bl_rule *p;
00344 struct bl_rule *q;
00345
00346 if (!first || !last || !ip_net){
00347 LM_ERR("wrong input parameter format\n");
00348 return -1;
00349 }
00350
00351 if (body && body->len==0)
00352 body = 0;
00353
00354
00355 for(q = *first ; q ; q = q->next) {
00356 if ( (flags==q->flags) && (port==q->port) &&
00357 (proto==q->proto) &&
00358 (ip_class_compare(ip_net, &q->ip_net)==1) &&
00359 ((body==NULL && q->body.s==NULL) || (body && q->body.s &&
00360 (body->len==q->body.len) &&
00361 !strncmp(body->s,q->body.s,body->len)) )
00362 ) {
00363 return 1;
00364 }
00365 }
00366
00367
00368
00369 if (no_shm)
00370 p = (struct bl_rule*)pkg_malloc
00371 (sizeof(struct bl_rule) + (body?(body->len + 1):0));
00372 else
00373 p = (struct bl_rule*)shm_malloc
00374 (sizeof(struct bl_rule) + (body?(body->len + 1):0));
00375 if(!p){
00376 LM_ERR("no more %s memory!\n", no_shm?"pkg":"shm");
00377 return -1;
00378 }
00379
00380
00381 p->flags = flags;
00382 p->ip_net = *ip_net;
00383 p->proto = proto;
00384 p->port = port;
00385 if (body) {
00386 p->body.s = (char *)p + sizeof(struct bl_rule);
00387 memcpy(p->body.s, body->s, body->len);
00388 (p->body.s)[body->len] = '\0';
00389 p->body.len = body->len;
00390 } else {
00391 p->body.s = NULL;
00392 p->body.len = 0;
00393 }
00394 p->next = NULL;
00395 p->expire_end = 0;
00396
00397
00398 if (!*first) {
00399 *first = *last = p;
00400 } else {
00401 (*last)->next = p;
00402 *last = p;
00403 }
00404
00405 return 0;
00406 }
00407
00408
00409
00410 static inline void rm_dups(struct bl_head *head,
00411 struct bl_rule **first, struct bl_rule **last)
00412 {
00413 struct bl_rule *p, *q;
00414 struct bl_rule *r;
00415
00416 for( p=0,q=*first ; q ; ) {
00417 for( r=head->first; r ; r = r->next) {
00418 if ( (r->flags==q->flags) && (r->port==q->port) &&
00419 (r->proto==q->proto) &&
00420 (ip_class_compare(&r->ip_net, &q->ip_net)==1) &&
00421 ((!r->body.s && !q->body.s) || ((r->body.len==q->body.len) &&
00422 !strncmp(r->body.s,q->body.s,q->body.len)) )
00423 ) {
00424 break;
00425 }
00426 }
00427 if (r) {
00428
00429 if (q->next==NULL) *last=p;
00430 if (p) {
00431 p->next = q->next;
00432 if (no_shm) pkg_free(q);
00433 else shm_free(q);
00434 q = p->next;
00435 } else {
00436 *first = q->next;
00437 if (no_shm) pkg_free(q);
00438 else shm_free(q);
00439 q = *first;
00440 }
00441 } else {
00442 p=q;
00443 q=q->next;
00444 }
00445 }
00446 }
00447
00448
00449
00450 static inline int reload_permanent_list(struct bl_rule *first,
00451 struct bl_rule *last,
00452 struct bl_head *head)
00453 {
00454 struct bl_rule *p, *q;
00455
00456
00457 lock_get( head->lock);
00458 while(head->count_write){
00459 lock_release( head->lock );
00460 sleep_us(5);
00461 lock_get( head->lock );
00462 }
00463 head->count_write = 1;
00464 while(head->count_read){
00465 lock_release( head->lock );
00466 sleep_us(5);
00467 lock_get( head->lock );
00468 }
00469 lock_release( head->lock );
00470
00471 for(p = head->first ; p ; p = p->next){
00472 q = p;
00473 p = p->next;
00474 shm_free(q);
00475 }
00476
00477 head->first = first;
00478 head->last = last;
00479
00480 head->count_write = 0;
00481
00482 return 0;
00483 }
00484
00485
00486
00487
00488 int add_list_to_head( struct bl_head *head,
00489 struct bl_rule *first, struct bl_rule *last,
00490 int truncate, int expire_limit)
00491 {
00492 struct bl_rule *p;
00493 unsigned int expire_end=0;
00494
00495 if (!head || !first || !last)
00496 return -1;
00497
00498
00499 if (head->flags&BL_READONLY_LIST) {
00500 LM_CRIT("list is readonly!!!\n");
00501 return -1;
00502 }
00503
00504 LM_DBG("adding to bl %.*s %p,%p\n",
00505 head->name.len, head->name.s, first,last);
00506
00507
00508 if (head->flags&BL_DO_EXPIRE) {
00509 if (expire_limit==0) {
00510 LM_CRIT("expire is zero!!!\n");
00511 return -1;
00512 }
00513 expire_end = get_ticks() + expire_limit;
00514
00515 for(p = first ; p ; p = p->next)
00516 p->expire_end = expire_end;
00517 }
00518
00519
00520 if (truncate)
00521 return reload_permanent_list( first, last, head);
00522
00523
00524 lock_get(head->lock);
00525 while(head->count_write){
00526 lock_release( head->lock );
00527 sleep_us(5);
00528 lock_get( head->lock );
00529 }
00530 head->count_write = 1;
00531 while(head->count_read){
00532 lock_release( head->lock );
00533 sleep_us(5);
00534 lock_get( head->lock );
00535 }
00536 lock_release( head->lock );
00537
00538 rm_dups( head, &first, &last);
00539 if (first==NULL)
00540 goto done;
00541
00542 if (head->first==NULL) {
00543 head->last = last;
00544 head->first = first;
00545 } else
00546 if (!head->flags&BL_DO_EXPIRE) {
00547 head->last->next = first;
00548 head->last = last;
00549 } else
00550 if( head->first->expire_end >= expire_end){
00551 last->next = head->first;
00552 head->first = first;
00553 } else
00554 if(head->last->expire_end <= expire_end){
00555 head->last->next = first;
00556 head->last = last;
00557 } else {
00558 for(p = head->first ; ; p = p->next)
00559 if( p->next->expire_end >= expire_end)
00560 break;
00561 last->next = p->next;
00562 p->next = first;
00563 }
00564
00565 done:
00566 head->count_write = 0;
00567
00568 return 0;
00569 }
00570
00571
00572
00573 struct bl_head *get_bl_head_by_name(str *name)
00574 {
00575 unsigned int i;
00576
00577 for(i = 0 ; i < used_heads ; i++){
00578 if ((name->len == blst_heads[i].name.len) &&
00579 !strncmp(name->s, blst_heads[i].name.s, name->len))
00580 return (blst_heads + i);
00581 }
00582
00583 return NULL;
00584 }
00585
00586
00587
00588 int mark_for_search(struct bl_head *list, int unsigned set)
00589 {
00590 unsigned int n;
00591
00592
00593 if (list==0) {
00594 bl_marker = set ? (unsigned int)-1 : 0 ;
00595 return 1;
00596 }
00597
00598 if( list<blst_heads || (n=(list - blst_heads)) >= used_heads )
00599 return 0;
00600
00601 if (set)
00602 bl_marker |= (1<<n);
00603 else
00604 bl_marker &= ~(1<<n);
00605
00606 return 1;
00607 }
00608
00609
00610
00611 void reset_bl_markers(void)
00612 {
00613 bl_marker = bl_default_marker;
00614 }
00615
00616
00617
00618 static inline int check_against_rule_list(struct ip_addr *ip, str *text,
00619 unsigned short port,
00620 unsigned short proto,
00621 int i)
00622 {
00623 struct bl_rule *p;
00624 int t_val;
00625 int ret = 0;
00626
00627 LM_DBG("using list %.*s \n",
00628 blst_heads[i].name.len, blst_heads[i].name.s);
00629
00630 if( !blst_heads[i].flags&BL_READONLY_LIST ) {
00631
00632 lock_get( blst_heads[i].lock );
00633 while(blst_heads[i].count_write) {
00634 lock_release( blst_heads[i].lock );
00635 sleep_us(5);
00636 lock_get( blst_heads[i].lock );
00637 }
00638 blst_heads[i].count_read++;
00639 lock_release(blst_heads[i].lock);
00640 }
00641
00642 for(p = blst_heads[i].first ; p ; p = p->next) {
00643 t_val = (p->port==0 || p->port==port) &&
00644 (p->proto==PROTO_NONE || p->proto==proto) &&
00645 (matchnet(ip, &(p->ip_net)) == 1) &&
00646 (p->body.s==NULL || !fnmatch(p->body.s, text->s, 0));
00647 if(!!(p->flags & BLR_APPLY_CONTRARY) ^ !!(t_val)){
00648 ret = 1;
00649 LM_DBG("matched list %.*s \n",
00650 blst_heads[i].name.len,blst_heads[i].name.s);
00651 break;
00652 }
00653 }
00654
00655 if( !blst_heads[i].flags&BL_READONLY_LIST ) {
00656 lock_get( blst_heads[i].lock );
00657 blst_heads[i].count_read--;
00658 lock_release(blst_heads[i].lock);
00659 }
00660 return ret;
00661 }
00662
00663
00664
00665 int check_against_blacklist(struct ip_addr *ip, str *text,
00666 unsigned short port, unsigned short proto)
00667 {
00668 unsigned int i;
00669
00670 for(i = 0 ; i < used_heads ; i++)
00671 if( (bl_marker&(1<<i)) &&
00672 check_against_rule_list(ip, text, port, proto, i))
00673 return 1;
00674 return 0;
00675 }
00676
00677
00678
00679 static struct mi_root* mi_print_blacklists(struct mi_root *cmd, void *param)
00680 {
00681 struct mi_root *rpl_tree;
00682 struct mi_node *rpl;
00683 struct mi_node *node;
00684 struct mi_node *node1;
00685 struct mi_node *node2;
00686 struct mi_attr *attr;
00687 unsigned int i;
00688 struct bl_rule *blr;
00689 char *p;
00690 int len;
00691
00692 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00693 if (rpl_tree==NULL)
00694 return 0;
00695 rpl = &rpl_tree->node;
00696
00697 for ( i=0 ; i<used_heads ; i++ ) {
00698
00699 if( !blst_heads[i].flags&BL_READONLY_LIST ) {
00700
00701 lock_get( blst_heads[i].lock );
00702 while(blst_heads[i].count_write) {
00703 lock_release( blst_heads[i].lock );
00704 sleep_us(5);
00705 lock_get( blst_heads[i].lock );
00706 }
00707 blst_heads[i].count_read++;
00708 lock_release(blst_heads[i].lock);
00709 }
00710
00711
00712 node = add_mi_node_child( rpl, 0, "List", 4,
00713 blst_heads[i].name.s, blst_heads[i].name.len );
00714 if (node==0)
00715 goto error;
00716
00717
00718 p= int2str((unsigned long)blst_heads[i].owner, &len);
00719 attr = add_mi_attr( node, MI_DUP_VALUE, "owner", 5, p, len);
00720 if (attr==0)
00721 goto error;
00722 p= int2str((unsigned long)blst_heads[i].flags, &len);
00723 attr = add_mi_attr( node, MI_DUP_VALUE, "flags", 5, p, len);
00724 if (attr==0)
00725 goto error;
00726
00727 for( blr = blst_heads[i].first ; blr ; blr = blr->next) {
00728
00729 node1 = add_mi_node_child( node, 0, "Rule", 4, 0, 0 );
00730 if (node1==0)
00731 goto error;
00732
00733 p= int2str((unsigned long)blr->flags, &len);
00734 attr = add_mi_attr( node1, MI_DUP_VALUE, "flags", 5, p, len);
00735 if (attr==0)
00736 goto error;
00737
00738
00739 p = ip_addr2a(&blr->ip_net.ip);
00740 len = p?strlen(p):0;
00741 node2 = add_mi_node_child( node1, MI_DUP_VALUE, "IP", 2, p, len);
00742 if (node2==0)
00743 goto error;
00744
00745 p = ip_addr2a(&blr->ip_net.mask);
00746 len = p?strlen(p):0;
00747 node2 = add_mi_node_child( node1, MI_DUP_VALUE, "Mask", 4, p, len);
00748 if (node2==0)
00749 goto error;
00750
00751 p= int2str((unsigned long)blr->proto, &len);
00752 node2 = add_mi_node_child( node1, MI_DUP_VALUE, "Proto", 5, p,len);
00753 if (node2==0)
00754 goto error;
00755
00756 p= int2str((unsigned long)blr->port, &len);
00757 node2 = add_mi_node_child( node1, MI_DUP_VALUE, "Port", 4, p,len);
00758 if (node2==0)
00759 goto error;
00760
00761 if (blr->body.s) {
00762 node2 = add_mi_node_child( node1, MI_DUP_VALUE, "Match", 5,
00763 blr->body.s, blr->body.len);
00764 if (node2==0)
00765 goto error;
00766 }
00767
00768 if (blst_heads[i].flags&BL_DO_EXPIRE) {
00769 p= int2str((unsigned long)blr->expire_end, &len);
00770 node2 = add_mi_node_child( node1, MI_DUP_VALUE, "Expire", 6,
00771 p, len);
00772 if (node2==0)
00773 goto error;
00774 }
00775
00776 }
00777
00778 if( !blst_heads[i].flags&BL_READONLY_LIST ) {
00779 lock_get( blst_heads[i].lock );
00780 blst_heads[i].count_read--;
00781 lock_release(blst_heads[i].lock);
00782 }
00783
00784 }
00785
00786 return rpl_tree;
00787 error:
00788 if( !blst_heads[i].flags&BL_READONLY_LIST ) {
00789 lock_get( blst_heads[i].lock );
00790 blst_heads[i].count_read--;
00791 lock_release(blst_heads[i].lock);
00792 }
00793 free_mi_tree(rpl_tree);
00794 return 0;
00795 }
00796
00797