/* frees all the expired entries until either there are no more of them * or the total memory used is <= target (to free all of them use -1 for * targer) * params: target - free expired entries until no more then taget memory * is used (use 0 to free all of them) * delta - consider an entry expired if it expires after delta * ticks from now * timeout - exit after timeout ticks * * returns: number of deleted entries * This function should be called periodically from a timer */ inline static int dst_blacklist_clean_expired(unsigned int target, ticks_t delta, ticks_t timeout) { static unsigned int start=0; unsigned int h; struct dst_blst_entry** crt; struct dst_blst_entry** tmp; struct dst_blst_entry* e; ticks_t start_time; ticks_t now; int no=0; int i; now=start_time=get_ticks_raw(); for(h=start; h!=(start+DST_BLST_HASH_SIZE); h++){ i=h%DST_BLST_HASH_SIZE; if (dst_blst_hash[i].first){ LOCK_BLST(i); for (crt=&dst_blst_hash[i].first, tmp=&(*crt)->next; *crt; crt=tmp, tmp=&(*crt)->next){ e=*crt; prefetch_loc_r((*crt)->next, 1); if ((s_ticks_t)(now+delta-(*crt)->expire)>=0){ *crt=(*crt)->next; tmp=crt; *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e); blst_destroy_entry(e); BLST_HASH_STATS_DEC(i); no++; if (*blst_mem_used<=target){ UNLOCK_BLST(i); goto skip; } } } UNLOCK_BLST(i); /* check for timeout only "between" hash cells */ now=get_ticks_raw(); if ((now-start_time)>=timeout){ DBG("_dst_blacklist_clean_expired_unsafe: timeout: %d > %d\n", TICKS_TO_MS(now-start_time), TICKS_TO_MS(timeout)); goto skip; } } } skip: start=h; /* next time we start where we left */ if (no){ DBG("dst_blacklist_clean_expired, %d entries removed\n", no); } return no; }
/* must be called with the lock held * returns 1 if a matching entry was deleted, 0 otherwise * it also deletes expired elements (expire<=now) as it searches * proto==PROTO_NONE = wildcard */ inline static int _dst_blacklist_del( unsigned short hash, struct ip_addr* ip, unsigned char proto, unsigned short port, ticks_t now) { struct dst_blst_entry** crt; struct dst_blst_entry** tmp; struct dst_blst_entry* e; struct dst_blst_entry** head; unsigned char type; head=&dst_blst_hash[hash].first; #ifdef USE_IPV6 type=(ip->af==AF_INET6)*BLST_IS_IPV6; #else /* USE_IPV6 */ if (unlikely(ip->af!=AF_INET)) return 0; type=0; #endif /* USE_IPV6 */ for (crt=head, tmp=&(*head)->next; *crt; crt=tmp, tmp=&(*crt)->next){ e=*crt; prefetch_loc_r((*crt)->next, 1); /* remove old expired entries */ if ((s_ticks_t)(now-(*crt)->expire)>=0){ *crt=(*crt)->next; tmp=crt; *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e); BLST_HASH_STATS_DEC(hash); blst_destroy_entry(e); }else if ((e->port==port) && ((e->flags & BLST_IS_IPV6)==type) && ((e->proto==PROTO_NONE) || (proto==PROTO_NONE) || (e->proto==proto)) && (memcmp(ip->u.addr, e->ip, ip->len)==0)){ *crt=(*crt)->next; tmp=crt; *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e); BLST_HASH_STATS_DEC(hash); blst_destroy_entry(e); return 1; } } return 0; }
/* deletes all the entries from the blacklist except the permanent ones * (which are marked with BLST_PERMANENT) */ void dst_blst_flush(void) { int h; struct dst_blst_entry* e; struct dst_blst_entry** crt; struct dst_blst_entry** tmp; for(h=0; h<DST_BLST_HASH_SIZE; h++){ LOCK_BLST(h); for (crt=&dst_blst_hash[h].first, tmp=&(*crt)->next; *crt; crt=tmp, tmp=&(*crt)->next){ e=*crt; prefetch_loc_r((*crt)->next, 1); if (!(e->flags & BLST_PERMANENT)){ *crt=(*crt)->next; tmp=crt; *blst_mem_used-=DST_BLST_ENTRY_SIZE(*e); blst_destroy_entry(e); BLST_HASH_STATS_DEC(h); } } UNLOCK_BLST(h); } }
/* note: it continues where it previously stopped and goes ahead until end is encountered or desired HFs are found; if you call it twice for the same HF which is present only once, it will fail the second time; if you call it twice and the HF is found on second time too, it's not replaced in the well-known HF pointer but just added to header list; if you want to use a dumb convenience function which will give you the first occurrence of a header you are interested in, look at check_transaction_quadruple */ int parse_headers(struct sip_msg* const msg, const hdr_flags_t flags, const int next) { struct hdr_field* hf; char* tmp; char* rest; char* end; hdr_flags_t orig_flag; end=msg->buf+msg->len; tmp=msg->unparsed; if (unlikely(next)) { orig_flag = msg->parsed_flag; msg->parsed_flag &= ~flags; } else orig_flag=0; #ifdef EXTRA_DEBUG DBG("parse_headers: flags=%llx\n", (unsigned long long)flags); #endif while( tmp<end && (flags & msg->parsed_flag) != flags) { prefetch_loc_r(tmp+64, 1); hf=pkg_malloc(sizeof(struct hdr_field)); if (unlikely(hf==0)) { ser_error=E_OUT_OF_MEM; LOG(L_ERR, "ERROR:parse_headers: memory allocation error\n"); goto error; } memset(hf,0, sizeof(struct hdr_field)); hf->type=HDR_ERROR_T; rest=get_hdr_field(tmp, end, hf); switch (hf->type) { case HDR_ERROR_T: LOG(L_INFO,"ERROR: bad header field [%.*s]\n", (end-tmp>20)?20:(int)(end-tmp), tmp); goto error; case HDR_EOH_T: msg->eoh=tmp; /* or rest?*/ msg->parsed_flag|=HDR_EOH_F; pkg_free(hf); goto skip; case HDR_ACCEPTCONTACT_T: case HDR_ALLOWEVENTS_T: case HDR_CONTENTENCODING_T: case HDR_REFERREDBY_T: case HDR_REJECTCONTACT_T: case HDR_REQUESTDISPOSITION_T: case HDR_WWW_AUTHENTICATE_T: case HDR_PROXY_AUTHENTICATE_T: case HDR_RETRY_AFTER_T: case HDR_OTHER_T: /* mark the type as found/parsed*/ msg->parsed_flag|=HDR_T2F(hf->type); break; case HDR_CALLID_T: if (msg->callid==0) msg->callid=hf; msg->parsed_flag|=HDR_CALLID_F; break; case HDR_SIPIFMATCH_T: if (msg->sipifmatch==0) msg->sipifmatch=hf; msg->parsed_flag|=HDR_SIPIFMATCH_F; break; case HDR_TO_T: if (msg->to==0) msg->to=hf; msg->parsed_flag|=HDR_TO_F; break; case HDR_CSEQ_T: if (msg->cseq==0) msg->cseq=hf; msg->parsed_flag|=HDR_CSEQ_F; break; case HDR_FROM_T: if (msg->from==0) msg->from=hf; msg->parsed_flag|=HDR_FROM_F; break; case HDR_CONTACT_T: if (msg->contact==0) msg->contact=hf; msg->parsed_flag|=HDR_CONTACT_F; break; case HDR_MAXFORWARDS_T: if(msg->maxforwards==0) msg->maxforwards=hf; msg->parsed_flag|=HDR_MAXFORWARDS_F; break; case HDR_ROUTE_T: if (msg->route==0) msg->route=hf; msg->parsed_flag|=HDR_ROUTE_F; break; case HDR_RECORDROUTE_T: if (msg->record_route==0) msg->record_route = hf; msg->parsed_flag|=HDR_RECORDROUTE_F; break; case HDR_CONTENTTYPE_T: if (msg->content_type==0) msg->content_type = hf; msg->parsed_flag|=HDR_CONTENTTYPE_F; break; case HDR_CONTENTLENGTH_T: if (msg->content_length==0) msg->content_length = hf; msg->parsed_flag|=HDR_CONTENTLENGTH_F; break; case HDR_AUTHORIZATION_T: if (msg->authorization==0) msg->authorization = hf; msg->parsed_flag|=HDR_AUTHORIZATION_F; break; case HDR_EXPIRES_T: if (msg->expires==0) msg->expires = hf; msg->parsed_flag|=HDR_EXPIRES_F; break; case HDR_PROXYAUTH_T: if (msg->proxy_auth==0) msg->proxy_auth = hf; msg->parsed_flag|=HDR_PROXYAUTH_F; break; case HDR_PROXYREQUIRE_T: if (msg->proxy_require==0) msg->proxy_require = hf; msg->parsed_flag|=HDR_PROXYREQUIRE_F; break; case HDR_SUPPORTED_T: if (msg->supported==0) msg->supported=hf; msg->parsed_flag|=HDR_SUPPORTED_F; break; case HDR_REQUIRE_T: if (msg->require==0) msg->require=hf; msg->parsed_flag|=HDR_REQUIRE_F; break; case HDR_UNSUPPORTED_T: if (msg->unsupported==0) msg->unsupported=hf; msg->parsed_flag|=HDR_UNSUPPORTED_F; break; case HDR_ALLOW_T: if (msg->allow==0) msg->allow = hf; msg->parsed_flag|=HDR_ALLOW_F; break; case HDR_EVENT_T: if (msg->event==0) msg->event = hf; msg->parsed_flag|=HDR_EVENT_F; break; case HDR_ACCEPT_T: if (msg->accept==0) msg->accept = hf; msg->parsed_flag|=HDR_ACCEPT_F; break; case HDR_ACCEPTLANGUAGE_T: if (msg->accept_language==0) msg->accept_language = hf; msg->parsed_flag|=HDR_ACCEPTLANGUAGE_F; break; case HDR_ORGANIZATION_T: if (msg->organization==0) msg->organization = hf; msg->parsed_flag|=HDR_ORGANIZATION_F; break; case HDR_PRIORITY_T: if (msg->priority==0) msg->priority = hf; msg->parsed_flag|=HDR_PRIORITY_F; break; case HDR_SUBJECT_T: if (msg->subject==0) msg->subject = hf; msg->parsed_flag|=HDR_SUBJECT_F; break; case HDR_USERAGENT_T: if (msg->user_agent==0) msg->user_agent = hf; msg->parsed_flag|=HDR_USERAGENT_F; break; case HDR_SERVER_T: if (msg->server==0) msg->server = hf; msg->parsed_flag|=HDR_SERVER_F; break; case HDR_CONTENTDISPOSITION_T: if (msg->content_disposition==0) msg->content_disposition = hf; msg->parsed_flag|=HDR_CONTENTDISPOSITION_F; break; case HDR_DIVERSION_T: if (msg->diversion==0) msg->diversion = hf; msg->parsed_flag|=HDR_DIVERSION_F; break; case HDR_RPID_T: if (msg->rpid==0) msg->rpid = hf; msg->parsed_flag|=HDR_RPID_F; break; case HDR_REFER_TO_T: if (msg->refer_to==0) msg->refer_to = hf; msg->parsed_flag|=HDR_REFER_TO_F; break; case HDR_SESSIONEXPIRES_T: if (msg->session_expires==0) msg->session_expires = hf; msg->parsed_flag|=HDR_SESSIONEXPIRES_F; break; case HDR_MIN_SE_T: if (msg->min_se==0) msg->min_se = hf; msg->parsed_flag|=HDR_MIN_SE_F; break; case HDR_SUBSCRIPTION_STATE_T: if (msg->subscription_state==0) msg->subscription_state = hf; msg->parsed_flag|=HDR_SUBSCRIPTION_STATE_F; break; case HDR_VIA_T: msg->parsed_flag|=HDR_VIA_F; DBG("parse_headers: Via found, flags=%llx\n", (unsigned long long)flags); if (msg->via1==0) { DBG("parse_headers: this is the first via\n"); msg->h_via1=hf; msg->via1=hf->parsed; if (msg->via1->next) { msg->via2=msg->via1->next; msg->parsed_flag|=HDR_VIA2_F; } } else if (msg->via2==0) { msg->h_via2=hf; msg->via2=hf->parsed; msg->parsed_flag|=HDR_VIA2_F; DBG("parse_headers: this is the second via\n"); } break; case HDR_DATE_T: if (msg->date==0) msg->date=hf; msg->parsed_flag|=HDR_DATE_F; break; case HDR_IDENTITY_T: if (msg->identity==0) msg->identity=hf; msg->parsed_flag|=HDR_IDENTITY_F; break; case HDR_IDENTITY_INFO_T: if (msg->identity_info==0) msg->identity_info=hf; msg->parsed_flag|=HDR_IDENTITY_INFO_F; break; case HDR_PATH_T: if (msg->path==0) msg->path=hf; msg->parsed_flag|=HDR_PATH_F; break; case HDR_PRIVACY_T: if (msg->privacy==0) msg->privacy=hf; msg->parsed_flag|=HDR_PRIVACY_F; break; case HDR_PAI_T: if (msg->pai==0) msg->pai=hf; msg->parsed_flag|=HDR_PAI_F; break; case HDR_PPI_T: if (msg->ppi==0) msg->ppi=hf; msg->parsed_flag|=HDR_PPI_F; break; case HDR_REASON_T: msg->parsed_flag|=HDR_REASON_F; break; default: LOG(L_CRIT, "BUG: parse_headers: unknown header type %d\n", hf->type); goto error; } /* add the header to the list*/ if (msg->last_header==0) { msg->headers=hf; msg->last_header=hf; } else { msg->last_header->next=hf; msg->last_header=hf; } #ifdef EXTRA_DEBUG DBG("header field type %d, name=<%.*s>, body=<%.*s>\n", hf->type, hf->name.len, ZSW(hf->name.s), hf->body.len, ZSW(hf->body.s)); #endif tmp=rest; } skip: msg->unparsed=tmp; /* restore original flags */ msg->parsed_flag |= orig_flag; return 0; error: ser_error=E_BAD_REQ; if (hf) pkg_free(hf); /* restore original flags */ msg->parsed_flag |= orig_flag; return -1; }